ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

四、Redis,一站式高性能存储方案

2021-07-01 09:03:53  阅读:171  来源: 互联网

标签:return String 一站式 int Redis userId 高性能 user public


、Redis,一站式高性能存储方案

在这里插入图片描述

4.1、spring整合redis

  • 导入依赖:spring-boot-starter-data-redis

    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-data-redis</artifactId>
    		</dependency>
    
  • 配置redis

    • 配置数据库参数
    # RedisProperties
    spring.redis.database=11
    spring.redis.host=localhost
    spring.redis.port=6379
    
    • 编写配置类,构造RedisTemplate

      config.RedisConfig.java

      @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;
          }
      }
      
  • 访问redis

    • redisTemplate.opsForValue()
    • redisTemplate.opsForHash()
    • redisTemplate.opsForList()
    • redisTemplate.opsForSet()
    • redisTemplate.opsForZSet()
        // 多次访问同一个key
        @Test
        public void testBoundOperations() {
            String redisKey = "test:count";
            BoundValueOperations operations = redisTemplate.boundValueOps(redisKey);
            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");
    
                    System.out.println(operations.opsForSet().members(redisKey));//[]
    
                    return operations.exec();
                }
            });
            System.out.println(obj);//[1, 1, 1, [zhangsan, lisi, wangwu]]
        }
    

4.2、点赞

在这里插入图片描述

(1)service层

生成key的工具类RedisKeyUtil

直接写业务层,调用redisTemplate往redis中读取和存入数据即可,面向key编程,为了能够复用key,先创建一个可生成key的工具类: RedisKeyUtil,有些key是静态常量的,而有些key是动态的,由方法加入更明确的值并返回。

RedisKeyUtil.java:

实体的赞使用set集合,里面放入的是多个用户的id。set(userId), 既可以获取当前实体点赞数量,又可以获取点赞的用户,能够最大程度地满足各种各样需求的变化。

public class RedisKeyUtil {

    private static final String SPLIT = ":";
    private static final String PREFIX_ENTITY_LIKE = "like:entity";
    private static final String PREFIX_USER_LIKE = "like:user";

    // 某个实体的赞.entityType:被点赞的实体:帖子1、评论2、回复3;
    // like:entity:entityType:entityId -> set(userId)
    public static String getEntityLikeKey(int entityType, int entityId) {
        return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId;
    }
}

LikeService

@Service
public class LikeService {
    @Autowired
    private RedisTemplate redisTemplate;
    //点赞
    //userID:谁点的赞;entityType:被点赞的实体:帖子1、评论2、回复3;
    public void like(int userId, int entityType, int entityId){
        //先拼好两个key
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        //判断某个用户是否对某个实体点过赞
        boolean isMember = operations.opsForSet().isMember(entityLikeKey,userId);
        if(isMember){
            operations.opsForSet().remove(entityLikeKey, userId);
        }
        else{
            operations.opsForSet().add(entityLikeKey, userId);
        }
    }

    // 查询某实体被点赞的数量
    public long findEntityLikeCount(int entityType, int entityId) {
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().size(entityLikeKey);
    }

    // 查询某人对某实体的点赞状态
    public int findEntityLikeStatus(int userId, int entityType, int entityId) {
        String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().isMember(entityLikeKey, userId) ? 1 : 0;
    }
}

(2)controller层

LikeController

异步请求:

@Controller
public class LikeController implements CommunityConstant {
    @Autowired
    private LikeService likeService;
 
    @Autowired
    private HostHolder hostHolder;
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @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);
    }
}

discuss-detail.html:

可以给三个地方点赞:给帖子点赞、给评论点赞、给回复点赞

HomeController

完善在首页显示帖子点赞的数量

    @Autowired
    private LikeService likeService;
	
	@RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page) {
        //.....
        long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, post.getId());
        map.put("likeCount", likeCount);
        //.....
    }

index.html

DiscussPostController

方法getDiscussPost获取帖子详情中

(1) 增加获取帖子点赞数量的处理代码

//点赞数量
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST,discussPostId);
model.addAttribute("likeCount", likeCount);
//点赞状态(当前用户是否对帖子点过赞),如果用户未登录的话,也是显示未赞的状态
//likeStatus 为0,否则再去查询
int likeStatus = 0;
if(hostHolder.getUser() != null){
    likeStatus = likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_POST, discussPostId);

