现在让我们更深入地研究Spring。 在本文中,我们将学习验证从表单中获取的数据。 让我们更仔细地看一下验证任务。
场景1 :我们可能需要验证,例如,所提供的电子邮件确实确实看起来像一封电子邮件(以简化的x @ xx格式显示)。 这可以通过仅在电子邮件字段本身上运行一些脚本来完成。 那应该很简单。 我们可以编写一些可在浏览器本身上运行JavaScript。 并且还要在服务器端写相同的验证[为什么? 在这里阅读 ]。 对于所有隔离的验证都是如此,例如,检查数据是否不为空,检查数据是否为一定长度等。
场景2 :希望生活如此简单。 由于我们正在讨论电子邮件验证,因此可以说其中一项验证要求我们检查电子邮件是否属于某些域(例如合作伙伴组织),以便系统也可以通过电子邮件发送某些特权信息。 假设我们需要检查电子邮件的格式为x @ partner1.com,x @ partner2.com或x@partner3.com。 可能很琐碎,这是无法仅对表单本身的数据进行验证的类型的示例。 无论验证代码是什么,它都需要知道哪些域有效。 并且此数据不存在于最终用户以表格形式提供的数据中。 如果您稍微发挥想象力,则可以轻松地创建用例,其中可能需要业务规则引擎(例如,规则过于灵活)和/或可以引入国际化元素(例如,所有国家/地区的成年人年龄都未满18岁) )或其他复杂性。 这些是非隔离的验证,需要访问同步可用的其他信息。 这些验证可以在服务器端和客户端都进行编码,尽管可以说它将更多地依赖于服务器端。
场景3 :同样,希望生活如此简单。 如果我们处于验证电子邮件的主题上,我们可能还需要检查电子邮件是否有效,即它不是thisemail@doesnot.exist(我不确定该电子邮件是否存在-或在其中不存在未来-但您希望我能想到)。 我们将需要向该电子邮件ID发送一封电子邮件,并可能要求用户单击并确认。 我们需要通过SMTP与其他系统进行异步交互。 同样,稍微依靠您的想象力,整个潘多拉盒子就会破裂。 很快,您将通过REST,SOAP,JMS,文件服务器进行集成,并通过分布式系统处理安全性和身份验证问题。 我敢打赌,大多数系统都将在该领域中进行服务器端验证,并且客户端验证(尽管在技术上是可行的)不会经常使用。
方案4 :而且我们还没有违反相同的领域对象的问题,这些领域对象不仅从基于Web的表单填充,而且还从Feed文件,JMS消息等填充,因此需要将相同的验证逻辑应用于多个渠道。 在本讨论开始时,它最初是一个微不足道的小形式,带有少量无辜的文本框,如今已演变为一个怪物。
幸运的是,JSR 303或Bean验证[ 此处 ]可以拯救。 它立即解决了上述情况1和4。 它支持您解决方案2和3。我建议您阅读标有“此标准对用户有何好处?”的部分。 它会解决什么问题?” 在此链接 。
该Java规范于2006年提出要求,并于2009年底发布。 换句话说,可用的实现已经有机会在一年中成熟。 作为一流的开源公民,Spring 3使您可以使用此标准解决方案,而不必重新发明轮子。 而且,如果您绝对需要重新发明轮子(所有专业应用程序都需要编写myAppSpecificKickAssValidator()),Spring也会允许这样做。 让我们一一看看这两种情况。
将JSR 303支持添加到任何基于Maven的项目
JSR 303是一个开放的api。 您可以在此链接中找到它。 任何人都可以实现。 有hibernate和apache bval的实现。 让我们一起进行Hibernate实现。 在此链接中,您可以在Maven Central看到他们的罐子。 在撰写本文时,最新的稳定版本是4.3.0.Final。 您只需要在pom中添加此依赖项即可。 该实现也捆绑了api,因此您无需添加任何一个。
档案:pom.xml
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> [...]
<hibernate.validation.version>4.3.0.Final</hibernate.validation.version> [...]
</properties> <!-- Hibernate validations -->
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate.validation.version}</version>
</dependency>
只需添加此依赖项,您就可以进入实体/表单类并声明约束。 JSR 303有一些标准约束( 在此处列出 ),涵盖了NotNull之类的标准检查。 Hibernate添加了一些非标准的自定义约束[ 此处列出 ]。 它们不是标准的,但是非常方便,例如检查有效的电子邮件。 让我们在ContactFrm.java中介绍这两项检查。 如果您不知道那是从哪里来的,那么您很可能没有阅读本系列的上一篇文章,即使用Spring 3 MVC处理表单 。
文件:/org/academy/ui/spring3/forms/ContactFrm.java
package org.academy.ui.spring3.forms; import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.Email; public class ContactFrm { @NotNull private String firstname; private String lastname; @Email private String email; private String telephone; // Getter and setters omitted for brevity. [...]
}
单元测试
到目前为止,我们的ContactFrm bean没有任何功能,因此我不费心进行单元测试(尽管TDD爱好者会对此表示怀疑)。 但是,现在仅通过添加几个注释,我们就为Bean添加了功能,并且可以进行单元测试(TDD爱好者可以从现在开始感到高兴)。 让我们添加一个单元测试。
文件:/src/test/java/org/academy/ui/spring3/forms/ContactFrmTest.java
package org.academy.ui.spring3.forms; import static org.junit.Assert.*; import java.util.Set; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator; import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class ContactFrmTest { private final static Logger logger = LoggerFactory .getLogger(ContactFrmTest.class); private static Validator validator; @BeforeClass public static void init() { validator = Validation.buildDefaultValidatorFactory().getValidator(); } @Test public void test() { Set<ConstraintViolation<ContactFrm>> errors; ContactFrm contactFrm = new ContactFrm(); errors = validator.validate(contactFrm); printErrors(errors); // We are expecting 1 error here. // Just the NotNull. assertEquals(1, errors.size()); errors.clear(); contactFrm.setFirstname("partha"); errors = validator.validate(contactFrm); printErrors(errors); // We are not expecting any errors here. assertEquals(0, errors.size()); errors.clear(); contactFrm.setEmail("this can not be a valid email"); errors = validator.validate(contactFrm); printErrors(errors); // We are expecting 1 errors here. assertEquals(1, errors.size()); errors.clear(); contactFrm.setEmail("this@mightbevalid.email"); errors = validator.validate(contactFrm); printErrors(errors); // We are not expecting any errors here. assertEquals(0, errors.size()); errors.clear(); } // Utility function to print out errors from validation. private void printErrors(Set<ConstraintViolation<ContactFrm>> errors) { if (errors.size() > 0) { for (ConstraintViolation<ContactFrm> error : errors) { logger.debug(error.getMessage()); } } else { logger.debug("There were no errors to print."); } } }
您会发现我不需要使用任何Hibernate,Spring或JSR特定代码进行单元测试。 它只是一个简单的JUnit。 在我看来,只需添加几个批注就可以在POJO上添加验证,然后我可以使用标准的单元测试框架进行单元测试,而无需进行任何调整,这一事实是一个巨大的进步。 我们才刚刚开始。
单元测试–使用Spring功能。
当然,可以放心的是,我们可以在不依赖Spring的情况下完成完整的验证和单元测试。 但是,如果我们不探索在网站上使用Spring将这些功能整合在一起有多么容易,我们将完全错过本练习的重点。
首先,将所有必需的Spring依赖项添加到我们的项目中,并按照上一篇文章中的说明从公共记录中删除它们。
文件:/pom.xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions>
</dependency> [...] <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> <scope>test</scope> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions>
</dependency>
现在, 如上一篇文章中所述,在单元测试中添加@RunWith和@ContextConfiguration魔术。
文件:/src/test/java/org/academy/ui/spring3/forms/ContactFrmTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class ContactFrmTest { private final static Logger logger = LoggerFactory .getLogger(ContactFrmTest.class); @Autowired private Validator validator; // This is no more required as Spring does it for us. // @BeforeClass // public static void init() { // validator = Validation.buildDefaultValidatorFactory().getValidator(); // }
[省略了其余代码,因为它仍然相同。] 现在,剩下的就是让我们告诉Spring应该在验证器中自动装配什么。 我们使用配置而不是代码来做到这一点。
文件:/src/test/resources/org/academy/ui/spring3/forms/ContactFrmTest-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
</beans>
你们都准备好了。 您现在可以使用“ mvn -e clean install”来运行整个代码并对其进行单元测试。 如果您觉得要求太高,可以使用“ mvn -e网站”创建一个不错HTML网站,该网站将报告代码覆盖率。
:
- JSR 303的主页
- Hibernate Validator主页
- Hibernate Validation首席开发人员访谈– Emmanuel Bernard
- Spring关于验证的官方文档
参考:我们的JCG合作伙伴 Partho在Tech for Enterprise博客上使用Spring 3 MVC处理表单验证
翻译自: https://www.javacodegeeks.com/2012/08/handling-forms-with-spring-3-mvc.html