我们都知道,Spring MVC的与Hibernate的验证和JSR-303一般很好地集成。 但是Hibernate验证,正如有人说的,是一些只有Bean验证,这意味着更复杂的验证应该推到数据层。 这种验证的例子:业务键唯一性,内记录的依赖(这通常是一些在DB设计问题指指点点,但我们都生活在一个完美的世界)。 甚至简单的验证等字符串字段长度可以通过一些DB值,这使得Hibernate验证不可用来驱动。
所以我的问题是,是否有一些Spring或Hibernate或者JSR提供了执行这种复杂的验证? 有一些既定的模式或技术一块基于Spring和Hibernate标准的控制器-服务-库设置进行这样的验证?
更新:让我更具体。 例如,有其中发送AJAX保存请求到控制器的一个形式save
方法。 如果发生验证错误 - 简单或“复杂” - 我们应该返回给浏览器一些JSON表示有问题的领域和相关的错误。 对于简单的错误,我可以提取字段(如有的话)和错误消息从BindingResult
。 什么基础设施(也许具体的,不是临时的例外?)你会提出了“复杂”的错误? 使用异常处理程序似乎是个好主意,我不是,因为之间的验证分离单个进程save
方法和@ExceptionHandler
使事情变得复杂。 目前我使用一些特设除外(例如, ValidationException
):
public @ResponseBody Result save(@Valid Entity entity, BindingResult errors) {
Result r = new Result();
if (errors.hasErrors()) {
r.setStatus(Result.VALIDATION_ERROR);
// ...
} else {
try {
dao.save(entity);
r.setStatus(Result.SUCCESS);
} except (ValidationException e) {
r.setStatus(Result.VALIDATION_ERROR);
r.setText(e.getMessage());
}
}
return r;
}
你能否提供一些更优化的方法呢?
是的,有抛出异常的好老建立在JAVA模式。
Spring MVC的集成也相当不错(代码示例,您可以直接跳到我的回答的第二部分)。
你叫什么“复杂的验证”实际上例外:业务键唯一性错误,低层或DB错误等。
提醒:什么是Spring MVC的验证?
验证应该发生在表示层上。 它基本上是有关验证提交的表单字段。
我们可以将它们分为两类:
1)光验证 (与JSR-303 /休眠验证):检查所提交的字段具有给定@Size
/ @Length
,它是@NotNull
或@NotEmpty
/ @NotBlank
,检查它具有@Email
格式等。
2)重验证,或复杂的验证是更多关于字段验证,如交字段验证的具体例:
- 实施例1:该形式具有
fieldA
, fieldB
和fieldC
。 单独来看,每个字段可以是空的,但其中至少有一个不能为空。 - 实施例2:如果
userAge
字段具有18下的值, responsibleUser
字段不能为空,且responsibleUser
的年龄必须超过21。
这些验证可以实现春验证器实现 ,或自定义的注释/约束 。
现在我明白了所有这些验证facilites,再加上事实,春天是不侵扰的一切,让你做任何你想要的(或好或坏),一个可以尝试使用了“验证锤”任何东西隐约相关错误处理。
而且它的工作:与验证而已,你在你的验证/注解检查每一个可能出现的问题(几乎不扔在较低层的任何异常)。 这是不好的,因为你祈祷,你想过所有的案件。 你不利用Java异常,它会让你简化你的逻辑和减少忘记检查的东西有一个错误犯了一个错误的机会。
所以在Spring MVC的世界里,人们不应该误解验证(也就是说,UI验证 )为下层的例外 ,例如有服务例外或DB例外(键唯一性等)。
如何处理Spring MVC中的例外在一个方便的方法是什么?
有些人认为“哦,上帝,所以在我的控制器我会逐个检查所有可能检查的异常之一,想想他们每个人?NO WAY!消息错误”。 我是那些人的其中一个。 :-)
对于大多数的情况下,只需要使用一些通用的检查异常类,所有的异常将延长。 然后简单地处理它在你的Spring MVC控制器@ExceptionHandler和一般错误消息。
代码示例:
public class MyAppTechnicalException extends Exception { ... }
和
@Controller
public class MyController {
...
@RequestMapping(...)
public void createMyObject(...) throws MyAppTechnicalException {
...
someServiceThanCanThrowMyAppTechnicalException.create(...);
...
}
...
@ExceptionHandler(MyAppTechnicalException.class)
public String handleMyAppTechnicalException(MyAppTechnicalException e, Model model) {
// Compute your generic error message/code with e.
// Or just use a generic error/code, in which case you can remove e from the parameters
String genericErrorMessage = "Some technical exception has occured blah blah blah" ;
// There are many other ways to pass an error to the view, but you get the idea
model.addAttribute("myErrors", genericErrorMessage);
return "myView";
}
}
简单,快捷,方便,干净!
对于那些时候,你需要为某些特定的异常显示错误消息,或当你不能因为一个设计不当的遗留系统不能修改的通用顶级异常,只需添加其他@ExceptionHandler
秒。
另一个技巧:为更简洁的代码,你可以处理多个异常
@ExceptionHandler({MyException1.class, MyException2.class, ...})
public String yourMethod(Exception e, Model model) {
...
}
底线:当使用验证? 何时使用异常?
- 从UI =验证=验证设施(JSR-303注解,定制注释,春天验证)错误
- 从较低层=异常的错误
当我说“从UI错误”,我的意思是“用户输入错误的东西在他的形式”。
参考文献:
- 传球失误回视图从服务层
- 非常翔实的博客帖子大约Bean验证