MyBatis分页插件pagehelper和PageInterceptor版本问题——源码分析


MyBatis分页插件版本问题

Cause: java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor

问题背景:

在某商城的学习过程中用到的分页插件的版本是4.0以下的版本,基本不支持多边查询的分页,学习资料中是经过高手重新编写的,后来查资料发现最新的5.0及以上的版本已经有了解决方案,便直接用了5.0的版本,除了引用这个pagehelper-x.x.x.jar 和其依赖包 jsqlparser-0.9.5.jar,开始的配置就照着原来的配置在SqlMapConfig.xml进行了配置

一、5.0以下版本分页插件的xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <!-- com.github.pagehelper 为 PageHelper 类所在包名 -->
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL 六种数据库-->
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>
</configuration>

在5.0版本以下xml配置文件中需要配置数据库名

二 、5.0以上版本分页插件的xml配置文件

 <configuration>
    	<plugins>
    		<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    	</plugins>
    </configuration>

在5.0版本以上xml配置文件中是不需要配置数据库名

三、配置错误时的运行错误日志

一月 09, 2021 10:31:01 下午 org.apache.catalina.core.StandardContext listenerStart
严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in URL [jar:file:/E:/apache-maven-3.6.3-bin/m2/com/pinyougou/pinyougou-dao/1.0-SNAPSHOT/pinyougou-dao-1.0-SNAPSHOT.jar!/spring/applicationContext-dao.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse config resource: class path resource [mybatis/SqlMapConfig.xml]; nested exception is org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)

四、分析

合后的mybatiesspring都是通过配置文件联系起来的,如果配置文件有问题一些映射就会出错,也就会导致一些class或者bean无法成功生成或找到,经过多次查找,发现是分页的插件配置的问题,如果把mybatis的分页插件的配置注释掉就能运行

异常信息

java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to 
org.apache.ibatis.plugin.Interceptor

mybatis的配置文件,SqlMapConfig.xml配置可能有误,核查了一遍依然报错,考虑版本的问题呢,一搜看到了这篇博客,他用的是PageInterceptor,我用的是pagehelper

五、直接原因:

PageHelper5.0版本pagehelper是继承了PageMethod和实现了Dialect,PageInterceptor是实现了Interceptor接口

在这里插入图片描述
在这里插入图片描述
pageHelper是如何在mybatis中工作呢,是通过mybatis的pulgin实现了Interceptor接口,从而获得要执行的sql语句实现分页技术。所以最开始报错能解释了,可改成了PageInterceptor又报错是怎么回事呢,这这篇博客中,才注意到了错误日志里的这句话

Error parsing SQL Mapper Configuration. Cause: com.github.pagehelper.PageException: 
java.lang.ClassNotFoundException: mysql

给出的解释是PageHelper插件4.0.0以后的版本支持自动识别使用的数据库,可以不用配置 <property

name=“dialect” value=“mysql”/> 这,抱着侥幸的心理,我再一次试了,然后就成功了,真是一波三折,后来打开这个类发现了这么几句代码
在这里插入图片描述
在这里插入图片描述
通过读取properties里面的配置文件来自动识别数据库的,只需要在分页插件配置文件中配置这个类即可,无需指定数据库

六、感悟

主要还是要学习其工作的原理,一些源码的简单理解

分页展示数据的服务端代码

在这里插入图片描述

服务端

a) 创建PageBean对象

public class PageBean<T> {

    private int totalCount;//总记录数
    private int totalPage;//总页数
    private int currentPage;//当前页码
    private int pageSize;//每页显示的条数

    private List<T> list;//每页显示的数据集合

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}

b) RouteServlet

@WebServlet("/route/*")
public class RouteServlet extends BaseServlet {

    private RouteService routeService = new RouteServiceImpl();

    /** * 分页查询 * @param request * @param response * @throws ServletException * @throws IOException */
    public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.接受参数
        String currentPageStr = request.getParameter("currentPage");
        String pageSizeStr = request.getParameter("pageSize");
        String cidStr = request.getParameter("cid");

        int cid = 0;//类别id
        //2.处理参数
        if(cidStr != null && cidStr.length() > 0){
            cid = Integer.parseInt(cidStr);
        }
        int currentPage = 0;//当前页码,如果不传递,则默认为第一页
        if(currentPageStr != null && currentPageStr.length() > 0){
            currentPage = Integer.parseInt(currentPageStr);
        }else{
            currentPage = 1;
        }

        int pageSize = 0;//每页显示条数,如果不传递,默认每页显示5条记录
        if(pageSizeStr != null && pageSizeStr.length() > 0){
            pageSize = Integer.parseInt(pageSizeStr);
        }else{
            pageSize = 5;
        }

        //3. 调用service查询PageBean对象
        PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize);

        //4. 将pageBean对象序列化为json,返回
        writeValue(pb,response);

    }

}

c) RouteService

public class RouteServiceImpl implements RouteService {
    private RouteDao routeDao = new RouteDaoImpl();
    @Override
    public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize) {
        //封装PageBean
        PageBean<Route> pb = new PageBean<Route>();
        //设置当前页码
        pb.setCurrentPage(currentPage);
        //设置每页显示条数
        pb.setPageSize(pageSize);
        
        //设置总记录数
        int totalCount = routeDao.findTotalCount(cid);
        pb.setTotalCount(totalCount);
        //设置当前页显示的数据集合
        int start = (currentPage - 1) * pageSize;//开始的记录数
        List<Route> list = routeDao.findByPage(cid,start,pageSize);
        pb.setList(list);

        //设置总页数 = 总记录数/每页显示条数
        int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize :(totalCount / pageSize) + 1 ;
        pb.setTotalPage(totalPage);


        return pb;
    }
}

d) RouteDao

public class RouteDaoImpl implements RouteDao {
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    @Override
    public int findTotalCount(int cid) {
        String sql = "select count(*) from tab_route where cid = ?";
        return template.queryForObject(sql,Integer.class,cid);
    }

    @Override
    public List<Route> findByPage(int cid, int start, int pageSize) {
        String sql = "select * from tab_route where cid = ? limit ? , ?";

        return template.query(sql,new BeanPropertyRowMapper<Route>(Route.class),cid,start,pageSize);
    }
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM