牛客项目学习第四章

一、Redis入门

  • Redis是一款基于键值对的NoSQL数据库,它的值支持多种数据结构:
    字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。
  • Redis将所有的数据都存放在内存中,所以它的读写性能十分惊人。
    同时,Redis还可以将内存中的数据以快照或日志的形式保存到硬盘上,以保证数据的安全性。
  • Redis典型的应用场景包括:缓存、排行榜、计数器、社交网络、消息队列等。

redis相关链接:官网,github

Redis使用演示

1.reids默认有16个库,从0-15,可以使用下边的语句切换

select [index]

牛客项目学习第四章_第1张图片

2.刷新数据库FLUSHDB命令,如下
牛客项目学习第四章_第2张图片
3.String类型的演示

set key value [EX seconds] [PX milliseconds] [NX|XX]
get key
incr key
decr key

4.hash类型数据

hset key field value
hget key field

5.list类型数据

lpush key value [value ...]
llen key
lindex key index
lrange key start stop
lpop key
rpush key value [value ...]
rpop key

6.set类型数据

sadd key member [member ...]
scard key  //统计集合中有多少元素,输出个数
spop key [count]  //随机从集合中弹出数据
smembers key  //相比于scard来说,输出set中所有的member

7.sortset类型数据

zadd key [NX|XX] [CH] [INCR] score member [score member ...]
zcard key
zscore key member
zrank key member  //返回排名
zrange key start stop [WITHSCORES]

8.常用命令

keys *
type key
exists key [key ...]
del key
expire key seconds

二、 Spring整合Redis

  • 引入依赖
    • spring-boot-starter-data-redis
  • 配置Redis
    • 配置数据库参数
    • 编写配置类,构造RedisTemplate
  • 访问Redis
    • redisTemplate.opsForValue()
    • redisTemplate.opsForHash()
    • redisTemplate.opsForList()
    • redisTemplate.opsForSet()
    • redisTemplate.opsForZSet()

导包

日常操作你懂得

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

配置Redis

application.properties中
牛客项目学习第四章_第3张图片

  • database=11表示使用第12个库

因为RedisTemplate是类型的不利于我们操作所以要写一个配置类
牛客项目学习第四章_第4张图片
RedisConfig 配置类

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String,Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //设置key的序列化方式
        template.setKeySerializer(RedisSerializer.string());
        //设置value的序列化方式
        template.setValueSerializer(RedisSerializer.json());
        //设置hash的key序列化方式
        template.setHashKeySerializer(RedisSerializer.string());
        //设置hash的value的序列化方式
        template.setHashValueSerializer(RedisSerializer.json());
        template.afterPropertiesSet();
        return template;
    }
}

RedisTemplate访问redis

1.写一个测试类

