2016-10-24 3 views
1

Ich versuche, Spring Data REST Repositories mit Annotation @RepositoryRestResource Annotation zusammen mit benutzerdefinierten Methoden Implementierung zu verwenden. Es gibt 2 Fälle:Spring Data REST: benutzerdefinierte Methoden Validierung

1) Ich habe REST-Repository mit @RepositoryRestResource annotiert, die /users Endpoint zugeordnet ist. Ich habe auch @RestController, die auf den gleichen Endpunkt zugeordnet ist. Das führt dazu, dass Methoden (die angezeigt werden sollten) in @RepositoryRestResource nicht sichtbar sind und Ergebnis 405 auf ihnen erhalten. Die Methodenvalidierung mit @Valid Annotation arbeitet jedoch an @RestController Methoden. z.B. dies funktioniert:

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

2) Controller, die zusammen mit REST-Repositories arbeiten, sind @RepositoryRestController Controller. Auf diese Weise funktionieren beide in @RepositoryRestController und @RepositoryRestResource deklarierten Methoden. Allerdings JSR-303 @Valid Annotation auf Methoden nicht mehr funktioniert, so kann ich nicht verwenden @Valid Annotation. Dieses Problem wurde bereits beschrieben DATAREST-593.

Irgendwelche Ideen, wie mindestens eines von zwei Problemen gelöst werden kann? Die Hauptidee besteht darin, @RepositoryRestResource Repositories zusammen mit benutzerdefinierten Controller-Methoden und Annotation-Validierung zu verwenden.

Antwort

1

Scheint, dass es keine gute Lösung in diesem Fall gibt und @Valid Annotation wird in keiner Weise standardmäßig unterstützt, siehe DATAREST-593. Deshalb, @Valid Anmerkung auf @RepositoryRestController Methoden zu unterstützen, habe ich folgende @ControllerAdvice Klasse erstellt:

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

Dank für die gemeinsame Nutzung. Ihr Lösungsprodukt ist eine Antwort, die sich stark von der Antwort unterscheidet, die von einem SDR-Standardrepository zurückgegeben wird. Außerdem wird in Ihrem Fall ein 500 http-Status anstelle eines 4xx zurückgegeben. Ein Ratschlag? – drenda

+0

Sie können die Antwort in der createErrorMessage-Methode anpassen. Für einen anderen Statuscode müssen Sie nur die ValidationException in der entsprechenden Ausnahmebedingungsroutine abfangen. –

1

Sie können auch diese zu Ihrem @RepositoryRestController hinzufügen:

@Inject 
private LocalValidatorFactoryBean validator; 

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

Ihre Lösung scheint sehr kompakt. Es funktioniert, ich bekomme einen 400 Fehler, aber der JSON der Antwort unterscheidet sich von dem des "Standard" SDR-Repository, gibt es eine Möglichkeit, es anzupassen? – drenda

Verwandte Themen