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)
四、分析
合后的mybaties
和spring
都是通过配置文件联系起来的,如果配置文件有问题一些映射就会出错,也就会导致一些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);
}
}