@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testStrings() {
        String redisKey = "test:count";

        redisTemplate.opsForValue().set(redisKey, 1);

        System.out.println(redisTemplate.opsForValue().get(redisKey));
        System.out.println(redisTemplate.opsForValue().increment(redisKey));
        System.out.println(redisTemplate.opsForValue().decrement(redisKey));
    }

    @Test
    public void testHashes() {
        String redisKey = "test:user";

        redisTemplate.opsForHash().put(redisKey, "id", 1);
        redisTemplate.opsForHash().put(redisKey, "username", "zhangsan");

        System.out.println(redisTemplate.opsForHash().get(redisKey, "id"));
        System.out.println(redisTemplate.opsForHash().get(redisKey, "username"));
    }

    @Test
    public void testLists() {
        String redisKey = "test:ids";

        redisTemplate.opsForList().leftPush(redisKey, 101);
        redisTemplate.opsForList().leftPush(redisKey, 102);
        redisTemplate.opsForList().leftPush(redisKey, 103);

        System.out.println(redisTemplate.opsForList().size(redisKey));
        System.out.println(redisTemplate.opsForList().index(redisKey, 0));
        System.out.println(redisTemplate.opsForList().range(redisKey, 0, 2));

        System.out.println(redisTemplate.opsForList().leftPop(redisKey));
        System.out.println(redisTemplate.opsForList().leftPop(redisKey));
        System.out.println(redisTemplate.opsForList().leftPop(redisKey));
    }

    @Test
    public void testSets() {
        String redisKey = "test:teachers";

        redisTemplate.opsForSet().add(redisKey, "刘备", "关羽", "张飞", "赵云", "诸葛亮");

        System.out.println(redisTemplate.opsForSet().size(redisKey));
        System.out.println(redisTemplate.opsForSet().pop(redisKey));
        System.out.println(redisTemplate.opsForSet().members(redisKey));
    }

    @Test
    public void testSortedSets() {
        String redisKey = "test:students";

        redisTemplate.opsForZSet().add(redisKey, "唐僧", 80);
        redisTemplate.opsForZSet().add(redisKey, "悟空", 90);
        redisTemplate.opsForZSet().add(redisKey, "八戒", 50);
        redisTemplate.opsForZSet().add(redisKey, "沙僧", 70);
        redisTemplate.opsForZSet().add(redisKey, "白龙马", 60);

        System.out.println(redisTemplate.opsForZSet().zCard(redisKey));
        System.out.println(redisTemplate.opsForZSet().score(redisKey, "八戒"));
        System.out.println(redisTemplate.opsForZSet().reverseRank(redisKey, "八戒"));
        System.out.println(redisTemplate.opsForZSet().reverseRange(redisKey, 0, 2));
    }

    @Test
    public void testKeys() {
        redisTemplate.delete("test:user");

        System.out.println(redisTemplate.hasKey("test:user"));

        redisTemplate.expire("test:students", 10, TimeUnit.SECONDS);
    }

    // 多次访问同一个key
    @Test
    public void testBoundOperations() {
        String redisKey = "test:count";
        BoundValueOperations operations = redisTemplate.boundValueOps(redisKey);
        operations.increment();
        operations.increment();
        operations.increment();
        operations.increment();
        operations.increment();
        System.out.println(operations.get());
    }
	//声明式事务作用于整个方法,方法中需要查询时就不合适了,所以演示编程式事务
    // 编程式事务
    @Test
    public void testTransactional() {
        Object obj = redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String redisKey = "test:tx";

                operations.multi();

                operations.opsForSet().add(redisKey, "zhangsan");
                operations.opsForSet().add(redisKey, "lisi");
                operations.opsForSet().add(redisKey, "wangwu");
				//显示为[],所以一定不要在redis事务中做查询。
                System.out.println(operations.opsForSet().members(redisKey));
                return operations.exec();
            }
        });
        //这里会显示所有的操作结果
        System.out.println(obj);
    }
}

三、点赞

  • 点赞
    • 支持对帖子、评论点赞。
    • 第1次点赞,第2次取消点赞。
  • 首页点赞数量
    • 统计帖子的点赞数量。
  • 详情页点赞数量
    • 统计点赞数量。
    • 显示点赞状态。

牛客项目学习第四章_第5张图片

Redis生成key的工具类

public class RedisUtil {
    private static final String SPLIT=":";
    private static final String PREFIX_ENTITY_LIKE = "like:entity";
    
    //某个实体的赞
    //key长这个样:like:entity:entityType:entityId
    //value是个set:存的是用户id,为了统计谁给我点了赞
    public static String getEntityLikeKey(int entityType,int entityId){
        return PREFIX_ENTITY_LIKE+SPLIT+entityType+SPLIT+entityId;
    }
}

业务层

@Service
public class LikeService {
    @Autowired
    private RedisTemplate redisTemplate;
    
    //点赞
    public void like(int userId,int entityType,int entityId){
        String entityLikeKey = RedisUtil.getEntityLikeKey(entityType,entityId);
        //第一次点是点赞,第二次点是取消赞
        //先判断是否点过赞  value是set集合存的是userId
        Boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);
        if(isMember){
            //说明点过赞,这次是取消赞
            redisTemplate.opsForSet().remove(entityLikeKey,userId);
        }else{
            //说明是第一次点赞
            redisTemplate.opsForSet().add(entityLikeKey,userId);
        }
    }
    //查询实体点赞的数量
    public long findEntityLikeCount(int entityType,int entityId){
        String entityLikeKey = RedisUtil.getEntityLikeKey(entityType,entityId);
        return redisTemplate.opsForSet().size(entityLikeKey);
    }
    //查询某人对某实体的点赞状态
    //返回int 是为了以后业务扩展 比如点了踩啥的记录状态
    public int findEntityLikeStatus(int userId,int entityType,int entityId){
        String entityLikeKey = RedisUtil.getEntityLikeKey(entityType,entityId);
        return redisTemplate.opsForSet().isMember(entityLikeKey,userId)?1:0;
    }
}

