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

com.kasinf.framework.rest.support.SearchRequest Maven / Gradle / Ivy

The newest version!
package com.kasinf.framework.rest.support;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.kasinf.framework.rest.config.SearchableConfiguration;
import com.kasinf.framework.rest.exception.InvalidSearchPropertyException;
import com.kasinf.framework.rest.exception.InvalidSearchValueException;
import com.kasinf.framework.rest.exception.SearchException;
import com.kasinf.framework.rest.support.filter.*;
import com.kasinf.framework.rest.util.SearchableConvertUtils;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;

import java.util.*;

/**
 * @author lkhsh
 * 查询接口实现,包括条件、分页、排序
 */
@Data
@NoArgsConstructor
@ToString(of = {"searchFilterMap", "page", "sort"})
public final class SearchRequest implements Searchable {

    private final Map searchFilterMap = new HashMap<>();

    /**
     * 使用这个的目的是保证拼sql的顺序是按照添加时的顺序
     */
    private final List searchFilters = new ArrayList<>();

    /**
     * 分页参数
     */
    private Pageable page;

    /**
     * 排序参数
     */
    private Sort sort;

    /**
     * 是否已转换
     */
    private boolean converted;

    /**
     * 搜索参数
     */
    private SearchableConfiguration config;

    /**
     * 投影对象
     */
    private Class projection;

    @Override
    public boolean hasProjection() {
        return projection != null && projection != void.class;
    }

    @Override
    public Searchable setProjection(Class projection) {
        this.projection = projection;
        return this;
    }

    public SearchRequest(final Map searchParams) {
        this(searchParams, null, null);
    }

    public SearchRequest(final Map searchParams, final Pageable page) {
        this(searchParams, page, null);
    }

    public SearchRequest(final Map searchParams, final Sort sort) {
        this(searchParams, null, sort);
    }

    /**
     * 根据查询参数拼Search
     * 查询参数格式:property_op=value 或 customerProperty=value
     * customerProperty查找规则是:
     * 1、先查找domain的属性,
     * 2、如果找不到查找domain上的SearchPropertyMappings映射规则
     * 属性、操作符之间用_分割,op可省略/或custom,省略后值默认为custom,即程序中自定义
     * 如果op=custom,property也可以自定义(即可以与domain的不一样)
     *
     * @param searchParams 查询参数组
     * @param page         分页
     * @param sort         排序
     */
    public SearchRequest(final Map searchParams, final Pageable page, final Sort sort) throws SearchException {
        toSearchFilters(searchParams);
        merge(sort, page);
    }

    /**
     * 组装查询条件
     *
     * @param searchParams 查询条件
     */
    private void toSearchFilters(final Map searchParams) throws SearchException {
        if (searchParams == null || searchParams.size() == 0) {
            return;
        }
        for (Map.Entry entry : searchParams.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            addFilter(SearchFilterHelper.newCondition(key, value));
        }
    }

    @Override
    public void changeDataCondition() {
        changeDataCondition(this.searchFilters);
    }

