java通過註解實現分頁功能

java通過註解實現分頁功能

一. 概述

1.1 爲什麼要使用分頁功能?

  • 在我們的業務系統中,經常會涉及到查詢列表查詢,使用分頁功能可以靈活清晰的展現出我們的數據結果,就像翻書一樣,達到了非常棒的閱讀體驗。

1.2 傳統分頁與註解分頁的區別?

  • 優點:
    1. 使用簡單,使用註解分頁,我們可以只用去關心如何拿到數據,而不需要關心如何按前端要求去拿;
    2. 精簡代碼,提升效率,通過自定義註解的使用,我們只需要加一個註解即可對其進行分頁,而不需要再代碼中再去做分頁操作;
    3. 更加優雅,逼格滿滿,閱讀註解中所涉及到的反射,自定義註解,以及切面等技術,無疑又是對自己的一個提高;
  • 缺點:
    1. 靈活性降低,統一都是使用一種分頁方式,且查詢出來的數據先必須是全部數據,明顯靈活性降低了;
    2. 性能降低,使用反射等技術本身會使得機器性能更低一點,且查出來的數據首先得是全部數據,會導致查詢數據庫也會增加耗時;

    隨着機器的配置越來越好,使用註解分頁無疑是更優雅更前衛的選擇;當然任何時候都得考慮這種技術適用於什麼場景。自定義註解分頁適用於數據量較少的數據;

1.3 註解分頁效果圖

  • 接口加上 @PageQuery
    在這裏插入圖片描述
  • 返回數據已展示分頁:
    1. pageIndex=1,pageSize=10 ,結果如圖:
      在這裏插入圖片描述
    2. pageIndex=1,pageSize=5 ,結果如圖:
      在這裏插入圖片描述

      分頁效果與我們平時所需要的效果一致。僅僅在接口上加了一個自定義註解,即可自動分頁。返回的pageInfo如果覺得少了,還能自定義進行添加;

二. 實戰自定義註解分頁

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 回顧

  1. 講述了傳統pageQuery與現在的註解分頁的區別
  2. 講述了相關的源碼

3.2 注意:

  1. 這裏用到了Swagger-ui,所以使用代碼的時候,如果相關的爆紅則可以直接註釋掉或者導入swagger-ui,具體使用swagger-ui請網上找相關資料
  2. 請先閱讀源碼後再使用,可進行自定義修改。剛寫完肯定有一些的瑕疵,勿怪~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章