SpringBoot 把PageHelper分页信息返回给前端

第1步:定义收纳HttpHeaders和HttpStatus的 线程容器

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;


public class ResponseContext {
    private static ThreadLocal<HttpHeaders> ThreadLocalHeaders = new InheritableThreadLocal<>();
    private static ThreadLocal<HttpStatus> ThreadLocalStatus = new InheritableThreadLocal<>();

    public static void addHeaders(String key, String value) {
        if (ThreadLocalHeaders.get() == null) {
            ThreadLocalHeaders.set(new HttpHeaders());
        }
        ThreadLocalHeaders.get().add(key, value);
    }

    public static void setResponseCode(HttpStatus httpStatus) {
        ThreadLocalStatus.set(httpStatus);
    }

    public static HttpHeaders getHeaders() {
        return ThreadLocalHeaders.get();
    }

    public static HttpStatus getResponseCode() {
        return ThreadLocalStatus.get();
    }

    public static void clear() {
        if (ThreadLocalHeaders.get() != null) {
            ThreadLocalHeaders.remove();
        }
        if (ThreadLocalStatus.get() != null) {
            ThreadLocalStatus.remove();
        }
    }
}

第2步:封装 把分页信息转储到线程容器 的方法

import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.zhangziwa.practisesvr.utils.response.ResponseContext;

public class PageHeaderUtils {
    private static final String PAGE_NUM = "page_num"; // 当前第几页
    private static final String PAGE_SIZE = "page_size"; // 每页显示的条数
    private static final String PREV_PAGE = "prev_page"; // 上一页页码
    private static final String NEXT_PAGE = "next_page"; // 下一页页码
    private static final String TOTAL_COUNT = "total_count"; // 总条数
    private static final String TOTAL_PAGE = "total_page"; // 总页数

    public static <E> void setPageHeader(Page<E> page) {
        if (page == null) {
            return;
        }
        ResponseContext.addHeaders(PAGE_NUM, String.valueOf(page.getPageNum()));
        ResponseContext.addHeaders(PAGE_SIZE, String.valueOf(page.getPageSize()));
        ResponseContext.addHeaders(TOTAL_COUNT, String.valueOf(page.getTotal()));
        ResponseContext.addHeaders(TOTAL_PAGE, String.valueOf(page.getPages() == 0 ? 1 : page.getPages()));
        if (page.getPages() == 0 || page.getPages() == 1) {
            ResponseContext.addHeaders(PREV_PAGE, "");
            ResponseContext.addHeaders(NEXT_PAGE, "");
        } else if (page.getPageNum() == 1) {
            ResponseContext.addHeaders(PREV_PAGE, "");
            ResponseContext.addHeaders(NEXT_PAGE, String.valueOf(page.getPages() + 1));
        } else if (page.getPageNum() == page.getPages()) {
            ResponseContext.addHeaders(PREV_PAGE, String.valueOf(page.getPages() - 1));
            ResponseContext.addHeaders(NEXT_PAGE, "");
        } else {
            ResponseContext.addHeaders(PREV_PAGE, String.valueOf(page.getPages() - 1));
            ResponseContext.addHeaders(NEXT_PAGE, String.valueOf(page.getPages() + 1));
        }
    }

    /**
     * 设置分页头信息
     * @param page 分页对象
     * @param <E> 分页对象的数据类型
     */
    public static <E> void setPageHeader(PageInfo<E> page) {
        if (page == null) {
            return;
        }
        ResponseContext.addHeaders(PAGE_NUM, String.valueOf(page.getPageNum()));  // 设置当前页码
        ResponseContext.addHeaders(PAGE_SIZE, String.valueOf(page.getPageSize()));  // 设置每页显示数量
        ResponseContext.addHeaders(TOTAL_COUNT, String.valueOf(page.getTotal()));  // 设置总记录数
        ResponseContext.addHeaders(TOTAL_PAGE, String.valueOf(page.getPages() == 0 ? 1 : page.getPages()));  // 设置总页数
        // page.getPages()=1表示就1页,前后页都不存在,故也算特殊场景.也为了page.getPages()+1和page.getPages()-1不会对[1,page.getPages()]越界
        if (page.getPages() == 0 || page.getPages() == 1) {
            ResponseContext.addHeaders(PREV_PAGE, "");  // 上一页
            ResponseContext.addHeaders(NEXT_PAGE, "");  // 下一页
        } else if (page.getPageNum() == 1) {
            ResponseContext.addHeaders(PREV_PAGE, "");  // 上一页
            ResponseContext.addHeaders(NEXT_PAGE, String.valueOf(page.getPages() + 1));  // 下一页
        } else if (page.getPageNum() == page.getPages()) {
            ResponseContext.addHeaders(PREV_PAGE, String.valueOf(page.getPages() - 1));  // 上一页
            ResponseContext.addHeaders(NEXT_PAGE, "");  // 下一页
        } else {
            ResponseContext.addHeaders(PREV_PAGE, String.valueOf(page.getPages() - 1));  // 上一页
            ResponseContext.addHeaders(NEXT_PAGE, String.valueOf(page.getPages() + 1));  // 下一页
        }
    }
}

