[SpringBoot] 多模块统一返回格式带分页信息

✨✨个人主页:沫洺的主页

📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                           📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                           📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

💖💖如果文章对你有所帮助请留下三连✨✨

🍸效果 

在后端向前端返回统一格式data里一般按照需求是要包含分页信息的,比如总条数和按照每页的条数去返回对应的总页数等

🍹搭建多模块环境(父子项目) 

项目创建参考SpringBoot专栏里:

父项目scm-root的pom.xml

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/>
    </parent>
    <groupId>com.moming</groupId>
    <artifactId>scm-root</artifactId>
    <version>14-SNAPSHOT</version>
    <packaging>pom</packaging>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <modules>
        <module>scm-authority</module>
        <module>scm-app</module>
        <module>scm-dao</module>
        <module>scm-dto</module>
        <module>scm-entity</module>
        <module>scm-service</module>
        <module>scm-api</module>
        <module>scm-core</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.6</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.8.5</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>

    </build>

</project>

数据库

首先实现简单的查询业务

scm-dto模块

pom.xml依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

创建UserDto实体类

package com.moming.dto;

import lombok.Data;

@Data
public class UserDto {
    private Integer id;
    private String username;
    private String password;
}

scm-entity模块

pom.xml依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

创建UserEntity实体类

package com.moming.entity;

import lombok.Data;

@Data
public class UserEntity {
    private Integer id;
    private String username;
    private String password;
}

scm-dao模块

pom.xml依赖

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.moming</groupId>
            <artifactId>scm-entity</artifactId>
            <version>14-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

创建UserDao接口

package com.moming.dao;

import com.moming.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserDao {

    @Select("select * from tb_user order by id")
    List<UserEntity> select();

}

scm-service模块

pom.xml依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <dependency>
            <groupId>com.moming</groupId>
            <artifactId>scm-dao</artifactId>
            <version>14-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.moming</groupId>
            <artifactId>scm-dto</artifactId>
            <version>14-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

创建UserService业务类

package com.moming.service;

import cn.hutool.core.bean.BeanUtil;
import com.moming.dao.UserDao;
import com.moming.dto.UserDto;
import com.moming.entity.UserEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public List<UserDto> select(){
        List<UserEntity> entityList = userDao.select();
        List<UserDto> userDtos = BeanUtil.copyToList(entityList, UserDto.class);
        return userDtos;
    }
}

scm-app模块

pom.xml依赖

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

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.9</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>com.moming</groupId>
            <artifactId>scm-service</artifactId>
            <version>14-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

创建controller/UserController

package com.moming.controller;

import com.moming.dto.UserDto;
import com.moming.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/user")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/select")
    public List<UserDto> select(){
        return userService.select();
    }
}

创建resources/application.yml

#数据库连接信息配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db5?useSSL=false&useServerPrepStmts=true
    username: root
    password: 123456
    druid:
      initial-size: 10 # 初始化时建立物理连接的个数
      min-idle: 10 # 最小连接池数量
      maxActive: 200 # 最大连接池数量
      maxWait: 60000 # 获取连接时最大等待时间,单位毫秒
#映射文件所在位置
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  #别名
  type-aliases-package: com.moming.entity

#配置日志级别
logging:
  level:
    com.moming: debug

启动类App运行后调用接口测试

🥂统一返回格式

scm-dto模块

创建ResponseDto实体类

package com.moming.dto;

import lombok.Data;

@Data
public class ResponseDto {
    private int code;
    private String message;
    private Object data;
}

scm-app模块

创建advice/MyResponseAdvice

package com.moming.advice;

import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONUtil;
import com.moming.dto.PageInfo;
import com.moming.dto.ResponseDto;
import com.moming.local.PageInfoLocal;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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;


@RestControllerAdvice(basePackages = MyResponseAdvice.BASEPACKAGES)
public class MyResponseAdvice implements ResponseBodyAdvice<Object> {
    public static final String BASEPACKAGES="com.moming.controller";

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    @ExceptionHandler
    public  Object processException(Exception ex){
        ResponseDto responseDto = new ResponseDto();
        responseDto.setCode(1);
        responseDto.setMessage(ex.getMessage());
        return responseDto;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        ResponseDto responseDto = new ResponseDto();
        responseDto.setCode(0);
        responseDto.setMessage("");
        responseDto.setData(body);

        //处理返回类型为字符串
        if (selectedConverterType == StringHttpMessageConverter.class) {
            //hutool JSONUtil.toJsonStr字符串转换为json数据
            return JSONUtil.toJsonStr(responseDto);
        } else {
            return responseDto;
        }
    }
}

接口测试查看效果

🍻返回带分页信息格式 

业务需求:

不改变原有的代码,在返回的data中呈现总页数(pages)和(total)

分析:

首先完整的查询业务在上面已经写好了,根据业务需求要在不改变原有的代码的基础之上进行业务增强,就要使用AOP技术来实现,另外要获取总页数,那么在url接口上就需要传递每页多少条的参数(pageSize),既然实现了每页条数,那么同样的就可以传递第几页(pageNum)去动态查询某页的数据,接下来就是怎么去获取url传递的参数,可以通过AOP中的环绕通知,在环绕前使用RequestContextHolder对象去获取ServletRequestAttributes对象,然后通过它去获取HttpServletRequest对象,最后调用getParameter获取参数,获取参数之后使用PageHelper调用startPage方法会将目标方法返回值的类型改为Page类型(底层实现了ArrayList),而Page底层提供了total,pages等属性的get方法,因为属性有很多所以这里需要处理以下,通过我们自定义的PageInfo的set方法获取total,pages的值,然后使用ThreadLocal(本地线程)的机制去实现线程安全问题,ThreadLocal中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的(也就是线程安全的),ThreadLocal为变量在每个线程中创建了一个副本,这样每个线程就可以访问自己内部的副本变量,通过这种机制我们给当前线程脑门上贴一个变量(pageInfo),然后再获取当前线程脑门上的变量(pageInfo),最后移除当前线程脑门上的变量(pageInfo)

scm-app模块

pom.xml添加依赖

AOP坐标依赖

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

第三方pagehelper分页坐标依赖

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

相关模块导入依赖

        <dependency>
            <groupId>com.moming</groupId>
            <artifactId>scm-core</artifactId>
            <version>14-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

创建local/PageInfoLocal

package com.moming.local;

import com.moming.dto.PageInfo;

public class PageInfoLocal {
    private static ThreadLocal<PageInfo> threadLocal = new InheritableThreadLocal<>();

    //给当前线程头上贴一个变量 pageinfo
    public static void set(PageInfo pageInfo){
        threadLocal.set(pageInfo);
    }

    //获取当前线程头上的变量 pageinfo
    public static PageInfo get(){
        return threadLocal.get();
    }

    //移除当前线程头上的变量 pageinfo
    public static void remove(){
        threadLocal.remove();
    }
}

创建aop/DaoAop

package com.moming.aop;

import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.moming.dto.PageInfo;
import com.moming.local.PageInfoLocal;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Component
@Aspect
public class DaoAop {
    //通过注解方式定义切入点
    @Pointcut("@annotation(com.moming.annotation.PageCut)")
    public void point(){}

    //环绕通知
    @Around("point()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取url传递的参数
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String pageNum = request.getParameter("pageNum");
        String pageSize = request.getParameter("pageSize");
        //如果只传递pageSize,则默认pageNum为1
        if( ObjectUtil.isNotEmpty(pageSize)){
            int page_num =1;
            if(ObjectUtil.isNotEmpty(pageNum)){
                page_num = Integer.valueOf(pageNum);
            }
            int page_size = Integer.valueOf(pageSize);
            PageHelper.startPage(page_num,page_size);
        }
        //目标方法List<UserEntity> select()---
        Object result = pjp.proceed();
        //如果目标方法的返回值类型为Page,则将pageInfo对象贴在当前线程脑门上
        if(result instanceof Page){
            Page page = (Page) result;
            //使用自定义的PageInfo对象获取需要的分页信息
            PageInfo pageInfo = new PageInfo();
            pageInfo.setPages(page.getPages());
            pageInfo.setTotal(page.getTotal());
            PageInfoLocal.set(pageInfo);
        }
        return result;
    }
}

