MyBatis拦截器实现分页功能实例

由于业务关系 巴拉巴拉巴拉

好吧 简单来说就是

原来的业务是 需要再实现类里写 selectCount 和selectPage两个方法才能实现分页功能

现在想要达到效果是 只通过一个方法就可以实现 也就是功能合并 所以就有了下面的实践

既然是基于MyBatis 所以就先搭建一个Mybatis的小项目

1.01导入 mybatis和mysql的包

1.02.配置文件 Configuration.xml 中添加

 <environments default="development">
  <environment id="development">
  <transactionManager type="JDBC"/>
   <dataSource type="POOLED">
   <property name="driver" value="com.mysql.jdbc.Driver"/>
   <property name="url" value="jdbc:mysql://localhost:3306/test" />
   <property name="username" value="root"/>
   <property name="password" value=""/>
   </dataSource>
  </environment>
 </environments>

2.01.然后创建一个模块user  创建user表

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` char(32) NOT NULL,
 `t1` char(32) DEFAULT NULL,
 `t2` char(32) DEFAULT NULL,
 `t3` char(32) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

3.01.写对应bean:User.java

package lqb.bean;

public class User extends Common{

 private String id;
 private String name;
 private String t1;
 private String t2;
 private String t3;

 //省略get set
}

3.02.对应的mapper: UserMapper.java和UserMapper.xml 

简单实现下CRUD

public interface UserMapper {
 public User selectByID(int id);
 public List<User> select();
 public int insert(User u);
 public int update(User u);
 public int delete(User u);

}
<mapper namespace="lqb.mapper.UserMapper">
 <select id="selectByID" parameterType="int" resultType="lqb.bean.User">
  select * from `user` where id = #{id}
 </select>
 <select id="select" resultType="lqb.bean.User" parameterType="lqb.bean.User">
  select * from `user`
 </select>

 <insert id="insert" parameterType="lqb.bean.User">
  insert into user (id,name,t1,t2,t3) values (#{id},#{name},#{t1},#{t2},#{t3})
 </insert>
 <update id="update" parameterType="lqb.bean.User">
  update user set name=#{name},t1=#{t1},t2=#{t2},t3=#{t3} where id=#{id}
 </update>
 <delete id="delete" parameterType="lqb.bean.User">
  delete from user where id=#{id}
 </delete>
</mapper>

3.03.然后 在配置文件Configuration.xml中添加user的配置

<mappers>
  <mapper resource="lqb/mapper/UserMapper.xml"/>
</mappers>

3.04.然后是实现:UserService.java

public class UserService {
 private static SqlSessionFactory sqlSessionFactory;
 private static Reader reader;

 static{
  try{
   reader = Resources.getResourceAsReader("Configuration.xml");
   sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
  }catch(Exception e){
   e.printStackTrace();
  }
 }

 public static SqlSessionFactory getSession(){
  return sqlSessionFactory;
 }
}

4.01 好 然后是重点了

思路: 截获查询的sql 然后拼成 sqlPage和sqlCount 再进行查找取值 然后赋传入对象

所以我们就需要创建一个基础类来让user.java来继承

public class Common {
 private int pagesize;
 private int pageid;
 private int pagebegin;
 private int count;
 //省略 get set
}

4.02 然后 让User继承Common

public class User extends Common{

4.03 那怎么截获sql呢 我们就要写一个mybatis的拦截器 用来拦截sql请求 PageInterceptor

 @Intercepts({
  @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}),
  @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class PageInterceptor implements Interceptor {
  //插件运行的代码,它将代替原有的方法
 @Override
 public Object intercept(Invocation invocation) throws Throwable {
 }

 // 拦截类型StatementHandler
 @Override
 public Object plugin(Object target) {
 }

 @Override
 public void setProperties(Properties properties) {
 } 

4.04 首先 设置拦截类型 重写plugin方法

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

4.05 然后 就要重写最重要的intercept了

这里我们有一个设定  如果查询方法含有searchpage 就进行分页 其他方法无视

所以就要获取方法名

 StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
 MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
 MappedStatement mappedStatement=(MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
 String selectId=mappedStatement.getId();

4.06 然后判断下 如果含有searchpage 就获取sql

BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
// 分页参数作为参数对象parameterObject的一个属性
String sql = boundSql.getSql();
Common co=(Common)(boundSql.getParameterObject());

4.07 然后 根据这个sql 重新拼写countsql和pagesql

String countSql=concatCountSql(sql);
String pageSql=concatPageSql(sql,co);
...
public String concatCountSql(String sql){
  StringBuffer sb=new StringBuffer("select count(*) from ");
  sql=sql.toLowerCase();

  if(sql.lastIndexOf("order")>sql.lastIndexOf(")")){
   sb.append(sql.substring(sql.indexOf("from")+4, sql.lastIndexOf("order")));
  }else{
   sb.append(sql.substring(sql.indexOf("from")+4));
  }
  return sb.toString();
 }

public String concatPageSql(String sql,Common co){
  StringBuffer sb=new StringBuffer();
  sb.append(sql);
  sb.append(" limit ").append(co.getPagebegin()).append(" , ").append(co.getPagesize());
  return sb.toString();
 }

4.08 然后 通过jdbc查询count 然后把值绑定给common

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

    PreparedStatement countStmt = null;
    ResultSet rs = null;
    int totalCount = 0;
    try {
     countStmt = connection.prepareStatement(countSql);
     rs = countStmt.executeQuery();
     if (rs.next()) {
      totalCount = rs.getInt(1);
     } 

    } catch (SQLException e) {
     System.out.println("Ignore this exception"+e);
    } finally {
     try {
      rs.close();
      countStmt.close();
     } catch (SQLException e) {
      System.out.println("Ignore this exception"+ e);
     }
    } 

    //绑定count
    co.setCount(totalCount);

4.09 再把pagesql赋给元BoundSql

metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); 

4.10 最后在配置文件中添加拦截器配置

 <plugins>
 <plugin interceptor="lqb.interceptor.PageInterceptor"/>
</plugins> 

4.11 好然后 在UserMapper.java和UserMapper.xml中添加分页代码

 <select id="selectPage" parameterType="lqb.bean.User" resultType="lqb.bean.User">
  select * from `user` where id in(3,4,6,8) order by id
 </select>
public List<User> selectPage(User u);

5.01 最后是测试了

main...请允许本人的懒 就姑且在main方法测下吧

User u=new User();
u.setPagebegin(2);
u.setPagesize(3);
System.out.println("-u.getCount()------"+u.getCount());
List<User> l=userService.selectPage(u);
System.out.println(l.size());
System.out.println("-u.getCount()------"+u.getCount());

5.02 结果 略   然后就成功了 

下面附上拦截器的代码

package lqb.interceptor;

import java.util.Properties;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
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 java.sql.*;
import lqb.bean.Common;

@Intercepts({
  @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}),
  @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class PageInterceptor implements Interceptor { 

 private static final String SELECT_ID="selectpage";

 //插件运行的代码,它将代替原有的方法
 @Override
 public Object intercept(Invocation invocation) throws Throwable {
  System.out.println("PageInterceptor -- intercept");

  if (invocation.getTarget() instanceof StatementHandler) {
   StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
   MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
   MappedStatement mappedStatement=(MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
   String selectId=mappedStatement.getId();

   if(SELECT_ID.equals(selectId.substring(selectId.lastIndexOf(".")+1).toLowerCase())){
    BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
    // 分页参数作为参数对象parameterObject的一个属性
    String sql = boundSql.getSql();
    Common co=(Common)(boundSql.getParameterObject());

    // 重写sql
    String countSql=concatCountSql(sql);
    String pageSql=concatPageSql(sql,co);

    System.out.println("重写的 count sql  :"+countSql);
    System.out.println("重写的 select sql  :"+pageSql);

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

    PreparedStatement countStmt = null;
    ResultSet rs = null;
    int totalCount = 0;
    try {
     countStmt = connection.prepareStatement(countSql);
     rs = countStmt.executeQuery();
     if (rs.next()) {
      totalCount = rs.getInt(1);
     } 

    } catch (SQLException e) {
     System.out.println("Ignore this exception"+e);
    } finally {
     try {
      rs.close();
      countStmt.close();
     } catch (SQLException e) {
      System.out.println("Ignore this exception"+ e);
     }
    } 

    metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);   

    //绑定count
    co.setCount(totalCount);
   }
  } 

  return invocation.proceed();
 }

 /**
  * 拦截类型StatementHandler
  */
 @Override
 public Object plugin(Object target) {
  if (target instanceof StatementHandler) {
   return Plugin.wrap(target, this);
  } else {
   return target;
  }
 }

 @Override
 public void setProperties(Properties properties) {

 } 

 public String concatCountSql(String sql){
  StringBuffer sb=new StringBuffer("select count(*) from ");
  sql=sql.toLowerCase();

  if(sql.lastIndexOf("order")>sql.lastIndexOf(")")){
   sb.append(sql.substring(sql.indexOf("from")+4, sql.lastIndexOf("order")));
  }else{
   sb.append(sql.substring(sql.indexOf("from")+4));
  }
  return sb.toString();
 }

 public String concatPageSql(String sql,Common co){
  StringBuffer sb=new StringBuffer();
  sb.append(sql);
  sb.append(" limit ").append(co.getPagebegin()).append(" , ").append(co.getPagesize());
  return sb.toString();
 }

 public void setPageCount(){

 }

}

最后是下载地址:mybatisResolve_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • MyBatis拦截器实现分页功能的实现方法

    MyBatis拦截器实现分页功能的实现方法 前言: 首先说下实现原理.使用拦截器拦截原始的sql,然后加上分页查询的关键字和属性,拼装成新的sql语句再交给mybatis去执行. 除了业务代码之外,需要写的东西不多,提几个关键的: 1.分页对象Page类.给该对象设置一个当前页数(前端给).总记录数(拦截器内赋值)2个参数,他就能帮你计算出分页sql语句用的2个参数. /** * 分页对应的实体类 */ public class Page { /** * 总条数 */ private int t

  • MyBatis拦截器实现分页功能实例

    由于业务关系 巴拉巴拉巴拉 好吧 简单来说就是 原来的业务是 需要再实现类里写 selectCount 和selectPage两个方法才能实现分页功能 现在想要达到效果是 只通过一个方法就可以实现 也就是功能合并 所以就有了下面的实践 既然是基于MyBatis 所以就先搭建一个Mybatis的小项目 1.01导入 mybatis和mysql的包 1.02.配置文件 Configuration.xml 中添加 <environments default="development"&

  • mybatis拦截器与分页插件实例教程

    mybatis介绍 拦截器的一个作用就是我们可以拦截某些方法的调用,我们可以选择在这些被拦截的方法执行前后加上某些逻辑,也可以在执行这些被拦截的方法时执行自己的逻辑而不再执行被拦截的方法. MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型.接口和 Java 的 POJO(Plain Old Java Objects,普

  • 简单了解mybatis拦截器实现原理及实例

    这篇文章主要介绍了简单了解mybatis拦截器实现原理及实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 例行惯例,先看些基本概念: 1 拦截器的作用就是我们可以拦截某些方法的调用,在目标方法前后加上我们自己逻辑 2 Mybatis拦截器设计的一个初衷是为了供用户在某些时候可以实现自己的逻辑而不必去动Mybatis固有的逻辑. 自定义拦截器 /** * mybatis 自定义拦截器 * 三步骤: * 1 实现 {@link Intercept

  • Mybatis拦截器实现分页

    最终dao层结果: public interface ModelMapper { Page<Model> pageByConditions(RowBounds rowBounds, Model record); } 接下来一步一步来实现分页. 一.创建Page对象: public class Page<T> extends PageList<T> { private int pageNo = 1;// 页码,默认是第一页 private int pageSize = 1

  • MyBatis拦截器原理探究

    MyBatis拦截器介绍 MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis 允许使用插件来拦截的方法调用包括: Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) P

  • MyBatis拦截器:给参数对象属性赋值的实例

    该拦截器的作用:在进行增加.修改等操作时,给数据模型的一些通用操作属性(如:创建人.创建时间.修改人.修改时间等)自动赋值. 该实现是在DAO层拦截,即存入DB前最后一层.后经分析,不是很合理,改为在service层拦截,用spring AOP来实现了,该代码遂弃用.不过已经测试可用,记录备忘. package com.development; import java.lang.reflect.InvocationTargetException; import java.util.Date; i

  • Mybatis拦截器的实现介绍

     MyBatis介绍 MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .它支持普通 SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的

  • Mybatis Plus 自定义方法实现分页功能的示例代码

    一般物理分页,即通过sql语句分页,都是在sql语句后面添加limit分页语句,在xml文件里传入分页的参数,再多配置一条sql,用于查询总数: <select id="queryStudentsBySql" parameterType="map" resultMap="studentmapper"> select * from student limit #{currIndex} , #{pageSize} </select&

  • 使用mybatis拦截器处理敏感字段

    目录 mybatis拦截器处理敏感字段 前言 思路解析 代码 趟过的坑(敲黑板重点) mybatis Excutor 拦截器的使用 这里假设一个场景 实现过程的关键步骤和代码 重点 mybatis拦截器处理敏感字段 前言 由于公司业务要求,需要在不影响已有业务上对 数据库中已有数据的敏感字段加密解密,个人解决方案利用mybatis的拦截器加密解密敏感字段 思路解析 利用注解标明需要加密解密的entity类对象以及其中的数据 mybatis拦截Executor.class对象中的query,upd

随机推荐