第3步:分页查询后 把HttpHeaders和HttpStatus收集到线程容器

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

	# PageInfo方式
    @Override
    public List<Student> listStudents(Integer pageNum, Integer PageSize) {
        PageHelper.startPage(PageUtils.getPageNum(pageNum), PageUtils.getPageSize(PageSize), PageUtils.isQueryTotalCount());
        PageHelper.orderBy("age asc");

        List<Student> students = userMapper.listStudents();
        PageInfo<Student> studentPageInfo = PageInfo.of(students);

        // 收集分页信息到 ThreadLocal
        PageHeaderUtils.setPageHeader(studentPageInfo);

        // 收集HttpStatus到 ThreadLocal
        // ResponseContext.setResponseCode(num2HttpStatus("200")); // 为了使用一下num2HttpStatus方法
        ResponseContext.setResponseCode(HttpStatus.OK);
        return students;
    }

	# Page 方式
    @Override
    public List<Student> listStudents2(Integer pageNum, Integer PageSize) {
        PageHelper.startPage(PageUtils.getPageNum(pageNum), PageUtils.getPageSize(PageSize), PageUtils.isQueryTotalCount());
        PageHelper.orderBy("age asc");

        Page<Student> students = (Page<Student>) userMapper.listStudents();
        
        PageHeaderUtils.setPageHeader(students);
        ResponseContext.setResponseCode(HttpStatus.OK);
        return students;
    }

	# 多数据源聚合时的手工分页
    @Override
    public List<Student> listStudents3(Integer pageNum, Integer pageSize) {
        // 模拟数据聚合
        List<Student> students3 = new ArrayList<>();
        List<Student> students1 = userMapper.listStudents();
        List<Student> students2 = userMapper.listStudents();

        students3.addAll(students1);
        students3.addAll(students2);

        Page<Student> studentsPage = PageHeaderUtils.manualPage(students3, pageNum, pageSize);
        PageHeaderUtils.setPageHeader(studentsPage);
        ResponseContext.setResponseCode(HttpStatus.OK);
        return studentsPage;
    }
}
public class HttpStatusUtils {

    public static HttpStatus num2HttpStatus(String num) {
        HttpStatus httpStatus = HttpStatus.NOT_FOUND;
        for (HttpStatus status : HttpStatus.values()) {
            if (Integer.parseInt(num) == status.value()) {
                return status;
            }
        }
        return httpStatus;
    }
}

总结就是:单次分页查询可以使用PageHelper,但是如果多数据源数据聚合时PageHelper不再适用,可以使用手工分页的方式进行分页。

# 使用PageHelper进行分页时
PageHelper.startPage(PageUtils.getPageNum(pageNum), PageUtils.getPageSize(PageSize), PageUtils.isQueryTotalCount());

# 数据聚合场景下的手工分页
public class PageHeaderUtils {
    // 也适合EmptyList场景 Page{count=true, pageNum=1, pageSize=10, startRow=0, endRow=0, total=0, pages=0, reasonable=null, pageSizeZero=null}
    public static <E> Page<E> manualPage(List<E> res, Integer pageNum, Integer pageSize) {
        if (res == null) {
            res = new ArrayList<>();
        }

        int pageNumber = PageUtils.getPageNum(pageNum);
        int sizePerPage = PageUtils.getPageSize(pageSize);
        int totalSize = res.size();

        List<E> pageElements = res.stream().skip((long) (pageNumber - 1) * sizePerPage).limit(sizePerPage).toList(); // 分页

        Page<E> page = new Page<>();
        page.setPageNum(pageNumber);
        page.setPageSize(sizePerPage);
        page.setTotal(totalSize);
        page.setPages((totalSize / pageSize + ((totalSize % pageSize == 0) ? 0 : 1)));
        page.addAll(pageElements);

        return page;
    }
}

