检查Controller或Service层中的前提条件

时间:2012-08-13 07:22:10

标签: spring validation service controller

我正在使用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);
}

但我认为Service层中的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);
}

另一方面,服务层的方法只能在一个控制器中使用 我很困惑。检查控制器或服务中的前提条件的更好方法是什么? 提前致谢。

4 个答案:

答案 0 :(得分:23)

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

  • 验证(带错误处理)
  • Defensivie Programming(又名断言,又称合同设计)。

您绝对应该在控制器中执行验证,并在服务中执行防御性编程。这就是原因。

您需要验证表单和REST请求,以便您可以向客户端发送明智的错误。这包括哪些字段是坏的,然后进行错误消息的本地化......等等...(如果ProductInfo.name属性为null,您当前的示例将向我发送带有堆栈跟踪的可怕的500错误消息)。

Spring在控制器中有一个solution for validating objects

防御性编程在服务层完成但不是验证,因为您无权访问区域设置以生成正确的错误消息。有些人会这样做,但Spring并没有真正帮助你。

在服务层中未进行验证的另一个原因是ORM通常通过JSR Bean Validation规范(hibernate)执行此操作,但它不会生成合理的错误消息。

人们做的一个策略是创建自己的preconditions utils库,抛出自定义派生的RuntimeException而不是guava(和commons lang)IllegalArgumentExceptionIllegalStateException然后{{1} } ... try控制器中的异常将它们转换为验证错误消息。

答案 1 :(得分:2)

没有“更好”的方式。如果您认为该服务将由多个控制器(或其他代码段)使用,那么在那里进行检查可能是有意义的。如果您的应用程序在仍然在控制器中时检查无效请求很重要,那么在那里进行检查可能是有意义的。正如您所注意到的,这两者并不相互排斥。您可能需要检查两次才能涵盖这两种情况。

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

答案 2 :(得分:0)

我认为在您的特殊情况下,您需要在服务层上检查它,并在数据完整性错误的情况下将异常返回给Controller。

@controller
public class MyController{

@ExceptionHandler(MyDataIntegrityExcpetion.class)
public String handleException(MyDataIntegrityExcpetion ex, HttpServletRequest request) {
  //do someting on exception or return some view. 
}

}

它还取决于你在控制器中做了什么。是否返回View或仅使用@ResponseBody注释。 Spring MVC具有很好的“开箱即用”输入/数据验证解决方案我建议您检查这些库。

http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/validation.html

答案 3 :(得分:0)

前提条件,验证,无论是简单还是业务都应该在过滤层或拦截器处理,甚至在到达控制器或服务层之前。

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

将先决条件放在服务层中是为了向核心业务引入交叉问题。

为此目的构建过滤器或接收器。将前置条件放在过滤器层或拦截器中还允许您“选择和匹配”可以放置在堆栈中的每个servlet请求的规则,因此不会将特定规则限制为仅一个servlet请求或引入重复。