表现层:点赞功能的实现

@Controller
public class LikeController {
    @Autowired
    private LikeService likeService;
    @Autowired
    private HostHolder hostHolder;
    
    @RequestMapping(path = "/like",method = RequestMethod.POST)
    @ResponseBody
    public String like(int entityType,int entityId){
        User user = hostHolder.getUser();
        //实现点赞
        likeService.like(user.getId(),entityType,entityId);
        //统计数量
        long likeCount = likeService.findEntityLikeCount(entityType,entityId);
        //状态
        int likeStatus = likeService.findEntityLikeStatus(user.getId(),entityType,entityId);
        Map<String,Object> map = new HashMap<>();
        map.put("likeCount",likeCount);
        map.put("likeStatus",likeStatus);
        return CommunityUtil.getJsonString(0,null,map);
    }
}

处理页面

1.帖子点赞
牛客项目学习第四章_第6张图片

  • href的东西表名跳转的地方是找js的方法
  • onclick里的like方法有三个参数
    • this用来标志是哪里点的赞(帖子可以点赞,用户评论也可以点赞)
    • 1表明是给帖子点赞
    • post.id是帖子的id号
  • 为了方便显示数据把 赞 这个字用< b >标签包围,11用< i >包围

2.评论点赞

牛客项目学习第四章_第7张图片

  • 2表明给帖子评论点赞,其他同理

3.评论的回复点赞
牛客项目学习第四章_第8张图片- 3表示给评论回复点赞

4.处理js
在这里插入图片描述

  • 新建一个discuss.js
function like(btn,entityType,entityId) {
	$.post(
		CONTEXT_PATH+"/like",
		{"entityType":entityType,"entityId":entityId},
		function (data) {
			/*转化成json*/
			data = $.parseJSON(data);
			if(data.code==0){
				$(btn).children("i").text(data.likeCount);
				$(btn).children("b").text(data.likeStatus==1?"已赞":"赞");
			}else{
				alert(data.msg);
			}
		}
	);
}

表现层:点赞数量的显示

1.首页上点赞数量的显示
HomeController中getIndexPage方法
牛客项目学习第四章_第9张图片处理index.html
牛客项目学习第四章_第10张图片2.帖子详情·页面上点赞数量的显示
牛客项目学习第四章_第11张图片
页面处理
牛客项目学习第四章_第12张图片

四、我收到的赞

  • 重构点赞功能
    • 以用户为key,记录点赞数量
    • increment(key),decrement(key)
  • 开发个人主页
    • 以用户为key,查询点赞数量

牛客项目学习第四章_第13张图片

重构点赞功能

1.在RedisUtil中加一个key
牛客项目学习第四章_第14张图片2.LikeService增加一个操作记录用户获得点赞的数量
并用编程式事务完成。想想为啥不用声明式事务—代码中有答案

//点赞
    public void like(int userId,int entityType,int entityId,int entityUserId){  //entityUserId 就是被点赞的user的Id
/*        String entityLikeKey = RedisUtil.getEntityLikeKey(entityType,entityId);
        //第一次点是点赞,第二次点是取消赞
        //先判断是否点过赞  value是set集合存的是userId
        Boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);
        if(isMember){
            //说明点过赞,这次是取消赞
            redisTemplate.opsForSet().remove(entityLikeKey,userId);
        }else{
            //说明是第一次点赞
            redisTemplate.opsForSet().add(entityLikeKey,userId);
        }*/
        //编程式事务
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                String entityLikeKey = RedisUtil.getEntityLikeKey(entityType,entityId);
                String userLikeKey = RedisUtil.getUserLikeKey(entityUserId);
                //判断当前用户有没有点赞,这一步应该在事务开启前执行,因为在事务中的查询不会立即得到结果
                Boolean isMember = redisOperations.opsForSet().isMember(entityLikeKey, userId);
                //事务开启
                redisOperations.multi();
                if(isMember){
                    //说明点过赞,这次是取消赞
                    redisTemplate.opsForSet().remove(entityLikeKey,userId);
                    //被点赞的用户点赞数量减一
                    redisOperations.opsForValue().decrement(userLikeKey);

                }else{
                    //说明是第一次点赞
                    redisTemplate.opsForSet().add(entityLikeKey,userId);
                    //被点赞的用户点赞数量加一
                    redisOperations.opsForValue().increment(userLikeKey);
                }
                return redisOperations.exec();
            }
        });

    }

