来自 RESTful 网络服务的响应中字段的动态过滤指出 returns 域对象列表

Dynamic filtering of a field in the response from a RESTful webservice enpoint that returns a List of domain objects

鉴于使用 Spring 启动框架开发的 RESTful Web 服务,我想要一种方法来抑制响应中所有用户的 birthDate。这是我在四处寻找解决方案后实施的:

@RestController
public class UserResource {

    @Autowired
    private UserDAOservice userDAOService;

    @GetMapping("/users")
    public MappingJacksonValue users() {
        List<User> users = userDAOService.findAll();

        SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter
                .filterOutAllExcept("id", "name");

        FilterProvider filters = new SimpleFilterProvider().addFilter(
                "UserBirthDateFilter", filter);

        MappingJacksonValue mapping = new MappingJacksonValue(users);

        mapping.setFilters(filters);

        return mapping;
    }
}

但是,当我在浏览器中点击 rest 端点时,我仍然可以在响应中看到用户的出生日期:

{
    "id": 1,
    "name": "Adam",
    "birthDate": "1980-03-31T16:56:28.926+0000"
}

问题 1:我可以使用什么 API 来实现我的 objective?

接下来,假设我想结合过滤来遵守 HATEOAS,我该怎么做呢?我无法弄清楚可用于同时使用这两个功能的 APIs :

@GetMapping("/users/{id}")
public EntityModel<User> users(@PathVariable Integer id) {
    User user = userDAOService.findById(id);
    if (user == null) {
        throw new ResourceNotFoundException("id-" + id);
    }

    EntityModel<User> model = new EntityModel<>(user);
    WebMvcLinkBuilder linkTo = linkTo(methodOn(this.getClass()).users());
    model.add(linkTo.withRel("all-users"));

    //how do I combine EntityModel with filtering?
    return model;
}

问题 2 : 如何将 EntityModelMappingJacksonValue 合并?

注: 我知道 @JsonIgnore 注释,但它会对使用该域的所有端点应用过滤器;但是,我只想将过滤限制在上面的两个端点。

有一种更简单的方法可以做到这一点,在您的传输对象(您发送回客户端的 class)上,您可以简单地使用 @JsonIgnore 注释来确保该字段未被序列化,因此发送给客户端。因此,只需在您的用户 class 中为您的生日字段添加 @JsonIgnore。

您还可以在此处阅读有关此方法的更多信息:

https://www.baeldung.com/jackson-ignore-properties-on-serialization

如果您需要 return 不同的对象用于不同的端点(在您的情况下没有 birthDay 的用户,仅针对特定的),您应该创建单独的传输对象并将它们用于各自的端点。您可以将构造函数中的原始实体(用户)传递给那些 classes 并复制所有需要的字段。

您可以使用 Jackson 的@JsonView 功能。有了这个,您可以告诉某个请求映射生成具有选定属性集的序列化 JSON。

public class View {
    interface UserDetails {}
}

public class User {

    @JsonView(View.UserDetails.class)
    private Long id;

    @JsonView(View.UserDetails.class)
    private String name;

    private String birthdate;
}

控制器就像

    @JsonView(View.UserDetails.class)
    @GetMapping("/users")
    public MappingJacksonValue users() {
    ....
    }

原来为了这个工作,我必须在 DTO 上方添加 @JsonFilter 注释并提供在创建 SimpleFilterProvider.

时使用的相同名称
@JsonFilter("UserBirthDateFilter")
public class User {

    private Integer id;


    @Size(min=2, message="user name must be atleast 2 characters")
    @ApiModelProperty(notes="user name must be atleast 2 characters")
    private String name;

    @Past
    @ApiModelProperty(notes="birth date cannot be in the past")
    private Date birthDate;

   //other methods
}

对于问题 2,我遇到了与您完全相同的问题,这就是我所做的。它似乎在工作:

@GetMapping(path = "/users/{id}")
public MappingJacksonValue retrieveUser(@PathVariable int id){
    User user = service.findOne(id);
    if(user==null){
        throw new UserNotFoundException("id-"+id);
    }
    //"all-users", SERVER_PATH + "/users"
    EntityModel<User> resource = EntityModel.of(user);
    WebMvcLinkBuilder linkTo =
            linkTo(methodOn(this.getClass()).retrieveAllUsers());
    resource.add(linkTo.withRel("all-users"));

    SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("id");
    FilterProvider filters = new SimpleFilterProvider().addFilter("UserFilter",filter);
    MappingJacksonValue mapping = new MappingJacksonValue(resource);
    mapping.setFilters(filters);
    return mapping;
}

响应 HTTP GET localhost:8080/users/1

{
"id": 1,
"links": [
    {
        "rel": "all-users",
        "href": "http://localhost:8080/users"
    }
]}