2015-08-10 2 views
4

Я использую разбиение на весы данных в моем контроллере REST и возвращаю Paged entity. Я хотел бы управлять данными, возвращаемыми как JSON с помощью JSONView.Spring Data Pagination не возвращает никаких результатов с помощью JSONView

Я могу добиться результата, когда возвращаю один объект. Но когда я возвращаю страницу, я получаю пустой JSON в качестве ответа.

Ниже приведена моя подпись метода.

@JsonView(TravelRequestView.MyRequests.class) 
@RequestMapping("/travel/requests") 
public Page<TravelRequest> getUserTravelRequests(
      @RequestParam("ps") int pageSize, @RequestParam("p") int page, 
      @RequestParam(defaultValue = "", value = "q") String searchString) 

Я могу получить ответ, когда удаляю аннотацию @JsonView.

ответ

4

Попробовать ниже фрагмент кода,

@Configuration 
public class MyInterceptorConfig extends WebMvcConfigurerAdapter{ 

    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
     MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
     ObjectMapper mapper = new ObjectMapper() { 
     private static final long serialVersionUID = 1L; 
     @Override 
     protected DefaultSerializerProvider _serializerProvider(SerializationConfig config) { 
      // replace the configuration with my modified configuration. 
      // calling "withView" should keep previous config and just add my changes. 
      return super._serializerProvider(config.withView(TravelRequestView.MyRequests.class)); 
     }   
     }; 
     mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, true); 
     converter.setObjectMapper(mapper); 
     converters.add(converter); 
    } 

Хотя я не хочу брать кредит на это, Это была справка из

Jackson JsonView not being applied

Было бы извлечь все переменный объект, которые аннотированные с jsonview (TravelRequestView.MyRequests.class) вместе со всеми переменными, которые не аннотированными с jsonview. Если вам не нужны определенные свойства объекта, аннотированные с другим видом.

1

вам необходимо добавить аннотацию @JsonView (TravelRequestView.MyRequests.class) рекурсивно. Добавьте его в поле, которое вы хотите увидеть в классе страницы.

public class Page<T> { 
    @JsonView(TravelRequestView.MyRequests.class) 
    private T view; 
... 
} 

или включить DEFAULT_VIEW_INCLUSION для ObjectMapper:

<mvc:annotation-driven> 
    <mvc:message-converters> 
     <bean class="org.springframework.http.converter.StringHttpMessageConverter" /> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
      <property name="objectMapper"> 
       <bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> 
        <property name="defaultViewInclusion" value="true"/> 
       </bean> 
      </property> 
     </bean> 
    </mvc:message-converters> 
</mvc:annotation-driven> 

или использовать DTO объекты для ваших ответов, где вы можете контролировать все ваши взгляды

+0

страница здесь является частью библиотеки пружинных данных. Я не могу его изменить. – Pavan

+0

вы можете включить DEFAULT_VIEW_INCLUSION для вашего ObjectMapper –

+0

Можете ли вы вкратце объяснить, как? Спасибо .. – Pavan

1

Я действительно нашел более простой и лучший способ сделать это. Проблема, с которой я столкнулся, заключалась в том, что я не могу установить аннотации @JsonView на объект страницы, который я получал. Поэтому я создал реализацию интерфейса страницы и добавил к нему JsonView. И вместо того, чтобы вернуться страницу, я теперь возвращаюсь MYPAGE

public class MyPage<T> implements Page<T> { 

    private Page<T> pageObj; 