第4步:检查controller层, @Controller → @RestController

@RestController
@Slf4j
public class SearchController {
    @Autowired
    UserService userService;

    @RequestMapping(value = "/getAllStudents", method = RequestMethod.GET)
    public List<Student> getAllStudents() {
        List<Student> students = userService.listStudents(1, 10);
        students.forEach(System.out::println);
        return students;
    }

    @RequestMapping(value = "/getAllStudents2", method = RequestMethod.GET)
    public List<Student> getAllStudents2() {
        List<Student> students = userService.listStudents2(1, 10);
        students.forEach(System.out::println);
        return students;
    }

    @RequestMapping(value = "/getAllStudents3", method = RequestMethod.GET)
    public List<Student> getAllStudents3() {
        List<Student> students = userService.listStudents3(1, 5);
        students.forEach(System.out::println);
        return students;
    }
}

第5步:线程容器收纳的 HttpHeaders和HttpStatus 添加到ServerHttpResponse

import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import static java.util.Objects.nonNull;

@ControllerAdvice
public class ResponsePostAdvice implements ResponseBodyAdvice {


    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class clazz,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        HttpHeaders headers = response.getHeaders();

        // 分页信息添加到ServerHttpResponse
        HttpHeaders headersContext = ResponseContext.getHeaders();
        if (nonNull(headersContext) && !headersContext.isEmpty()) {
            headers.addAll(headersContext);
        }

        // 状态码添加到ServerHttpResponse
        if (nonNull(ResponseContext.getResponseCode())) {
            response.setStatusCode(ResponseContext.getResponseCode());
        }
        return body;
    }
}

第6步:清理 线程容器

定义拦截器执行ResponseContext.clear();,用于资源清理

import com.zhangziwa.practisesvr.utils.response.ResponseContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
public class ResponsePostInterceptor implements HandlerInterceptor {

    //在Controller执行之前调用,如果返回false,controller不执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.err.println("***ResponsePostInterceptor.preHandle***");
        return true;
    }

    //controller执行之后,且页面渲染之前调用
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.err.println("***ResponsePostInterceptor.postHandle***");
    }

    //页面渲染之后调用,一般用于资源清理操作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.err.println("***ResponsePostInterceptor.afterCompletion***");
        ResponseContext.clear(); // 清除业务层分页信息上下文
        PageMethod.clearPage(); // 清除PageHelper的分页信息上下文
    }
}

注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ResponsePostInterceptor responsePostInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(responsePostInterceptor);
    }
}

第7步:测试结果

