小堂最近在整理开源框架原理相关方面技术文档,持续为大家推送干货,欢迎大家关注【编程识堂】,不迷路!
⼀般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者⾃⾏拓展。这样的好处是显⽽易见的,⼀是增加了框架的灵活性。⼆是开发者可以结合实际需求,对框架进⾏拓展,使其能够更好的⼯作。以MyBatis为例,我们可基于MyBatis插件机制实现分页、分表,监控等功能。由于插件和业务⽆关,业务也⽆法感知插件的存在。因此可以⽆感植⼊插件,在⽆形中增强功能 。
Mybatis作为⼀个应⽤⼴泛的优秀的ORM开源框架,这个框架具有强⼤的灵活性,在四⼤组件 (Executor、StatementHandler、ParameterHandler、ResultSetHandler)处提供了简单易⽤的插件扩展机制。Mybatis对持久层的操作就是借助于四⼤核⼼对象。MyBatis⽀持⽤插件对四⼤核⼼对象进行拦截,对mybatis来说插件就是拦截器,⽤来增强核⼼对象的功能,增强功能本质上是借助于底层的动态代理实现的,换句话说,MyBatis中的四⼤对象都是代理对象。
Mybatis可以对这四个接口中所有的方法进行拦截
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
}
@Intercepts({
@Signature(
type = Executor.class,
method = "query",
args=
{MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}
)
})
public class ExeunplePlugin implements Interceptor {
//省略逻辑
}
<plugins>
<plugin interceptor="com.bcst.plugin.ExamplePlugin">
</plugin>
</plugins>
package com.bcst.plugin;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;
/*
*@description 欢迎关注公众号 编程识堂,每日更新技术相关文章,关注我不迷路
*@author 小堂
*@create 2023/7/16 21:54
*/
//注意看这个⼤花括号,也就这说这⾥可以定义多个@Signature对多个地⽅拦截,都⽤这个拦截器 ({
class, //这是指拦截哪个接⼝ (type = StatementHandler.
method = "prepare",//这个接⼝内的哪个⽅法名,不要拼错了
args = { Connection.class, Integer.class}),//// 这是拦截的⽅法的⼊参,按顺序写到这,不要多也不要少,如果⽅法重载,可是要通过⽅法名和⼊参来确定唯⼀的
})
public class MyPlugin implements Interceptor {
/**
* 拦截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
* @param invocation
* @return
* @throws Throwable
*/
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("MyPlugin插件 目标方法被增强。。。。");
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
// 将执行权交给下一个拦截器
return invocation.proceed();
}
/**
* 主要为了把当前的拦截器生成代理保存到拦截链中
* @Description 包装⽬标对象 为⽬标对象创建代理对象
* @Param target为要拦截的对象
* @Return 代理对象
*/
public Object plugin(Object target) {
System.out.println("MyPlugin插件将要包装的⽬标对象:"+target);
Object wrap = Plugin.wrap(target, this);
return wrap;
}
/**
* 获取配置文件的参数
* @param properties
*/
public void setProperties(Properties properties) {
System.out.println("获取配置文件的参数是:"+properties);
}
}
<plugins>
<plugin interceptor="com.bcst.plugin.MyPlugin">
<property name="name" value="小堂"/>
</plugin>
</plugins>
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<Interceptor>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor, autoCommit);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<>();
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
}}
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
}
executor =(Executor) interceptorChain.pluginAll(executor);
/**
* 每一个拦截器对目标类都进行一次代理
* @param target
* @return 层层代理后的对象
*/
public Object pluginAll(Object target) {
for(Interceptor interceptor : interceptors) {
target= interceptor.plugin(target);
}
return target;
}
@Intercepts({@Signature(type = Executor.class, method ="update", args = {MappedStatement.class, Object.class})})
public class ExamplePlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
package org.apache.ibatis.plugin;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.reflection.ExceptionUtil;
//这个类是Mybatis拦截器的核心,大家可以看到该类继承了InvocationHandler
//又是JDK动态代理机制
public class Plugin implements InvocationHandler {
//目标对象
private Object target;
//拦截器
private Interceptor interceptor;
//记录需要被拦截的类与方法
private Map<Class<?>, Set<Method>> signatureMap;
private Plugin(Object target, Interceptor interceptor, Map<Class<?>, Set<Method>> signatureMap) {
this.target = target;
this.interceptor = interceptor;
this.signatureMap = signatureMap;
}
//一个静态方法,对一个目标对象进行包装,生成代理类。
public static Object wrap(Object target, Interceptor interceptor) {
//首先根据interceptor上面定义的注解 获取需要拦截的信息
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
//目标对象的Class
Class<?> type = target.getClass();
//返回需要拦截的接口信息
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
//如果长度为>0 则返回代理类 否则不做处理
if (interfaces.length > 0) {
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
//代理对象每次调用的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//通过method参数定义的类 去signatureMap当中查询需要拦截的方法集合
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
//判断是否需要拦截
if (methods != null && methods.contains(method)) {
return interceptor.intercept(new Invocation(target, method, args));
}
//不拦截 直接通过目标对象调用方法
return method.invoke(target, args);
} catch (Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
//根据拦截器接口(Interceptor)实现类上面的注解获取相关信息
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
//获取注解信息
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
//为空则抛出异常
if (interceptsAnnotation == null) { // issue #251
throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
//获得Signature注解信息
Signature[] sigs = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>();
//循环注解信息
for (Signature sig : sigs) {
//根据Signature注解定义的type信息去signatureMap当中查询需要拦截方法的集合
Set<Method> methods = signatureMap.get(sig.type());
//第一次肯定为null 就创建一个并放入signatureMap
if (methods == null) {
methods = new HashSet<Method>();
signatureMap.put(sig.type(), methods);
}
try {
//找到sig.type当中定义的方法 并加入到集合
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
//根据对象类型与signatureMap获取接口信息
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<Class<?>>();
//循环type类型的接口信息 如果该类型存在与signatureMap当中则加入到set当中去
while (type != null) {
//type:Executor接口实现类,比如SimpleExecutor
//type.getInterfaces():例如org.apache.ibatis.executor.Executor
for (Class<?> c : type.getInterfaces()) {
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
//转换为数组返回
return interfaces.toArray(new Class<?>[interfaces.size()]);
}
}
package org.apache.ibatis.plugin;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
Signature[] value();
}
package org.apache.ibatis.plugin;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Signature {
Class<?> type();
String method();
Class<?>[] args();
}
public static Object wrap(Object target, Interceptor interceptor) {
// 从拦截器的注解中获取拦截的类名和方法信息
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
// 解析被拦截对象的所有接口(注意是接口)
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if(interfaces.length > 0) {
// 生成代理对象, Plugin对象为该代理对象的InvocationHandler (InvocationHandler属于java代理的一个重要概念,不熟悉的请参考相关概念)
return Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target,interceptor,signatureMap));
}
return target;
}
private Object target;// 被代理的目标类
private Interceptor interceptor;// 对应的拦截器
private Map<Class<?>, Set<Method>> signatureMap;// 拦截器拦截的方法缓存
private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) {
Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);
if (interceptsAnnotation == null) { // issue #251
throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());
}
Signature[] sigs = interceptsAnnotation.value();
Map<Class<?>, Set<Method>> signatureMap = new HashMap<Class<?>, Set<Method>>();
for (Signature sig : sigs) {
Set<Method> methods = signatureMap.get(sig.type());
if (methods == null) {
methods = new HashSet<Method>();
signatureMap.put(sig.type(), methods);
}
try {
Method method = sig.type().getMethod(sig.method(), sig.args());
methods.add(method);
} catch (NoSuchMethodException e) {
throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);
}
}
return signatureMap;
}
@Intercepts({@Signature(type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})})
private static Class<?>[] getAllInterfaces(Class<?> type, Map<Class<?>, Set<Method>> signatureMap) {
Set<Class<?>> interfaces = new HashSet<Class<?>>();
while (type != null) {
for (Class<?> c : type.getInterfaces()) {
if (signatureMap.containsKey(c)) {
interfaces.add(c);
}
}
type = type.getSuperclass();
}
return interfaces.toArray(new Class<?>[interfaces.size()]);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
Set<Method> methods = signatureMap.get(method.getDeclaringClass());
if(methods != null && methods.contains(method)) {
// 调用代理类所属拦截器的intercept方法,
return interceptor.intercept(new Invocation(target, method, args));
}
return method.invoke(target, args);
} catch(Exception e) {
throw ExceptionUtil.unwrapThrowable(e);
}
}
public class Invocation {
private Object target;
private Method method;
private Object[] args;
public Invocation(Object target, Method method, Object[] args) {
this.target =target;
this.method =method;
this.args =args;
}
...
public Object proceed() throws InvocationTargetException, IllegalAccessException {
return method.invoke(target, args);
}
}
public Object intercept(Invocation invocation) throws Throwable {
//完成代理类本身的逻辑
...
//通过invocation.proceed()方法完成调用链的推进
return invocation.proceed();
}
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.1</version>
</dependency>
<!--注意:分⻚助⼿的插件 配置在通⽤馆mapper之前*-->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!--指定⽅⾔-->
<property name="dialect" value="mysql"/>
</plugin>
public void test6() throws IOException {
//加载核⼼配置⽂件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//获得sqlSession⼯⼚对象
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(resourceAsStream);
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
IUsrDao usrDao = sqlSession.getMapper(IUsrDao.class);
PageHelper.startPage(1,20);
List<User> users = usrDao.findAll();
PageInfo<User> pageInfo = new PageInfo<>(users);
System.out.println(pageInfo.toString());
}
package com.bcst.plugin;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
/**
分页插件
*@description 欢迎关注公众号 编程识堂,每日更新技术相关文章,关注我不迷路
*@author 小堂
*@create 2023/7/20 20:54
*/
@Intercepts({@Signature(
method = "prepare",
type = StatementHandler.class,
args = {Connection.class, Integer.class}
)})
public class PageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("PageInterceptor插件 目标方法被增强。。。。");
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
// 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环
// 可以分离出最原始的的目标类)
while (metaStatementHandler.hasGetter("h")) {
Object object = metaStatementHandler.getValue("h");
metaStatementHandler = SystemMetaObject.forObject(object);
}
// 分离最后一个代理对象的目标类
while (metaStatementHandler.hasGetter("target")) {
Object object = metaStatementHandler.getValue("target");
metaStatementHandler = SystemMetaObject.forObject(object);
}
RowBounds rowBounds = null;
try {
rowBounds = (RowBounds)metaStatementHandler.getValue("delegate.rowBounds");
} catch (Exception var11) {
return invocation.proceed();
}
if (rowBounds != null && rowBounds != RowBounds.DEFAULT) {
String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
Connection connection = (Connection) invocation.getArgs()[0];
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
int totalCount = this.getPageTotalCount(originalSql, connection, mappedStatement, boundSql);
if (totalCount > 0) {
String sql = "";
if (rowBounds.getOffset() > 0) {
sql = originalSql + " limit " + rowBounds.getOffset() + "," + rowBounds.getLimit();
} else {
sql = originalSql + " limit " + rowBounds.getLimit();
}
// 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数
metaStatementHandler.setValue("delegate.boundSql.sql", sql);
metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
}
metaStatementHandler.setValue("delegate.boundSql.parameterObject.totalCount", totalCount);
}
// 将执行权交给下一个拦截器
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
//当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的
if (target instanceof StatementHandler){
System.out.println("PageInterceptor插件将要包装的⽬标对象:"+target);
return Plugin.wrap(target,this);
}
return target;
}
@Override
public void setProperties(Properties properties) {
}
private int getPageTotalCount(String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql) {
String countSql = "select count(0) from (" + sql + ") as total";
PreparedStatement countStmt = null;
ResultSet rs = null;
int totalCount = 0;
try {
countStmt = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
additionalParameter(boundSql,countBS);
this.setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());
rs = countStmt.executeQuery();
if (rs.next()) {
totalCount = rs.getInt(1);
}
} catch (SQLException var22) {
} finally {
try {
rs.close();
} catch (SQLException var21) {
var21.printStackTrace();
}
try {
countStmt.close();
} catch (SQLException var20) {
var20.printStackTrace();
}
}
return totalCount;
}
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, Object parameterObject) throws SQLException {
ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler.setParameters(ps);
}
private void additionalParameter(BoundSql boundSql,BoundSql targetBoundSql){
Class c = boundSql.getClass();
try {
Field field = c.getDeclaredField("additionalParameters");
field.setAccessible(true);
Map<String,Object> boundMap = (Map<String,Object>)field.get(boundSql);
if(boundMap!=null) {
for (Map.Entry<String, Object> entry : boundMap.entrySet()) {
targetBoundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
<plugins>
<plugin interceptor="com.bcst.plugin.MyPlugin">
<property name="name" value="小堂"/>
</plugin>
<!--注意:分⻚助⼿的插件 配置在通⽤馆mapper之前*-->
<plugin interceptor="com.bcst.plugin.PageInterceptor">
<!--指定⽅⾔-->
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
package com.bcst.pojo;
/**
分页请求体
*@description 欢迎关注公众号 编程识堂,每日更新技术相关文章,关注我不迷路
*@author 小堂
*@create 2023/7/20 20:54
*/
public class PagingListBo {
/**
* 偏移量
*/
private Integer offset=0;
/**
* 限量每页多少条(不填默认10
*/
private Integer limit=10;
/**
* 总数量
*/
private Integer totalCount=0;
//总页数
private Integer pageCount=0;
/**
* 页码当前多少页(不填默认1)
*/
private Integer pageIndex=1;
public Integer getOffset() {
offset = limit * (this.pageIndex-1);
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Integer getTotalCount() {
return totalCount;
}
public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}
public Integer getPageCount() {
pageCount= (this.totalCount + this.limit - 1) / this.limit;
return pageCount;
}
public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}
public Integer getPageIndex() {
return pageIndex;
}
public void setPageIndex(Integer pageIndex) {
this. pageIndex = pageIndex;
}
}
/**
用户请求体
*@description 欢迎关注公众号 编程识堂,每日更新技术相关文章,关注我不迷路
*@author 小堂
*@create 2023/7/20 20:54
*/
public class UserQueryBo extends PagingListBo{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.bcst.pojo;
import java.util.List;
/**
分页返回体
*@description 欢迎关注公众号 编程识堂,每日更新技术相关文章,关注我不迷路
*@author 小堂
*@create 2023/7/20 20:54
*/
public class PageVO<T>{
/**
* 分页总数
*/
private long total;
/**
* 数据集
*/
private List<T> rows;
public PageVO() {
}
public PageVO(long total, List<T> rows) {
this.total = total;
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
}
/*
*@description 欢迎关注公众号 编程识堂,每日更新技术相关文章,关注我不迷路
*@author 小堂
*@create 2023/7/9 11:58
*/
public interface IUsrDao {
List<User> findList( UserQueryBo userQueryBo, RowBounds rowBounds);
}
<select id="findList" resultType="com.bcst.pojo.User">
select username name,phone from user where username like concat('%',#{name},'%')
</select>
<plugins>
<plugin interceptor="com.bcst.plugin.MyPlugin">
<property name="name" value="小堂"/>
</plugin>
<!--注意:分⻚助⼿的插件 配置在通⽤馆mapper之前*-->
<plugin interceptor="com.bcst.plugin.PageInterceptor">
<!--指定⽅⾔-->
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
public void test7() throws IOException {
//加载核⼼配置⽂件
InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//获得sqlSession⼯⼚对象
SqlSessionFactory sqlSessionFactory = new
SqlSessionFactoryBuilder().build(resourceAsStream);
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
IUsrDao usrDao = sqlSession.getMapper(IUsrDao.class);
UserQueryBo userQueryBo = new UserQueryBo();
userQueryBo.setName("u1105");
RowBounds rowBounds = new RowBounds(1,20);
List<User> users = usrDao.findList(userQueryBo,rowBounds);
PageVO<User> pageVO = new PageVO<>(userQueryBo.getTotalCount(),users);
System.out.println("总条数:"+pageVO.getTotal()+"当前页条数:"+pageVO.getRows().size());
}
我是小堂,下期见~
·········· END ··············
在看、点赞、转发,是对我最大的鼓励。
技术资料、面试笔记公众号内回复[ 资料 ] Get。 文章项目源码公众号内回复[ 源码] Get。 ●Mybatis基础回顾 ●自定义持久层框架 ●Kubernetes系列之集群部署 ●Kubernetes系列之Pod生命周期 三连给小编加鸡腿!