    public MyPage(Page<T> pageObj) { 
     this.pageObj = pageObj; 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public int getNumber() { 
     return pageObj.getNumber(); 
    } 

    @Override 
    public int getSize() { 
     return pageObj.getSize(); 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public int getNumberOfElements() { 
     return pageObj.getNumberOfElements(); 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public List<T> getContent() { 
     return pageObj.getContent(); 
    } 

    @Override 
    public boolean hasContent() { 
     return pageObj.hasContent(); 
    } 

    @Override 
    public Sort getSort() { 
     return pageObj.getSort(); 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public boolean isFirst() { 
     return pageObj.isFirst(); 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public boolean isLast() { 
     return pageObj.isLast(); 
    } 

    @Override 
    public boolean hasNext() { 
     return pageObj.hasNext(); 
    } 

    @Override 
    public boolean hasPrevious() { 
     return pageObj.hasPrevious(); 
    } 

    @Override 
    public Pageable nextPageable() { 
     return pageObj.nextPageable(); 
    } 

    @Override 
    public Pageable previousPageable() { 
     return pageObj.previousPageable(); 
    } 

    @Override 
    public Iterator<T> iterator() { 
     return pageObj.iterator(); 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public int getTotalPages() { 
     return pageObj.getTotalPages(); 
    } 

    @JsonView(PaginatedResult.class) 
    @Override 
    public long getTotalElements() { 
     return pageObj.getTotalElements(); 
    } 

} 
+1

Что такое PaginatedResult? Класс, который будет отображаться? – LTroya

0

Еще уборщик сказать Джексон сериализовать все подпорки для фасоли типа страницы. Чтобы сделать это, вам просто нужно объявить, что нужно адаптироваться к Blans Jacker BeanSerializer: com.fasterxml.jackson.databind.ser.BeanSerializer Создайте класс, который расширяет этот BeanSerializer, называемый PageSerialier, и если bean-тип имеет тип Page <> НЕ ПРИМЕНЯЕТСЯ фильтрация свойств.

Как показано в приведенном ниже коде, я просто удалил фильтрации для экземпляров Page:

public class MyPageSerializer extends BeanSerializer { 

/** 
* MODIFIED By Gauthier PEEL 
*/ 
@Override 
protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider) 
     throws IOException, JsonGenerationException { 
    final BeanPropertyWriter[] props; 
    // ADDED 
    // ADDED 
    // ADDED 
    if (bean instanceof Page) { 
     // for Page DO NOT filter anything so that @JsonView is passthrough at this level 
     props = _props; 
    } else { 
     // ADDED 
     // ADDED 
     if (_filteredProps != null && provider.getActiveView() != null) { 
      props = _filteredProps; 
     } else { 
      props = _props; 
     } 
    } 

     // rest of the method unchanged 
    } 

    // inherited constructor removed for concision 
} 

Затем вам нужно объявить Джексона с модулем:

public class MyPageModule extends SimpleModule { 

    @Override 
    public void setupModule(SetupContext context) { 

     context.addBeanSerializerModifier(new BeanSerializerModifier() { 

      @Override 
      public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, 
        JsonSerializer<?> serializer) { 
       if (serializer instanceof BeanSerializerBase) { 
        return new MyPageSerializer ((BeanSerializerBase) serializer); 
       } 
       return serializer; 

      } 
     }); 
    } 
} 

Spring конф сейчас: в вашем @Configuration создать новый @Bean в MyPageModule

@Configuration 
public class WebConfigPage extends WebMvcConfigurerAdapter { 

    /** 
    * To enable Jackson @JsonView to work with Page<T> 
    */ 
    @Bean 
    public MyPageModule myPageModule() { 
     return new MyPageModule(); 
    } 

} 

И вы сделали.

+0

Что такое TworkSpringDataPageSerializer? –

+1

@Martin я исправил тип TworkSpringDataPageSerializer должен быть MyPageSerializer в этом примере. –

6

Установка DEFAULT_VIEW_INCLUSION имеет глобальный эффект, в то время как нам нужно всего лишь сериализовать объект Page. Следующий код будет регистрировать сериалайзер для страницы, и это простое изменение кода:

@Bean 
public Module springDataPageModule() { 
    return new SimpleModule().addSerializer(Page.class, new JsonSerializer<Page>() { 
     @Override 
     public void serialize(Page value, JsonGenerator gen, SerializerProvider serializers) throws IOException { 
      gen.writeStartObject(); 
      gen.writeNumberField("totalElements",value.getTotalElements()); 
      gen.writeNumberField("totalPages", value.getTotalPages()); 
      gen.writeNumberField("number", value.getNumber()); 
      gen.writeNumberField("size", value.getSize()); 
      gen.writeBooleanField("first", value.isFirst()); 
      gen.writeBooleanField("last", value.isLast()); 
      gen.writeFieldName("content"); 
      serializers.defaultSerializeValue(value.getContent(),gen); 
      gen.writeEndObject(); 
     } 
    }); 
} 

Другой (возможно, более элегантное) решение зарегистрировать следующие ResponseBodyAdvice. Он гарантирует, что конечная точка REST все равно вернет массив JSON и установит HTTP-заголовок «X-Has-Next-Page», чтобы указать, есть ли больше данных. Преимущества: 1) Нет дополнительный счет (*) запроса к вашей БД (один запрос) 2) Response более элегантна, поскольку он возвращает массив JSON

/** 
* ResponseBodyAdvice to support Spring data Slice object in JSON responses. 
* If the value is a slice, we'll write the List as an array, and add a header to the HTTP response 
* 
* @author blagerweij 
*/ 
@ControllerAdvice 
public class SliceResponseBodyAdvice implements ResponseBodyAdvice<Object> { 

    @Override 
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { 
     return true; 
    } 

    @Override 
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { 
     if (body instanceof Slice) { 
      Slice slice = (Slice) body; 
      response.getHeaders().add("X-Has-Next-Page", String.valueOf(slice.hasNext())); 
      return slice.getContent(); 
     } 
     return body; 
    } 
} 
+0

Большое вам спасибо, это единственное решение, которое работает для меня. Я использую весенний ботинок с весенними данными jpa :) –

+0

Ваш ответ работает как шарм. Но он удаляет некоторые атрибуты из класса страницы, такие как totalPages, last, first, sort, size, number и numberOfElements. Есть ли способ добавить эти поля? – LTroya

+0

Конечно, вы можете просто включить их в код сериализации, я обновлю код в предоставленном ответе – blagerweij

4

Если вы используете пружинные загрузки, затем еще более простое решение будет добавить следующее application.yml

spring: 
    jackson: 
    mapper: 
     DEFAULT_VIEW_INCLUSION: true 

или application.properties

spring.jackson.mapper.DEFAULT_VIEW_INCLUSION=true 

При таком подходе мы имеем т он имеет преимущество сохранения ObjectMapper, управляемого Spring Container, а не создания нового ObjectMapper. Поэтому, как только мы используем пружинные удались ObjectMapper, то любое пользовательское Serialzers мы определяем все равно будет продолжать работать CustomDateSerialzer например

Код: http://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html

+0

, это помогло мне. – kgs

Смежные вопросы