mybatis插件

  作者:记性不好的阁主


功能特性




分页插件实现流程




补充:参数对象,单个参数是其本身,多个参数为Map




分页插件功能实现


1、定义Page类


package com.laoxu.mybatis.executor.plugin;

public class Page {

public Page(int size, int index) {
this.size = size;
this.index = index;
}

private int total; // 总行数
private int size; // 每页大小
private int index; // 页码

public int getTotal() {
return total;
}

public void setTotal(int total) {
this.total = total;
}

public int getSize() {
return size;
}

public void setSize(int size) {
this.size = size;
}

public int getIndex() {
return size * (index - 1); // offset 0 limit 50<size>
}

public void setIndex(int index) {
this.index = index;
}
}


2、编写拦截器


package com.laoxu.mybatis.executor.plugin;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;

/**
* 分页拦截器
*/
@Intercepts(
@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}))
public class PageInterceptor implements Interceptor {


@Override
public Object intercept(Invocation invocation) throws Throwable {
// 1、检查当前是否满足分页条件
// 带上分页参数
StatementHandler target = (StatementHandler) invocation.getTarget();
// Sql sql,参数,参数映射
BoundSql boundSql = target.getBoundSql();
Object parameterObject = boundSql.getParameterObject();

Page page = null;

if(parameterObject instanceof Page){
page = (Page) parameterObject;
}else if (parameterObject instanceof Map){
page = (Page)((Map) parameterObject).values().stream().filter(v->v instanceof Page).findFirst().orElse(null);
}

if(page==null){
return invocation.proceed();
}


// 2、设置总行数
// select count(0) from (sql);
page.setTotal(selectCount(invocation));


// 3、修改原sql
// select * from person offset 0 , limit 50
String newSql = String.format("%s limit %s offset %s", boundSql.getSql(), page.getSize(), page
.getIndex());
SystemMetaObject.forObject(boundSql).setValue("sql", newSql);

return invocation.proceed();
}

private int selectCount(Invocation invocation) throws SQLException {
int count = 0;
StatementHandler target = (StatementHandler) invocation.getTarget();
// Sql sql,参数,参数映射
String countSql = String.format("select count(*) from (%s) as _page", target.getBoundSql().getSql());
// JDBC
Connection connection = (Connection) invocation.getArgs()[0];
PreparedStatement preparedStatement = connection.prepareStatement(countSql);
target.getParameterHandler().setParameters(preparedStatement);
ResultSet resultSet = preparedStatement.executeQuery();
if(resultSet.next()){
count = resultSet.getInt(1);
}
resultSet.close();
preparedStatement.close();
return count;
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {

}
}


  • 1、继承mybatis的拦截Interceptor类


/**
* Copyright 2009-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.plugin;

import java.util.Properties;

/**
* @author Clinton Begin
*/
public interface Interceptor {

Object intercept(Invocation invocation) throws Throwable;

default Object plugin(Object target) {
return Plugin.wrap(target, this);
}

default void setProperties(Properties properties) {
// NOP
}

}


Object intercept(Invocation invocation) throws Throwable; //主要实现拦截的主逻辑


Object plugin(Object target)  //插件包装

Plugin.wrap(target, this);

动态代理的方式对@Intercepts注解及拦截器进行包装解析



void setProperties(Properties properties)  //设置属性


  • 2、添加拦截器注解@Intercepts


@Intercepts(
@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}))


type 指定要拦截的处理器类

method 指定拦截处理器类李的方法

args 指定需要用到的参数


以上拦截器使用到了第一个参数,这个参数来自 StatementHandler类的prepare方法传入的参数


Connection connection = (Connection) invocation.getArgs()[0];


查看StatementHandler类的内容


/**
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.session.ResultHandler;

/**
* @author Clinton Begin
*/
public interface StatementHandler {

// 创建Statement,基于java.sql
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;

// 设置参数
void parameterize(Statement statement)
throws SQLException;
// 执行批处理
void batch(Statement statement)
throws SQLException;
// 执行修改
int update(Statement statement)
throws SQLException;
// 执行查询
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
// 查询游标
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
// 获取动态sql
BoundSql getBoundSql();
// 获取参数处理器
ParameterHandler getParameterHandler();

}


实现类部分代码:


/**
* Copyright 2009-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.executor.statement;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
* @author Clinton Begin
*/
public abstract class BaseStatementHandler implements StatementHandler {

@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}



}




3、执行测试


package com.laoxu.mybatis.executor.plugin;

import com.laoxu.mybatis.mapper.PersonMapper;
import com.laoxu.mybatis.modal.Person;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test {


public static void main(String[] args) throws IOException {

test1();
}

private static void test1() throws IOException {
String resource = "mapper/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) {
PersonMapper personMapper = session.getMapper(PersonMapper.class);
// 设置分页
Page page = new Page(2, 1);
List<Person> personList = personMapper.getAllPersonsByPage(page);
System.out.println("返回数量:" + personList.size());
System.out.println("总数:" + page.getTotal());
System.out.println(personList);
}

}
}


返回结果:


==>  Preparing: select count(*) from (select * from person) as _page
==> Parameters: 
<==    Columns: count(*)
<==        Row: 3
==>  Preparing: select * from person limit 2 offset 0
==> Parameters: 
<==    Columns: id, name, sex, age, create_time
<==        Row: 20210420172645864088a2a1ba11eb886d525400146075, 李四, 1, 20, 2021-04-20 17:26:45
<==        Row: 20210420172922e412b7bea1ba11eb886d525400146075, 张三, 1, 20, 2021-04-20 17:29:22
<==      Total: 2
返回数量:2
总数:3





相关推荐

评论 抢沙发

表情

分类选择