您的当前位置:首页正文

SpringBoot: 自定义MyBatis拦截器来实现分页

2024-11-29 来源:个人技术集锦

一、参照了PageHelper的源码,不是为了重复造轮子,只是为了能让自己有造轮子的水平。
二、准备:数据库 test,数据表:

insert into student(name,age) values('paul',33);
insert into student(name,age) values('david',23);

insert into student(name,age) values('kate',23);
insert into student(name,age) values('cindy',21);

insert into student(name,age) values('hilary',17);

insert into student(name,age) values('clinton',25);

insert into student(name,age) values('trump',34);

insert into student(name,age) values('yoke',21);

insert into student(name,age) values('owen',12);

insert into student(name,age) values('karick',29);

insert into student(name,age) values('tomas',35);

insert into student(name,age) values('muller',41);

三、创建spring boot项目,引入相关依赖,完整pom如下,

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.edu.tju</groupId>
    <artifactId>my-pager</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>


        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.6</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.30</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.13</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>


</project>

四、配置application.properties

server.port=8030
spring.datasource.url=jdbc:mysql://xxx.xxx.xxx.xxx/test
spring.datasource.username=root
spring.datasource.password=xxxxxx
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.configuration.map-underscore-to-camel-case=true

五、定义用来分页类、分页辅助类、拦截器类、拦截器配置类

package cn.edu.tju.config;

public class Pager {
    int pageNumber;
    int pageSize;

    public int getPageNumber() {
        return pageNumber;
    }

    public void setPageNumber(int pageNumber) {
        this.pageNumber = pageNumber;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
}
package cn.edu.tju.config;

public class MyPageHelper {
    protected static ThreadLocal<Pager> myPager=new ThreadLocal<>();
    public static void startPage(int pageNumber,int pageSize){
        Pager pager=new Pager();
        pager.setPageNumber(pageNumber);
        pager.setPageSize(pageSize);
        myPager.set(pager);
    }
    public static Pager getLocalPage(){
        return myPager.get();
    }
    public static void removeLocalPage(){
        myPager.remove();
    }
}


package cn.edu.tju.config;

import cn.edu.tju.config.MyPageHelper;
import cn.edu.tju.config.Pager;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
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.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.util.Properties;

@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args={Connection.class,Integer.class})})
public class MyInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //打印这句,说明拦截器起作用了
        System.out.println("my interceptor was called......");

        //通过invocation对象拿到StatementHandler对象
        StatementHandler statementHandler=(StatementHandler)invocation.getTarget();
        MetaObject metaObject= SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement=(MappedStatement)metaObject.getValue("delegate.mappedStatement");

        //拿到Mapper中的方法名 ,例如: cn.edu.tju.mapper.StudentMapper.getStudentList
        String id = mappedStatement.getId();
        //拿到要执行的SQL 语句, 例如:select * from student
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql();

        //从ThreadLocal中拿到pageNumber和pageSize
        Pager localPage = MyPageHelper.getLocalPage();
        int pageSize=localPage.getPageSize();
        int pageNumber=localPage.getPageNumber();

        //判断是否需要分页
        if(pageNumber>0 && pageSize>0 && sql.contains("select")){
            //计算SQL语句中需要添加的分页信息,例如: limit 2,10,并将其添加到sql 语句中
            String startPosition=String.valueOf((pageNumber-1)*pageSize);
            String count=String.valueOf(pageSize);
            String pageSql=sql+ " limit ";
            pageSql+= startPosition;
            pageSql+=",";
            pageSql+=count;

            //修改sql语句用来完成分页
            metaObject.setValue("delegate.boundSql.sql",pageSql);

            //清除分页信息
            MyPageHelper.removeLocalPage();
        }

        //执行SQL语句
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {

    }
}

package cn.edu.tju.config;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;



@Configuration
public class MyConfig {

    @Bean
    public MyInterceptor getInterceptor(){
        return new MyInterceptor();
    }
}

六、定义实体类、mapper类、controller类

package cn.edu.tju.domain;

public class Student {
    private int id;
    private String name;
    private String age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

package cn.edu.tju.mapper;

import cn.edu.tju.domain.Student;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface StudentMapper {
    @Select("select * from student")
    List<Student> getStudentList();
}

package cn.edu.tju.controller;

import cn.edu.tju.config.MyPageHelper;
import cn.edu.tju.domain.Student;
import cn.edu.tju.mapper.StudentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class StudentController {
    @Autowired
    private StudentMapper studentMapper;
    @RequestMapping("/getStudentByPage/{pageNumber}/{pageSize}")
    public List<Student> getStudentByPage(@PathVariable("pageNumber") int pageNumber,
                                          @PathVariable("pageSize")int pageSize){
        //开始分页
        MyPageHelper.startPage(pageNumber,pageSize);
        return studentMapper.getStudentList();
    }
}


七、定义启动类,并启动程序:

package cn.edu.tju;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Start {
    public static void main(String[] args) {
        SpringApplication.run(Start.class,args);
    }
}

八、运行结果:

显示全文