目录
一、需求
二、代码实现
父pom文件
pom文件
配置文件
手动注册SqlSessionFactory(MyBatisConfig )
对象
实体类Users
抽象类AbstractQuery
查询参数类UsersQuery
三层架构
UsersController
UsersServiceImpl
UsersMapper
UsersMapper.xml
PageX 注解
MyResponseBodyAdvice
构造返回对象泛型ResponseDto
拦截器PageMethodInterceptor
拦截器注入(PageMethodInterceptorConfig )
结果展示
使用ResponseBodyAdvice做分页处理_骑着蜗牛打天下的博客-CSDN博客
在之前使用过用ResponseBodyAdvice来做分页处理,但是我们还可以结合着Aop中的MethodInterceptor拦截器对分页进一步封装;
使用ResponseBodyAdvice的做法:
这样的做法就是使用ResponseBodyAdvice去拦截controller层返回值,然后对返回的page类型的值进行封装成带有 total、pages、body等;
而本篇的目的是使用aop拦截器去拦截标注切点的方法然后对此方法进行拦截,拦截后就在拦截器内去做 PageHelper.startPage处理,然后在controller层返回时再使用ResponseBodyAdvice拦截,进一步的把数据给封装!
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.5.RELEASE
com.chensir
springboot
0.0.1-SNAPSHOT
springboot
springboot
8
5.8.3
1.18.24
2.0.0
pom
servlet
spring-interceptor
spring-aop
spring-united-reslut
spring-jdbc
spring-mybatis
spring-mybatis-pageX
com.aliyun
alibaba-dingtalk-service-sdk
${alibaba-sdk.version}
cn.hutool
hutool-all
${hutool.version}
org.projectlombok
lombok
${lombok.version}
org.springframework.boot
spring-boot-maven-plugin
4.0.0
com.chensir
springboot
0.0.1-SNAPSHOT
../pom.xml
spring-mybatis-pageX
org.springframework.boot
spring-boot-starter-aop
com.github.pagehelper
pagehelper
5.1.10
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.4
mysql
mysql-connector-java
runtime
cn.hutool
hutool-all
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter-test
2.1.4
test
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
spring.datasource.url=jdbc:mysql://localhost/db1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
aop.MethodInterceptor.point = @annotation(com.chensir.annotation.PageX)
package com.chensir.config;
import com.github.pagehelper.PageInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
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;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.CollectionUtils;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration
@Slf4j
public class MyBatisConfig {
@Autowired
private ConfigurationCustomizer configurationCustomizer;
/**
* 自己注册SqlSessionFactory 目的是增强功能,添加分页插件
* @param ds 代表数据源
* @return
* @throws Exception
*/
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource ds) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 设置数据源
factoryBean.setDataSource(ds);
// 把分页插件设置到SqlSessionFactory插件库
factoryBean.setPlugins(new PageInterceptor());
// 配置mapper.xml地址
factoryBean.setMapperLocations(resolveMapperLocations());
//驼峰映射注册到SqlSessionFactory中
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configurationCustomizer.customize(configuration);
factoryBean.setConfiguration(configuration);
// 返回具体实例对象
SqlSessionFactory bean = factoryBean.getObject();
return bean;
}
/**
* 开启驼峰映射
* @return
*/
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
/**
* 查找 xxxMapper.xml
* @return
*/
public Resource[] resolveMapperLocations() {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List mapperLocations = new ArrayList<>();
mapperLocations.add("classpath*:mapper/*Mapper.xml");
// mapperLocations.add("classpath*:com/meiwei/ping/dao/**/*Mapper.xml");
List resources = new ArrayList();
if (!CollectionUtils.isEmpty(mapperLocations)) {
for (String mapperLocation : mapperLocations) {
try {
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
log.error("Get myBatis resources happened exception", e);
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
}
@Data
public class Users {
private Long id;
private String name;
private Integer age;
private String sex;
private String tel;
// 数据库timestamp类型时间转化java规定格式时间
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
// 接受前端表单传递过来的字符串类型的时间数
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date createTime;
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDateTime updateTime;
}
public abstract class AbstractQuery implements Serializable {
private Integer pageNum = 1;
private Integer pageSize = 10;
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
}
@Data
public class UsersQuery extends AbstractQuery {
private Long id;
private String name;
private Integer age;
private String sex;
private String tel;
}
@RestController
public class UsersController {
@Resource
private UsersService usersService;
@PostMapping("/pageQuery")
public List selectUsersByPageQuery(@RequestBody UsersQuery usersQuery){
// 使用MethodInterceptor进行分页 @PageX为切点,使用地方开启分页处理
List usersList = usersService.selectUsersByPageQuery(usersQuery);
return usersList;
}
@GetMapping("/demo1")
public List selectUsersList(Integer pageNum,Integer pageSize) {
// 启用分页,查询第一页,每页3条
PageHelper.startPage(pageNum,pageSize);
//-------------PageInfo方式---------------
// PageInfo usersPageInfo = new PageInfo<>(usersService.selectUsersList());
// return usersPageInfo;
//-------------PageInfo方式---------------
//-------------Page方式---------------
// List users = usersService.selectUsersList();
// Page page = (Page) users;
// int pages = page.getPages();
// long total = page.getTotal();
//
//
// Map pageMap = new HashMap<>();
// pageMap.put("pages",pages);
// pageMap.put("total",total);
// pageMap.put("items",users);
// return pageMap;
//-------------Page方式---------------
//-----------使用ResponseBodyAdvice------------
List users = usersService.selectUsersList();
return users;
//-----------使用ResponseBodyAdvice------------
}
@GetMapping("/demo2")
public Users selectUsers(){
Users users = usersService.selectUsers();
return users;
}
@GetMapping("/demo3")
public Map selectUsersToMap(){
return usersService.selectUsersToMap();
}
}
@Service
public class UsersServiceImpl implements UsersService {
@Resource
private UsersMapper usersMapper;
@Override
public List selectUsersList() {
return usersMapper.selectUsersList();
}
@Override
public Users selectUsers() {
return usersMapper.selectUsers();
}
@Override
public Map selectUsersToMap() {
return usersMapper.selectUsersToMap();
}
@Override
public List selectUsersByPageQuery(UsersQuery usersQuery) {
return usersMapper.selectUsersByPageQuery(usersQuery);
}
}
@Mapper
public interface UsersMapper {
List selectUsersList();
Users selectUsers();
Map selectUsersToMap();
//此接口带有@PageX 拦截器会拦截它 然后做分页处理
@PageX
List selectUsersByPageQuery(UsersQuery usersQuery);
}
注解来作为切点,使用时,在配置文件中先配置,注入@bean时使用@value取值,然后对带有此注解的方法进行扫描拦截;
@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PageX {
}
package com.chensir.advice;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.servlet.http.HttpServletRequest;
// 拦截范围为 com.chensir.controller包下内容
@RestControllerAdvice(basePackages = {"com.chensir.controller"})
public class MyResponseBodyAdvice implements ResponseBodyAdvice {
// 是否开启拦截 true开启 false不开启
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
// 此处应该改为true,否则除了异常外 走到此处为false后就直接返回,也不再继续往下走了!
return true;
}
// 如果接口返回异常就在此处拦截 进行封装;value = Exception.class 对所有的异常均拦截!
@ExceptionHandler(value = Exception.class)
public Object defaultErrorHandler(HttpServletRequest req, Exception ex){
ResponseDto
// 泛型
@Data
public class ResponseDto implements Serializable {
// 返回码(内部拟定)
private int code;
// 返回信息
private String message;
private T data;
}
package com.chensir.interceptor;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.chensir.domain.AbstractQuery;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
@Slf4j
public class PageMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取方法
Method method = invocation.getMethod();
//获取参数
Object[] arguments = invocation.getArguments();
//获取第一个参数
Object arg0 = arguments[0];
if (arg0 instanceof AbstractQuery) {
AbstractQuery query = (AbstractQuery) arg0;
Integer pageNum = query.getPageNum();//参数 第几页
Integer pageSize = query.getPageSize();//参数 每页多少条
if (ObjectUtil.isNotEmpty(pageNum) && ObjectUtil.isNotEmpty(pageSize)) {
//走到这肯定要分页了
PageHelper.startPage(pageNum,pageSize);
}
}
//获取返回值
Object value = invocation.proceed();
log.info("方法:{},参数:{},返回值:{}", method.getName(), JSONUtil.toJsonStr(arguments), value);
return value;
}
}
advisor.setExpression(point); 拦截切点为@PageX的注解
@Configuration
public class PageMethodInterceptorConfig {
@Value("${aop.MethodInterceptor.point}")
private String point;
@Bean
public AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor(){
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setAdvice(new PageMethodInterceptor());
advisor.setExpression(point);
return advisor;
}
}