    private void changeDataCondition(List searchFilters) {
        for (int i = 0; i < searchFilters.size(); i++) {
            SearchFilter searchFilter = searchFilters.get(i);
            if (searchFilter instanceof Condition) {
                Condition condition = (Condition) searchFilter;
                if (condition.isDateFilter()) {
                    Date today = DateUtil.beginOfDay(new Date()).toJdkDate();
                    Date begin = null;
                    Date end = null;
                    switch (condition.getOperator()) {
                        case yesterday:
                            // 操作符为昨天,取昨天0点-昨天23:59:59的区间
                            begin = DateUtil.offsetDay(today, -1).toJdkDate();
                            end = DateUtil.offsetSecond(today, -1).toJdkDate();
                            break;
                        case thisWeek:
                            //操作符为本周,获取本周一0点至上周日23:59:59
                            begin = DateUtil.beginOfWeek(today).toJdkDate();
                            end = DateUtil.endOfWeek(today).toJdkDate();
                            break;
                        case lastWeek:
                            //操作符为上周,获取上周一0点至上周日23:59:59
                            Date monday = DateUtil.beginOfWeek(today);
                            begin = DateUtil.offsetWeek(monday, -1).toJdkDate();
                            end = DateUtil.offsetSecond(monday, -1).toJdkDate();
                            break;
                        case thisMonth:
                            // 操作符为本月,获取本月1号0点至本月最后一天23:59:59
                            begin = DateUtil.beginOfMonth(today).toJdkDate();
                            end = DateUtil.endOfMonth(today).toJdkDate();
                            break;
                        case thisYear:
                            begin = DateUtil.beginOfYear(today).toJdkDate();
                            end = DateUtil.endOfYear(today).toJdkDate();
                            break;
                        case specific:
                            // 指定日期,生成当天0点至当天23:59:59的区间
                            Object value = condition.getValue();
                            if (value instanceof String) {
                                begin = DateUtil.parse((String) condition.getValue()).toJdkDate();
                            } else if (value instanceof Date) {
                                begin = DateUtil.beginOfDay((Date) value).toJdkDate();
                            }
                            Assert.notNull(begin, "指定的日期必须为 String 或 Date 类型");
                            end = DateUtil.endOfDay(begin).toJdkDate();
                            break;
                    }
                    condition.setOperator(SearchOperator.ge);
                    condition.setValue(begin);
                    condition.createKey();
                    // 为当前条件拼接一个and条件
                    SearchFilter newCondition = SearchFilterHelper.newCondition(condition.getSearchProperty(), SearchOperator.le, end);
                    searchFilter = SearchFilterHelper.and(condition, newCondition);
                    searchFilters.set(i, searchFilter);
                }
                return;
            }
            if (searchFilter instanceof OrCondition) {
                changeDataCondition(((OrCondition) searchFilter).getOrFilters());
                return;
            }
            if (searchFilter instanceof AndCondition) {
                changeDataCondition(((AndCondition) searchFilter).getAndFilters());
            }
        }
    }

    /**
     * 添加搜索参数
     *
     * @param key   如 name_like
     * @param value 如果是in查询 多个值之间","分隔
     * @return {@link Searchable}
     * @throws SearchException SearchException
     */
    @Override
    public Searchable addParam(String key, Object value) throws SearchException {
        addFilter(SearchFilterHelper.newCondition(key, value));
        return this;
    }

    /**
     * 添加一组查询参数
     *
     * @param searchParams 查询条件
     * @return {@link Searchable}
     * @throws SearchException SearchException
     */
    @Override
    public Searchable addParams(Map searchParams) throws SearchException {
        toSearchFilters(searchParams);
        return this;
    }

    /**
     * 添加过滤条件
     *
     * @param searchProperty 查询的属性名
     * @param operator       操作运算符
     * @param value          值
     * @return {@link Searchable}
     * @throws SearchException SearchException
     */
    @Override
    public Searchable addFilter(String searchProperty, SearchOperator operator, Object value) throws SearchException {
        SearchFilter searchFilter = SearchFilterHelper.newCondition(searchProperty, operator, value);
        return addFilter(searchFilter);
    }

    /**
     * 添加单目操作
     *
     * @param searchProperty 查询的属性名
     * @param operator       单目运算操作
     * @return {@link Searchable}
     * @throws SearchException SearchException
     */
    @Override
    public Searchable addFilter(String searchProperty, SearchOperator operator) throws SearchException {
        SearchFilter searchFilter = SearchFilterHelper.newCondition(searchProperty, operator, null);
        return addFilter(searchFilter);
    }

