2016-10-24 4 views
1

Я пытаюсь использовать Spring Data REST репозитории, аннотированные аннотацией @RepositoryRestResource вместе с реализацией пользовательских методов. Есть 2 случая:Spring Data REST: проверка методов на основе методов

1) У меня есть репозиторий REST, аннотированный @RepositoryRestResource, который сопоставляется с конечной точкой /users. Кроме того, у меня есть @RestController, который отображается на ту же конечную точку. Это приводит к тому, что методы (которые должны быть открыты) в @RepositoryRestResource не должны быть видимыми и получать результат 405 на них. Однако валидация метода с помощью @Valid аннотации работает над методами @RestController. например это работает:

@ResponseBody 
@RequestMapping(value = "/users") 
public ResponseEntity signUp(@RequestBody @Valid final UserSignUpRequest userSignUpRequest) 

2) Контроллеры, которые работают вместе с REST хранилищами являются @RepositoryRestController контроллерами. Таким образом работают оба метода, объявленные в @RepositoryRestController и @RepositoryRestResource. Однако JSR-303 @Valid аннотация по методам перестала работать, поэтому я не могу использовать @Valid аннотация. Эта проблема уже описана DATAREST-593.

Любые идеи о том, как можно решить хотя бы одну из двух проблем? Основная идея заключается в использовании репозиториев @RepositoryRestResource вместе с пользовательскими методами контроллера и проверкой аннотации.

ответ

1

Похоже, что в этом случае нет хорошего решения, и аннотация @Valid никак не поддерживается по умолчанию, см. DATAREST-593. Вот почему, чтобы поддержать @Valid аннотацию @RepositoryRestController методов, я создал следующий @ControllerAdvice класс:

package com.tivoli.api.application.advice; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.core.MethodParameter; 
import org.springframework.http.HttpInputMessage; 
import org.springframework.http.converter.HttpMessageConverter; 
import org.springframework.validation.BeanPropertyBindingResult; 
import org.springframework.validation.BindingResult; 
import org.springframework.validation.ObjectError; 
import org.springframework.validation.Validator; 
import org.springframework.web.bind.annotation.ControllerAdvice; 
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter; 

import javax.validation.Valid; 
import javax.validation.ValidationException; 
import java.lang.annotation.Annotation; 
import java.lang.reflect.Type; 

/** 
* Workaround class for making JSR-303 annotation validation work for controller method parameters. 
* Check the issue <a href="https://jira.spring.io/browse/DATAREST-593">DATAREST-593</a> 
*/ 
@ControllerAdvice 
public class RequestBodyValidationProcessor extends RequestBodyAdviceAdapter { 

    private final Validator validator; 

    public RequestBodyValidationProcessor(@Autowired final Validator validator) { 
     this.validator = validator; 
    } 

    @Override 
    public boolean supports(final MethodParameter methodParameter, final Type targetType, final Class<? extends 
      HttpMessageConverter<?>> converterType) { 
     final Annotation[] parameterAnnotations = methodParameter.getParameterAnnotations(); 
     for (final Annotation annotation : parameterAnnotations) { 
      if (annotation.annotationType().equals(Valid.class)) { 
       return true; 
      } 
     } 

     return false; 
    } 

    @Override 
    public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage, final MethodParameter 
      parameter, final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType) { 
     final Object obj = super.afterBodyRead(body, inputMessage, parameter, targetType, converterType); 
     final BindingResult bindingResult = new BeanPropertyBindingResult(obj, obj.getClass().getCanonicalName()); 
     validator.validate(obj, bindingResult); 
     if (bindingResult.hasErrors()) { 
      throw new ValidationException(createErrorMessage(bindingResult)); 
     } 

     return obj; 
    } 

    private String createErrorMessage(final BindingResult bindingResult) { 
     final StringBuilder stringBuilder = new StringBuilder("Invalid parameters specified."); 
     if (bindingResult.getFieldErrors() != null && !bindingResult.getFieldErrors().isEmpty()) { 
      stringBuilder.append(" Fields:"); 
      bindingResult.getFieldErrors().forEach(fieldError -> stringBuilder 
        .append(" [ ") 
        .append(fieldError.getField()) 
        .append(" : ") 
        .append(fieldError.getRejectedValue()) 
        .append(" ] ")); 
     } else if (bindingResult.getAllErrors() != null && !bindingResult.getAllErrors().isEmpty()) { 
      final ObjectError objectError = bindingResult.getAllErrors().get(0); // get the first error 
      stringBuilder.append(" Message: ") 
        .append(objectError.getDefaultMessage()); 
     } 

     return stringBuilder.toString(); 
    } 
} 
+0

Спасибо за обмен. Ваш продукт решения ответ, который сильно отличается от ответа, полученного из стандартного хранилища SDR. В вашем случае вам возвращается 500 http-статус вместо 4xx. Некоторые советы? – drenda

+0

Вы можете настроить ответ в методе createErrorMessage. Для другого кода состояния вам просто нужно поймать ValidationException в соответствующем обработчике исключений. –

1

Вы также можете добавить это к вашему @RepositoryRestController:

@Inject 
private LocalValidatorFactoryBean validator; 

@InitBinder 
protected void initBinder(WebDataBinder binder) { 
    binder.addValidators(validator); 
} 
+0

Ваше решение кажется очень компактным. Он работает, я получаю ошибку 400, но json ответа отличается от одного из «стандартного» хранилища SDR, есть ли способ его настроить? – drenda

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

  • Нет связанных вопросов^_^