java通過註解實現分頁功能
文章目錄
一. 概述
1.1 爲什麼要使用分頁功能?
- 在我們的業務系統中,經常會涉及到查詢列表查詢,使用分頁功能可以靈活清晰的展現出我們的數據結果,就像翻書一樣,達到了非常棒的閱讀體驗。
1.2 傳統分頁與註解分頁的區別?
- 優點:
- 使用簡單,使用註解分頁,我們可以只用去關心如何拿到數據,而不需要關心如何按前端要求去拿;
- 精簡代碼,提升效率,通過自定義註解的使用,我們只需要加一個註解即可對其進行分頁,而不需要再代碼中再去做分頁操作;
- 更加優雅,逼格滿滿,閱讀註解中所涉及到的反射,自定義註解,以及切面等技術,無疑又是對自己的一個提高;
- 缺點:
- 靈活性降低,統一都是使用一種分頁方式,且查詢出來的數據先必須是全部數據,明顯靈活性降低了;
- 性能降低,使用反射等技術本身會使得機器性能更低一點,且查出來的數據首先得是全部數據,會導致查詢數據庫也會增加耗時;
隨着機器的配置越來越好,使用註解分頁無疑是更優雅更前衛的選擇;當然任何時候都得考慮這種技術適用於什麼場景。自定義註解分頁適用於數據量較少的數據;
1.3 註解分頁效果圖
- 接口加上 @PageQuery
- 返回數據已展示分頁:
- pageIndex=1,pageSize=10 ,結果如圖:
- pageIndex=1,pageSize=5 ,結果如圖:
分頁效果與我們平時所需要的效果一致。僅僅在接口上加了一個自定義註解,即可自動分頁。返回的pageInfo如果覺得少了,還能自定義進行添加;
- pageIndex=1,pageSize=10 ,結果如圖:
二. 實戰自定義註解分頁
2.1 定義核心註解類 @PageQuery
package com.annotation.page;
import java.lang.annotation.*;
/**
* @program: xxxx
* @description: PageSize註解類
* @author: an yu
* @create: 2020-03-23
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PageQuery {
String pageIndexName() default "pageIndex";//頁號的參數名
String pageSizeName() default "pageSize";//每頁行數的參數名
}
2.2 定義PageInfo類(返回的分頁信息)PageInfo
package com.annotation.page;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* @program: xxxx
* @description: 自定義PageInfo
* @author: anyu
* @create: 2020-03-23
*/
@Data
@Accessors(chain = true)
@SuppressWarnings("all")
public class PageInfo implements Serializable {
private int pageNum; //
private int pageSize;
private long total;
private List<Object> list;
public PageInfo(int pageNum, int pageSize, long total, List<Object> list) {
this.pageNum = pageNum;
this.pageSize = pageSize;
this.total = total;
this.list = list;
}
public PageInfo(int pageNum, int pageSize, List<Object> list) {
this.pageNum = pageNum;
this.pageSize = pageSize;
this.list = list;
}
public PageInfo(List<Object> list) {
this.list = list;
}
public PageInfo() {
}
}
2.3 定義切面類
package com.annotation.page;
import com.alibaba.dubbo.common.utils.IOUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cdmtc.response.RespEntity;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
* @program: xxxx
* @description: 分頁切面
* @author: anyu
* @create: 2020-03-23
*/
@Aspect
@Component
public class PageAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(PageAspect.class);
@Around("@annotation(pageQuery)")
public Object pagingQuery(ProceedingJoinPoint joinPoint, PageQuery pageQuery) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Class<?> returnType = signature.getMethod().getReturnType();
if (("com.cdmtc.response.RespEntity").equals(returnType.getName())) {
/* 1. 獲取分頁名稱*/
String pageIndexName = pageQuery.pageIndexName();
String pageSizeName = pageQuery.pageSizeName();
/* 2. 獲取分頁值 */
ServletRequestAttributes currentRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = currentRequestAttributes.getRequest();
String body = IOUtils.read(request.getReader());
JSONObject jsonObject = JSONObject.parseObject(body);
String pageNum = jsonObject.getString(pageIndexName);
String pageSize = jsonObject.getString(pageSizeName);
/* 3. 賦默認值 */
try {
/* 進行分頁 */
Object respEntityObj = joinPoint.proceed();
RespEntity respEntity = JSON.parseObject(JSON.toJSONString(respEntityObj), RespEntity.class); // 這裏根據自己的接口通用返回實體類進行對應修改
Object result = respEntity.getResult(); // 這裏根據自己的接口通用返回實體類進行對應修改
List list = JSON.parseObject(JSON.toJSONString(result), List.class);
Integer pageNumInt = Integer.valueOf(pageNum);
Integer pageSizeInt = Integer.valueOf(pageSize);
List list1 = pageBySubList(list, pageNumInt, pageSizeInt);
PageInfo pageInfo = new PageInfo(pageNumInt, pageSizeInt, list.size(), list1); // 將結果存入
return RespEntity.success(pageInfo);
} catch (Exception e) {
LOGGER.error("查詢失敗", e);
return RespEntity.success(new PageInfo());
}
}
return joinPoint.proceed();
}
/**
* 利用subList方法進行分頁
*
* @param list 分頁數據
* @param pageSize 頁面大小
* @param currentPage 當前頁面
*/
public static List pageBySubList(List list, int currentPage, int pageSize) {
if (pageSize < 1 || currentPage < 1 || list.size() / pageSize < currentPage - 1) {
return new ArrayList();
}
return list.subList((currentPage - 1) * pageSize, pageSize * currentPage < list.size() ? pageSize * currentPage : list.size());
}
}
2.4 定義 PageQuery實體類
package com.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
/**
* @Create anyu
* @CraeteTime 2019/5/31
* @Description
*/
@Data
@ToString
public class PageQuery<T> implements Serializable {
private static final long serialVersionUID = 1918876594784006915L;
@ApiModelProperty(value="頁碼",name="pageIndex",example="1")
@NotBlank(message = "當前頁不能爲空")
@Pattern(regexp = "[1-9]\\d*",message = "參數錯誤")
private int pageIndex;
@ApiModelProperty(value="每頁條數",name="pageSize",example="10")
@NotBlank(message = "每頁記錄數不能爲空")
@Pattern(regexp = "[1-9]\\d*",message = "參數錯誤")
private int pageSize;
@ApiModelProperty(value="請求條件",name="param",example="")
private T param;
}
2.5 定義接口類
package com.controller;
import com.cdmtc.annotation.page.PageQuery;
import com.cdmtc.response.RespEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @program: xxxx
* @description: ceshilei
* @author: zhang lei
* @create: 2020-03-13
*/
@RestController
@RequestMapping("api")
@Api(value="CustomMonitor",tags={"測試類"})
public class DemoController {
@ApiOperation("測試分頁集合")
@PostMapping("getList")
@PageQuery
public RespEntity getList(@RequestBody com.cdmtc.param.PageQuery<String> pageQuerys){
List<String> list=new ArrayList<>();
Collections.addAll(list,"0","1","2","3","4","5","6","7","8","9","10","11","12","13");
return RespEntity.success(list);
}
}
2.6 定義返回值類
package com.response;
import com.model.response.RespResult;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.integration.annotation.InboundChannelAdapter;
import org.springframework.util.MultiValueMap;
import java.io.Serializable;
/**
* @create_by: anyu
* @craete_time 2019/7/17
*/
@Data
@Accessors(chain = true)
public class RespEntity implements Serializable {
public int errCode=0;
public String errMsg="success";
public Object result="";
private static final RespEntity fail = new RespEntity().setErrCode(1).setErrMsg("fail").setResult("");
private static final RespEntity success = new RespEntity().setResult("");
private RespEntity() {
}
public static RespEntity fail() {
return fail;
}
public static RespEntity success(){
return success;
}
public static RespEntity fail(String errMsg,Object object){
RespEntity fail= RespEntity.fail();
fail.setErrMsg(errMsg);
fail.setResult(object);
return fail;
}
public static RespEntity fail(String errMsg){
RespEntity fail= RespEntity.fail();
fail.setErrMsg(errMsg);
return fail;
}
public static RespEntity success(Object object){
RespEntity success = RespEntity.success;
success.setResult(object);
return success;
}
}
三. 總結
3.1 回顧
- 講述了傳統pageQuery與現在的註解分頁的區別
- 講述了相關的源碼
3.2 注意:
- 這裏用到了Swagger-ui,所以使用代碼的時候,如果相關的爆紅則可以直接註釋掉或者導入swagger-ui,具體使用swagger-ui請網上找相關資料
- 請先閱讀源碼後再使用,可進行自定義修改。剛寫完肯定有一些的瑕疵,勿怪~