Mybaits拦截器实现查询分页

1.创建两个实体类

CommandContent类和Command类

public class CommandContent {
private String id; //主键
private String content;
private String commandId;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCommandId() {
return commandId;
}
public void setCommandId(String commandId) {
this.commandId = commandId;
}
}

package com.jh.bean;


import java.util.List;


public class Command {
//主键
private String id;
//指令名称
private String name;
//指令描述
private String descrption;
//指令对应得多条回复
private List<CommandContent> contentlist;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescrption() {
return descrption;
}
public void setDescrption(String descrption) {
this.descrption = descrption;
}
public List<CommandContent> getContentlist() {
return contentlist;
}
public void setContentlist(List<CommandContent> contentlist) {
this.contentlist = contentlist;
}
}

2.在数据库创建两个表,具有关联关系

3.配置文件

//command实体类配置文件

<mapper namespace="Command">


  <resultMap type="com.jh.bean.Command" id="Command">
    <id column="c_id" jdbcType="VARCHAR" property="id"/>
    <result column="name" jdbcType="VARCHAR" property="name"/>
    <result column="descrption" jdbcType="VARCHAR" property="descrption"/>
    <collection property="contentlist" resultMap="CommandContent.Content"/>
  </resultMap>
  
  <select  id="getCommandList" parameterType="com.jh.bean.Command" resultMap="Command">
     select c.id c_id,c.name,c.descrption,d.id,d.content,d.commandId 
     from command c left join commandContent d on c.ID=d.commandId
     <where>
    <if test="name != null and !&quot;&quot;.equals(name.trim())"> and c.name=#{name}</if>   <!-- c:if标签里用上一个ognl表达式  xml得双引号为:&quot&quot &&在xml里是&amp;&amp -->
    <if test="descrption != null and !&quot;&quot;.equals(descrption.trim())"> and a.descrption like '%' #{descrption} '%'</if>
     </where>
  </select>
 <update id="updateMessage" parameterType="com.jh.bean.Command">
     update command c left join commandContent d on c.ID=d.commandId set c.name=#{name},c.descrption=#{descrption},d.content=#{content}
     where c.id c_id=#{id}
 </update> 
  
</mapper>

commandContent配置文件

<mapper namespace="CommandContent">


  <resultMap type="com.jh.bean.CommandContent" id="Content">
    <id column="id" jdbcType="VARCHAR" property="id"/>
    <result column="content" jdbcType="VARCHAR" property="content"/>
    <result column="commandId" jdbcType="VARCHAR" property="commandId"/>
  </resultMap>
  <!-- 
  <insert id="addBacth" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
      insert into message(content,commandId) values
      <foreach collection="list" item="item" separator=",">
          (#{item.content},#{item.commandId})
      </foreach>
  </insert>
   -->
  </mapper>

实现拦截的类:

package com.jh.intercept;
import java.sql.Connection;


import java.sql.ResultSet;
import java.util.Map;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;


import com.jh.entiy.Page;
import com.mysql.jdbc.PreparedStatement;

//type参数表示拦截的部分,method表示拦截的方法,args表示参数
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})
public class PageIntercept implements Interceptor {

@Override
/*
 * 跟踪源码
 * 查询是通过excute调度statementHandler来完成的,调度statementHandler是通过prepare方法进行与预编译SQL
 * 需拦截的方法是prepare,在此之前完成SQL的重新编写
 * 使用mybatis的拦截器进行分页
 * 实现intercept接口
 * 注意几大对象
 *1.statementHandler对象是通过接口里的参数获取.getTarget,它的作用是让数据库的statement(preparedStatement)执行操作
 *(此对象是通过routingStatementHandler对象获取)
 *2.获取metaobject对象传入的参数为上面的对象
 *8.delegate对象的适配器 他是StatementHandler接口对象
 *3.MappedStatement对象,是通过metaobject对象的getValue方法,参数为delegate.mappedStatement
 *4.Boundsql对象,通过statementHandler对象的getBoundsql方法
 *5.mappedStatement对象保存映射的节点(select insert update delete)包括配置的id,缓存信息,resultMap parameterType 等重要配置信息
 *7.ParameterHandler用于sql对参数的处理,获取的方法同MappedStatement
 *6.boundsql是建立sql语句和参数的对象,有三个常用的属性(sql parameterType parameterOject parameterMappings)
 * */
public Object intercept(Invocation invocation) throws Throwable {
//获取StatementHandler对象,通过getTarget方法
StatementHandler statementHandler=(StatementHandler)invocation.getTarget();
//获得metaObject对象
MetaObject metaObject=SystemMetaObject.forObject(statementHandler);
MappedStatement mappedStatement=(MappedStatement) metaObject.getValue("delegate.mappedStatement");
//获取sql语句的id
String id=mappedStatement.getId();
//用正则表达式选择id
if(id.matches(".+Bypage$")){
//获得原始的sql语句
BoundSql boundSql=statementHandler.getBoundSql();
//通过boundsql获取sql
String sql=boundSql.getSql();
//查询总条数的语句
String sqlCount="select count(*) from ("+sql+")a";
//获取连接,通过invocation参数的getArgs方法
Connection connection=(Connection)invocation.getArgs()[0];
PreparedStatement ps= (PreparedStatement) connection.prepareStatement(sqlCount);
//获取parameterHandler对象
ParameterHandler parameterHandler=(ParameterHandler)metaObject.getValue("delegate.parameterHandler");
//为ps设置参数
parameterHandler.setParameters(ps);
ResultSet rs=ps.executeQuery();
//通过boundsql获取参数
Map<?,?> parameter=(Map<?, ?>)boundSql.getParameterObject();
//获得page参数
Page page=(Page)parameter.get("page");
if(rs.next()){
//设置属性
page.setTotleNumber(rs.getInt(1));
//改造后分页查询的语句,sql语句由boundsql获得,boundsql由delegate获得
String pageSpl=sql+"limit"+page.getDbIndex()+page.getDbNumber();
metaObject.setValue("delegate.boundsql.sql",pageSpl);
}
}
return invocation.proceed();
}

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


@Override
public void setProperties(Properties arg0) {
// TODO Auto-generated method stub
}
}

总结:理解理解java反射机制,理解myBatis执行sql语句的过程,底层代码的实现,映射器的内部组成(三部分)1.MappedStatement  2.SqlSource:提供BoundSql的地方,是上一个的属性  3.Boundsql:它是建立sql的对象,有三个属性(sql,parameterObject,parameterMapping)

在拦截器都需用到这些对象

SqlSession下的四大对象(及拦截器拦截的对象)1

1.Executor代表执行器,其它三大对象都由它来调度 2.statementHandler 3.ParameterHandler 4.ResultHandler:时进行最后数据集的封装返回处理

StatementHandler接口是有RoutingStatementHandler对象实现,而它的delegate对象才是真正服务的statementHandler,真实的statementHandler对象有一个属性Boundsql,而BoundSql里有sql属性,所以最后的获取的sql语句:delegate.BoundSql.Sql

查询的过程是通过Executor调度StatemnetHandler来完成的,调度StatemnetHandler的prepare方法预编译sql,所以我们需要拦截的方法便是prepare

MyBatis的工具类-MethodObject:可以有效的读取或者修改一些重要的对象的参数,其有三个方法普遍使用1.MethodObkect.forObject(Objectobj,ObjectFactoryobjectFactory,ObjectWrapperFactor objectWrapperFactory ),2:Object. getValue(String name)方法用于获取属性的值 支持OGNL 3.void setValue(String name,Object Value)用于修改值 也支持OGNL表达式(PammedStatement,statementHandler都是由MethodObject获取,而MethodObject是由SystemMetaObject.forObject获取)

在完成拦截后要交回给底层代码执行sql语句,invocation.proced()进入责任链下一层

plugin方法:使用默认的MyBatis提供的类生成代理对象


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值