    /**
     * 添加过滤条件
     *
     * @param searchFilter 查询条件{@link SearchFilter}
     * @return {@link Searchable}
     */
    @Override
    public Searchable addFilter(SearchFilter searchFilter) {
        if (searchFilter == null) {
            return this;
        }
        if (searchFilter instanceof Condition) {
            Condition condition = (Condition) searchFilter;
            String key = condition.getKey();
            searchFilterMap.put(key, condition);
        }
        int index = searchFilters.indexOf(searchFilter);
        if (index != -1) {
            searchFilters.set(index, searchFilter);
        } else {
            searchFilters.add(searchFilter);
        }
        return this;
    }

    /**
     * 添加多个过滤条件
     *
     * @param searchFilters 过滤条件{@link SearchFilter}
     * @return {@link Searchable}
     */
    @Override
    public Searchable addFilters(Collection searchFilters) {
        if (CollectionUtil.isNotEmpty(searchFilters)) {
            searchFilters.forEach(this::addFilter);
        }
        return this;
    }

    /**
     * 添加多个or连接的过滤条件
     *
     * @param first  第一个
     * @param others 其他
     * @return {@link Searchable}
     */
    @Override
    public Searchable or(final SearchFilter first, final SearchFilter... others) {
        addFilter(SearchFilterHelper.or(first, others));
        return this;
    }

    /**
     * 添加多个and连接的过滤条件
     *
     * @param first  第一个
     * @param others 其他
     * @return {@link Searchable}
     */
    @Override
    public Searchable and(final SearchFilter first, final SearchFilter... others) {
        addFilter(SearchFilterHelper.and(first, others));
        return this;
    }

    /**
     * 移除指定key的过滤条件
     *
     * @param key 键
     * @return {@link Searchable}
     */
    @Override
    public Searchable removeFilter(final String key) {
        if (key == null) {
            return this;
        }
        SearchFilter searchFilter = searchFilterMap.get(key);

        if (searchFilter == null) {
            searchFilter = searchFilterMap.remove(getCustomKey(key));
        }

        if (searchFilter == null) {
            return this;
        }

        searchFilters.remove(searchFilter);
        return this;
    }

    /**
     * 获取自定义key
     *
     * @param key:
     */
    private String getCustomKey(String key) {
        return key + Condition.separator + SearchOperator.custom;
    }

    /**
     * 移除指定属性 和 操作符的过滤条件
     *
     * @param searchProperty 查询属性
     * @param operator       操作符
     * @return {@link Searchable}
     */
    @Override
    public Searchable removeFilter(final String searchProperty, final SearchOperator operator) {
        return removeFilter(searchProperty + Condition.separator + operator);
    }

    /**
     * 将搜索的值转换为实体对应的值
     *
     * @param entityClass 实体类
     * @param          实体对应的类型
     * @return {@link Searchable}
     * @throws InvalidSearchValueException    非法搜索值异常
     * @throws InvalidSearchPropertyException 非法搜索属性异常
     */
    @Override
    public  Searchable convert(Class entityClass) throws InvalidSearchValueException, InvalidSearchPropertyException {
        SearchableConvertUtils.convertSearchValueToEntityValue(this, entityClass);
        markConverted();
        return this;
    }

    /**
     * 获取所有搜索条件
     *
     * @return searchFilters
     */
    @Override
    public List getSearchFilters() {
        return searchFilters;
    }

    /**
     * 标识为已经转换过了 避免多次转换
     *
     * @return {@link Searchable}
     */
    @Override
    public Searchable markConverted() {
        this.converted = true;
        return this;
    }

    /**
     * 设置分页
     *
     * @param page 分页信息
     * @return 查询实现类 {@link SearchRequest}
     */
    @Override
    public Searchable setPage(final Pageable page) {
        merge(sort, page);
        return this;
    }

    /**
     * 设置分页
     *
     * @param pageNumber 分页页码 索引从 0 开始
     * @param pageSize   每页大小
     * @return 查询实现类 {@link SearchRequest}
     */
    @Override
    public Searchable setPage(int pageNumber, int pageSize) {
        merge(sort, PageRequest.of(pageNumber, pageSize));
        return this;
    }

