需求:分頁查詢學生信息java
項目環境:Spring Boot 2.0.6.RELEASEmysql
<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依賴:git
<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>
分頁查詢返回體類:github
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; } }
Controller層:spring
@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請求,請求體有頁數、每頁條數、查詢參數等屬性。sql
Service層:api
@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,提供查詢須要的參數,最後調用通用方法返回結果。app
Mapper層:ide
@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語句,查詢參數,返回體類型便可。spring-boot
每一個Query只能調用一次getResultList方法,調用以後再次調用就會拋異常,因此方法中有兩處entityManager.createNaticeQuery(sql),一次是爲了查詢總條數,另外一次是查詢當前頁的數據。
查詢總條數的時候能夠改成使用COUNT(主鍵或者非NULL索引);讀者有其餘能提升查詢性能的方法,方便的話,分享一下吧。