All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.kasinf.framework.rest.web.method.PageableMethodArgumentResolver Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
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);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy