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请网上找相关资料
- 请先阅读源码后再使用,可进行自定义修改。刚写完肯定有一些的瑕疵,勿怪~