com.kasinf.framework.rest.web.method.PageableMethodArgumentResolver Maven / Gradle / Ivy
package com.kasinf.framework.rest.web.method;
import com.kasinf.framework.rest.annotation.PageableDefaults;
import com.kasinf.framework.rest.config.SearchableConfiguration;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.ModelAndViewContainer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @author lkhsh
* 请求分页数据绑定到Pageable,支持请求参数和uri template数据的绑定
*/
public class PageableMethodArgumentResolver extends BaseMethodArgumentResolver {
/**
* 默认分页参数前缀
*/
private final String PAGE_PREFIX;
/**
* 默认排序参数前缀
*/
private final String SORT_PREFIX;
/**
* 默认每页数据量参数的前缀
*/
private final String SIZE_PREFIX;
/**
* 最小分页大小
*/
private final int MIN_PAGE_SIZE;
/**
* 最大分页大小
*/
private final int MAX_PAGE_SIZE;
/**
* 默认分页
*/
private final Pageable DEFAULT_PAGEABLE;
public PageableMethodArgumentResolver(SearchableConfiguration config) {
this.PAGE_PREFIX = config.getPageParamName();
this.SORT_PREFIX = config.getSortParamName();
this.SIZE_PREFIX = config.getLimitParamName();
this.MIN_PAGE_SIZE = config.getMinPageSize();
this.MAX_PAGE_SIZE = config.getMaxPageSize();
this.DEFAULT_PAGEABLE = PageRequest.of(0, config.getDefaultPageSize());
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Pageable.class.isAssignableFrom(parameter.getParameterType());
}
/**
* 从请求参数中分离出分页条件
*
* @param parameter 请求参数
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
PageableDefaults pageableDefaults = getPageableDefault(parameter);
//默认的page request
Pageable defaultPageRequest = getDefaultFromAnnotationOrFallback(pageableDefaults);
// 获取以默认排序参数开头的数据
Map sortMap = getPrefixParameterMap(SORT_PREFIX, webRequest, false);
// 若有多个排序条件,且指定了排序顺序,则按指定的顺序组装排序条件
Sort sort = getSort(SORT_PREFIX, sortMap, defaultPageRequest);
// 获取页码
int pn = getPn(webRequest, defaultPageRequest);
int pageSize = getPageSize(webRequest, defaultPageRequest);
return PageRequest.of(pn - 1, pageSize, sort);
}
/**
* 查找方法或参数上的@PageableDefault注释
*
* @param parameter 参数
* @return PageableDefault
*/
private PageableDefaults getPageableDefault(MethodParameter parameter) {
//首先从参数上找
PageableDefaults pageableDefaults = parameter.getParameterAnnotation(PageableDefaults.class);
//找不到从方法上找
if (pageableDefaults == null) {
pageableDefaults = parameter.getMethodAnnotation(PageableDefaults.class);
}
return pageableDefaults;
}
/**
* 根据@PageableDefault注释,组装Pageable对象
*
* @param pageableDefaults 注释
* @return 分页参数
*/
private Pageable getDefaultFromAnnotationOrFallback(PageableDefaults pageableDefaults) {
if (pageableDefaults == null) {
return DEFAULT_PAGEABLE;
}
int pageNumber = pageableDefaults.pageNumber();
int pageSize = pageableDefaults.value();
String[] sortStrArray = pageableDefaults.sort();
Sort sort = null;
for (String sortStr : sortStrArray) {
String[] sortStrPair = sortStr.split("=");
Sort newSort = Sort.by(Sort.Direction.fromString(sortStrPair[1]), sortStrPair[0]);
if (sort == null) {
sort = newSort;
} else {
sort = sort.and(newSort);
}
}
return PageRequest.of(pageNumber, pageSize, sort);
}
private Sort getSort(String sortNamePrefix, Map sortMap, Pageable defaultPageRequest) {
Sort sort = null;
List orderedSortList = new ArrayList<>();
sortMap.forEach((k, v) -> {
int order = 0;
String orderStr = k.replace(sortNamePrefix, "");
try {
if (!StringUtils.isEmpty(orderStr)) {
order = Integer.parseInt(orderStr);
}
} catch (Exception ignore) {
}
String[] arr = v[0].split(",");
assertSortProperty(arr[0]);
Sort.Direction direction;
if (arr.length == 2) {
direction = Sort.Direction.fromString(arr[1]);
} else {
direction = Sort.Direction.ASC;
}
orderedSortList.add(new OrderedSort(arr[0], direction, order));
});
Collections.sort(orderedSortList);
for (OrderedSort orderedSort : orderedSortList) {
Sort newSort = Sort.by(orderedSort.direction, orderedSort.property);
sort = sort == null ? newSort : sort.and(newSort);
}
return sort == null ? defaultPageRequest.getSort() : sort;
}
/**
* 防止sql注入,排序字符串只能包含字符 数字 下划线 点 ` "
*
* @param property 参数值
*/
private void assertSortProperty(String property) {
if (!property.matches("[a-zA-Z0-9_、.`\"]*")) {
throw new IllegalStateException("Sort property exception, only contains [a-zA-Z0-9_.`\"]");
}
}
/**
* 获取当前页数
*
* @param webRequest 请求对象
* @param defaultPageRequest 得到的分页对象
*/
private int getPn(NativeWebRequest webRequest, Pageable defaultPageRequest) {
String page = webRequest.getParameter(PAGE_PREFIX);
int pn = page == null ? defaultPageRequest.getPageNumber() : Integer.parseInt(page);
if (pn < 1) {
pn = 1;
}
return pn;
}
/**
* 获取分页大小
*
* @param webRequest 请求对象
* @param defaultPageRequest 分页对象
*/
private int getPageSize(NativeWebRequest webRequest, Pageable defaultPageRequest) {
String limit = webRequest.getParameter(SIZE_PREFIX);
int size = limit == null ? defaultPageRequest.getPageSize() : Integer.parseInt(limit);
if (size < MIN_PAGE_SIZE) {
size = MIN_PAGE_SIZE;
}
if (size > MAX_PAGE_SIZE) {
size = MAX_PAGE_SIZE;
}
return size;
}
static class OrderedSort implements Comparable {
private String property;
private Sort.Direction direction;
private int order = 0; //默认0 即无序
OrderedSort(String property, Sort.Direction direction, int order) {
this.property = property;
this.direction = direction;
this.order = order;
}
@Override
public int compareTo(OrderedSort o) {
return o == null ? -1 : Integer.compare(this.order, o.order);
}
}
}