在@RepositoryRestController中验证

问题描述 投票:3回答:2

我想用javax注释@RepositoryRestController在我的@Valid中验证我的DTO。然而@RepositoryRestController目前不支持@Valid,你可以在这张票中看到:https://jira.spring.io/browse/DATAREST-593

如果我使用@RestController我的@Valid工作正常,但是然后我的@RepositoryRestResource将不再工作。我需要在@RestController中为每个功能手动编写一个方法(findOne(),findAll()等)。目前我可以使用带有投影的@RepositoryRestResource方法findAll()等。

如何验证@RepositoryRestController中的DTO?

库:

@RepositoryRestResource(excerptProjection = ChipProjection.class)
public interface ChipRepository extends JpaRepository<Chip, Long> {

}

投影:

@Projection(name = "summary", types = Chip.class)
public interface ChipProjection {
    Long getId();
    ChipIdentifier getChipIdentifier();
}

控制器:

@RepositoryRestController
public class ChipRestController {
    @Autowired
    ChipService chipService;

    @RequestMapping(value = "/chips", method = RequestMethod.POST)
    public @ResponseBody ChipHelper saveChip(@Valid @RequestBody ChipHelper chip, BindingResult result){
        List<FieldError> errors = result.getFieldErrors();
        //errors is always empty, @Valid not working
        chipService.save(chip);
        return chip;
    }
}

芯片助手:

@Data
public class ChipHelper {
    @NotNull
    private Long id;

    @NotNull
    @Size(min = 10)
    private String identifier;
}
spring validation spring-data spring-restcontroller spring-rest
2个回答
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();
    }
}

1
投票

这个答案:https://stackoverflow.com/a/44304198/5435182适合我:

只需将此添加到您的@RepositoryRestController

@Inject
private LocalValidatorFactoryBean validator;

@InitBinder
protected void initBinder(WebDataBinder binder) {
    binder.addValidators(validator);
}
© www.soinside.com 2019 - 2024. All rights reserved.