在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Spring Boot中使用PageHelper非常简单。只需按照以下步骤操作: 1. 添加依赖项:在pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.13</version> </dependency> ``` 2. 配置PageHelper:在application.properties文件中添加以下配置: ``` # 分页插件配置 pagehelper.helperDialect=mysql pagehelper.reasonable=true pagehelper.supportMethodsArguments=true pagehelper.params=count=countSql ``` 3. 在Mapper中使用PageHelper:在Mapper接口中添加@Mapper注解,并在方法中使用PageHelper.startPage()方法来启用分页功能。例如: ``` @Mapper public interface UserMapper { List<User> findAll(); @Select("SELECT * FROM user WHERE name = #{name}") List<User> findByName(@Param("name") String name); @Select("SELECT * FROM user") void findByPage(); @Select("SELECT * FROM user") void findByPage2(Page page); } ``` 在上面的示例中,findByPage()和findByPage2()方法都使用了PageHelper.startPage()方法来启用分页功能。findByPage()方法使用默认的分页参数,而findByPage2()方法使用自定义的分页参数。 4. 在Service中使用Mapper:在Service中注入Mapper,并在方法中调用Mapper的方法来获取分页数据。例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public PageInfo<User> findAll(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<User> userList = userMapper.findAll(); return new PageInfo<>(userList); } @Override public PageInfo<User> findByName(String name, int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); List<User> userList = userMapper.findByName(name); return new PageInfo<>(userList); } @Override public PageInfo<User> findByPage(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); userMapper.findByPage(); return new PageInfo<>(userMapper.findByPage()); } @Override public PageInfo<User> findByPage2(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); userMapper.findByPage2(new Page(pageNum, pageSize)); return new PageInfo<>(userMapper.findByPage2(new Page(pageNum, pageSize))); } } ``` 在上面的示例中,findAll()和findByName()方法使用Mapper的方法来获取分页数据,并将结果封装为PageInfo对象返回。findByPage()和findByPage2()方法分别使用Mapper的findByPage()和findByPage2()方法来获取分页数据,并将结果封装为PageInfo对象返回。 总之,使用PageHelper来实现分页功能非常简单,只需按照上述步骤操作即可。 ### 回答2: SpringBoot是一个非常流行的Java开发框架,在使用SpringBoot开发Web应用程序时,程序员们经常要与关系型数据库打交道。在处理大量数据时,分页展示数据是非常必要的,PageHelper是一个非常优秀的分页插件,它可以很好的与SpringBoot集成,帮助开发人员实现数据分页展示。 PageHelper是Mybatis的分页插件,它采用拦截SQL语句的方式,来实现数据分页。在SpringBoot中使用PageHelper,首先需要在pom.xml文件中引入PageHelper的依赖: ```xml <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> ``` 引入依赖后,需要在application.yml或application.properties文件中配置PageHelper的相关参数,例如: ```yml pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql autoRuntimeDialect: true closeConn: true ``` 然后,在DAO层中,引入PageHelper插件: ```java import com.github.pagehelper.PageHelper; import org.springframework.stereotype.Repository; @Repository public interface UserDao { /** * 获取用户列表 * * @param pageNum 页码 * @param pageSize 每页大小 * @return 用户列表 */ List<User> getUsers(int pageNum, int pageSize); } ``` 在Service层中,调用DAO中的方法,并传入分页参数: ```java import com.github.pagehelper.PageHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl implements UserService { private final UserDao userDao; @Autowired public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } @Override public List<User> getUsers(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); return userDao.getUsers(pageNum, pageSize); } } ``` 最后,在Controller层中,接收前端传来的分页参数,调用Service层的方法,并将结果返回前端: ```java import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class UserController { private final UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } @GetMapping("/user") public List<User> getUsers(@RequestParam("pageNum") int pageNum, @RequestParam("pageSize") int pageSize) { return userService.getUsers(pageNum, pageSize); } } ``` 以上就是使用SpringBoot中使用PageHelper的简单示例,大家可以在自己的开发中根据实际情况使用。PageHelper是一个非常强大、易用的分页插件,在大部分Java开发中都非常使用广泛。 ### 回答3: Spring Boot是基于Spring框架的一种快速开发框架,并且具有很好的适应性和灵活性。在Spring Boot中,我们需要使用PageHelper插件来分页查询。 PageHelper是一个开源的MyBatis分页插件,可以帮助我们实现MyBatis分页功能。在Spring Boot中使用PageHelper分页插件,需要进行以下操作: 1. 在pom.xml文件中添加PageHelper依赖 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.13</version> </dependency> 2. 在配置文件中添加PageHelper配置 在application.yml或者application.properties中添加以下配置即可: pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql 具体配置项可以参考PageHelper官方文档。 3. 在mapper.xml中配置分页查询 在mapper.xml中使用PageHelper提供的startPage方法来进行数据分页查询: <select id="getList" resultMap="resultMap"> select * from user <where> <if test="name!=null and name!=''"> and name like concat(concat('%', #{name}), '%') </if> </where> order by id desc //分页查询 limit #{pageNo}, #{pageSize} </select> 这里使用了PageHelper默认的分页方式,传入页码和每页大小两个参数即可。如果需要使用其他方式进行分页,可以参考PageHelper官方文档进行配置。 4. 在Service中调用mapper方法 最后,在Service中调用mapper中的getList方法即可实现分页查询: public PageInfo<User> getList(String name, int pageNo, int pageSize) { PageInfo<User> pageInfo = PageHelper.startPage(pageNo, pageSize) .doSelectPageInfo(() -> this.userMapper.getList(name)); return pageInfo; } 这里使用了PageHelper提供的startPage方法来启动分页功能,并且使用doSelectPageInfo方法将查询结果封装成PageInfo对象返回。通过这种方式,就可以很方便地在Spring Boot中实现分页查询。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值