【秒杀项目1】分布式会话模块

刚入门Java的硕士宝宝,实验室没什么Java项目,看到网上的秒杀项目,跟着学习并且记录一下,可能错误会很多,欢迎大家指正。



前言

本文介绍分布式会话模块,具体详细介绍实现用户登录和分布式session。


一、实现登录功能

1.两次MD5加密

这种方式是一种增加密码安全性的常见做法,通过在密码的两次加密过程中引入固定盐值和随机盐值,提高了密码的复杂度,增加了破解的难度。

  1. 第一次加密(前端):

用户在前端输入密码。
前端使用固定的盐值(固定 salt)对密码进行 MD5 加密,得到第一次加密结果。
这个固定的盐值在前端就已经确定了,通常作为一个字符串硬编码在前端代码中。

  1. 第二次加密(后端):

前端将第一次加密的结果以及用户输入的用户名等信息发送给后端。
后端根据接收到的用户名等信息,在服务端生成一个随机的盐值(随机 salt)。
后端将第一次加密的结果与随机盐值结合,再进行一次 MD5 加密,得到最终的密码存储结果。

2.参数校验

  1. 添加依赖:
<!-- validation组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  1. 自定义手机号码验证规则:
public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {
   private boolean required = false;
   @Override
   public void initialize(IsMobile constraintAnnotation) {
      required = constraintAnnotation.required();
   }
   @Override
   public boolean isValid(String value, ConstraintValidatorContext context) {
      if (required){
         return ValidatorUtil.isMobile(value);
     }else {
         if (StringUtils.isEmpty(value)){
            return true;
         }else {
            return ValidatorUtil.isMobile(value);
         }
     }
   }
}
  1. 自定义注解:
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {IsMobileValidator.class})
public @interface IsMobile {
   boolean required() default true;
   String message() default "手机号码格式错误";
   Class<?>[] groups() default {};
   Class<? extends Payload>[] payload() default {};
}

3.异常处理

在 Spring Boot 中,可以使用全局异常处理器来统一处理系统中出现的异常,以确保异常信息的统一处理和维护。主要的两种全局异常处理方式包括:

①使用 @ControllerAdvice 注解:

创建一个类并使用 @ControllerAdvice 注解标注,该类中定义 @ExceptionHandler 注解的方法来处理特定类型的异常。
这种方式允许您将异常处理逻辑集中在一个地方,并且可以处理多个控制器中抛出的异常。

②实现 ErrorController 接口:

创建一个类实现 Spring Boot 提供的 ErrorController 接口,并实现 getErrorPath() 方法和@RequestMapping 注解的方法来处理异常。
这种方式允许您自定义错误页面或者返回特定的错误信息。

二、分布式Session

在部署多台系统,并使用 Nginx 进行负载均衡时可能出现的用户登录问题。具体原因如下:

  1. 当部署多台系统时,每台系统都会维护自己的 Session;
  2. 如果使用 Nginx 进行负载均衡,默认的负载均衡策略是轮询,即将请求按照时间顺序逐一分发到后端应用上;
  3. 假设用户首先在 Tomcat1 上登录,那么用户信息将存储在 Tomcat1 的 Session 中;
  4. 过了一段时间后,Nginx 可能会将用户的下一个请求发送到 Tomcat2 上,但此时 Tomcat2 的 Session 中并没有用户信息;
  5. 因此,用户会被重定向到登录页面,需要重新登录。

解决这个问题的一种方法是实现分布式会话管理,确保用户的会话信息可以在多个 Tomcat 实例之间共享。常见的做法包括:

  1. 使用 Redis 或 Memcached 等分布式缓存服务来存储会话信息,从而实现跨多个 Tomcat 实例的会话共享;
  2. 使用 Spring Session 等框架来管理分布式会话,这些框架提供了方便的集成方式,并且可以与 Redis、JDBC 等后端存储进行集成;
  3. 将会话信息存储在数据库中,并确保所有 Tomcat 实例都能访问同一个数据库,从而实现会话共享。

Redis实现分布式Session

方法一:使用SpringSession实现

添加依赖:

<!-- 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>

方法二:将用户信息存入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>
  1. Redis配置类:
@Configuration
public class RedisConfig {
   @Bean
   public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory
connectionFactory){
      RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
      //key序列器
      redisTemplate.setKeySerializer(new StringRedisSerializer());
      //value序列器
      redisTemplate.setValueSerializer(new
GenericJackson2JsonRedisSerializer());
      //Hash类型 key序列器
      redisTemplate.setHashKeySerializer(new StringRedisSerializer());
      //Hash类型 value序列器
      redisTemplate.setHashValueSerializer(new
GenericJackson2JsonRedisSerializer());
      redisTemplate.setConnectionFactory(connectionFactory);
      return redisTemplate;
   }
}
  1. Json工具类:
public class JsonUtil {
    private static ObjectMapper objectMapper = new ObjectMapper();
    public static String object2JsonStr(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
       } catch (JsonProcessingException e) {
            e.printStackTrace();
       }
        return null;
   }
     public static <T> T jsonStr2Object(String jsonStr, Class<T> clazz) {
        try {
            return objectMapper.readValue(jsonStr.getBytes("UTF-8"), clazz);
       } catch (JsonParseException e) {
            e.printStackTrace();
       } catch (JsonMappingException e) {
            e.printStackTrace();
       } catch (IOException e) {
            e.printStackTrace();
       }
        return null;
   }
    public static <T> List<T> jsonToList(String jsonStr, Class<T> beanType) {
        JavaType javaType =
objectMapper.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = objectMapper.readValue(jsonStr, javaType);
            return list;
       } catch (Exception e) {
            e.printStackTrace();
       }
        return null;
   }
}

总结

以上就是今天要讲的内容,本文简单介绍了分布式会话模块,具体参考 乐字节 Java电商秒杀项目。

  • 19
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值