(2) 对评论做相同的处理

likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT,comment.getId());
commentVo.put("likeCount", likeCount);
//点赞状态
likeStatus = 0;
if(hostHolder.getUser() != null){
    likeStatus = likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_COMMENT, comment.getId());
}
commentVo.put("likeStatus", likeStatus)

(3) 对回复做相同的处理

likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT,reply.getId());
replyVo.put("likeCount", likeCount);
//点赞状态
likeStatus = 0;
if(hostHolder.getUser() != null){
    likeStatus = likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_COMMENT, reply.getId());
}
replyVo.put("likeStatus", likeStatus);

discuss-detail.html

4.3、我收到的赞

在这里插入图片描述

在用户点赞的是时候,增加一个维度。

RedisKeyUtil

//某个用户的赞
private static final String PREFIX_USER_LIKE = "like:user";

//like:user:userId -> int
public static String getUserLikeKey(int useId){
    return PREFIX_USER_LIKE + SPLIT + useId;
}

LikeService(涉及事务)

涉及到了多个操作,使用事务,另外,查询要放到事务之外,如果放到事务之内,不会立马就返回查询结果

    //userID:谁点的赞;entityType:被点赞的实体:帖子1、评论2、回复3;entityID:实体id
	//entityUserId:被赞的用户id
    public void like(int userId, int entityType, int entityId, int entityUserId){
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {

                String entityLikeKey = 
                    RedisKeyUtil.getEntityLikeKey(entityType, entityId);
                //被赞的用户id的key
                String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId);
                //判断某个用户是否对某个实体点过赞
                boolean isMember =
                    operations.opsForSet().isMember(entityLikeKey,userId);
                operations.multi();//开启事务:放在查询之后
                if(isMember){//取消赞
                    operations.opsForSet().remove(entityLikeKey, userId);
                    operations.opsForValue().decrement(userLikeKey);
                }else{//点赞
                    operations.opsForSet().add(entityLikeKey, userId);
                    if(operations.opsForValue().get(userLikeKey) == null){
                        operations.opsForValue().set(userLikeKey, 0);
                    }
                    operations.opsForValue().increment(userLikeKey);
                }
                return operations.exec();//表示的是提交事务
            }
        });
    }

额外添加一个查询某个用户获得的赞的数量的方法:

    //查询某个用户获得的赞
	public int findUserLikeCount(int userId){
        String userLikeKey = RedisKeyUtil.getUserLikeKey(userId);
        Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey);
        return count == null ? 0: count.intValue();
    }

LikeController

需要额外添加 一个entityUserId输入参数:

@RequestMapping(path="/like",method = RequestMethod.POST)
@ResponseBody
public String like(int entityType, int entityId, int entityUserId){
    //当前用户点赞
    User user = hostHolder.getUser();
 
    //点赞
    likeService.like(user.getId(), entityType, entityId, entityUserId);
    //数量
    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);
}

discuss-detail.html 传入entityUserId

UserController

显示个人主页时需要把用户收到的赞的总数量放到Model之中去。

个人主页不仅仅可以显示当前用户的主页,任意用户的主页也可以查看,因此路径中传入userID

    @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(userId);
        model.addAttribute("likeCount", likeCount);
 
        return "/site/profile";
    }

index.html 添加个人主页的路径

profile.html 个人主页

4.4、关注、取消关注

在这里插入图片描述

关键:设计好key!!!

RedisKeyUtil

zset,按照时间来统计,进行排序

public class RedisKeyUtil {
    private static final String PREFIX_FOLLOWEE = "followee";//某个userID的关注
    private static final String PREFIX_FOLLOWER = "follower";//某个uerID的粉丝
    
    // entityType:被关注的实体:用户1、帖子2、题目3...等;
    // 某个用户关注的实体
    // followee:userId:entityType -> zset(entityId,now) 有序,以时间为顺序
    public static String getFolloweeKey(int userId, int entityType) {
        return PREFIX_FOLLOWEE + SPLIT + userId + SPLIT + entityType;
    }

    // 某个实体拥有的粉丝 
    // follower:entityType:entityId -> zset(userId,now)
    public static String getFollowerKey(int entityType, int entityId) {
        return PREFIX_FOLLOWER + SPLIT + entityType + SPLIT + entityId;
    }
}

FollowService

