Spring验证不断验证错误的参数
我有一个控制器,其web方法如下所示:Spring验证不断验证错误的参数,spring,bean-validation,Spring,Bean Validation,我有一个控制器,其web方法如下所示: public Response registerDevice( @Valid final Device device, @RequestBody final Tokens tokens ) {...} public class DeviceValidator implements Validator { @Override public boolean supports(Class<?> clazz) {
public Response registerDevice(
@Valid final Device device,
@RequestBody final Tokens tokens
) {...}
public class DeviceValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Device.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// Do magic
}
}
}
@RequestMapping(...)
public MyMsgObject handleRequest (
@Valid final MyHeaderObj myHeaderObj,
@RequestBody final MyRequestPayload myRequestPayload
) {...}
以及一个如下所示的验证器:
public Response registerDevice(
@Valid final Device device,
@RequestBody final Tokens tokens
) {...}
public class DeviceValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Device.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// Do magic
}
}
}
@RequestMapping(...)
public MyMsgObject handleRequest (
@Valid final MyHeaderObj myHeaderObj,
@RequestBody final MyRequestPayload myRequestPayload
) {...}
公共类设备验证器实现验证器{
@凌驾
公共布尔支持(类clazz){
返回设备.class.isAssignableFrom(clazz);
}
@凌驾
公共无效验证(对象目标、错误){
//变魔术
}
}
}
我试图让Spring验证由拦截器生成的设备参数。但每次我尝试时,它都会验证tokens参数
我尝试使用@InitBinder
指定验证器,@Validated
而不是@Validated
,并注册方法验证后处理器
类。到目前为止没有运气
要么根本不调用验证器,要么在验证设备参数时验证tokens参数
我正在使用Spring4.1.6和HibernateValidator 5.1.3
有人能提供我做错了什么的线索吗?我整个下午都在网上搜索,想把这件事弄清楚。我不敢相信spring的验证领域仍然像5年前一样混乱:-(好的。经过两天的各种变化,我们现在已经解决了它。如果spring的验证让你做一件事的话——它提出了一系列难以置信的不起作用的事情!但是回到我的解决方案上来 基本上,我需要的是一种手动创建请求映射参数的方法,验证它们,然后确保无论成功还是失败,调用方始终收到自定义JSON响应。这样做比我想象的要困难得多,因为尽管有大量的博客文章和stackoverflow答案,我从未找到一个完整的解决方案。所以我努力勾勒出实现我想要的每一块拼图 注意:在下面的代码示例中,我概括了事物的名称,以帮助澄清什么是自定义的,什么不是自定义的 配置 虽然我读过几篇博文,其中谈到了各种类,如
方法验证后处理器
,但最终我发现除了@EnableWebMvc
注释之外,我不需要任何设置。默认的解析器等证明是我所需要的
请求映射
我的最终请求映射签名如下所示:
public Response registerDevice(
@Valid final Device device,
@RequestBody final Tokens tokens
) {...}
public class DeviceValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Device.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// Do magic
}
}
}
@RequestMapping(...)
public MyMsgObject handleRequest (
@Valid final MyHeaderObj myHeaderObj,
@RequestBody final MyRequestPayload myRequestPayload
) {...}
这里您会注意到,与我找到的几乎每一篇博客文章和示例不同,我有两个对象被传递给该方法。第一个是我希望从标题动态生成的对象。第二个是JSON负载中的反序列化对象。其他对象也可以很容易地被包含,例如路径参数等。请尝试其他方法如果不使用下面的代码,您将遇到各种各样的奇怪和奇妙的错误
引起我所有痛苦的棘手部分是,我想验证myHeaderObj
实例,而不是验证myRequestPayload
实例。这让我很头疼
还要注意MyMsgObject
result对象。这里我想返回一个将序列化为JSON的对象。包括异常发生的时间,因为该类包含除HttpStatus代码外还需要填充的错误字段
控制员建议
接下来,我创建了一个ControllerAdvice
类,其中包含用于验证的绑定和一个常规错误陷阱
@ControllerAdvice
public class MyControllerAdvice {
@Autowired
private MyCustomValidator customValidator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
if (binder.getTarget() == null) {
// Plain arguments have a null target.
return;
}
if (MyHeaderObj.class.isAssignableFrom(binder.getTarget().getClass())) {
binder.addValidators(this.customValidator);
}
}
@ExceptionHandler(Exception.class)
@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public MyMsgObject handleException(Exception e) {
MyMsgObject myMsgObject = new MyMsgObject();
myMsgObject.setStatus(MyStatus.Failure);
myMsgObject.setMessage(e.getMessage());
return myMsgObject;
}
}
这里有两件事。第一件事是注册验证器。请注意,我们必须检查参数的类型。这是因为对@RequestMapping
的每个参数都调用@InitBinder
,我们只需要MyHeaderObj
参数上的验证器。如果我们不这样做,将抛出异常en-Spring试图将验证器应用于它对其无效的参数
第二件事是异常处理程序。我们必须使用@ResponseBody
来确保Spring将返回的对象视为要序列化的对象。否则,我们将只得到标准的HTML异常报告
验证器
这里我们使用了一个非常标准的验证器实现
@Component
public class MyCustomValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return MyHeaderObj.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
...
errors.rejectValue("fieldName", "ErrorCode", "Invalid ...");
}
}
这个类的主要工作是使用它需要的任何方法来构建参数(myHeaderObj
)。一旦构建,它就会继续调用Spring验证器来检查这个实例。如果有问题(通过检查返回的错误来检测),然后抛出一个异常,@ExceptionHandler
可以检测并处理该异常
注意validateIfApplicable(WebDataBinder活页夹,MethodParameter methodParam)
方法。这是我在许多Spring类中找到的代码。它的工作是检测是否有任何参数具有@Validated
或@Validated
注释,如果是,则调用相关的验证器。默认情况下,Spring不会对像这样的自定义参数处理程序执行此操作,因此由我们来添加此功能。真的吗春天???没有什么东西
最后一部分,显式异常捕获
最后,我还需要捕获更明确的异常。例如上面抛出的MyCustomException
。因此,我在这里创建了第二个@ControllerAdvise
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE) // Make sure we get the highest priority.
public class MyCustomExceptionHandler {
@ExceptionHandler
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public Response handleException(MyCustomException e) {
MyMsgObject myMsgObject = new MyMsgObject();
myMsgObject.setStatus(MyStatus.Failure);
myMsgObject.setMessage(e.getMessage());
return myMsgObject;
}
}
虽然表面上类似于一般的异常处理程序。但有一个不同。我们需要指定@顺序(Ordered.HIGHEST\u优先级)
annotation。如果没有此注释,Spring将只执行与抛出的异常匹配的第一个异常处理程序。无论是否有更好的匹配处理程序。因此,我们使用此注释来确保此异常处理程序优先于常规处理程序
总结
这个解决方案对我来说很好。我不确定我是否有最好的解决方案,可能还有一些Spring类我还没有找到可以帮助我的。我希望这能帮助任何有相同或相同问题的人