Java Spring Boot 2和方法参数验证
我创建了以下服务接口:Java Spring Boot 2和方法参数验证,java,spring,spring-boot,spring-validator,Java,Spring,Spring Boot,Spring Validator,我创建了以下服务接口: import javax.validation.constraints.NotBlank; import org.springframework.lang.NonNull; import org.springframework.validation.annotation.Validated; @Validated public interface UserService { User create(@NonNull Long telegramId, @Not
import javax.validation.constraints.NotBlank;
import org.springframework.lang.NonNull;
import org.springframework.validation.annotation.Validated;
@Validated
public interface UserService {
User create(@NonNull Long telegramId, @NotBlank String name, @NonNull Boolean isBot);
}
但是下面的调用:
userService.create(telegramId, "Mike", null);
通过
isBot
参数的@NotNull
验证。如何正确配置Spring Boot和my service,以便考虑@NonNull
注释,并防止在null
参数的情况下执行方法?在实现类中使用相同的东西,而不是在接口中使用。
还可以编写一个全局异常,如:
@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class GlobalRestException extends ResponseEntityExceptionHandler {
...
...
/**
* Handle MethodArgumentNotValidException. Triggered when an object fails @Valid
* validation.
*
* @param ex the MethodArgumentNotValidException that is thrown when @Valid
* validation fails
* @param headers HttpHeaders
* @param status HttpStatus
* @param request WebRequest
* @return the ApiException object
*/
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
Error apiError = new Error(BAD_REQUEST);
apiError.setMessage("Validation error");
apiError.addValidationErrors(ex.getBindingResult().getFieldErrors());
apiError.addValidationError(ex.getBindingResult().getGlobalErrors());
return buildResponseEntity(apiError);
}
}
@顺序(有序。最高优先级)
@再控制建议
公共类GlobalRestException扩展了ResponseEntityExceptionHandler{
...
...
/**
*Handle MethodArgumentNotValidException。当对象失败@Valid时触发
*验证。
*
*@param ex在@Valid时引发的MethodArgumentNotValidException
*验证失败
*@param headers-HttpHeaders
*@param status HttpStatus
*@param request WebRequest
*@返回ApiException对象
*/
@凌驾
受保护响应handleMethodArgumentNotValid无效(MethodArgumentNotValidException ex,
HttpHeaders标头、HttpStatus状态、WebRequest请求){
Error APIRROR=新错误(错误请求);
setMessage(“验证错误”);
addValidationErrors(例如getBindingResult().getFieldErrors());
apiError.addValidationError(例如getBindingResult().getGlobalErrors());
返回buildResponseEntity(apiError);
}
}
可以重写更多方法来处理不同类型的异常,如:
/**
* Handles javax.validation.ConstraintViolationException. Thrown when @Validated
* fails.
*
* @param ex the ConstraintViolationException
* @return the ApiException object
*/
@ExceptionHandler(javax.validation.ConstraintViolationException.class)
protected ResponseEntity<Object> handleConstraintViolation(javax.validation.ConstraintViolationException ex) {
Error apiError = new Error(BAD_REQUEST);
apiError.setMessage("Validation error");
apiError.addValidationErrors(ex.getConstraintViolations());
return buildResponseEntity(apiError);
}
/**
*处理javax.validation.ConstraintViolationException。当@Validated时抛出
*失败了。
*
*@param exconstraintviolationexception
*@返回ApiException对象
*/
@ExceptionHandler(javax.validation.ConstraintViolationException.class)
受保护的响应handleConstraintViolation(javax.validation.ConstraintViolationException ex){
Error APIRROR=新错误(错误请求);
setMessage(“验证错误”);
apierro.addValidationErrors(例如getConstraintViolations());
返回buildResponseEntity(apiError);
}
我把这个问题处理了一会儿
您的代码在我看来很好:请确保UserService
的实现也包含验证注释
确保允许Spring创建Bean;它应该像你期望的那样工作
实例
服务定义
服务实现
测试向量
测试用例对我来说是绿色的
Github:
资料来源:
嗯 您是否尝试将
@Validated
注释放在服务的实际实现上?是的,不幸的是,在这种情况下,我得到了相同的结果只是在这些注释上打一下就不起作用了。这仅适用于控制器,因为它已备份到RequestMappingHandlerAdapter
。要为其他bean启用它,您还需要添加MethodValidationPostProcessor
以注册AOP部件。我认为它对我不起作用,因为现在没有抛出MethodArgumentNotValidException
。这就是问题所在-在这种情况下如何获得抛出的MethodArgumentNotValidException
?您永远不会在这里得到该异常,因为它是服务层的一部分。MethodArgumentNotValidException
是一个特定的web绑定异常。因此,服务上的验证错误永远不会出现后者。非常感谢您提供的解决方案!是否可以使其与@Service
注释一起工作?可以。我真傻。只需在实现(在我的例子中)上添加@Service
注释HelloGreetingService
并删除bean。做了这些之后,我的测试用例仍然是绿色的。更新了我的代码,如果需要,请查看github上的更新帖子和更新代码。
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Validated
public interface GreetingService {
String greet(@NotNull @NotBlank String greeting);
}
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Service
public class HelloGreetingService implements GreetingService {
public String greet(@NotNull @NotBlank String greeting) {
return "hello " + greeting;
}
}
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import javax.validation.ConstraintViolationException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
class HelloGreetingServiceTest {
@Autowired
private GreetingService helloGreetingService;
@Test
void whenGreetWithStringInput_shouldDisplayGreeting() {
String input = "john doe";
assertEquals("hello john doe", helloGreetingService.greet(input));
}
@Test
void whenGreetWithNullInput_shouldThrowException() {
assertThrows(ConstraintViolationException.class, () -> helloGreetingService.greet(null));
}
@Test
void whenGreetWithBlankInput_shouldThrowException() {
assertThrows(ConstraintViolationException.class, () -> helloGreetingService.greet(""));
}
}