检查控制器或服务层的前提条件

问题描述 投票:18回答:4

我正在使用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方法。我很困惑。请问控制器和服务层中检查前置条件的方法哪个更好?先谢谢你了。

spring validation service controller
4个回答
32
投票

理想情况下,你会在两个地方都做。但是你混淆了两件不同的事情。

  • 验证(带错误处理)
  • 防御性编程(又称断言,又称契约设计)。

你绝对应该做 验证 在控制器和 防御性编程 在你的服务。这就是为什么。

你需要 鉴定 的表单和REST请求,这样你就可以向客户端发送一个合理的错误信息。这包括哪些字段是坏的,然后做错误信息的本地化,等等......(如果ProductInfo.name属性是空的,你当前的例子会给我发送一个可怕的500错误信息和堆栈跟踪)。

Spring有一个 验证方案 在控制器中。

防御性编程 是在服务层完成的,但不是 验证 因为你没有访问locale来生成正确的错误信息。有些人可以,但Spring并没有真正帮助你。

另一个没有在服务层进行验证的原因是,ORM已经典型地通过JSR Bean Validation规范(hibernate)来进行验证,但它不会生成合理的错误信息。

人们做的一个策略是创建自己的前提条件utils库,抛出自定义的dedicated RuntimeException瓜子酱 IllegalArgumentExceptionIllegalStateException 然后 try...catch ...控制器中的异常,并将其转换为验证错误信息。


2
投票

没有 "更好 "的方法。如果你认为该服务将被多个控制器(或其他代码)使用,那么在那里做检查可能很有意义。如果对你的应用程序来说,在无效请求还在控制器中时就对其进行检查是很重要的,那么在那里做检查也是很有意义的。正如你所注意到的,这两者并不相互排斥。你可能需要检查两次才能覆盖这两种情况。

另一个可能的解决方案是:使用Bean Validation (JSR-303)把检查(前提条件)放到ProductInfo bean本身。这样你只需要指定一次检查,任何需要的东西都可以快速验证Bean。


0
投票

我认为在你的特殊情况下,你需要在服务层上进行检查,并在数据完整性错误的情况下返回异常给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。


0
投票

先决条件、验证,不管是简单的还是业务的,都应该在过滤器层或拦截器处理,甚至在到达控制器层或服务层之前。

如果你在控制器层检查,危险的是违反了控制器的单一责任原则,控制器的唯一目的是委托请求和响应。

把前置条件放在服务层,就是把核心业务引入了交叉关注。

Filter或inceptor就是为了这个目的而建立的。把前置条件放在过滤器层或拦截器中,还可以让你 "挑选和匹配 "你可以为每个servlet请求放置在堆栈中的规则,这样就不会把某条规则仅仅局限于一个servlet请求,也不会引入重复。

© www.soinside.com 2019 - 2024. All rights reserved.