事务管理:当前用户关注了实体的同时,被关注的实体的用户的粉丝增加

@Service
public class FollowService implements CommunityConstant {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserService userService;
    
    //==================关注=======================
    public void follow(int userId, int entityType, int entityId){
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                //用户的关注集合
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
                //实体的粉丝集合
                String followerKey = 
                    RedisKeyUtil.getFollowerKey(entityType, entityId);
                redisOperations.multi();
                //opsForZSet:有序集合
                redisOperations.opsForZSet().add(
                    followeeKey, entityId, System.currentTimeMillis());
                redisOperations.opsForZSet().add(
                    followerKey, 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 followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
                //实体的粉丝集合
                String followerKey = 
                    RedisKeyUtil.getFollowerKey(entityType, entityId);
                redisOperations.multi(); //开启事务
                redisOperations.opsForZSet().remove(followeeKey, entityId);
                redisOperations.opsForZSet().remove(followerKey, userId);
                return redisOperations.exec(); //提交事务
            }
        });
    }
    
    //查询关注的实体的数量 followee:userId:entityType -> zset(entityId,now)
    public long findFolloweeCount(int userId, int entityType){
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().zCard(followeeKey);
    }
 
    //查询实体的粉丝的数量 follower:entityType:entityId -> zset(userId,now)
    public long findFollowerCount(int entityType, int entityId){
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        return  redisTemplate.opsForZSet().zCard(followerKey);
    }
 
    //查询当前用户是否已关注该实体
    public boolean hasFollowed(int userId, int entityType, int entityId){
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
    }
}

FollowController(异步请求)

@Controller
public class FollowController implements CommunityConstant {

    @Autowired
    private FollowService followService;

    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private UserService userService;
	
    //关注
    @RequestMapping(path = "/follow", method = RequestMethod.POST)
    @ResponseBody
    public String follow(int entityType, int entityId) {
        User user = hostHolder.getUser();

        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();

        followService.unfollow(user.getId(), entityType, entityId);

        return CommunityUtil.getJSONString(0, "已取消关注!");
    }
}

UserController

UserController中getProfilePage方法中补充一些代码逻辑

    // 个人主页
    @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(userId);
        model.addAttribute("likeCount", likeCount);
		//============================新增===================================
        // 关注数量
        long followeeCount = 
            followService.findFolloweeCount(userId, ENTITY_TYPE_USER);
        model.addAttribute("followeeCount", followeeCount);
        // 粉丝数量
        long followerCount = 
            followService.findFollowerCount(ENTITY_TYPE_USER, userId);
        model.addAttribute("followerCount", followerCount);
        // 当前登录的用户是否已关注显示的该个人主页的用户
        boolean hasFollowed = false;
        if (hostHolder.getUser() != null) {
            hasFollowed = followService.hasFollowed(
                hostHolder.getUser().getId(), ENTITY_TYPE_USER, userId);
        }
        model.addAttribute("hasFollowed", hasFollowed);

        return "/site/profile";
    }

4.5、关注列表、粉丝列表

在这里插入图片描述

FollowService

分页显示

    // ==========================查询某用户userID关注的人============================
    public List<Map<String, Object>> findFollowees(int userId, int offset, int limit) {		  //实体类型entityType是 ENTITY_TYPE_USER
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
        //range范围查询默认是从小到大,reverseRange从大到小
        Set<Integer> targetIds = 
            redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);//起始索引和截止索引

        if (targetIds == null) {
            return null;
        }
		
        List<Map<String, Object>> list = new ArrayList<>();
        for (Integer targetId : targetIds) {
            Map<String, Object> map = new HashMap<>();
            User user = userService.findUserById(targetId);
            map.put("user", user);
            Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
            map.put("followTime", new Date(score.longValue()));
            list.add(map);//一个map封装一个被关注的user的信息
        }

        return list;
    }

    // ==========================查询某用户的粉丝===========================
    public List<Map<String, Object>> findFollowers(int userId, int offset, int limit) {
        String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);

        if (targetIds == null) {
            return null;
        }

        List<Map<String, Object>> list = new ArrayList<>();
        for (Integer targetId : targetIds) {
            Map<String, Object> map = new HashMap<>();
            User user = userService.findUserById(targetId);
            map.put("user", user);
            Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
            map.put("followTime", new Date(score.longValue()));
            list.add(map);
        }

        return list;
    }

