springboot集成mybatis详细教程同时实现自定义拦截器分页功能

private int total;

private String sortBy;

private String rank = “DESC”;

public int getPageNo() {

return pageNo;

}

public int getPageSize() {

return pageSize;

}

public int getTotal() {

return total;

}

public String getSortBy() {

return sortBy;

}

public String getRank() {

return rank;

}

public Pager setPageNo(int pageNo) throws IllegalAccessException {

if(pageNo <= 0){

throw new IllegalAccessException(“分页页码必须大于0”);

}

this.pageNo = pageNo;

return this;

}

public Pager setPageSize(int pageSize) throws IllegalAccessException {

if(pageSize <= 0){

throw new IllegalAccessException(“单页数据量必须大于0”);

}

this.pageSize = pageSize;

return this;

}

public Pager setTotal(int total) {

this.total = total;

return this;

}

public Pager setSortBy(String sortBy) {

this.sortBy = sortBy;

return this;

}

public Pager setRank(String rank) {

this.rank = rank;

return this;

}

}

我们会用到UserDao中重载过的两个getUser方法,其中一个只接受用于查询的User参数,另一个额外接受一个Pager对象用于分页。

然后在spring配置文件中指定的包内编写用于映射UserDao的mybatis映射配置文件UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

ID,USERNAME,U_NAME,PHONE,EMAIL,CITY_ID,CITY_NAME,PROVIENCE_ID,PROVIENCE_NAME,ADDRESS,PHOTO,BIRTHDAY,ORGANIZATION_ID,ROLE_ID

,PASSWORD

SELECT

FROM USER

WHERE USERNAME = #{userName}

SELECT

FROM USER

ID = #{id}

AND USERNAME = #{userName}

AND U_NAME LIKE #{uName}

AND PHONE = #{phone}

AND EMAIL = #{email}

AND CITY_ID = #{cityID}

AND PROVIENCE_ID = #{provienceID}

AND ADDRESS LIKE #{address}

AND ORGANIZATION_ID = #{organizationID}

AND ROLE_ID = #{roleID}

insert into USER (ID,USERNAME,PASSWORD,U_NAME,PHONE,EMAIL,CITY_ID,CITY_NAME,PROVIENCE_ID,PROVIENCE_NAME,ADDRESS,PHOTO,BIRTHDAY,ORGANIZATION_ID,ROLE_ID)

