1. 原理: 无非就是基于mybaits插件机制,拦截执行过程中某个阶段(Executor, StatementHandler, ParamterStatementHander,ResultSetHandler), 获取到待执行SQL, 利用反射对SQL重新赋值 (拼接上分页参数);
2. SQL触发执行是在 StatementHandler阶段,故这里对StatementHandler拦截 (具体原因,自行看源码 从 Executor #query()方法debug)
2. 上代码
1 /** 2 * @author yangxj 3 * @date 2021/6/4-23:21 4 */ 5 @Slf4j 6 @Component 7 @Intercepts({@Signature(type = StatementHandler.class, method = "prepare",args = {Connection.class, Integer.class})}) 8 public class PageHelper implements Interceptor { 9 10 private static final ThreadLocal<Page> localCache = new ThreadLocal<>(); 11 12 @Override 13 public Object intercept(Invocation invocation) throws Throwable { 14 StatementHandler stm = (StatementHandler) invocation.getTarget(); 15 16 BoundSql boundSql = stm.getBoundSql(); 17 18 Page page = getPage(); // 取到分页参数 19 20 if (page != null) { 21 Field SQLField = BoundSql.class.getDeclaredField("sql"); // 利用反射对SQL重新赋值 22 SQLField.setAccessible(true); 23 SQLField.set(boundSql, page.getPageSQL(boundSql.getSql())); 24 clearPage(); // 用完清空分页参数 25 } 26 27 log.info("待执行SQL: " + boundSql.getSql().replaceAll("\\n", "").replaceAll("\\t", "")); 28 29 return invocation.proceed(); 30 } 31 32 @Override 33 public Object plugin(Object o) { 34 return o instanceof StatementHandler ? Plugin.wrap(o, this) : o; 35 } 36 37 @Override 38 public void setProperties(Properties properties) { 39 40 } 41 42 43 public static void startPage(Long pageNum, Long pageSize) { 44 localCache.set(new Page(pageNum, pageSize)); 45 } 46 47 private Page getPage() { 48 return localCache.get(); 49 } 50 51 private void clearPage() { 52 localCache.remove(); 53 } 54 55 private static class Page { 56 private Long pageNum; 57 private Long pageSize; 58 59 private Page(Long pageNum, Long pageSize) { 60 this.pageNum = pageNum; 61 this.pageSize = pageSize; 62 } 63 64 private String getPageSQL(String SQL) { 65 if (pageNum != null && pageSize != null) { 66 return SQL + " limit " + (pageNum - 1) * pageSize + " ," + pageSize; 67 } 68 return SQL; 69 } 70 } 71 }
浙公网安备 33010602011771号