FollowController

    //=============查询某一用户关注的人,在路径中传入当前用户的userID============
	@RequestMapping(path = "/followees/{userId}", method = RequestMethod.GET)
    public String getFollowees(@PathVariable("userId") int userId, Page page, Model model) {
        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_TYPE_USER));

        List<Map<String, Object>> userList = followService.findFollowees(userId, page.getOffset(), page.getLimit());//page.getOffset()当前页的起始行
        if (userList != null) {
            for (Map<String, Object> map : userList) {
                User u = (User) map.get("user");
                //判断当前用户是否关注了当前页面被关注的用户
                map.put("hasFollowed", hasFollowed(u.getId()));
            }
        }
        model.addAttribute("users", userList);

        return "/site/followee";
    }
	
	//==========================查询某用户userId的粉丝===========================
    @RequestMapping(path = "/followers/{userId}", method = RequestMethod.GET)
    public String getFollowers(@PathVariable("userId") int userId, Page page, Model model) {
        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_TYPE_USER, userId));

        List<Map<String, Object>> userList = followService.findFollowers(userId, page.getOffset(), page.getLimit());
        if (userList != null) {
            for (Map<String, Object> map : userList) {
                User u = (User) map.get("user");
                map.put("hasFollowed", hasFollowed(u.getId()));
            }
        }
        model.addAttribute("users", userList);

        return "/site/follower";
    }

    private boolean hasFollowed(int userId) {
        if (hostHolder.getUser() == null) {//先判断是否登录
            return false;
        }
        return followService.hasFollowed(
            hostHolder.getUser().getId(), ENTITY_TYPE_USER, userId);
    }

profile.html

followee.html

4.6、优化登录模块

在这里插入图片描述

之前的验证码是存储在session里的,登录凭证存储在数据库中,每次请求都要被拦截然后再数据库中查询,用户的信息也是每次都从数据库中查询得到,效率低。

mysql中login_ticket表作废,user表仍然保存,只是同时缓存在redis中,过了有效时间就过期被清除。

(1)使用redis存储验证码

RedisKeyUtil

验证码应该和用户关联,但是一开始还没登录,因此不能传入userID,为了识别用户是谁,在客户端访问登录页面的时候,给用户发送一个随机生成的凭证owner,存在cookie中并设置过期时间

    private static final String PREFIX_KAPTCHA = "kaptcha";//验证码

    // 登录验证码
    public static String getKaptchaKey(String owner) {
        return PREFIX_KAPTCHA + SPLIT + owner;
    }

LoginController

getKaptcha方法之中,替换之前的 session.setAttribute("kaptcha", text) ,将验证码缓存入redis

    @RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
    public void getKaptcha(HttpServletResponse response/*, HttpSession session*/) {
        // 生成验证码
        String text = kaptchaProducer.createText();
        BufferedImage image = kaptchaProducer.createImage(text);

        // 将验证码存入session
        // session.setAttribute("kaptcha", text);

        // 验证码的归属
        String kaptchaOwner = CommunityUtil.generateUUID();
        Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
        cookie.setMaxAge(60);//有效时间
        cookie.setPath(contextPath);//整个项目的路径都有效
        response.addCookie(cookie);
        // 将验证码存入Redis
        String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
        redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);

        // 将突图片输出给浏览器
        response.setContentType("image/png");
        try {
            OutputStream os = response.getOutputStream();
            ImageIO.write(image, "png", os);
        } catch (IOException e) {
            logger.error("响应验证码失败:" + e.getMessage());
        }
    }

存入验证码至redis之后,在登录时需要使用,判断用户输入的验证码是否正确

login方法需要使用kaptchaOwner,从 请求参数的Cookie中取即可

    @RequestMapping(path = "/login", method = RequestMethod.POST)
    public String login(String username, String password, String code, boolean rememberme,Model model, /*HttpSession session, */HttpServletResponse response, @CookieValue("kaptchaOwner") String kaptchaOwner) {
        // 检查验证码
        // String kaptcha = (String) session.getAttribute("kaptcha");
        String kaptcha = null;
        if (StringUtils.isNotBlank(kaptchaOwner)) {//验证码没有失效
            String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
            kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
        }

        if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
            model.addAttribute("codeMsg", "验证码不正确!");
            return "/site/login";
        }

(2)使用redis存储登录凭证

RedisKeyUtil

private static final String PREFIX_TICKET = "ticket";
//登录的凭证
public static String getTicketKey(String ticket){
    return PREFIX_TICKET + SPLIT + ticket;
}

UserService

login方法

    public Map<String, Object> login(String username, String password, int expiredSeconds) {
        Map<String, Object> map = new HashMap<>();
        // 空值处理
        if (StringUtils.isBlank(username)) {
            map.put("usernameMsg", "账号不能为空!");
            return map;
        }
        if (StringUtils.isBlank(password)) {
            map.put("passwordMsg", "密码不能为空!");
            return map;
        }
        // 验证账号
        User user = userMapper.selectByName(username);
        if (user == null) {
            map.put("usernameMsg", "该账号不存在!");
            return map;
        }
        // 验证状态
        if (user.getStatus() == 0) {
            map.put("usernameMsg", "该账号未激活!");
            return map;
        }
        // 验证密码
        password = CommunityUtil.md5(password + user.getSalt());
        if (!user.getPassword().equals(password)) {
            map.put("passwordMsg", "密码不正确!");
            return map;
        }
        // 生成登录凭证
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        loginTicket.setTicket(CommunityUtil.generateUUID());
        loginTicket.setStatus(0);
        loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
//        loginTicketMapper.insertLoginTicket(loginTicket);
//============================以下为修改==========================
        String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
        redisTemplate.opsForValue().set(redisKey, loginTicket);

        map.put("ticket", loginTicket.getTicket());
        return map;
    }

logout方法:

失效用户登录凭证,不是真正地删除,只是修改状态即可。 先查询再修改状态然后再重新存入redis缓存中去。不删除的原因是将来可能需要查询用户的历史登录时间等。

    public void logout(String ticket) {
//        loginTicketMapper.updateStatus(ticket, 1);
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        LoginTicket loginTicket = 
            (LoginTicket)redisTemplate.opsForValue().get(redisKey);
        loginTicket.setStatus(1);//1:失效状态
        redisTemplate.opsForValue().set(redisKey, loginTicket);
    }

findLoginTicket 查询凭证的方法:

    public LoginTicket findLoginTicket(String ticket){
        //return loginTicketMapper.selectByTicket(ticket);
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        return (LoginTicket) redisTemplate.opsForValue().get(redisKey);
    }

(3)使用Redis缓存用户信息

RedisKeyUtil

private static final String PREFIX_USER = "user";
//用户
public static String getUserKey(int userId){
    return PREFIX_USER + SPLIT + userId;
}

UserService

额外添加几个方法

    //1.优先从缓存中取值
    private User getCatche(int userId){
        String redisKey = RedisKeyUtil.getUserKey(userId);
        return (User) redisTemplate.opsForValue().get(redisKey);
    }
 
    //2.取不到时初始化缓存数据
    private User initCache(int userId){
        //需要从mysql中查询数据
        User user = userMapper.selectById(userId);
        String redisKey = RedisKeyUtil.getUserKey(userId);
        //注意:需要设置一个过期时间
        redisTemplate.opsForValue().set(redisKey, user, 3600, TimeUnit.SECONDS);
        return user;
 
    }
    //3. 数据变更时清除缓存数据
    private void clearCache(int userId){
        String redisKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.delete(redisKey);
    }

修改根据用户id获取User的方法 :

    public User findUserById(int id){
        //现在缓存中查找,如果缓存中没有值的话,则需要初始化缓存的值
        User user = getCatche(id);
        if(user == null){
            user = initCache(id);
        }
        return user;
    }

在有修改User对象的地方,要先清空缓存,然后再重新加入缓存(从数据库中读取)

activation方法:

    public int activation(int userId, String code) {
        User user = userMapper.selectById(userId);
        if (user.getStatus() == 1) {
            return ACTIVATION_REPEAT;
        } else if (user.getActivationCode().equals(code)) {
            userMapper.updateStatus(userId, 1);
            clearCache(userId);
            return ACTIVATION_SUCCESS;
        } else {
            return ACTIVATION_FAILURE;
        }
    }

updateHeader方法:

    public int updateHeader(int userId, String headerUrl){
        int rows = userMapper.updateHeader(userId, headerUrl);
        clearCache(userId);
        return rows;
    }

标签:return,String,一站式,int,Redis,userId,高性能,user,public
来源: https://blog.csdn.net/zxiaohaha/article/details/118378643

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有