【学习笔记】seckill-秒杀项目--(3)分布式Session

分布式Session问题
由于Nginx使用默认负载均衡策略(轮询),请求会按照时间顺序逐一发到后端应用。在Tomcat1登录后,用户信息存放在Tomcat1的Session里,后来被分到了Tomcat2上,这时候Tomcat2的Session没有用户信息,所以需要重新登录。
解决方案有:Session复制、前端存储、Session粘滞、后端集中存储这些方法。几种方法各有优缺点,需要我们根据实际情况选择。

一、使用SprignSession实现

1. 添加依赖

spring data redis、对象池commons-pool2、spring-session

<!-- spring data redis 依赖 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 对象池依赖 -->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
</dependency>
<!-- spring-session 依赖 -->
<dependency>
	<groupId>org.springframework.session</groupId>
	<artifactId>spring-session-data-redis</artifactId>
</dependency>

2. 添加配置

redis:
    # 超时时间
    timeout: 10000ms
    # 服务器地址
    host: 192.168.222.129
    # 服务器端口,默认6379
    port: 6379
    # 数据库,默认0
    database: 0
    # 密码
    password: root
    lettuce:
        pool:
            #最大连接数,默认8
            max-active: 1024
            #最大连接阻塞等待时间,默认-1
            max-wait: 10000ms
            #最大空闲连接,默认8
            max-idle: 200
            #最小空闲连接,默认0
            min-idle: 5

二、将用户信息存入Redis

1. 添加依赖

<!-- spring data redis 依赖 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 对象池依赖 -->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
</dependency>

2. 添加配置

这部分和方法一一样。

3. redis配置类

主要完成对象的序列化

/**
 * @author 47roro
 * @create 2022/4/5
 * @description: Redis配置类
 */
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //Key序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //Value序列化
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        //Hash序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        //注入连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}

4. 修改代码

之前是将cookie值存在了session中,现在把cookie值存入redis

/**
 *  服务实现类
 * @author 47roro
 * @since 2022-04-03
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 登录
     * @author 47roro
     * @date 2022/4/3
     * @param loginVo
     * @return com.example.seckill.vo.RespBean
     **/
    @Override
    public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
        User user = userMapper.selectById(mobile);
        if(null == user){
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }
        if(!MD5Util.frompassToDBPass(password, user.getSalt()).equals(user.getPassword())){
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }
        // 生成cookie
        String cookie = UUIDUtil.uuid();
        // 将用户信息存入redis
        redisTemplate.opsForValue().set("user:" + cookie, user);
        // 使用session
        //request.getSession().setAttribute(cookie, user);
        CookieUtil.setCookie(request, response, "userCookie", cookie);
        return RespBean.success();
    }
    /**
     * 根据Cookie获取用户
     * @author 47roro
     * @date 2022/4/5
     * @param userCookie
     * @param request
     * @param response 
     * @return com.example.seckill.pojo.User
     **/
    @Override
    public User getUserByCookie(String userCookie, HttpServletRequest request, HttpServletResponse response) {
        if(!StringUtils.hasLength(userCookie)){
            return null;
        }
        User user = (User)redisTemplate.opsForValue().get("user:" + userCookie);
        if(user != null){
            CookieUtil.setCookie(request, response, "userCookie", userCookie);
        }
        return user;
    }
}

商品页面跳转获取用户方式修改

/**
 * @author 47roro
 * @create 2022/4/3
 * @description: 商品页面跳转
 */
@Controller
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private UserServiceImpl userService;

    /**
     * 跳转到商品列表页面
     * @author 47roro
     * @date 2022/4/3
     * @param request,response
     * @param model
     * @param cookie
     * @return java.lang.String
     **/
    @RequestMapping("/toList")
    public String toList(HttpServletRequest request, HttpServletResponse response, Model model, @CookieValue("userCookie") String cookie){
        if(StringUtils.isEmpty(cookie)){
            return "login";
        }
        //通过session获取cookie
        //User user = (User) session.getAttribute(cookie);
        //通过cookie获取用户
        User user = userService.getUserByCookie(cookie, request, response);
        if(null == user){
            return "login";
        }
        model.addAttribute("user", user);
        return "goodsList";
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值