3.LikeService增加查询某个用户获得赞的数量
牛客项目学习第四章_第15张图片4.重构表现层
牛客项目学习第四章_第16张图片
detail页面
牛客项目学习第四章_第17张图片
js
牛客项目学习第四章_第18张图片

开发个人主页

1.UserController增加找用户页面的方法

@Autowired
    private LikeService likeService;
    //个人主页
    @RequestMapping(path = "/profile/{userId}",method = RequestMethod.GET)
    public String getProfilePage(@PathVariable("userId")int userId,Model model){
        User user = userService.findUserById(userId);
        if(user==null){
            throw new RuntimeException("该用户不存在");
        }
        //用户
        model.addAttribute("user",user);
        int likeCount = likeService.findUserLikeCount(user.getId());
        model.addAttribute("likeCount",likeCount);
        return "/site/profile";
    }

2.处理index.html中的链接
牛客项目学习第四章_第19张图片
所有用户头像也得加链接
这里只处理了首页上的,其他的暂时没有处理。
牛客项目学习第四章_第20张图片3.处理profile.html
牛客项目学习第四章_第21张图片

五、关注、取消关注

  • 需求
    • 开发关注、取消关注功能。
    • 统计用户的关注数、粉丝数。
  • 关键
    • 若A关注了B,则A是B的Follower(粉丝),B是A的Followee(目标)。
    • 关注的目标可以是用户、帖子、题目等,在实现时将这些目标抽象为实体。

RedisUtil中增加获得key的方法

牛客项目学习第四章_第22张图片

业务层

@Service
public class FollowService {
    @Autowired
    private RedisTemplate redisTemplate;
    //关注
    public void follow(int userId,int entityType,int entityId){
        //还得依靠事务解决,因为有多次操作
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                String followee = RedisUtil.getFolloweeKey(userId,entityType);
                String follower = RedisUtil.getFollowerKey(entityType,entityId);
                //启用事务
                redisOperations.multi();
                //userId关注entityId
                redisOperations.opsForZSet().add(followee,entityId,System.currentTimeMillis());
                //entityId的粉丝是userId
                redisOperations.opsForZSet().add(follower,userId,System.currentTimeMillis());
                return redisOperations.exec();
            }
        });
    }
    //取消关注
    public void unFollow(int userId,int entityType,int entityId){
        //还得依靠事务解决,因为有多次操作
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                String followee = RedisUtil.getFolloweeKey(userId,entityType);
                String follower = RedisUtil.getFollowerKey(entityType,entityId);
                //启用事务
                redisOperations.multi();
                //userId没有关注谁
                redisOperations.opsForZSet().remove(followee,entityId);
                //谁的粉丝没有userId
                redisOperations.opsForZSet().remove(follower,userId);
                return redisOperations.exec();
            }
        });
    }
    //查询关注的实体的数量
    public long findFolloweeCount(int userId,int entityType){
        String followee = RedisUtil.getFolloweeKey(userId,entityType);
        return redisTemplate.opsForZSet().zCard(followee);
    }
    //查询实体的粉丝数量
    public long findFollowerCount(int entityType,int entityId){
        String follower = RedisUtil.getFollowerKey(entityType,entityId);
        return redisTemplate.opsForZSet().zCard(follower);
    }
    //查询当前用户是否关注该实体
    public boolean hasFollowed(int userId,int entityType,int entityId){
        String followee = RedisUtil.getFolloweeKey(userId,entityType);
        return redisTemplate.opsForZSet().score(followee,entityId)!=null?true:false;
    }
}

表现层

FollowController