    /**
     * 添加排序条件
     *
     * @param sort 排序
     * @return 查询实现类 {@link SearchRequest}
     */
    @Override
    public Searchable addSort(Sort sort) {
        merge(sort, page);
        return this;
    }

    /**
     * 添加排序条件
     *
     * @param direction 排序方向
     * @param property  属性
     * @return 查询实现类 {@link SearchRequest}
     */
    @Override
    public Searchable addSort(Sort.Direction direction, String property) {
        merge(Sort.by(direction, property), page);
        return this;
    }

    /**
     * 是否有查询参数
     *
     * @return 标识符
     */
    @Override
    public boolean hasSearchFilter() {
        return searchFilters.size() > 0;
    }

    /**
     * 是否有排序
     *
     * @return 标识符
     */
    @Override
    public boolean hashSort() {
        return this.sort != null && this.sort.iterator().hasNext();
    }

    /**
     * 移除排序
     */
    @Override
    public void removeSort() {
        this.sort = null;
        if (this.page != null) {
            this.page = PageRequest.of(page.getPageNumber(), page.getPageSize());
        }
    }

    /**
     * 是否有分页
     *
     * @return 标识符
     */
    @Override
    public boolean hasPageable() {
        return this.page != null && this.page.getPageSize() > 0;
    }

    /**
     * 移除分页
     */
    @Override
    public void removePageable() {
        this.page = null;
    }

    /**
     * 是否包含要搜索的键,如 name_like,包括and和or
     *
     * @param key 查询条件
     * @return 查询实现类 {@link SearchRequest}
     */
    @Override
    public boolean containsSearchKey(String key) {
        //先检查自身是否包含,否则检查其中的or 和 and
        return searchFilterMap.containsKey(key) || searchFilterMap.containsKey(getCustomKey(key)) || containsSearchKey(searchFilters, key);
    }

    /**
     * 是否存在查询条件
     *
     * @param searchFilters:
     * @param key:
     */
    private boolean containsSearchKey(List searchFilters, String key) {
        boolean contains = false;
        for (SearchFilter searchFilter : searchFilters) {
            if (searchFilter instanceof OrCondition) {
                OrCondition orCondition = (OrCondition) searchFilter;
                contains = containsSearchKey(orCondition.getOrFilters(), key);
            }
            if (searchFilter instanceof AndCondition) {
                AndCondition andCondition = (AndCondition) searchFilter;
                contains = containsSearchKey(andCondition.getAndFilters(), key);
            }
            if (searchFilter instanceof Condition) {
                Condition condition = (Condition) searchFilter;
                contains = condition.getKey().equals(key) || condition.getSearchProperty().equals(key);
            }
        }
        return contains;
    }

    @Override
    public Object getValue(String key) {
        SearchFilter searchFilter = searchFilterMap.get(key);
        if (searchFilter == null) {
            searchFilter = searchFilterMap.get(getCustomKey(key));
        }
        if (searchFilter == null) {
            return null;
        }

        if (searchFilter instanceof Condition) {
            Condition condition = (Condition) searchFilter;
            return condition.getValue();
        }
        return null;
    }

    /**
     * 合并
     *
     * @param sort 排序
     * @param page 分页
     */
    private void merge(Sort sort, Pageable page) {
        if (sort == null) {
            sort = this.sort;
        }
        if (page == null) {
            page = this.page;
        }

        // 合并排序
        if (sort == null) {
            this.sort = page != null ? page.getSort() : null;
        } else {
            this.sort = (page != null ? sort.and(page.getSort()) : sort);
        }
        // 把排序合并到page中
        if (page != null) {
            this.page = PageRequest.of(page.getPageNumber(), page.getPageSize(), this.sort);
        } else {
            this.page = null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy