GET接口中fields参数的实现

GET接口中fields参数的实现

黄鹏宇 525 2022-08-12

一、场景

存在如下对象

class User{
    int ID;
    String name;
    Integer age;
    Double money;
}

对于 /userInfo这样的get接口,有时候我们并不需要返回所有的用户属性,所以添加fields参数,类型为String数组。
满足如下几点规则

二、规则

  1. fields为空,或不传,则返回所有属性
  2. fields=[name,age]等与属性一一对应的参数时,返回对应的属性
  3. 响应群,定义profile = {name,age} ,则当fields = [profile]时,返回nameage属性
  4. 去重,即便fields=[profile,name,name],也只返回nameage属性
  5. 异常:fields获取了不存在的属性,比如weight,则返回错误

三、核心流程

  1. 动态返回VO的字段
    使用jackson的ObjectMapper、@JsonFilter,这里有坑:就算不过滤,也需要定义一下JsonFilter:SimpleBeanPropertyFilter.serializeAll()
  2. 响应群的展开与去重
    抽象成了Class FieldsFilter,后续只需要继承该类,并定义_querySettingAllowFieldSet,_rawFieldsGroupRoutes
  3. 大小写insensitive
    rawFieldsGroupRoutes.keySet().stream().anyMatch(field::equalsIgnoreCase)

四、流程

定义:
FP = 用户传来的fileds数组。判断为空,即为null或length == 0
FS = 所有符合条件的field参数的集合

未命名文件 (2)

五、核心代码

一、对fields参数进行预处理(1.2.3)

1. FieldsFilter
public class FieldsFilter {
    Map<String, Set<String>> rawFieldsGroupRoutes;
    HashSet<String> allRawFields;

    public FieldsFilter(Map<String, Set<String>> rawFieldsGroupRoutes, HashSet querySettingAllowFieldSet) {
        this.rawFieldsGroupRoutes = rawFieldsGroupRoutes;
        this.allRawFields = querySettingAllowFieldSet;
    }

    public boolean isValid(String[] rawFields) {
        return allRawFields.containsAll(Arrays.asList(rawFields));
    }

    /**
     * 将参数的响应群展开,并且过滤掉重复项
     *
     * @param rawFields
     * @return
     */
    public FieldFilterResult doFilter(String[] rawFields) {
        FieldFilterResult fieldFilterResult = new FieldFilterResult();

        HashSet<String> allTargetFields = new HashSet<>();
        HashSet<String> targetIncludeFieldGroup = new HashSet<>();
        for (String field : rawFields) {
            // 忽略大小写
            if (rawFieldsGroupRoutes.keySet().stream().anyMatch(field::equalsIgnoreCase)) {
                allTargetFields.addAll(rawFieldsGroupRoutes.get(field));
                targetIncludeFieldGroup.add(field);
            } else {
                // 这里也要找到他的group
                for (Map.Entry<String, Set<String>> entry : rawFieldsGroupRoutes.entrySet()) {
                    if (entry.getValue().stream().anyMatch(field::equalsIgnoreCase)) {
                        targetIncludeFieldGroup.add(entry.getKey());
                    }
                }
                allTargetFields.add(field);
            }
        }

        fieldFilterResult.setAllTargetFields(allTargetFields);
        fieldFilterResult.setTargetIncludeFieldGroup(targetIncludeFieldGroup);
        return fieldFilterResult;
    }
}
2. SettingFieldsFilter
public class SettingFieldsFilter extends FieldsFilter {

    final static private HashSet _querySettingAllowFieldSet = new HashSet(Arrays.asList("notif", "preference", "learning", "profile", "triggerCondition", "triggerTime", "outfit", "showCountDown", "showFinishedCard", "openAutoPronunciation", "pronType", "dailyTargetNum", "currentWordBookCode", "avatarUrl", "nickName"));
    final static private Map<String, Set<String>> _rawFieldsGroupRoutes = Map.of("notif", Set.of("triggerCondition", "triggerTime"), "preference", Set.of("outfit", "showCountDown", "showFinishedCard", "openAutoPronunciation", "pronType"), "learning", Set.of("dailyTargetNum", "currentWordBookCode"), "profile", Set.of("nickName", "avatarUrl"));

    private final static SettingFieldsFilter Instance = new SettingFieldsFilter(_rawFieldsGroupRoutes, _querySettingAllowFieldSet);

    public static SettingFieldsFilter getInstance() {
        return Instance;
    }

    private SettingFieldsFilter(Map<String, Set<String>> _rawFieldsGroupRoutes, HashSet _querySettingAllowFieldSet) {
        super(_rawFieldsGroupRoutes, _querySettingAllowFieldSet);
    }
}
3. FieldFilterResult
@Data
public class FieldFilterResult {
    HashSet<String> allTargetFields;
    HashSet<String> TargetIncludeFieldGroup;
}

二、 去掉无用的VO属性

4. JsonUtil
@Slf4j
public class JsonUtil {
    @SneakyThrows
    public static JSONObject defaultFilter(String filterName, Object sourceObject) {
        SimpleFilterProvider filterProvider = new SimpleFilterProvider();
        filterProvider.addFilter(filterName, SimpleBeanPropertyFilter.serializeAll());

        String s = new ObjectMapper().setFilterProvider(filterProvider).writeValueAsString(sourceObject);
        // 转成jsonObject,方便封装统一返回格式
        JSONObject jsonObject = JSONObject.parseObject(s);
        return jsonObject;

    }

    /**java
     * 动态只留下bean的某些属性
     *
     * @param filterName          Bean的注解@JsonFilter("filterName")
     * @param sourceObject        Bean的实例
     * @param exceptPropertyArray 需要保留的属性
     * @return
     * @throws JsonProcessingException
     */
    @SneakyThrows
    public static JSONObject jsonFilter(String filterName, Object sourceObject, String... exceptPropertyArray) {
        SimpleFilterProvider filterProvider = new SimpleFilterProvider();
        filterProvider.addFilter(filterName,
                SimpleBeanPropertyFilter.filterOutAllExcept(exceptPropertyArray));

        String s = new ObjectMapper().setFilterProvider(filterProvider).writeValueAsString(sourceObject);

        JSONObject jsonObject = JSONObject.parseObject(s);
        return jsonObject;
    }

    public static JSONObject jsonFilter(String filterName, Object sourceObject, Set<String> exceptPropertySet) {
        return JsonUtil.jsonFilter(filterName, sourceObject, exceptPropertySet.toArray(new String[exceptPropertySet.size()]));
    }
}

六、附录

PUT修改setting

一、流程