Spring Boot可以通过使用Jackson库的注解来实现RESTful动态过滤嵌套对象字段。

  1. 创建一个注解类,用于标记需要动态过滤的字段。
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonFilter("nestedFilter")
public @interface NestedFieldFilter {
}
  1. 在需要动态过滤的字段上添加注解。
public class User {
    private Long id;
    
    @NestedFieldFilter
    private Address address;
    
    // getter and setter
}

public class Address {
    private String city;
    private String street;
    
    // getter and setter
}
  1. 在Controller中使用ObjectMapper来序列化对象。
@GetMapping("/users")
public MappingJacksonValue getUsers(@RequestParam(required = false) String fields) {
    List<User> users = userService.getUsers();
    
    MappingJacksonValue mapping = new MappingJacksonValue(users);
    
    SimpleFilterProvider filterProvider = new SimpleFilterProvider()
            .addFilter("nestedFilter", new NestedFieldFilterSerializer());
    
    if (fields != null) {
        filterProvider.addFilter("userFilter", new DynamicFieldFilterSerializer(fields));
    }
    
    mapping.setFilters(filterProvider);
    
    return mapping;
}
  1. 创建一个NestedFieldFilterSerializer类,用于序列化被@NestedFieldFilter注解标记的字段。
public class NestedFieldFilterSerializer extends JsonSerializer<Object> {
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        
        SimpleFilterProvider filterProvider = new SimpleFilterProvider()
                .addFilter("userFilter", new DynamicFieldFilterSerializer());
        
        if (value instanceof List) {
            List<Object> list = (List<Object>) value;
            List<Object> filteredList = new ArrayList<>();
            for (Object obj : list) {
                filteredList.add(filterObject(obj, filterProvider));
            }
            gen.writeObject(filteredList);
        } else {
            gen.writeObject(filterObject(value, filterProvider));
        }
    }
    
    private Object filterObject(Object obj, SimpleFilterProvider filterProvider) {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setFilterProvider(filterProvider);
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
  1. 创建一个DynamicFieldFilterSerializer类,用于序列化动态过滤的字段。
public class DynamicFieldFilterSerializer extends JsonSerializer<Object> {
    private String fields;
    
    public DynamicFieldFilterSerializer() {
    }
    
    public DynamicFieldFilterSerializer(String fields) {
        this.fields = fields;
    }
    
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        
        if (fields != null) {
            String[] fieldArray = fields.split(",");
            Set<String> fieldSet = new HashSet<>(Arrays.asList(fieldArray));
            filterFields(value, fieldSet);
        }
        
        mapper.writeValue(gen, value);
    }
    
    private void filterFields(Object obj, Set<String> fieldSet) {
        if (obj instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) obj;
            for (Object key : map.keySet()) {
                if (!fieldSet.contains(key.toString())) {
                    map.remove(key);
                } else {
                    filterFields(map.get(key), fieldSet);
                }
            }
        } else if (obj instanceof List) {
            List<?> list = (List<?>) obj;
            for (Object item : list) {
                filterFields(item, fieldSet);
            }
        } else {
            Class<?> clazz = obj.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (!fieldSet.contains(field.getName())) {
                    field.setAccessible(true);
                    try {
                        field.set(obj, null);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    field.setAccessible(true);
                    try {
                        Object fieldValue = field.get(obj);
                        if (fieldValue != null) {
                            filterFields(fieldValue, fieldSet);
                        }
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}

现在,当请求/users接口时,可以通过fields参数动态过滤嵌套对象的字段。例如,请求/users?fields=id,address.city将只返回id和address.city字段的值。


原文地址: https://www.cveoy.top/t/topic/bgaY 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录