1.自定义插件
- type: 拦截对象
- Executor: 执行SQL全过程,包含组装参数,组装结果集返回和执行SQL,比较广泛
- StatementHandler: 执行SQL的过程,最常用的拦截
- ParameterHandler: 拦截执行SQL的参数组装,可以重写组装参数规则
- ResultSetHandler: 拦截执行结果的组装,可以重写组装结果的规则
- method: 拦截方法,必须对应拦截对象中的方法
- args: 参数,必须和接口中的拦截方法参数列表相同
2.自定义插件打印SQL执行情况
@Intercepts({@Signature(
type= StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class})})
public class ExamplePlugin implements Interceptor {
private Logger log = Logger.getLogger(ExamplePlugin.class);
private Properties properties = new Properties();
//实现拦截逻辑
@Override
public Object intercept(Invocation invocation) throws Throwable {
//获取执行目标类
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
//封装获取工具类对象
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
//获取绑定SQL对象
BoundSql boundSql = (BoundSql)metaStatementHandler.getValue("delegate.boundSql");
//获取参数对象
Object parameterObject = boundSql.getParameterObject();
log.warn("|--参数名称\t|\t参数值|");
//使用注解@Parm或Map传递多个参数本质都是map类型
if (parameterObject instanceof Map){
Map<String, Object> paraMap = (Map<String, Object>)parameterObject;
for (Map.Entry<String, Object> entry : paraMap.entrySet()) {
log.warn("|--"+ entry.getKey() +"\t|\t"+ entry.getValue() +"--|");
}
}else{
log.warn("参数列表:" + (Book) parameterObject);
}
//获取执行SQL语句
String sql = boundSql.getSql();
long start = System.currentTimeMillis();
//执行原始SQL
Object obj = invocation.proceed();
log.warn("执行SQL: [ "+ sql +" ], 耗时:" + (System.currentTimeMillis() - start) +"ms");
return obj;
}
//生成代理对象
@Override
public Object plugin(Object target) {
//系统默认方法生成代理对象
Object wrap = Plugin.wrap(target, this);
return wrap;
}
//设置参数
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
}
**
3.自定义分页插件
@Intercepts({@Signature(
type= StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class})})
public class ExamplePlugin implements Interceptor {
private Logger log = Logger.getLogger(ExamplePlugin.class);
private Integer defaultPageNum;
private Integer defaultPageSize;
private Boolean defaultIsUsePage;
//实现拦截逻辑
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
BoundSql boundSql = (BoundSql)metaStatementHandler.getValue("delegate.boundSql");
String sql = boundSql.getSql();
//获取分页参数列表
PageParams pageParams = parameterList(boundSql);
Integer pageNum = pageParams.getPageNum() == null ? defaultPageNum : pageParams.getPageNum();
Integer pageSize = pageParams.getPageSize() == null ? defaultPageSize : pageParams.getPageSize();
Boolean isUsePage = pageParams.getPageSize() == null ? defaultIsUsePage : pageParams.getIsUsePage();
//是否执行分页操作
if(!sql.trim().toLowerCase().startsWith("select") || !isUsePage){
return invocation.proceed();
}
log.warn("PageNum="+ pageNum +", pageSize="+ pageSize +", isUsePage="+ isUsePage);
return preparedSQL(invocation, metaStatementHandler, sql, pageNum, pageSize);
}
//生成代理对象
@Override
public Object plugin(Object target) {
//系统默认方法生成代理对象
Object wrap = Plugin.wrap(target, this);
return wrap;
}
//设置参数
@Override
public void setProperties(Properties properties) {
this.defaultPageNum = Integer.parseInt(properties.getProperty("default.pageNum", "1"));
this.defaultPageSize = Integer.parseInt(properties.getProperty("default.pageSize", "10"));
this.defaultIsUsePage = Boolean.parseBoolean(properties.getProperty("default.isUsePage", "true"));
}
//预编译新SQL
private Object preparedSQL(Invocation invocation, MetaObject metaStatementHandler, String sql, int pageNum, int pageSize) throws InvocationTargetException, IllegalAccessException, SQLException {
String newSql = "select * from (" + sql + ") tmp_table limit ?, ?";
log.warn("newSql: "+ newSql);
//替换将要执行的SQL
metaStatementHandler.setValue("delegate.boundSql.sql", newSql);
//执行SQL
Object obj = invocation.proceed();
preparePageDataParams((PreparedStatement) obj, pageNum, pageSize);
return obj;
}
//设置分页参数
private void preparePageDataParams(PreparedStatement ps, int pageNum, int pageSize) throws SQLException {
//获取参数数量
int parameterCount = ps.getParameterMetaData().getParameterCount();
//设置参数
ps.setInt(parameterCount - 1, (pageNum - 1) * pageSize); //offset
ps.setInt(parameterCount, pageSize); //显示行数
}
//获取参数
private PageParams parameterList(BoundSql boundSql){
PageParams pageParams = null;
Object parameterObject = boundSql.getParameterObject();
if (parameterObject instanceof Map) {
Map<String, Object> paraMap = (Map<String, Object>)parameterObject;
for(Object value: paraMap.values()){
if (value instanceof PageParams) {
pageParams = (PageParams) value;
}
}
}else{
pageParams = (PageParams) parameterObject;
}
return pageParams;
}
}
@Data
public class PageParams {
//页码
private Integer pageNum;
//每页行数
private Integer pageSize;
//是否使用分页
private Boolean isUsePage;
}
4.使用分页插件PageHelper
- 添加依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
- 配置
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--reasonable:分页合理化参数,默认值为false,直接根据参数进行查询
当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum >pages(超过总数时),会查询最后一页-->
<!--<property name="reasonable" value="true"/>-->
</plugin>
</plugins>
- 程序中使用
-对使用分页的SQL语句前执行PageHelper.startPage(pageNum, pageSize)