项目环境:Spring Boot 2.0.6.RELEASE
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
Maven依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency>
分页查询返回体类:
public class IPagination<T> { /** 当前页数 **/ private int pager; /** 总页数 **/ private int pages; /** 每页条数 **/ private int size; /** 总条数 **/ private long total; /** 忽略数据条数 **/ private int offset; /** 列表数据 **/ private List<T> list = new ArrayList<>(); public IPagination() { } public IPagination(int pager, int size) { if (pager >= 1 && size >= 1) { this.pager = pager; this.size = size; } else { throw new RuntimeException("invalid pager: " + pager + " or size: " + size); } } public static IPagination create(int pager, int size) { return new IPagination(pager, size); } public void setTotal(long total) { this.total = total; } public void setList(List<T> list) { this.list = list; } public int getSize() { return size; } public int getPager() { return pager == 0 ? 1 : pager; } public int getOffset() { return size * (getPager() - 1); } public int getPages() { return Double.valueOf(Math.ceil((double) total / (double) size)).intValue(); } public long getTotal() { return total; } public List<T> getList() { return list; } }
View Code
Controller层:
@RestController @RequestMapping("/api/student") public class StudentApiController { @Autowired private StudentService studentService; @PostMapping("/search") public IPagination<StudentResponse> search(@RequestBody StudentSearchRequest request) { return studentService.search(request); } }
就一个简单的POST请求,请求体有页数、每页条数、查询参数等属性。
Service层:
@Service public class StudentService { @Autowired private PaginationMapper paginationMapper; /** * 分页查询学生信息 * @param request * @return */ public IPagination<StudentResponse> search(StudentSearchRequest request) { // 拼接SQL语句 StringBuilder sql = new StringBuilder("SELECT id, name FROM t_galidun_student "); // 查询需要的参数,先存进Map Map<String, Object> maps = new HashMap<>(); if (request.name != null) { sql.append("WHERE name LIKE :name"); maps.put("name", "%" + request.name + "%"); } // 调用通用方法返回查询结果 return paginationMapper.nativeSearch(request.nowPage, request.pageSize, sql.toString(), maps, StudentResponse.class); } }
在这一层主要是拼接sql,提供查询需要的参数,最后调用通用方法返回结果。
Mapper层:
@Component public class PaginationMapper { @PersistenceContext private EntityManager entityManager; /** * 分页查询通用方法 * * @param nowPage 当前页 * @param pageSize 每页条数 * @param sql sql语句 * @param maps sql查询参数 * @param clazz 返回类型 * @param <T> * @return */ public <T> IPagination<T> search(Integer nowPage, Integer pageSize, String sql, Map<String, Object> maps, Class<T> clazz) { // 初始化分页返回体 IPagination pagination = IPagination.create(nowPage, pageSize); // 查询结果总条数 int total = getQueryWithParameters(entityManager.createNativeQuery(sql), maps).getResultList().size(); pagination.setTotal(total); if (total == 0) return pagination; Query query = getQueryWithParameters(entityManager.createNativeQuery(sql), maps); // 忽略指定条数据,返回一页数据 query.setFirstResult(pagination.getOffset()).setMaxResults(pagination.getSize()); // 指定返回对象类型 query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(clazz)); // 列表数据 pagination.setList(query.getResultList()); return pagination; } /** * 设置查询所需的参数 * * @param query * @param maps * @return */ private Query getQueryWithParameters(Query query, Map<String, Object> maps) { if (maps.size() > 0) { for (String key : maps.keySet()) { query.setParameter(key, maps.get(key)); } } return query; } }
这是个通用的方法,只需要传入查询的页数,每页数据条数,sql语句,查询参数,返回体类型即可。
每个Query只能调用一次getResultList方法,调用之后再次调用就会抛异常,所以方法中有两处entityManager.createNaticeQuery(sql),一次是为了查询总条数,另一次是查询当前页的数据。
查询总条数的时候可以改为使用COUNT(主键或者非NULL索引);读者有其他能提高查询性能的方法,方便的话,欢迎交流指导。