SpringDataJpa之强大的手动分页查询(封装与技巧)

背景

JPA对于简单类的查询还是不错的,但通常业务场景不会那么简单,必须用到sql语句来组成一些查询,这个时候我们最好就用手动分页了。类似于MyBatis的用法。

实体类

这是一个员工的实体,即将对他进行操刀

@Entity
@NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e")
public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private int id;
    private Timestamp createtime;
    private String empImage;
    private String empName;
    private String empNum;
    private Timestamp lastupdatetime;
    private String status;
    ......
}

Repository类

手写语句,这样的好处在于,全部自定义,功能强大,能想出什么强大的sql就能用到什么强大的功能。

(c.emp_num=?1 or ?1 is null)
这种是做个非空判断,如果是空,就跳过这个条件,不执行。

@Repository
public interface EmployeeRepositrory extends JpaRepository<Employee, Integer> {
    @Query(value ="select * from employee c "
            + "where (c.emp_num=?1 or ?1 is null) and (c.status=?2 or ?2 is null) "
            + "order by c.lastupdatetime desc  limit ?3,?4 ",nativeQuery = true)
    List<Employee> findAllList(String empNum,String status,Integer pageNumber,Integer pageSize);

    @Query(value ="select count(*) from employee c "
            + "where (c.emp_num=?1 or ?1 is null) and (c.status=?2 or ?2 is null) "
            + "order by c.lastupdatetime desc ",nativeQuery = true)
    Integer countAllList(String empNum,String status);
}

Controller控制器

    @PostMapping("/list")
    public ApiReturnObject findAll(String empNum,String status, Integer pageNumber, Integer pageSize) {
            //检查pageNumber, pageSize非空
            CheckUtils.checkPageNumberPageSize(pageNumber, pageSize);
            //获取数据
            List<Employee> list=employeeRepositrory.findAllList(empNum, status,(pageNumber-1)*pageSize, pageSize);
            //获取计数
            Integer countNum=employeeRepositrory.countAllList(empNum, status);
            //封装返回
            return ApiReturnUtil.pageManual(pageNumber, pageSize, countNum, list);      
    }

(pageNumber-1)*pageSize, pageSize
这个是因为,mysql的limit x,y;x代表从第几条数据开始,y代表获取多少
所以从数学的角度来讲,这里是(pageNumber-1)*pageSize代表第几条数据开始。
例如一共12条纪录,pageNumber=2,pageSize=10
(pageNumber-1)*pageSize, pageSize=10,10
代表从第10条开始,连续拿10条(0~9,10~19)

如果不会Limit的,这里补充一下,Limit是mysql的语法select * from table limit m,n 其中m是指记录开始的index,从0开始,表示第一条是指从第m+1条开始, 取n条。

ApiReturnUtil&ApiReturnObject

这些根据大家的需要封装,这里这是做个示例

public class ApiReturnObject implements Serializable{
    String errorCode="00";
    Object errorMessage;
    Object returnObject;
    String pageNumber;
    String pageSize;
    String totalElements;
    String totalPages;
    public ApiReturnObject(String pageNumber,String pageSize,String totalElements,String totalPages,String errorCode, Object errorMessage, Object returnObject) {
        super();
        this.pageNumber = pageNumber;
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
        this.returnObject = returnObject;
        this.pageSize = pageSize;
        this.totalElements = totalElements;
        this.totalPages = totalPages;
    }
}
    public static ApiReturnObject pageManual(Integer pageNumber, Integer pageSize,Integer countNum, List returnObject) {
        return new ApiReturnObject(pageNumber+"",pageSize+"",countNum+"",getTotalPages(countNum, pageSize),"00","success",returnObject);
    }

    public static String getTotalPages(Integer countNum, Integer pageSize) {
        if((countNum%pageSize)==0) {
            return ((countNum/pageSize))+"";
        }else {
            return ((countNum/pageSize)+1)+"";
        }
    }

返回格式如下

{
    "errorCode": "00", //返回码,一般00代表成功
    "errorMessage": "success", //返回信息
    "pageNumber": "1", //分页页码
    "pageSize": "10", //分页大小
    "returnObject": [{......}], //返回的list,这里不陈列
    "totalElements": "12",//count语句查询出来有多少条纪录
    "totalPages": "2" //一共分多少页,通过总数/分页大小再+1可以算出((countNum/pageSize)+1)
}

总结

到这里就完成啦,怎么样,是不是很好用,定制性很强。这里有几点技巧提示一下:
1. 例如你要多关联一些表,那就尽情的再sql语句里面left join吧,如果要先!
2. 如果有字段是主表没有的,希望加上去的,就加个@Transient注释,代表不实体化这个字段,但是查询又可以关联出来
3. 判断多用(c.emp_num=?1 or ?1 is null)这个形式的,可以少走很多弯路(除非有特殊需求)

猜你喜欢

转载自blog.csdn.net/moshowgame/article/details/80672617