首页 > 代码库 > 苦B程序员的数据验证之路

苦B程序员的数据验证之路

发生了什么事

在一次苦B程序员苦C程序员的结对编程中发生的一段对话

代码是这样的:

public void deleteAllExtendAclsFromContent(String contentId) throwsContentAclServiceException {

// 参数验证

if (StringUtils.isBlank(contentId)) {

logger.warn("参数异常,内容唯一标识为空");

throw new ContentAclServiceException("参数异常,内容唯一标识为空");

}

// 检查内容合法性

contentAclService.checkContentId(contentId);

contentAclCoreService.deleteAllExtendAclsFromContent(contentId);

}

苦C程序员:会什么你的每个方法都要去检查一下参数是不是null,参数是不是指定的几种可选数据?

苦B程序员:因为如果我不检查,后面的操作将会是对一个错误的对象进行,会影响程序的正确执行。

苦C程序员:但是这个方法应该只关注自己的业务逻辑而不应该做一些与业务无关的参数的正确性判断,否则这个方法可能10行中有7行都是做参数合法性验证,真正的业务可能只有3行,你不觉得这会很怪异吗?

苦B程序员:那我有什么办法,我的程序跑不下去了,测试来找我的麻烦了!

苦C程序员:我看你的每个方法都要对参数做合法性检查,那是否可以将这样一个行为提取出来使所有的方法在被调用之前让一个类去做参数的合法性检查,我们只要给参数一个说明比如这样

public void deleteAllExtendAclsFromContent(@NotEmpty(message="参数异常,内容唯一标识为空") String contentId) throws ContentAclServiceException {

// 检查内容合法性

contentAclService.checkContentId(contentId);

contentAclCoreService.deleteAllExtendAclsFromContent(contentId);

}

苦B程序员:嗯,这样看起来很不错,我们可以利用spring的aop做个拦截,在所有的方法被调用前先让一个拦截器来检查所有的参数是否合法。

苦C程序员:对,我们就这样干。


 没多久时序图片就出来了。

.

.

.

半天后,两个人只有一个想法,那就是太苦B了,这是一整个体系两个人一天怎么做的完?在项目的时间进度压力下两人只有放弃(看来很多情况下不是程序员不想把事情做好,时间、时间、还是时间),于是程序又回到了刚开始,并且他们不得不为这一次冒险所耽搁的时间去自己加班完成工作。

这样的事情发生的多了大家就再也不会想在项目里使用什么优美的方式或好的模式来编写与设计代码了,而是以完成功能为目地的编码。

回顾上面的对话我们发现

? 苦B程序员的做法,是为了防止程序出现异常而对输入参数为了检查。

? 苦C程序员的想法,是让这种检查工作不必分散到各业务方法中。

两个程序员都是想把程序做的更健壮、业务更清晰、职责更分明,但是由于客观的原因他们的努力失败了。

神的出现

继续上面,此时的苦C程序员依然没有放弃,他利用项目的空闲时间继续研究,他认为这种需求应该不只他一个人有,世界上还有那么多的苦X程序员,可能早就有人想到了这个需求,也许早就有人已经完成了这个工作,苦C程序员突然想起了spring的mvc中好像可以验证参数的正确性,于是他求助了万能的google大神,终于被他找了解决这个问题的究极方案。

当当当“JSR303”闪亮登场。http://jcp.org/en/jsr/detail?id=303

这个规范当前较好的实现是Hibernate Validator,http://www.hibernate.org/subprojects/validator.html并且也可较方便的与spring集成。此时的苦C程序员感觉到浑身充满了力量,他大叫一声“JSR303赐予我力量吧!Google,live for ever”。从此苦C程序员在开发这条苦B的不归路上走的更坚实了,因为他又多了一把称手的神器—“JSR303”。

苦B程序员和苦C程序员皈依了我神最终升华为苦A程序员

网上有这样一个例子https://github.com/ghillert/spring-hibernate-validator-sample,这里面就是讲述如何使用JSR303来验证方法参数的。这里面需要在spring中做如下配置

<bean id="validator"

class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

<beanclass="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>

关键就在MethodValidationPostProcessor这个类,它的作用就是给所有的标记了要做验证的接口添加一个org.springframework.validation.beanvalidation.MethodValidationInterceptor拦截器,这个拦截器会负责验证你所要验证的参数。

但这个拦截器会抛出一个org.hibernate.validator.method.MethodConstraintViolationException.MethodConstraintViolationException异常,对于有些人来说也许他们并不希望得到这样的异常,可能是因为这个异常长的太怪异,也可能是其它的原因,总之就是不希望用这个,他们希望自已来控制验证出错后的处理方式。谢天谢地这一切都是开源的(感谢天,感谢地,感谢Spring……熟悉的旋律出现在耳边),那么分析MethodValidationPostProcessor与MethodValidationInterceptor代码后我们可以很容易的做到这一点,聪明的程序员们应该很快就可以明白了。

苦C程序员以最快的速度将这个消息告诉了苦B程序员,苦B程序员得到这个消息后第一直觉就是要尽快将这个成果分享到整个团队中,于是不久后整个团队的成员都皈依了我神(JSR303)最终升华为了苦A程序员(为什么还是苦A程序员?因为还有新的麻烦会不断的出现,我勒个去……)。

苦B程序员的数据验证之路