在通知类里对分页信息进行封装

        //分页组件扩展开始
        PageInfo pageInfo = PageInfoLocal.get();
        try{
            if(pageInfo!=null){
                Dict dict = Dict.create()
                        .set("pages",pageInfo.getPages())
                        .set("total", pageInfo.getTotal())
                        .set("items",body);
                responseDto.setData(dict);
            }
            else {
                responseDto.setData(body);
            }
            //分页组件扩展结束
        }finally {
            //移除当前线程头上的变量标签
            if(pageInfo!=null){
                PageInfoLocal.remove();
            }
        }

advice/MyResponseAdvice

package com.moming.advice;

import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONUtil;
import com.moming.dto.PageInfo;
import com.moming.dto.ResponseDto;
import com.moming.local.PageInfoLocal;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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;


@RestControllerAdvice(basePackages = MyResponseAdvice.BASEPACKAGES)
public class MyResponseAdvice implements ResponseBodyAdvice<Object> {
    public static final String BASEPACKAGES="com.moming.controller";

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    @ExceptionHandler
    public  Object processException(Exception ex){
        ResponseDto responseDto = new ResponseDto();
        responseDto.setCode(1);
        responseDto.setMessage(ex.getMessage());
        return responseDto;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        ResponseDto responseDto = new ResponseDto();
        responseDto.setCode(0);
        responseDto.setMessage("");
        //分页组件扩展开始
        PageInfo pageInfo = PageInfoLocal.get();
        try{
            if(pageInfo!=null){
                Dict dict = Dict.create()
                        .set("pages",pageInfo.getPages())
                        .set("total", pageInfo.getTotal())
                        .set("items",body);
                responseDto.setData(dict);
            }
            else {
                responseDto.setData(body);
            }
            //分页组件扩展结束
        }finally {
            //移除当前线程头上的变量标签
            if(pageInfo!=null){
                PageInfoLocal.remove();
            }
        }

        //responseDto.setData(body);
        //处理返回类型为字符串
        if (selectedConverterType == StringHttpMessageConverter.class) {
            //hutool JSONUtil.toJsonStr字符串转换为json数据
            return JSONUtil.toJsonStr(responseDto);
        } else {
            return responseDto;
        }
    }
}

scm-core模块

pom.xml依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

创建annotation/PageCut注解

package com.moming.annotation;

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PageCut {
}

创建dto/PageInfo实体类

package com.moming.dto;

import lombok.Data;

@Data
public class PageInfo {
    private int pages;
    private long total;
}

scm-dao模块

目标方法添加切入点注解

package com.moming.dao;

import com.moming.annotation.PageCut;
import com.moming.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserDao {

    @PageCut
    @Select("select * from tb_user order by id")
    List<UserEntity> select();

}

测试

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Spring Boot集成PageHelper实现一对多分页,可以按照以下步骤进行操作: 1. 首先,在pom.xml文件中添加PageHelper依赖: ```xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.13</version> </dependency> ``` 2. 在application.properties或application.yml文件中配置PageHelper的属性: ```properties # MySQL数据库配置 spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root # PageHelper配置 pagehelper.helper-dialect=mysql pagehelper.reasonable=true pagehelper.support-methods-arguments=true pagehelper.params=count=countSql ``` 3. 创建一个包含一对多关系的实体类。例如,如果存在一个"User"实体类,每个用户可以有多个订单 "Order",那么可以这样定义实体类: ```java public class User { private Long id; private String name; private List<Order> orders; // 省略getter和setter方法 } public class Order { private Long id; private String orderName; // 省略getter和setter方法 } ``` 4. 创建Mapper接口和对应的SQL映射文件。在Mapper接口中声明需要的查询方法: ```java @Mapper public interface UserMapper { List<User> getUsersWithOrders(); } ``` 在对应的SQL映射文件中编写相应的查询语句,关联查询用户和订单信息。 5. 在Service层中调用Mapper接口中的方法: ```java @Service public class UserService { @Autowired private UserMapper userMapper; public PageInfo<User> getUsersWithOrders(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.getUsersWithOrders(); return new PageInfo<>(users); } } ``` 6. 在Controller层中调用Service层的方法,并将结果返回: ```java @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/users") public PageInfo<User> getUsers(@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { return userService.getUsersWithOrders(pageNum, pageSize); } } ``` 这样,通过访问"/users"接口,即可实现一对多关系的分页查询。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沫洺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值