com.kasinf.framework.rest.web.method.SearchableMethodArgumentResolver Maven / Gradle / Ivy
package com.kasinf.framework.rest.web.method;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateException;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.kasinf.framework.core.util.JsonUtils;
import com.kasinf.framework.rest.annotation.SearchableDefaults;
import com.kasinf.framework.rest.config.SearchableConfiguration;
import com.kasinf.framework.rest.support.SearchOperator;
import com.kasinf.framework.rest.support.Searchable;
import com.kasinf.framework.rest.support.filter.FilterSos;
import com.kasinf.framework.rest.support.filter.SearchFilter;
import com.kasinf.framework.rest.support.filter.SearchFilterHelper;
import com.kasinf.framework.rest.util.ProjectionUtils;
import com.kasinf.framework.rest.web.util.SearchableBeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author lkhsh
* 查询参数解析器
*
* 1.1、默认查询字符串
* search.baseInfo.realname_like=zhang
* search.age_lt=12
* 排序及分页请参考 {@link PageableMethodArgumentResolver}
*
* 1.2、分组查询字串,构造以下json数据
*/
public class SearchableMethodArgumentResolver extends BaseMethodArgumentResolver {
private final PageableMethodArgumentResolver pageableMethodArgumentResolver;
private final String SEARCH_PREFIX;
private final String BASE_PATH;
public SearchableMethodArgumentResolver(PageableMethodArgumentResolver pageableMethodArgumentResolver, SearchableConfiguration config) {
this.pageableMethodArgumentResolver = pageableMethodArgumentResolver;
this.SEARCH_PREFIX = config.getSearchParamName();
this.BASE_PATH = config.getBaseUri().toString();
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Searchable.class.isAssignableFrom(parameter.getParameterType());
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Map searchableMap = getPrefixParameterMap(SEARCH_PREFIX, webRequest, true);
boolean notCustomSearchFilter = searchableMap.size() == 0;
SearchableDefaults searchDefaults = getSearchableDefaults(parameter);
boolean needMergeDefault = searchDefaults != null && searchDefaults.merge();
Searchable searchable = Searchable.of();
// 获取投影名称
String projectionName = webRequest.getParameter("projection");
if (StrUtil.isNotEmpty(projectionName)) {
String requestUri = ((ServletWebRequest) webRequest).getRequest().getRequestURI();
String contentPath = webRequest.getContextPath();
String mapping = requestUri.replace(contentPath + BASE_PATH + "/", "");
Class> projection = ProjectionUtils.getProjectionType(SearchableBeanUtils.getEntity(mapping), projectionName);
if (projection != null) {
searchable.setProjection(projection);
}
}
//自定义覆盖默认
if (needMergeDefault || notCustomSearchFilter) {
defaultSearchable(searchable, searchDefaults);
}
// 若带查询条件,组装条件
if (!notCustomSearchFilter) {
boolean isComplex = searchableMap.containsKey("filterSos");
// 启用了复杂查询,需要转换JSON至实体对象
if (!isComplex) {
// 字符串形式查询
for (String name : searchableMap.keySet()) {
List mapValues = filterSearchValues(searchableMap.get(name));
if (mapValues.size() == 1) {
// 处理日期格式的
if (name.endsWith("*date")) {
name = name.replace("*date", "");
try {
Date date = DateUtil.parseDate(mapValues.get(0));
searchable.addParam(name, date);
continue;
} catch (DateException ignore) {
}
} else if (name.endsWith("datetime")) {
name = name.replace("*datetime", "");
try {
Date date = DateUtil.parseDateTime(mapValues.get(0));
searchable.addParam(name, date);
continue;
} catch (DateException ignore) {
}
}
searchable.addParam(name, mapValues.get(0));
} else {
searchable.addParam(name, mapValues);
}
}
} else if (searchableMap.get("filterSos")[0] != null) {
List filterSosList = JsonUtils.nativeRead(searchableMap.get("filterSos")[0], new TypeReference>() {
});
if (filterSosList != null) {
Map filedType = null;
if (searchableMap.containsKey("tableFilterType")) {
filedType = JsonUtils.toMap(searchableMap.get("tableFilterType")[0], String.class, String.class);
}
SearchFilter searchFilter = changeFilterToSearchable(filterSosList, filedType);
searchable.addFilter(searchFilter);
}
}
}
Pageable pageable = (Pageable) pageableMethodArgumentResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
//默认分页及排序
if (searchDefaults == null) {
searchable.setPage(pageable);
}
//needPage=true 分页及排序
if (searchDefaults != null && searchDefaults.needPage()) {
searchable.setPage(pageable);
}
//needPage=false needSort=true 不要分页,但排序
if (searchDefaults != null && !searchDefaults.needPage() && searchDefaults.needSort()) {
searchable.addSort(Objects.requireNonNull(pageable).getSort());
}
return searchable;
}
/**
* 转换前台传过来的组合查询条件
*
* @param filterSos 查询条件
* @param filedType 需要进行转换的字段
* @return 内部使用的查询条件
*/
private SearchFilter changeFilterToSearchable(List filterSos, Map filedType) {
SearchFilter searchFilter = null;
for (FilterSos filter : filterSos) {
SearchFilter condition;
if (CollectionUtil.isNotEmpty(filter.getChildren())) {
condition = changeFilterToSearchable(filter.getChildren(), filedType);
} else {
// 若没有进行分组,则生成查询条件,需要对value做类型的转换,主要是时间类型
Object value = filter.getValue();
// if (filedType != null && filedType.containsKey(filter.getField())) {
// // 进行值的类型转换
// String valStr = filedType.get(filter.getField());
// value = getValue(value, filter.getType(), valStr);
// }
condition = SearchFilterHelper.newCondition(filter.getField(), filter.getType(), value);
}
if (searchFilter == null) {
searchFilter = condition;
} else {
if ("and".equals(filter.getPrefix())) {
searchFilter = SearchFilterHelper.and(searchFilter, condition);
} else if ("or".equals(filter.getPrefix())) {
searchFilter = SearchFilterHelper.or(searchFilter, condition);
}
}
}
return searchFilter;
}
/**
* 转换date类型的值
*
* @param value 接收到的日期字符串
* @param type: 操作类型
* @param format:格式化字符串
*/
private Object getValue(Object value, SearchOperator type, String format) {
// 暂时不需要类型转换的操作
return value;
}
private SearchableDefaults getSearchableDefaults(MethodParameter parameter) {
//首先从参数上找
SearchableDefaults searchDefaults = parameter.getParameterAnnotation(SearchableDefaults.class);
//找不到从方法上找
if (searchDefaults == null) {
searchDefaults = parameter.getMethodAnnotation(SearchableDefaults.class);
}
return searchDefaults;
}
private void defaultSearchable(Searchable searchable, SearchableDefaults searchableDefaults) {
if (searchableDefaults != null) {
for (String searchParam : searchableDefaults.value()) {
String[] searchPair = searchParam.split("=");
String paramName = searchPair[0];
String paramValue = searchPair[1];
if (paramName.endsWith("in")) {
searchable.addParam(paramName, paramValue.split(","));
} else {
searchable.addParam(paramName, paramValue);
}
}
// 没有传入projection参数,那么取默认的
if (!searchable.hasProjection()) {
Class> projection = searchableDefaults.projection();
searchable.setProjection(projection);
}
}
}
private List filterSearchValues(String[] values) {
return Stream.of(values)
.filter(StrUtil::isNotEmpty)
.collect(Collectors.toList());
}
}