考试系统交接日记(四):session共享与ThreadLocal传递参数

一、session共享

考试系统是一个高并发项目,可能同时有百万级用户在线考试,因此生产环境有30台服务器,涉及到session共享的问题。

项目中,使用spring-session解决session共享问题。

spring-session借助redis实现session共享。(生产上用到了2台服务器分别部署了1个redis)

 

springboot项目使用spring-session使用方法:

1.pom.xml中引入jar包

<modelVersion>4.0.0</modelVersion>
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.6.RELEASE</version>
  <relativePath/>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
  </dependency>
</dependencies>

2.配置文件application.properties中,配置redis相关信息

spring.redis.database=1
spring.redis.host=127.0.0.1
spring.redis.port=37652
spring.redis.password=root

3.Application.java中增加注解启动spring-session

@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 2 * 3600)

其中设置了过期时间是2小时。

4.这样就实现了session共享,后续可以编写controller方法、配置nginx,进行测试。

 

相关文章:

https://blog.csdn.net/qq_39669058/article/details/90235990

https://www.cnblogs.com/david1216/p/11468772.html

 

二、ThreadLocal传递参数

ThreadLocal是一个仅供当前线程使用的存储类,每个线程各自有一个ThreadLocalMap对象,可以set与get值。(与全局变量不同)

考试系统中,当一个controller接收到http请求时,会把其中的参数存入ThreadLocal,供后续方法使用;当所有方法结束时,清除该ThreadLocal中的内容;是通过拦截器实现的。

这样看起来简洁些,不需要把request对象或参数对象沿着方法传递下去。

大致记录如下:

1.编写一个存放ThreadLocal的java类

public class ProjectLocal {
  public static ThreadLocal<ParamInfo> paramLocal = new ThreadLocal<>();
  
  @Data
  public static class ParamInfo{
    private String name;
    private String phone;
  }
}

2.编写一个拦截器,从http请求的header中获取参数,new一个ThreadLocal对象并存入参数。

@Component
@Slf4j
public class ParamVerifyInterceptor extends HandlerInterceptorAdapter {

  private Set<String> paramSet = new HashSet<>(Arrays.asList("name","phone","sign"));
  
  @Autowired
  private VerifyConfig verifyConfig;
  
  //进入controller前执行的方法
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
    //清空ThreadLocal中的内容,准备重新设置内容;仅在当次controller线程自身中使用
    ProjectLocal.paramLocal.remove();
    //从http请求的header中拿出参数来(通过header传参)
    String paramString = request.getHeader("Params");
    //如果没有参数,则返回
    if(StringUtils.isEmpty(paramString)){
      return true;
    }
    //转换为map
    Map<String, String> params = paramsToMap(paramString);
    String name = params.get("name");
    String phone = params.get("phone");
    String sign = params.get("sign");
    //如果不需要验签,则返回
    if(sign == null){
      return true;
    }
    //验签;当然,会移除sign字段
    //验证name与phone拼接后的字符串经过sha256Hex与md5Hex后,是否与sign相同
    boolean verify = VerifyUtil.verifySign(params, VerifyConfig.getSecretKey(), sign);
    if(verify){
      //new一个javabean,将参数存入,供程序后续使用
      ProjectLocal.paramLocal.set(new ProjectLocal.paramInfo());
      ProjectLocal.paramLocal.get().setName(name);
      ProjectLocal.paramLocal.get().setPhone(phone);
      return true;
    }
    //验签失败,拒绝访问
    else{
      response.sendError(HttpServletResponse.SC_FORBIDDEN,"FORBIDDEN");
      return false;
    }
  }
  
  //执行完controller后执行的方法
  @Override
  public boolean afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    super.afterCompletion(request, response, handler, ex);
    //清空ThreadLocal中的内容
    ProjectLocal.paramLocal.remove();
  }


}

3.注册该拦截器

@Configuration
public class WebAppConfig implements WebMvcConfigurer {
  @Autowired
  private ParamVerifyInterceptor paramVerifyInterceptor;
  
  @Override
  public void addInterceptors(InterceptorRegistry registry){
    registry.addInterceptor(paramVerifyInterceptor).addPathPatterns("/exams/**/sign","exams/**/login");
  }
  
  @Bean
  public LocaleResolver localeResolver(){
    return new CustomLocaleResolver();
  }

}

4.后续方法中,通过ThreadLocal获取需要的参数

String name = ParamLocal.get().getName();
String phone = ParamLocal.get().getPhone();

相关文章:

https://www.jianshu.com/p/3c5d7f09dfbd

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追逐梦想永不停

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值