我正在使用Google的Preconditions类来验证用户的输入数据。但我担心使用Preconditions类检查用户输入数据的最佳点在哪里。首先,我在Controller中写了如下的验证检查代码。
@Controller
...
public void register(ProductInfo data) {
Preconditions.checkArgument(StringUtils.hasText(data.getName()),
"Empty name parameter.");
productService.register(data);
}
@Service
...
public void register(ProductInfo data) {
productDao.register(data);
}
但我认为 register
服务层的方法将使用另一个Controller方法,如下图所示。
@Controller
...
public void register(ProductInfo data) {
productService.register(data);
}
public void anotherRegister(ProductInfo data) {
productService.register(data);
}
@Service
...
public void register(ProductInfo data) {
Preconditions.checkArgument(StringUtils.hasText(data.getName()),
"Empty name parameter.");
productDao.register(data);
}
另一方面,服务层的方法只用一个Controller方法。我很困惑。请问控制器和服务层中检查前置条件的方法哪个更好?先谢谢你了。
理想情况下,你会在两个地方都做。但是你混淆了两件不同的事情。
你绝对应该做 验证 在控制器和 防御性编程 在你的服务。这就是为什么。
你需要 鉴定 的表单和REST请求,这样你就可以向客户端发送一个合理的错误信息。这包括哪些字段是坏的,然后做错误信息的本地化,等等......(如果ProductInfo.name属性是空的,你当前的例子会给我发送一个可怕的500错误信息和堆栈跟踪)。
Spring有一个 验证方案 在控制器中。
防御性编程 是在服务层完成的,但不是 验证 因为你没有访问locale来生成正确的错误信息。有些人可以,但Spring并没有真正帮助你。
另一个没有在服务层进行验证的原因是,ORM已经典型地通过JSR Bean Validation规范(hibernate)来进行验证,但它不会生成合理的错误信息。
人们做的一个策略是创建自己的前提条件utils库,抛出自定义的dedicated RuntimeException
瓜子酱 IllegalArgumentException
和 IllegalStateException
然后 try
...catch
...控制器中的异常,并将其转换为验证错误信息。
没有 "更好 "的方法。如果你认为该服务将被多个控制器(或其他代码)使用,那么在那里做检查可能很有意义。如果对你的应用程序来说,在无效请求还在控制器中时就对其进行检查是很重要的,那么在那里做检查也是很有意义的。正如你所注意到的,这两者并不相互排斥。你可能需要检查两次才能覆盖这两种情况。
另一个可能的解决方案是:使用Bean Validation (JSR-303)把检查(前提条件)放到ProductInfo bean本身。这样你只需要指定一次检查,任何需要的东西都可以快速验证Bean。
我认为在你的特殊情况下,你需要在服务层上进行检查,并在数据完整性错误的情况下返回异常给Controller。
@controller
public class MyController{
@ExceptionHandler(MyDataIntegrityExcpetion.class)
public String handleException(MyDataIntegrityExcpetion ex, HttpServletRequest request) {
//do someting on exception or return some view.
}
}
这也取决于你在Controller中做了什么,是返回View还是只用 @ResponseBody
注释:Spring MVC有一个很好的 "开箱即用 "的解决方案,用于输入数据的验证,我推荐你看看这个库。Spring MVC有很好的 "开箱即用 "的输入数据验证解决方案,我推荐你看看这个库。
http:/static.springsource.orgspringdocs3.1.xspring-framework-referencehtmlvalidation.html。
先决条件、验证,不管是简单的还是业务的,都应该在过滤器层或拦截器处理,甚至在到达控制器层或服务层之前。
如果你在控制器层检查,危险的是违反了控制器的单一责任原则,控制器的唯一目的是委托请求和响应。
把前置条件放在服务层,就是把核心业务引入了交叉关注。
Filter或inceptor就是为了这个目的而建立的。把前置条件放在过滤器层或拦截器中,还可以让你 "挑选和匹配 "你可以为每个servlet请求放置在堆栈中的规则,这样就不会把某条规则仅仅局限于一个servlet请求,也不会引入重复。