【发布时间】:2023-04-01 13:13:01
【问题描述】:
我有一个 Spring Boot 2 应用程序,我希望能够使用 Hibernate 验证器验证控制器参数 - 我正在成功使用它。我将所有控制器都注释为@Validated,并且我正在使用@PathVariable @AssertUuid final String customerId 等请求参数的验证 - 到目前为止一切顺利,一切正常。
但是,我还希望能够从表单中验证 @ModelAttribute。
@Controller
@PreAuthorize("hasRole('ADMIN')")
@RequestMapping(path = "/customers")
@Validated
public class CustomerController
{
private final CustomerFacade customerFacade;
public CustomerController(
final CustomerFacade customerFacade
)
{
this.customerFacade = customerFacade;
}
@GetMapping("/create")
public ModelAndView create(
final AccessToken accessToken
)
{
return new ModelAndView("customer/create")
.addObject("customer", new CreateCustomerRequest());
}
@PostMapping("/create")
public ModelAndView handleCreate(
final AccessToken accessToken,
@Validated @ModelAttribute("customer") final CreateCustomerRequest customerValues,
final BindingResult validation
) throws
UserDoesNotHaveAdminAccessException
{
if (validation.hasErrors()) {
return new ModelAndView("customer/create")
.addObject("customer", customerValues);
}
CustomerResult newCustomer = customerFacade.createCustomer(
accessToken,
customerValues.getName()
);
return new ModelAndView(new RedirectView("..."));
}
public static final class CreateCustomerRequest
{
@NotNull
@NotBlank
private String name;
public CreateCustomerRequest(final String name)
{
this.name = name;
}
public CreateCustomerRequest()
{
}
public String getName()
{
return name;
}
}
}
但这会导致MethodValidationInterceptor 在我发送无效数据时抛出ConstraintViolationException。这通常是有道理的,我希望在所有其他情况下都有这种行为,但在这种情况下,如您所见,我想使用 BindingResult 来处理验证错误 - 这在处理表单时是必需的。
有没有办法告诉 Spring 不使用 MethodValidationInterceptor 验证这个特定参数,因为它已经被 binder 验证了,我想以不同的方式处理它?
我一直在研究 spring 代码,它看起来并不是为了协同工作而设计的。我有一些想法可以解决这个问题:
- 从参数中删除
@Validated并- 在控制器方法中显式调用
validator.validate()- 丑陋而危险(你可能忘记调用它) - 创建另一个 AOP 拦截器,它将找到
@ModelAttribute和BindingResult的“对”并在那里调用验证器,从而强制全局验证
- 在控制器方法中显式调用
我这样做完全错了吗?我错过了什么吗?有没有更好的办法?
【问题讨论】:
标签: java spring spring-mvc spring-boot hibernate-validator