Изменить ответ API REST, чтобы включить только поля, запрошенные в параметре запроса - PullRequest
3 голосов
/ 10 ноября 2019

Я хочу отправить ответ, содержащий только запрошенные поля для GET api. Уменьшение общего размера ответа.

Пример, поведение по умолчанию, когда к конкретным запрашиваемым полям

GET /v1/users/

{
   "data" : 
     [
        {
            "name" : "User1",
            "phone" : "800-999-9999",
            "city" : "XYZ1",
            "country" : "PQR1"
        },
        {
            "name" : "User2",
            "phone" : "800-999-9999",
            "city" : "XYZ2",
            "country" : "PQR2"
         }
     ]
}

Вариант использования, когда необходимые поля передаются в качестве параметров запроса

GET /v1/users/?fields=name,city

{
   "data" : 
     [
        {
            "name" : "User1",
            "city" : "XYZ1"
        },
        {
            "name" : "User2",
            "city" : "XYZ2"
         }
     ]
}

Наткнулся "https://github.com/monitorjbl/json-view". Но был сбит командой.

Как реализовать эту функцию с помощью весенней загрузки? Как организации, использующие микросервисы Java, реализуют эту функцию? Спасибо!

Ответы [ 2 ]

1 голос
/ 10 ноября 2019

Вот еще один подход:

Предположение 1: я считаю, что лучше определить тип возвращаемого контроллера как объект домена, и пусть Spring будет самостоятельно заниматься преобразованием его в JSON (в отличие от ответа @Alexander Pavlov)). IMO лучше для общей читабельности кода и для таких инструментов, как swagger, который анализирует контроллер и должен знать, что должно быть возвращено.

Предположение 2. У вас нет примитивов в вашем классе User.

Хорошо, теперь контроллер, очевидно, вызывает некоторую «службу», которая делает некоторые запросы к БД, или вообще выполняет некоторую логику, которая в конечном итоге создает список пользователей (список, который вы возвращаете клиенту). Возвращаемый объект должен выглядеть примерно так:

class Users {

     private List<User> data;
}

class User { // + constructors, getters, setters, etc.
   private String name;
   private String city;
   private String phone;
   private String country;    
}

В этом случае в сервисе вы можете поместить «null» в поле, которое вы не хотите возвращать:

User user = new User("John", "LA", null, null); // you only have name and city

Сейчасвы можете поместить аннотацию @JsonInclude(Include.NON_NULL) в классе User, и это будет указывать Джексону вообще не включать поля, имеющие значение 'null', в сериализованный ответ.

Если вы хотите, чтобы это поведение применялось глобально,Вы можете настроить ObjectMapper bean:

 ObjectMapper mapper = new ObjectMapper();
 mapper.setSerializationInclusion(Include.NON_NULL);
1 голос
/ 10 ноября 2019

Метод 1: Преобразовать объекты в карту, удалить лишние ключи, преобразовать карту в Json

@GetMapping("/v1/users")
@ResponseBody
public List<Map> getUsers(@RequestParam(required = false) Set<String> fields) { 
    List<User> users = ...;
    ObjectMapper oMapper = new ObjectMapper();
    return users.stream().map(u -> oMapper.convertValue(u, Map.class))
       .peek(map -> { 
          if (fields != null) map.keySet().retainAll(fields)
       })
       .collect(Collectors.toList());
}

Метод 2: Использовать Gson

@GetMapping("/v1/users")
@ResponseBody
public String getUsers(@RequestParam(required = false) Set<String> fields) { 
    List<User> users = ...;
    Gson gson = new GsonBuilder()
            .setExclusionStrategies(new ExclusionStrategy() {
                @Override
                public boolean shouldSkipField(FieldAttributes f) {
                    return f.getDeclaringClass().equals(User.class)
                             && fields != null 
                             && !fields.contains(f.getFieldName())
                            ;
                }

                @Override
                public boolean shouldSkipClass(Class<?> clazz) {
                    return false;
                }
            }).create();
    return gson.toJson(users); 
}

Столкнулся с "https://github.com/monitorjbl/json-view". Но был сбит командой.

Кстати, Джексон имеет @JsonView поддержку аннотаций, но он не позволяет включать /динамически исключать поля, как вы хотите. Вы можете определить подмножество полей, а затем вернуть эти подмножества

public class Views {
    public static class Short {
    }
}

public class User {
    @JsonView(Views.Short.class)
    public String city;

    @JsonView(Views.Short.class)
    public String name;

    public String phone;

    public String country;
}

@GetMapping("/v1/users")
@ResponseBody
public String getUsers(@RequestParam(required = false) boolean shortView) { 
    List<User> users = ...;
    ObjectMapper mapper = new ObjectMapper();
    if (shortView) mapper = mapper.writerWithView(Views.Short.class);
    return mapper.writeValueAsString(users);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...