feat: 重构filter
This commit is contained in:
parent
4654f80222
commit
af1ad3cda2
@ -4,36 +4,29 @@ import cn.axzo.foundation.gateway.support.entity.GateResponse;
|
||||
import cn.axzo.foundation.gateway.support.entity.ProxyContext;
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.ProxyHook;
|
||||
import cn.axzo.foundation.page.IPageReq;
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import cn.axzo.foundation.result.ResultCode;
|
||||
import cn.axzo.foundation.util.DataAssembleHelper;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.filters.*;
|
||||
import cn.axzo.foundation.util.FastjsonUtils;
|
||||
import cn.axzo.foundation.web.support.rpc.RequestParams;
|
||||
import cn.axzo.foundation.web.support.rpc.RpcClient;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* 对请求外部扩展插件。 使用如下:
|
||||
@ -62,9 +55,6 @@ import java.util.stream.IntStream;
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RequestFilterHook implements ProxyHook {
|
||||
public static final String FILTER_BEAN = "bean";
|
||||
public static final String BEAN_SEPARATOR = "|";
|
||||
@ -74,9 +64,24 @@ public class RequestFilterHook implements ProxyHook {
|
||||
* key: bean 名称
|
||||
* value: transformer 对象。
|
||||
*/
|
||||
@NonNull
|
||||
private Function<String, RequestFilter> filterBeanResolver;
|
||||
|
||||
private static final Map<String, RequestFilter> DEFAULT_FILTERS = ImmutableMap.<String, RequestFilter>builder()
|
||||
.put("convertListAsObjectFilter", new ConvertListAsObjectFilter())
|
||||
.put("convertListAsPageFilter", new ConvertListAsPageFilter())
|
||||
.put("convertPageAsListFilter", new ConvertPageAsListFilter())
|
||||
.put("cropContentFilter", new CropContentFilter())
|
||||
.put("requestParamCheckFilter", new RequestParamCheckFilter())
|
||||
.put("moveInputFieldFilter", new MoveInputFieldFilter())
|
||||
.put("keyNoQueryFilter", new KeyNoQueryFilter())
|
||||
.build();
|
||||
|
||||
|
||||
public RequestFilterHook(@NonNull Function<String, RequestFilter> filterBeanResolver) {
|
||||
//优先从外部传入, 没有时则从default获取
|
||||
this.filterBeanResolver = s -> Optional.ofNullable(filterBeanResolver.apply(s)).orElse(DEFAULT_FILTERS.get(s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestParams preRequest(RequestContext reqContext, ProxyContext proxyContext, RpcClient rpcClient, String postURL, RequestParams postParams) {
|
||||
if (proxyContext.getParameterFilter() == null || proxyContext.getParameterFilter().getInFilterExtends().isEmpty()) {
|
||||
@ -183,446 +188,6 @@ public class RequestFilterHook implements ProxyHook {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台页面中通过关键字段查询时, 需要移除其他字段的查询场景. 添加通用的请求过滤器来处理此类需求.
|
||||
* 使用时, 需要单独注入.
|
||||
*/
|
||||
public final static class KeyNoQueryFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject config) {
|
||||
if (params == null) {
|
||||
return params;
|
||||
}
|
||||
|
||||
Set<String> keyNoFields = Splitter.on(",").omitEmptyStrings().trimResults()
|
||||
.splitToStream(Strings.nullToEmpty(config.getString("keyNoFields")))
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> removeFields = Splitter.on(",").omitEmptyStrings().trimResults()
|
||||
.splitToStream(Strings.nullToEmpty(config.getString("removeFields")))
|
||||
.collect(Collectors.toSet());
|
||||
if (keyNoFields.isEmpty() || removeFields.isEmpty()) {
|
||||
return params;
|
||||
}
|
||||
|
||||
JSONObject paramsJson = (JSONObject) params;
|
||||
if (paramsJson.keySet().stream().noneMatch(keyNoFields::contains)) {
|
||||
return paramsJson;
|
||||
}
|
||||
|
||||
removeFields.forEach(paramsJson::remove);
|
||||
return paramsJson;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class ListOrPageRecordsFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (!(content instanceof JSONObject) && !(content instanceof JSONArray)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (content instanceof JSONArray) {
|
||||
List<JSONObject> records = ((JSONArray) content).toJavaList(JSONObject.class);
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
return response;
|
||||
}
|
||||
JSONArray filtered = new JSONArray().fluentAddAll(filterRecords(reqContext, records, config));
|
||||
return jsonResp.fluentPut("data", filtered);
|
||||
}
|
||||
|
||||
JSONObject page = (JSONObject) content;
|
||||
JSONArray records = page.getJSONArray("data");
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
return response;
|
||||
}
|
||||
List<JSONObject> filtered = filterRecords(reqContext, records.toJavaList(JSONObject.class), config);
|
||||
page.put("data", new JSONArray().fluentAddAll(filtered));
|
||||
return response;
|
||||
}
|
||||
|
||||
public abstract List<JSONObject> filterRecords(RequestContext reqContext, List<JSONObject> records, JSONObject config);
|
||||
}
|
||||
|
||||
public abstract static class ConvertContentFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (content == null) {
|
||||
return response;
|
||||
}
|
||||
Preconditions.checkArgument(content instanceof JSON, "ConvertContentFilter不支持原始response.content非json的情况");
|
||||
return jsonResp.fluentPut("data", filterContent(reqContext, (JSON) content, config));
|
||||
}
|
||||
|
||||
public abstract JSON filterContent(RequestContext reqContext, JSON content, JSONObject config);
|
||||
}
|
||||
|
||||
public static class ConvertPageAsListFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (!(content instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
JSONArray records = ((JSONObject) content).getJSONArray("data");
|
||||
return jsonResp.fluentPut("data", Optional.ofNullable(records).orElseGet(JSONArray::new));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConvertListAsObjectFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
|
||||
JSONArray arrayContent = null;
|
||||
if (content instanceof JSONArray) {
|
||||
arrayContent = (JSONArray) content;
|
||||
} else if (content instanceof JSONObject) {
|
||||
JSONArray records = ((JSONObject) content).getJSONArray("data");
|
||||
arrayContent = records == null ? new JSONArray() : records;
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
JSONObject obj = IntStream.range(0, arrayContent.size())
|
||||
.mapToObj(arrayContent::getJSONObject)
|
||||
.findFirst()
|
||||
.orElseGet(JSONObject::new);
|
||||
return jsonResp.fluentPut("data", filterObject(reqContext, obj, config));
|
||||
}
|
||||
|
||||
public JSONObject filterObject(RequestContext reqContext, JSONObject obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
public JSONObject filterObject(RequestContext reqContext, JSONObject obj, JSONObject config) {
|
||||
return filterObject(reqContext, obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConvertListAsPageFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (!(content instanceof JSONArray)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
List<JSONObject> records = ((JSONArray) content).toJavaList(JSONObject.class);
|
||||
PageResp<JSONObject> page = PageResp.<JSONObject>builder().total(records.size()).build();
|
||||
|
||||
IPageReq pageParam = JSONObject.parseObject(reqContext.getRequestBody(), IPageReq.class);
|
||||
Optional.ofNullable(pageParam).map(IPageReq::getPage).ifPresent(page::setCurrent);
|
||||
Optional.ofNullable(pageParam).map(IPageReq::getPageSize).ifPresent(page::setSize);
|
||||
|
||||
page.setData(records.stream()
|
||||
.skip((page.getCurrent() - 1) * page.getSize())
|
||||
.limit(page.getSize())
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return jsonResp.fluentPut("data", page);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequestParamCheckFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject config) {
|
||||
boolean isConfigRulePresent = config != null && !config.isEmpty() && config.containsKey("rules");
|
||||
Preconditions.checkArgument(isConfigRulePresent, "RequestParamCheckFilter必须指定检查规则");
|
||||
Preconditions.checkArgument(JSONObject.class.isAssignableFrom(params.getClass()),
|
||||
"RequestParamCheckFilter只能检查JSONObject类型参数");
|
||||
//spring list默认读取为 map(key=0...N). 将values转换为Rule
|
||||
List<Rule> rules = config.getJSONObject("rules").entrySet().stream()
|
||||
.map(e -> ((JSONObject) e.getValue()).toJavaObject(Rule.class))
|
||||
.collect(Collectors.toList());
|
||||
rules.stream().forEach(p ->
|
||||
Preconditions.checkArgument(!StringUtils.isAllBlank(p.getField(), p.getJsonPath()),
|
||||
"RequestParamCheckFilter规则错误field, jsonPath不能都为空"));
|
||||
Operator operator = Optional.ofNullable(config.getString("operator"))
|
||||
.map(e -> Operator.valueOf(e)).orElse(Operator.AND);
|
||||
|
||||
List<Optional<String>> errors = rules.stream()
|
||||
.map(rule -> rule.check((JSONObject) params))
|
||||
.collect(Collectors.toList());
|
||||
//如果operator=AND. & 任意一个检查错误 则告警
|
||||
if (operator == Operator.AND && errors.stream().anyMatch(Optional::isPresent)) {
|
||||
throw ResultCode.INVALID_PARAMS.toException(errors.stream().filter(Optional::isPresent).findFirst().get().get());
|
||||
}
|
||||
//如果operator=OR. & 所有检查都是错误 则告警
|
||||
if (operator == Operator.OR && errors.stream().allMatch(Optional::isPresent)) {
|
||||
throw ResultCode.INVALID_PARAMS.toException(errors.stream().filter(Optional::isPresent).findFirst().get().get());
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Rule {
|
||||
String jsonPath;
|
||||
String field;
|
||||
boolean required;
|
||||
String regex;
|
||||
private transient Pattern pattern;
|
||||
|
||||
/** 检查值并返回错误信息, 正确则返回empty */
|
||||
protected Optional<String> check(JSONObject param) {
|
||||
Object value = getValue(param);
|
||||
if (required && value == null) {
|
||||
return Optional.of(field + "不能为空");
|
||||
}
|
||||
Optional<Pattern> pattern = tryGetPattern();
|
||||
if (pattern.isPresent() && value != null && !pattern.get().matcher(value.toString()).find()) {
|
||||
return Optional.of(field + "参数校验失败:" + regex);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/** 优先根据field获取value. 否则根据jsonPath */
|
||||
private Object getValue(JSONObject param) {
|
||||
if (!Strings.isNullOrEmpty(field)) {
|
||||
return param.get(field);
|
||||
}
|
||||
return JSONPath.eval(param, jsonPath);
|
||||
}
|
||||
|
||||
private Optional<Pattern> tryGetPattern() {
|
||||
if (Strings.isNullOrEmpty(regex)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (pattern == null) {
|
||||
pattern = Pattern.compile(regex);
|
||||
}
|
||||
return Optional.of(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Operator {
|
||||
AND,
|
||||
OR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪返回的content内容
|
||||
* 仅支持:
|
||||
* 1.content是JSONObject
|
||||
* 2.content是JSONArray,且其中是JSONObject
|
||||
* 3.content是分页返回对象,即{"data":[{}]}
|
||||
*/
|
||||
public static class CropContentFilter extends ConvertContentFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
throw new UnsupportedOperationException("使用CropContentFilter必须指定裁剪配置");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterContent(RequestContext reqContext, JSON content, JSONObject config) {
|
||||
// see class: CropConfig
|
||||
if (CollectionUtils.isEmpty(config)) {
|
||||
throw new UnsupportedOperationException("使用CropContentFilter必须指定裁剪配置");
|
||||
}
|
||||
return cropContent(content, config);
|
||||
}
|
||||
|
||||
private JSON cropContent(JSON content, JSONObject config) {
|
||||
// content是json数组
|
||||
if (content instanceof JSONArray) {
|
||||
return cropJSONArrayContent((JSONArray) content, config);
|
||||
}
|
||||
// content是json对象
|
||||
if (content instanceof JSONObject) {
|
||||
JSONObject contentJSONObject = (JSONObject) content;
|
||||
// 可能是分页content,此时支持裁剪分页列表中的json对象
|
||||
if (contentJSONObject.containsKey("data")) {
|
||||
contentJSONObject.put("data",
|
||||
cropJSONArrayContent(contentJSONObject.getJSONArray("data"), config));
|
||||
}
|
||||
return doCrop(contentJSONObject, config);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private JSONArray cropJSONArrayContent(JSONArray content, JSONObject config) {
|
||||
// 只考虑JSONArray中是JSONObject对象的情况
|
||||
List<JSONObject> contentList = content.stream()
|
||||
.filter(obj -> obj instanceof JSONObject)
|
||||
.map(obj -> JSONObject.parseObject(JSON.toJSONString(obj)))
|
||||
.collect(Collectors.toList());
|
||||
if (contentList.isEmpty()) {
|
||||
return content;
|
||||
}
|
||||
return JSON.parseArray(JSON.toJSONString(contentList.stream()
|
||||
.map(c -> doCrop(c, config))
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪data中的字段
|
||||
*
|
||||
* @param data
|
||||
* @param config {@link CropConfig}
|
||||
* @return
|
||||
*/
|
||||
private static JSONObject doCrop(JSONObject data, JSONObject config) {
|
||||
if (CollectionUtils.isEmpty(config) || CollectionUtils.isEmpty(data)) {
|
||||
return data;
|
||||
}
|
||||
CropConfig cropConfig = config.toJavaObject(CropConfig.class);
|
||||
// 优先用includeKeys
|
||||
if (!CollectionUtils.isEmpty(cropConfig.getIncludeKeys())) {
|
||||
return DataAssembleHelper.filterBean(data, cropConfig.getIncludeKeys(), true);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(cropConfig.getExcludeKeys())) {
|
||||
return DataAssembleHelper.filterBean(data, cropConfig.getExcludeKeys(), false);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪content时的配置
|
||||
*
|
||||
* @see CropContentFilter
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
private static class CropConfig {
|
||||
/**
|
||||
* 希望只包含这些key,只支持第一层key
|
||||
* 如果有值,将忽略excludeKeys
|
||||
*/
|
||||
private String includeKeys;
|
||||
/**
|
||||
* 希望排除的key,只支持第一层key
|
||||
*/
|
||||
private String excludeKeys;
|
||||
|
||||
public Set<String> getIncludeKeys() {
|
||||
if (Strings.isNullOrEmpty(includeKeys)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return ImmutableSet.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().splitToList(includeKeys));
|
||||
}
|
||||
|
||||
public Set<String> getExcludeKeys() {
|
||||
if (Strings.isNullOrEmpty(excludeKeys)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return ImmutableSet.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().splitToList(excludeKeys));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动请求输入参数中字段到指定字段下.
|
||||
*/
|
||||
public final static class MoveInputFieldFilter implements RequestFilter {
|
||||
@Override
|
||||
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject configJSON) {
|
||||
if (params == null) {
|
||||
return params;
|
||||
}
|
||||
|
||||
Config config = configJSON.toJavaObject(Config.class);
|
||||
if (!config.isValid()) {
|
||||
throw new IllegalArgumentException("不正确的配置参数");
|
||||
}
|
||||
|
||||
Set<String> sourceFields = config.getSourceFields();
|
||||
JSONObject sourceValue = DataAssembleHelper.filterBean(params, sourceFields);
|
||||
JSONObject res = DataAssembleHelper.filterBean(params, sourceFields, false);
|
||||
Preconditions.checkArgument(!res.containsKey(config.getTargetField()), "目标字段已经存在, 不能被覆盖");
|
||||
|
||||
res.put(config.getTargetField(), config.getTargetFieldType() == Config.FieldType.PROPERTY
|
||||
// 如果是把字段move到listField作为它的第一个元素
|
||||
? sourceValue : Lists.newArrayList(sourceValue));
|
||||
return res;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
static class Config {
|
||||
private String targetField;
|
||||
private String sourceFields;
|
||||
private FieldType targetFieldType;
|
||||
|
||||
public Set<String> getSourceFields() {
|
||||
return Splitter.on(",").omitEmptyStrings().trimResults()
|
||||
.splitToStream(Strings.nullToEmpty(sourceFields))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
boolean isValid() {
|
||||
return !getSourceFields().isEmpty() && !StringUtils.isBlank(targetField);
|
||||
}
|
||||
|
||||
public FieldType getTargetFieldType() {
|
||||
if (targetFieldType == null) {
|
||||
return FieldType.PROPERTY;
|
||||
}
|
||||
return targetFieldType;
|
||||
}
|
||||
|
||||
enum FieldType {
|
||||
PROPERTY,
|
||||
/**
|
||||
* 将Field看做一个列表, 将 moveields 放在toField下作为第一个元素.
|
||||
*/
|
||||
LIST;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
public abstract class ConvertContentFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (content == null) {
|
||||
return response;
|
||||
}
|
||||
Preconditions.checkArgument(content instanceof JSON, "ConvertContentFilter不支持原始response.content非json的情况");
|
||||
return jsonResp.fluentPut("data", filterContent(reqContext, (JSON) content, config));
|
||||
}
|
||||
|
||||
public abstract JSON filterContent(RequestContext reqContext, JSON content, JSONObject config);
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class ConvertListAsObjectFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
|
||||
JSONArray arrayContent = null;
|
||||
if (content instanceof JSONArray) {
|
||||
arrayContent = (JSONArray) content;
|
||||
} else if (content instanceof JSONObject) {
|
||||
JSONArray records = ((JSONObject) content).getJSONArray("data");
|
||||
arrayContent = records == null ? new JSONArray() : records;
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
JSONObject obj = IntStream.range(0, arrayContent.size())
|
||||
.mapToObj(arrayContent::getJSONObject)
|
||||
.findFirst()
|
||||
.orElseGet(JSONObject::new);
|
||||
return jsonResp.fluentPut("data", filterObject(reqContext, obj, config));
|
||||
}
|
||||
|
||||
public JSONObject filterObject(RequestContext reqContext, JSONObject obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
public JSONObject filterObject(RequestContext reqContext, JSONObject obj, JSONObject config) {
|
||||
return filterObject(reqContext, obj);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import cn.axzo.foundation.page.IPageReq;
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ConvertListAsPageFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (!(content instanceof JSONArray)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
List<JSONObject> records = ((JSONArray) content).toJavaList(JSONObject.class);
|
||||
PageResp<JSONObject> page = PageResp.<JSONObject>builder().total(records.size()).build();
|
||||
|
||||
IPageReq pageParam = JSONObject.parseObject(reqContext.getRequestBody(), IPageReq.class);
|
||||
Optional.ofNullable(pageParam).map(IPageReq::getPage).ifPresent(page::setCurrent);
|
||||
Optional.ofNullable(pageParam).map(IPageReq::getPageSize).ifPresent(page::setSize);
|
||||
|
||||
page.setData(records.stream()
|
||||
.skip((page.getCurrent() - 1) * page.getSize())
|
||||
.limit(page.getSize())
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return jsonResp.fluentPut("data", page);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ConvertPageAsListFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (!(content instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
JSONArray records = ((JSONObject) content).getJSONArray("data");
|
||||
return jsonResp.fluentPut("data", Optional.ofNullable(records).orElseGet(JSONArray::new));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import cn.axzo.foundation.util.DataAssembleHelper;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 裁剪返回的content内容
|
||||
* 仅支持:
|
||||
* 1.content是JSONObject
|
||||
* 2.content是JSONArray,且其中是JSONObject
|
||||
* 3.content是分页返回对象,即{"data":[{}]}
|
||||
*/
|
||||
public class CropContentFilter extends ConvertContentFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
throw new UnsupportedOperationException("使用CropContentFilter必须指定裁剪配置");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterContent(RequestContext reqContext, JSON content, JSONObject config) {
|
||||
// see class: CropConfig
|
||||
if (CollectionUtils.isEmpty(config)) {
|
||||
throw new UnsupportedOperationException("使用CropContentFilter必须指定裁剪配置");
|
||||
}
|
||||
return cropContent(content, config);
|
||||
}
|
||||
|
||||
private JSON cropContent(JSON content, JSONObject config) {
|
||||
// content是json数组
|
||||
if (content instanceof JSONArray) {
|
||||
return cropJSONArrayContent((JSONArray) content, config);
|
||||
}
|
||||
// content是json对象
|
||||
if (content instanceof JSONObject) {
|
||||
JSONObject contentJSONObject = (JSONObject) content;
|
||||
// 可能是分页content,此时支持裁剪分页列表中的json对象
|
||||
if (contentJSONObject.containsKey("data")) {
|
||||
contentJSONObject.put("data",
|
||||
cropJSONArrayContent(contentJSONObject.getJSONArray("data"), config));
|
||||
}
|
||||
return doCrop(contentJSONObject, config);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
private JSONArray cropJSONArrayContent(JSONArray content, JSONObject config) {
|
||||
// 只考虑JSONArray中是JSONObject对象的情况
|
||||
List<JSONObject> contentList = content.stream()
|
||||
.filter(obj -> obj instanceof JSONObject)
|
||||
.map(obj -> JSONObject.parseObject(JSON.toJSONString(obj)))
|
||||
.collect(Collectors.toList());
|
||||
if (contentList.isEmpty()) {
|
||||
return content;
|
||||
}
|
||||
return JSON.parseArray(JSON.toJSONString(contentList.stream()
|
||||
.map(c -> doCrop(c, config))
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪data中的字段
|
||||
*
|
||||
* @param data
|
||||
* @param config {@link CropConfig}
|
||||
* @return
|
||||
*/
|
||||
private static JSONObject doCrop(JSONObject data, JSONObject config) {
|
||||
if (CollectionUtils.isEmpty(config) || CollectionUtils.isEmpty(data)) {
|
||||
return data;
|
||||
}
|
||||
CropConfig cropConfig = config.toJavaObject(CropConfig.class);
|
||||
// 优先用includeKeys
|
||||
if (!CollectionUtils.isEmpty(cropConfig.getIncludeKeys())) {
|
||||
return DataAssembleHelper.filterBean(data, cropConfig.getIncludeKeys(), true);
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(cropConfig.getExcludeKeys())) {
|
||||
return DataAssembleHelper.filterBean(data, cropConfig.getExcludeKeys(), false);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪content时的配置
|
||||
*
|
||||
* @see CropContentFilter
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
private static class CropConfig {
|
||||
/**
|
||||
* 希望只包含这些key,只支持第一层key
|
||||
* 如果有值,将忽略excludeKeys
|
||||
*/
|
||||
private String includeKeys;
|
||||
/**
|
||||
* 希望排除的key,只支持第一层key
|
||||
*/
|
||||
private String excludeKeys;
|
||||
|
||||
public Set<String> getIncludeKeys() {
|
||||
if (Strings.isNullOrEmpty(includeKeys)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return ImmutableSet.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().splitToList(includeKeys));
|
||||
}
|
||||
|
||||
public Set<String> getExcludeKeys() {
|
||||
if (Strings.isNullOrEmpty(excludeKeys)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return ImmutableSet.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().splitToList(excludeKeys));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 后台页面中通过关键字段查询时, 需要移除其他字段的查询场景. 添加通用的请求过滤器来处理此类需求.
|
||||
* 使用时, 需要单独注入.
|
||||
*/
|
||||
public class KeyNoQueryFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject config) {
|
||||
if (params == null) {
|
||||
return params;
|
||||
}
|
||||
|
||||
Set<String> keyNoFields = Splitter.on(",").omitEmptyStrings().trimResults()
|
||||
.splitToStream(Strings.nullToEmpty(config.getString("keyNoFields")))
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> removeFields = Splitter.on(",").omitEmptyStrings().trimResults()
|
||||
.splitToStream(Strings.nullToEmpty(config.getString("removeFields")))
|
||||
.collect(Collectors.toSet());
|
||||
if (keyNoFields.isEmpty() || removeFields.isEmpty()) {
|
||||
return params;
|
||||
}
|
||||
|
||||
JSONObject paramsJson = (JSONObject) params;
|
||||
if (paramsJson.keySet().stream().noneMatch(keyNoFields::contains)) {
|
||||
return paramsJson;
|
||||
}
|
||||
|
||||
removeFields.forEach(paramsJson::remove);
|
||||
return paramsJson;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ListOrPageRecordsFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response) {
|
||||
return filterOut(reqContext, response, new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSON filterOut(RequestContext reqContext, JSON response, JSONObject config) {
|
||||
if (!(response instanceof JSONObject)) {
|
||||
return response;
|
||||
}
|
||||
JSONObject jsonResp = (JSONObject) response;
|
||||
Object content = jsonResp.get("data");
|
||||
if (!(content instanceof JSONObject) && !(content instanceof JSONArray)) {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (content instanceof JSONArray) {
|
||||
List<JSONObject> records = ((JSONArray) content).toJavaList(JSONObject.class);
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
return response;
|
||||
}
|
||||
JSONArray filtered = new JSONArray().fluentAddAll(filterRecords(reqContext, records, config));
|
||||
return jsonResp.fluentPut("data", filtered);
|
||||
}
|
||||
|
||||
JSONObject page = (JSONObject) content;
|
||||
JSONArray records = page.getJSONArray("data");
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
return response;
|
||||
}
|
||||
List<JSONObject> filtered = filterRecords(reqContext, records.toJavaList(JSONObject.class), config);
|
||||
page.put("data", new JSONArray().fluentAddAll(filtered));
|
||||
return response;
|
||||
}
|
||||
|
||||
public abstract List<JSONObject> filterRecords(RequestContext reqContext, List<JSONObject> records, JSONObject config);
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import cn.axzo.foundation.util.DataAssembleHelper;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 移动请求输入参数中字段到指定字段下.
|
||||
*/
|
||||
public class MoveInputFieldFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject configJSON) {
|
||||
if (params == null) {
|
||||
return params;
|
||||
}
|
||||
|
||||
Config config = configJSON.toJavaObject(Config.class);
|
||||
if (!config.isValid()) {
|
||||
throw new IllegalArgumentException("不正确的配置参数");
|
||||
}
|
||||
|
||||
Set<String> sourceFields = config.getSourceFields();
|
||||
JSONObject sourceValue = DataAssembleHelper.filterBean(params, sourceFields);
|
||||
JSONObject res = DataAssembleHelper.filterBean(params, sourceFields, false);
|
||||
Preconditions.checkArgument(!res.containsKey(config.getTargetField()), "目标字段已经存在, 不能被覆盖");
|
||||
|
||||
res.put(config.getTargetField(), config.getTargetFieldType() == Config.FieldType.PROPERTY
|
||||
// 如果是把字段move到listField作为它的第一个元素
|
||||
? sourceValue : Lists.newArrayList(sourceValue));
|
||||
return res;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
static class Config {
|
||||
private String targetField;
|
||||
private String sourceFields;
|
||||
private Config.FieldType targetFieldType;
|
||||
|
||||
public Set<String> getSourceFields() {
|
||||
return Splitter.on(",").omitEmptyStrings().trimResults()
|
||||
.splitToStream(Strings.nullToEmpty(sourceFields))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
boolean isValid() {
|
||||
return !getSourceFields().isEmpty() && !StringUtils.isBlank(targetField);
|
||||
}
|
||||
|
||||
public Config.FieldType getTargetFieldType() {
|
||||
if (targetFieldType == null) {
|
||||
return Config.FieldType.PROPERTY;
|
||||
}
|
||||
return targetFieldType;
|
||||
}
|
||||
|
||||
enum FieldType {
|
||||
PROPERTY,
|
||||
/**
|
||||
* 将Field看做一个列表, 将 moveields 放在toField下作为第一个元素.
|
||||
*/
|
||||
LIST;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package cn.axzo.foundation.gateway.support.plugin.impl.filters;
|
||||
|
||||
import cn.axzo.foundation.gateway.support.entity.RequestContext;
|
||||
import cn.axzo.foundation.gateway.support.plugin.impl.RequestFilterHook;
|
||||
import cn.axzo.foundation.result.ResultCode;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RequestParamCheckFilter implements RequestFilterHook.RequestFilter {
|
||||
@Override
|
||||
public JSON filterIn(RequestContext reqContext, JSON params, JSONObject config) {
|
||||
boolean isConfigRulePresent = config != null && !config.isEmpty() && config.containsKey("rules");
|
||||
Preconditions.checkArgument(isConfigRulePresent, "RequestParamCheckFilter必须指定检查规则");
|
||||
Preconditions.checkArgument(JSONObject.class.isAssignableFrom(params.getClass()),
|
||||
"RequestParamCheckFilter只能检查JSONObject类型参数");
|
||||
//spring list默认读取为 map(key=0...N). 将values转换为Rule
|
||||
List<Rule> rules = config.getJSONObject("rules").entrySet().stream()
|
||||
.map(e -> ((JSONObject) e.getValue()).toJavaObject(Rule.class))
|
||||
.collect(Collectors.toList());
|
||||
rules.stream().forEach(p ->
|
||||
Preconditions.checkArgument(!StringUtils.isAllBlank(p.getField(), p.getJsonPath()),
|
||||
"RequestParamCheckFilter规则错误field, jsonPath不能都为空"));
|
||||
Operator operator = Optional.ofNullable(config.getString("operator"))
|
||||
.map(e -> Operator.valueOf(e)).orElse(Operator.AND);
|
||||
|
||||
List<Optional<String>> errors = rules.stream()
|
||||
.map(rule -> rule.check((JSONObject) params))
|
||||
.collect(Collectors.toList());
|
||||
//如果operator=AND. & 任意一个检查错误 则告警
|
||||
if (operator == Operator.AND && errors.stream().anyMatch(Optional::isPresent)) {
|
||||
throw ResultCode.INVALID_PARAMS.toException(errors.stream().filter(Optional::isPresent).findFirst().get().get());
|
||||
}
|
||||
//如果operator=OR. & 所有检查都是错误 则告警
|
||||
if (operator == Operator.OR && errors.stream().allMatch(Optional::isPresent)) {
|
||||
throw ResultCode.INVALID_PARAMS.toException(errors.stream().filter(Optional::isPresent).findFirst().get().get());
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class Rule {
|
||||
String jsonPath;
|
||||
String field;
|
||||
boolean required;
|
||||
String regex;
|
||||
private transient Pattern pattern;
|
||||
|
||||
/** 检查值并返回错误信息, 正确则返回empty */
|
||||
protected Optional<String> check(JSONObject param) {
|
||||
Object value = getValue(param);
|
||||
if (required && value == null) {
|
||||
return Optional.of(field + "不能为空");
|
||||
}
|
||||
Optional<Pattern> pattern = tryGetPattern();
|
||||
if (pattern.isPresent() && value != null && !pattern.get().matcher(value.toString()).find()) {
|
||||
return Optional.of(field + "参数校验失败:" + regex);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/** 优先根据field获取value. 否则根据jsonPath */
|
||||
private Object getValue(JSONObject param) {
|
||||
if (!Strings.isNullOrEmpty(field)) {
|
||||
return param.get(field);
|
||||
}
|
||||
return JSONPath.eval(param, jsonPath);
|
||||
}
|
||||
|
||||
private Optional<Pattern> tryGetPattern() {
|
||||
if (Strings.isNullOrEmpty(regex)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (pattern == null) {
|
||||
pattern = Pattern.compile(regex);
|
||||
}
|
||||
return Optional.of(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Operator {
|
||||
AND,
|
||||
OR;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user