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