目录
前言
使用ThreadLocal对存储分页参数有以下好处:
- 避免多层级参数传递:在复杂的系统或框架中,分页参数可能需要跨越多个层级进行传递。使用ThreadLocal可以避免这种多层级传递,使代码更加简洁和易于维护。
- 提高性能:ThreadLocal避免了使用线程同步机制(如锁)来保护共享数据,从而提高程序的并发性能。由于每个线程都拥有自己的数据副本,因此不会出现线程间的竞争和冲突,从而避免了锁竞争带来的性能损耗。
- 便于管理线程特定的资源:在某些场景下,我们需要为每个线程分配一些特定的资源,并且在线程结束时进行清理工作。ThreadLocal可以通过在对象中存储和管理线程特定的资源,使得这些资源能够方便地与线程相关联,同时在线程结束时自动清理。
- 解决上下文切换问题:在一些需要维护上下文关系的场景中,例如数据库连接、会话管理等,使用ThreadLocal可以很好地解决上下文切换的问题。通过将上下文相关的信息存储在ThreadLocal中,可以在同一线程内共享这些信息,而无需通过参数传递或全局变量访问来维护。
一、代码实现
1.工具类
在工具类中,通过封装ThreadLocal,并提供将分页参数封装进ThreadLocal的几个方法。
package com.pzg.chat.utils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
public class PageUtil {
private static ThreadLocal<Page<?>> pageThreadLocal = new ThreadLocal<>();
public static void setPage(Integer currentPage,Integer size){
pageThreadLocal.set(new Page<>(currentPage,size));
}
public static long getCurrentPage(){
long size = pageThreadLocal.get().getSize();
return (pageThreadLocal.get().getCurrent()-1)*size;
}
public static long getLimitPage(){
long size = pageThreadLocal.get().getSize();
return (pageThreadLocal.get().getCurrent()-1)*size;
}
public static long getSize(){
return pageThreadLocal.get().getSize();
}
public static void removeThreadLocal(){
pageThreadLocal.remove();
}
}
2.拦截器
在拦截器中,当请求进入方法前,获取request中分页的字段参数,然后通过调用PageUtil.setPage(page,size);方法,将分页参数存储到ThreadLocal当中
@Component
public class PageInterception implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String currentPage = request.getParameter("currentPage");
String currentSize = request.getParameter("size");
Integer page = Integer.valueOf(currentPage != null ? currentPage : "1");
Integer size = Integer.valueOf(currentSize != null ? currentSize : "10");
PageUtil.setPage(page,size);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
PageUtil.removeThreadLocal();
}
}
注意:前端分页参数字段当前页currentPage,每页显示的字段为size,可自行修改。
3.配置类
通过配置类注册拦截器,让拦截器起到拦截的效果,若不配置,则拦截器不生效。
@Configuration
@SuppressWarnings("all")
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LimitInterception limitInterception;
@Autowired
private PageInterception pageInterception;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(pageInterception);
}
/**
* 解决跨域
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
//运行所有方式请求
.addMapping("/**")
//运行跨域请求的域名
.allowedOrigins("*")
//是否允许证书
.allowCredentials(true)
//运行任何头
.allowedHeaders("*")
//运行的方法
.allowedMethods("*");
}
}
4.使用
在Mybatis中通过PageUtil.getLimitPage(), PageUtil.getSize()来获取当前页和每页显示条数。
Page<JobLog> page = new Page<>(PageUtil.getLimitPage(), PageUtil.getSize());
在SQL语句中通过传入PageUtil.getCurrentPage(),PageUtil.getSize(),因为SQL当前页需要(当前页-1)*每页显示条数;
二、总结
通过ThreadLocal加上拦截器,我们就不需要在Controller通过获取分页的参数来写许多重复的代码,而是通过自己封装的一个工具类,如果想要分页参数时调用工具类里边的方法即可,大大降低了代码的耦合度。