values (#{id},

#{userName},

#{passWord},

#{uName},

#{phone},

#{email},

#{cityID},

#{cityName},

#{provienceID},

#{provienceName},

#{address},

#{photo},

#{birthday},

#{organizationID},

#{roleID})

这里需要说明的是我们在UserDao中有两个getUser方法,但在配置文件中只映射了一个select标签,这是因为mybatis和dao层之间的映射只与方法名称有关,而与方法参数无关。所以在sql语句不变,只是参数增加的情况下我们可以用一个select标签映射多个方法。唯一要注意的是传入多个对象参数时要在dao层中使@Param注解为参数指定名称。

然后添加一个mybatis配置类MybatisConfig

package com.feng.config;

import database.mybatis.plug.PageInterceptor;

import org.mybatis.spring.annotation.MapperScan;

import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

  • Created by Feng

*/

@MapperScan(“com.feng.dao”)

@Configuration

public class MybatisConfig {

}

使用MapperScan用于指定dao层位置。

这个时候我们已经可以通过注入的方式使用UserDao来查询用户数据了,但为了规范,我们在dao层之上增加一个service层,编写UserService接口和实现类

package com.feng.service;

import com.feng.entity.User;

import database.support.Pager;

import java.util.List;

/**

  • Created by Feng

*/

public interface UserService {

public User getUserByID(int id);

public int removeUserByID(int id);

public User loadUserByUserName(String userName);

public List getUser(Pager pager,User user);

public List getUser(User user);

}

package com.feng.service;

import com.feng.dao.UserDao;

import com.feng.entity.User;

import database.support.Pager;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.util.List;

/**

  • Created by Feng

*/

@Service

public class UserServiceImpl implements UserService {

@Resource

private UserDao userDao;

@Override

public User getUserByID(int id) {

User queryUser = new User();

queryUser.setId(id);

List users = userDao.getUser(queryUser);

if(users != null && users.size() > 0){

return users.get(0);

}

return null;

}

@Override

public int removeUserByID(int id) {

return 0;

}

@Override

public User loadUserByUserName(String userName) {

return userDao.loadUserByUserName(userName);

}

@Override

public List getUser(Pager pager, User user) {

return userDao.getUser(pager,user);

}

@Override

public List getUser(User user) {

return userDao.getUser(user);

}

}

创建启动类和junit测试类

package com.feng;

import org.springframework.boot.SpringApplication;

@SpringBootApplication

public class SpringBootWebApplication {

public static void main(String[] args){

SpringApplication.run(SpringBootWebApplication.class, args);

}

}

import com.feng.SpringBootWebApplication;

import com.feng.entity.User;

import com.feng.service.UserService;

import database.support.Pager;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

/**

  • Created by Feng

*/

@RunWith(SpringJUnit4ClassRunner.class)

@SpringBootTest(classes = SpringBootWebApplication.class)

public class JDBCTest {

@Autowired

private UserService userService;

@Test

public void testQuery() throws IllegalAccessException {

List users = userService.getUser(new User());

System.out.println(users);

}

}

测试普通查询成功

在这里插入图片描述

4.使用自定义拦截器分页


mybatis分页的三种方法就不废话了,基本上很少有用内存或者sql语句来分页的,在实际生产中,大多数还是使用拦截器分页。我在网上找相关中文资料,百分之九十都是直接用pageHelper插件来做。很费解的是一个中文文档这么全面的,由国人编写的插件为啥还要写一大堆教程,直接看文档不好吗。。。

言归正传,这里我们自己编写拦截器(插件)用于自动拦截包含Pager参数的查询方法

先看官方文档里关于拦截器的描述

插件(plugins)

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

ParameterHandler (getParameterObject, setParameters)

ResultSetHandler (handleResultSets, handleOutputParameters)

StatementHandler (prepare, parameterize, batch, update, query)

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。

通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

至于这几个对象和其内部方法的作用,大家可以在网上找相关资料,我们要拦截的是StatementHandler.prepare方法,这个方法用于生成statement,参数包含一个Connection对象,我们可以借助它在查询发起前先先执行计数操作并替换原有的sql语句

先编写一个工具类用于构建分页和计数sql语句

package database.support;

/**

  • Created by Feng

*/

public interface JDBCSupport {

public String generatePageSql(Pager pager,String sql);

public String generateCountSql(String sql);

}

package database.support;

import org.springframework.util.StringUtils;

/**

  • Created by Feng

*/

public class MySqlSupport implements JDBCSupport {

/**

  • 拼接分页sql

  • @param pager

  • @param sql

  • @return

*/

@Override

public String generatePageSql(Pager pager, String sql) {

long startIndex = (pager.getPageNo() - 1) * pager.getPageSize()+1;

long endIndex = startIndex + pager.getPageSize()-1;

StringBuilder sqlBuilder = new StringBuilder(sql);

if(!StringUtils.isEmpty(pager.getSortBy())){

sqlBuilder.append(" ORDER BY ");

sqlBuilder.append(pager.getSortBy());

sqlBuilder.append(pager.getRank());

}

sqlBuilder.append(" limit ");

sqlBuilder.append(startIndex);

sqlBuilder.append(“,”);

sqlBuilder.append(endIndex);

return sqlBuilder.toString().toUpperCase();

}

/**

  • 拼接计数sql

  • @param sql

  • @return

*/

@Override

public String generateCountSql(String sql) {

return (“SELECT COUNT(*) FROM (” + sql + “) A”).toUpperCase();

}

}

接下来就是最重要的拦截器了

package database.mybatis.plug;

import database.support.JDBCSupport;

import database.support.MySqlSupport;

import database.support.Pager;

import org.apache.ibatis.executor.resultset.ResultSetHandler;

import org.apache.ibatis.executor.statement.StatementHandler;

import org.apache.ibatis.plugin.*;

import org.apache.ibatis.reflection.MetaObject;

import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.Statement;

import java.util.Map;

import java.util.Properties;

/**

  • Created by Feng

*/

@Intercepts({

@Signature(type = StatementHandler.class, method = “prepare”, args = {Connection.class,Integer.class}),

})

public class PageInterceptor implements Interceptor {

private JDBCSupport jdbcSupport = new MySqlSupport();

@Override

public Object intercept(Invocation invocation) throws Throwable {

StatementHandler statementHandler = (StatementHandler)invocation.getTarget();

Map<String,Object> paramsMap = (Map<String, Object>) statementHandler.getParameterHandler().getParameterObject();

String sql = statementHandler.getBoundSql().getSql();

for(String key:paramsMap.keySet()){

if(paramsMap.get(key) instanceof Pager){

Pager pager = (Pager) paramsMap.get(key);

Connection connection = (Connection)invocation.getArgs()[0];

PreparedStatement countStatement = connection.prepareStatement(jdbcSupport.generateCountSql(sql));

ResultSet rs = countStatement.executeQuery();

if(rs.next()) {

pager.setTotal(rs.getInt(1));

}

MetaObject metaObject = SystemMetaObject.forObject(statementHandler);

String pageSql = jdbcSupport.generatePageSql(pager,sql);

metaObject.setValue(“delegate.boundSql.sql”, pageSql);

break;

}

}

return invocation.proceed();

}

@Override

public Object plugin(Object o) {

if (o instanceof StatementHandler) {

return Plugin.wrap(o, this);

} else {

return o;

}

}

@Override

public void setProperties(Properties properties) {

}

}

Intercepts注解用于标识该拦截器作用的目标对象和目标方法。在intercept方法中我们先获取查询方法的所有参数并进行遍历,当发现包含Pager参数后我们先构建计数语句执行查询并将结果写入Pager中,然后借助mybatis自带的反射工具将sql替换成构建好的分页查询语句。

在之前的mybatis配置类中添加这个拦截器

package com.feng.config;

import database.mybatis.plug.PageInterceptor;

import org.mybatis.spring.annotation.MapperScan;

import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

  • Created by Feng

*/

@MapperScan(“com.feng.dao”)

@Configuration

public class MybatisConfig {

/**

  • 添加mybatis分页拦截器

  • @return

*/

@Bean

public PageInterceptor pageInterceptor(){

return new PageInterceptor();

}

}

新增测试方法

总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

大厂Java架构核心笔记(适合中高级程序员阅读):

g.mybatis.spring.annotation.MapperScan;

import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

  • Created by Feng

*/

@MapperScan(“com.feng.dao”)

@Configuration

public class MybatisConfig {

/**

  • 添加mybatis分页拦截器

  • @return

*/

@Bean

public PageInterceptor pageInterceptor(){

return new PageInterceptor();

}

}

新增测试方法

总结:心得体会

既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。

学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。

面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。

最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。

大厂Java架构核心笔记(适合中高级程序员阅读):

[外链图片转存中…(img-B92YHSVg-1714465550260)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值