@Controller
public class FollowController {
    @Autowired
    private FollowService followService;
    @Autowired
    private HostHolder hostHolder;
    @RequestMapping(path = "/follow",method = RequestMethod.POST)
    @ResponseBody
    public String follow(int entityType,int entityId){
        User user = hostHolder.getUser();
        if(user==null){
            throw new RuntimeException("用户没有登录");
        }
        followService.follow(user.getId(),entityType,entityId);
        return CommunityUtil.getJsonString(0,"已关注");
    }
    @RequestMapping(path = "/unfollow",method = RequestMethod.POST)
    @ResponseBody
    public String unfollow(int entityType,int entityId){
        User user = hostHolder.getUser();
        if(user==null){
            throw new RuntimeException("用户没有登录");
        }
        followService.unFollow(user.getId(),entityType,entityId);
        return CommunityUtil.getJsonString(0,"已取消关注");
    }
}

UserController中如下方法增加功能
牛客项目学习第四章_第23张图片牛客项目学习第四章_第24张图片

页面处理

因为各种地方都可以关注,此处只演示在用户主页关注人,其他大同小异
牛客项目学习第四章_第25张图片继续改成这样,处理关注按钮
牛客项目学习第四章_第26张图片

在profile.js中写处理逻辑

$(function(){
	$(".follow-btn").click(follow);
});

function follow() {
	var btn = this;
	if($(btn).hasClass("btn-info")) {
		// 关注TA
		$.post(
			CONTEXT_PATH+"/follow",
			{"entityType":4,"entityId":$(btn).prev().val()},
			function (data) {
				data = $.parseJSON(data);
				if(data.code==0){
					window.location.reload();
				}else{
					alert(data.msg)
				}
			}
		)
	} else {
		// 取消关注
		$.post(
			CONTEXT_PATH+"/unfollow",
			{"entityType":4,"entityId":$(btn).prev().val()},
			function (data) {
				data = $.parseJSON(data);
				if(data.code==0){
					window.location.reload();
				}else{
					alert(data.msg)
				}
			}
		)
		//$(btn).text("关注TA").removeClass("btn-secondary").addClass("btn-info");
	}
}

继续修改profile.html处理显示
在这里插入图片描述

六、关注列表、粉丝列表

  • 业务层
    • 查询某个用户关注的人,支持分页。
    • 查询某个用户的粉丝,支持分页。
  • 表现层
    • 处理“查询关注的人”、“查询粉丝”请求。
    • 编写“查询关注的人”、“查询粉丝”模板。

业务层

FollowService中增加方法

@Autowired
    private UserService userService;
    //查询某个用户关注的人
    public List<Map<String,Object>> findFollowees(int userId,int offset,int limit){
        String followee = RedisUtil.getFolloweeKey(userId,ENTITY_USER);
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followee, offset, offset + limit - 1);
        if(targetIds==null){
            return null;
        }
        List<Map<String,Object>> list = new ArrayList<>();
        for(Integer id:targetIds){
            Map<String,Object> map = new HashMap<>();
            User user = userService.findUserById(id);
            //用户
            map.put("user",user);
            Double score = redisTemplate.opsForZSet().score(followee, id);
            //关注时间
            map.put("followTime",new Date(score.longValue()));
            list.add(map);
        }
        return list;
    } 
    //查询某个用户的粉丝
    public List<Map<String,Object>> findFollowers(int userId,int offset,int limit){
        String follower = RedisUtil.getFollowerKey(ENTITY_USER,userId);
        //虽然返回的是set但是是redis内置实现了一个set可以有序排列
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(follower, offset, offset + limit - 1);
        if(targetIds==null){
            return null;
        }
        List<Map<String,Object>> list = new ArrayList<>();
        for(Integer id:targetIds){
            Map<String,Object> map = new HashMap<>();
            User user = userService.findUserById(id);
            //用户
            map.put("user",user);
            Double score = redisTemplate.opsForZSet().score(follower, id);
            //关注时间
            map.put("followTime",new Date(score.longValue()));
            list.add(map);
        }
        return list;
    }

表现层

1.某个用户关注了谁—FollowController增加如下方法

@Autowired
    private UserService userService;
    @RequestMapping(path="/followees/{userId}",method = RequestMethod.GET)
    public String getFollowees(@PathVariable("userId")int userId, Page page, Model model){
        //页面需要用username
        User user = userService.findUserById(userId);
        if(user==null){
            throw new RuntimeException("该用户不存在");
        }
        model.addAttribute("user",user);
        page.setLimit(5);
        page.setPath("/followees/"+userId);
        page.setRows((int)followService.findFolloweeCount(userId,ENTITY_USER));
        List<Map<String, Object>> followees = followService.findFollowees(userId, page.getOffset(), page.getLimit());
        if(followees!=null){
            for(Map<String,Object> map:followees){
                //判段当前用户对这个用户的关注状态
                User followeeUser = (User)map.get("user");
                boolean hasFollowed = hasFollowed(followeeUser.getId());
                map.put("hasFollowed",hasFollowed);
            }
        }
        model.addAttribute("users",followees);
        return "/site/followee";
    }
    private boolean hasFollowed(int userId){
        if(hostHolder.getUser()==null){
            return false;
        }
        return followService.hasFollowed(hostHolder.getUser().getId(),CommunityContant.ENTITY_USER,userId);
    }

2.某个用户的粉丝

 @RequestMapping(path="/followers/{userId}",method = RequestMethod.GET)
    public String getFollowers(@PathVariable("userId")int userId, Page page, Model model){
        //页面需要用username
        User user = userService.findUserById(userId);
        if(user==null){
            throw new RuntimeException("该用户不存在");
        }
        model.addAttribute("user",user);
        page.setLimit(5);
        page.setPath("/followers/"+userId);
        page.setRows((int)followService.findFollowerCount(ENTITY_USER,userId));
        List<Map<String, Object>> followers = followService.findFollowers(userId, page.getOffset(), page.getLimit());
        if(followers!=null){
            for(Map<String,Object> map:followers){
                //判段当前用户对这个用户的关注状态
                User followeeUser = (User)map.get("user");
                boolean hasFollowed = hasFollowed(followeeUser.getId());
                map.put("hasFollowed",hasFollowed);
            }
        }
        model.addAttribute("users",followers);
        return "/site/follower";
    }

处理页面

1.profile.html

在这里插入图片描述
2.followee.html
牛客项目学习第四章_第27张图片3.follower.html

同理,仔细点尤其是处理已关注未关注按钮那里

七、优化登录模块

  • 使用Redis存储验证码
    • 验证码需要频繁的访问与刷新,对性能要求较高。
    • 验证码不需永久保存,通常在很短的时间后就会失效。
    • 分布式部署时,存在Session共享的问题。
  • 使用Redis存储登录凭证
    • 处理每次请求时,都要查询用户的登录凭证,访问的频率非常高。
  • 使用Redis缓存用户信息
    • 处理每次请求时,都要根据凭证查询用户信息,访问的频率非常高。

使用Redis存储验证码

最初,我们把验证码存在了session里,这样不好。使用Redis存验证码的好处:

  • Redis性能较高
  • Redis可以设置失效时间
  • 存到Redis里分布式部署的时候避免了Session共享的问题

1.RedisUtil中增加存储验证码的key
牛客项目学习第四章_第28张图片
2.LoginController里方法
修改getKaptcha方法
牛客项目学习第四章_第29张图片
修改Login方法
牛客项目学习第四章_第30张图片

使用Redis存储登录凭证

最初,我们把登陆凭证存到了MySql里,每次都需要频繁的查询,因为设置了拦截器查询登陆状态。替换用login_ticket表存数据
牛客项目学习第四章_第31张图片

1.RedisUtil中定义key

牛客项目学习第四章_第32张图片

2.LoginTicketMapper加@Deprecated注解表名不推荐使用
牛客项目学习第四章_第33张图片3.重构代码主要集中在UserService和LoginService中
1.LoginService中login方法
牛客项目学习第四章_第34张图片2.LoginService中logout方法
牛客项目学习第四章_第35张图片
3.UserService中findLoginTicket方法
牛客项目学习第四章_第36张图片

使用Redis缓存用户信息

就是查询用户的时候先从Redis中取,没有的话先从数据库中取然后存到redis中。用户状态变化时直接删除Redis中的数据。
1.RedisUtil中增加key
牛客项目学习第四章_第37张图片

2.在UserService中封装三个方法:

  • 从redis中取数据
    牛客项目学习第四章_第38张图片
  • redis没有的时候数据库找到user后写入redis
    牛客项目学习第四章_第39张图片
  • 数据变更时删除缓存
    牛客项目学习第四章_第40张图片

3.其他涉及查询User的地方调这三个方法

牛客项目学习第四章_第41张图片牛客项目学习第四章_第42张图片牛客项目学习第四章_第43张图片

当然还有其他可以修改的

你可能感兴趣的:(牛客项目)