中的一个字符串,格式为用逗号分隔的字段名。

首先,我们需要定义一个注解@Fields,用于标注哪些方法需要进行字段过滤。注解中包含一个属性value,表示需要返回的字段名。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Fields {
    String value();
}

然后,我们定义一个切面类,用于拦截带有@Fields注解的方法,并根据请求参数中的fields参数进行字段过滤。

@Aspect
@Component
public class FieldsAspect {

    @Autowired
    private ObjectMapper objectMapper;

    @Around("@annotation(fields)")
    public Object filterFields(ProceedingJoinPoint joinPoint, Fields fields) throws Throwable {
        Object result = joinPoint.proceed();
        if (result == null) {
            return null;
        }
        String fieldsParam = ServletRequestUtils.getStringParameter(
                RequestContextHolder.getRequestAttributes().getRequest(), "fields", "");
        if (StringUtils.isEmpty(fieldsParam)) {
            return result;
        }
        Set<String> fieldsSet = new HashSet<>(Arrays.asList(fieldsParam.split(",")));
        if (fieldsSet.isEmpty()) {
            return result;
        }
        if (result instanceof Collection) {
            List<Map<String, Object>> resultList = new ArrayList<>();
            for (Object obj : (Collection) result) {
                Map<String, Object> resultMap = objectMapper.convertValue(obj, Map.class);
                filterFields(resultMap, fieldsSet);
                resultList.add(resultMap);
            }
            return resultList;
        } else {
            Map<String, Object> resultMap = objectMapper.convertValue(result, Map.class);
            filterFields(resultMap, fieldsSet);
            return resultMap;
        }
    }

    private void filterFields(Map<String, Object> map, Set<String> fieldsSet) {
        Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            if (entry.getValue() instanceof Map) {
                filterFields((Map<String, Object>) entry.getValue(), fieldsSet);
            } else if (entry.getValue() instanceof Collection) {
                List<Map<String, Object>> resultList = new ArrayList<>();
                for (Object obj : (Collection) entry.getValue()) {
                    Map<String, Object> resultMap = objectMapper.convertValue(obj, Map.class);
                    filterFields(resultMap, fieldsSet);
                    resultList.add(resultMap);
                }
                entry.setValue(resultList);
            } else if (!fieldsSet.contains(entry.getKey())) {
                iterator.remove();
            }
        }
    }
}

在切面类中,我们使用了Spring Boot自带的ObjectMapper类,将对象转换为Map,方便进行字段过滤。filterFields方法用于递归遍历Map中的所有字段,并根据fields参数进行过滤。

最后,我们在需要进行字段过滤的方法上添加@Fields注解即可。

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users")
    @Fields("id,username,profile(id,name)")
    public List<User> getUsers() {
        return userService.getUsers();
    }
}

在上面的例子中,我们希望返回用户的id、username和profile中的id和name字段。如果profile为null,则正常返回null值。如果请求参数中没有fields参数,则返回所有字段。如果fields参数为空,则也返回所有字段。

使用时,我们可以通过GET请求访问/users接口,并在请求参数中添加fields参数,如:/users?fields=id,username,profile(id,name)。

$ curl -X GET http://localhost:8080/users?fields=id,username,profile(id,name)
[ {
  "id" : 1,
  "username" : "user1",
  "profile" : {
    "id" : 1,
    "name" : "profile1"
  }
}, {
  "id" : 2,
  "username" : "user2",
  "profile" : {
    "id" : 2,
    "name" : "profile2"
  }
} ]
Spring Boot通过AOP的方式实现RESTful根据请求参数中的fields返回嵌套对象字段而且需要保证对象为null值时正常返回并写出使用案例 其中fields是请求参数

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

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