Biorąc pod uwagę usługę sieciową RESTful opracowaną przy użyciu frameworka Spring Boot, chciałem znaleźć sposób na pominięcie birthDate wszystkich użytkowników w odpowiedzi. Oto, co zaimplementowałem po rozejrzeniu się za rozwiązaniem:

@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;
    }
}

Jednak gdy w przeglądarce trafiam w punkt końcowy odpoczynku, nadal widzę w odpowiedzi datę urodzenia użytkownika:

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

Pytanie 1: jakiego interfejsu API mogę użyć, aby osiągnąć mój cel?

Następnie zakładając, że chcę przestrzegać HATEOAS w połączeniu z filtrowaniem, w jaki sposób mogę robiąc to. Nie mogę znaleźć interfejsów API, których można użyć do jednoczesnego korzystania z tych dwóch funkcji:

@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;
}

Pytanie 2: Jak połączyć EntityModel z MappingJacksonValue?

Uwaga: znam adnotację @JsonIgnore, która zastosuje filtr do wszystkich punktów końcowych korzystających z domeny; jednak chcę ograniczyć filtrowanie tylko do dwóch powyższych punktów końcowych.

1
Ping 31 marzec 2020, 20:19

4 odpowiedzi

Najlepsza odpowiedź

Okazuje się, że to zadziała, muszę dodać adnotację @JsonFilter nad DTO i podać tę samą nazwę, która została użyta podczas tworzenia 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
}
1
Ping 1 kwiecień 2020, 05:35

Możesz użyć funkcji @JsonView Jacksona. Dzięki temu możesz nakazać mapowaniu żądań, aby utworzyły serializowany kod JSON z wybranym zestawem właściwości.

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;
}

Kontroler jest jak

    @JsonView(View.UserDetails.class)
    @GetMapping("/users")
    public MappingJacksonValue users() {
    ....
    }
0
Eklavya - UpvoteDon'tSayThanks 31 marzec 2020, 17:46

W przypadku pytania 2 zadałem dokładnie to samo pytanie, co Ty, a oto, co zrobiłem. Wygląda na to że działa:

@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;
}

Odpowiedź dla HTTP GET localhost:8080/users/1

{
"id": 1,
"links": [
    {
        "rel": "all-users",
        "href": "http://localhost:8080/users"
    }
]}
0
Peiyi Yang 20 sierpień 2020, 19:29

Jest łatwiejszy sposób, aby to zrobić, na obiekcie transferu (klasie, którą odsyłasz do klienta), możesz po prostu użyć adnotacji @JsonIgnore, aby upewnić się, że pole nie jest serializowane, a zatem wysyłane do klienta. Po prostu dodaj @JsonIgnore w swojej klasie użytkownika w polu birthDay.

Możesz również przeczytać więcej o tym podejściu tutaj:

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

Jeśli chcesz zwrócić inny obiekt dla różnych punktów końcowych (w twoim przypadku użytkownika bez birthDay, tylko dla określonych), powinieneś utworzyć oddzielne obiekty transferu i użyć ich dla odpowiednich punktów końcowych. Możesz przekazać swoją oryginalną jednostkę (User) w konstruktorze do tych klas i skopiować wszystkie potrzebne pola.

0
Ali Nasserzadeh 31 marzec 2020, 17:37