SpringMVC支持的数据校验是JSR303的标准,通过在bean的属性上打上annotation @NotNull @Max等进行验证。JSR303提供有很多annotation借口,而SpringMVC对于这些验证是使用hibernate的实现,所以我们需要添加hibernate的一个validator包:
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.1.Final</version> </dependency>
hibernate除了JSR303的标准之外还额外提供了其他的验证annotation。
以下是JSR303和hibernate额外支持的验证annotation,这个表是我在IBM官网找到的:
Bean Validation 中的 constraint
表 1. Bean Validation 中内置的 constraint
Constraint | 详细信息 |
---|---|
@Null | 被注释的元素必须为 null |
@NotNull | 被注释的元素必须不为 null |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为 false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
表 2. Hibernate Validator 附加的 constraint
Constraint | 详细信息 |
---|---|
@Email | 被注释的元素必须是电子邮箱地址 |
@Length | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串的必须非空 |
@Range | 被注释的元素必须在合适的范围内 |
贴出一下IBM这篇文章的地址:https://www.ibm.com/developerworks/cn/java/j-lo-jsr303/
如果我们需要在SpringMVC中使用validator需要定义一个bean
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
然后 <mvc:annotation-driven />会自动扫描上下文去发现这个bean。
然后在相应的类属性中绑定相关的验证annotation,下面以User类为例:
@NumberFormat(pattern = "#,###.##") @DecimalMax(value = "2000") @DecimalMin(value = "1000") @NotNull private long balance;
使用Pattern注解可以直接绑定正则表达式:
@Pattern(regexp = "w{6,20}") private String username;
以下是精简过的User类:
public class User{ private int userId; @Pattern(regexp = "w{6,20}") private String username; private String pwd; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date registerDate; @NumberFormat(pattern = "#,###.##") @DecimalMax(value = "2000") @DecimalMin(value = "1000") @NotNull private long balance; }
然后我们可以在controller中进行验证测试:
@RequestMapping("/validator.html") public ModelAndView validatorTest(@Valid User user){ ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("user",user); modelAndView.setViewName("user/main"); return modelAndView; }
注意需要打上@Valid 注解标记需要进行属性验证。
我们尝试去调用这个处理器会发现,只要验证不成功就直接报错:
但是我们并不希望这样,希望如果在发现验证错误的时候跳转至合适的页面,然后发现其错误并提示用户,所以我们需要用到BindingResult类去获得验证的结果,BindingResult的常用方法有如下这些:
List<FieldError> getFieldErrors(); //获得验证失败的字段错误信息
FieldError getFieldError(String var1); //获得相应属性名的验证错误信息
Object getFieldValue(String var1); //获得属性的值
int getErrorCount(); //错误的数量
boolean hasErrors(); //是否存在错误
所以我们可以改成这样:
@RequestMapping("/validator.html") public ModelAndView validatorTest(@Valid User user,BindingResult bindingResult){ ModelAndView modelAndView = new ModelAndView(); if (bindingResult.hasErrors()) { modelAndView.setViewName("user/login"); } else { modelAndView.addObject("user", user); modelAndView.setViewName("user/main"); } return modelAndView; }
然后我们喜欢在页面上显示错误,可以使用SpringMVC提供的form标签库,我们就以登录页面为例,虽然这个页面的业务不太切合实际业务,但是为了方便演示就这样写:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <html> <head> <title>Register</title> </head> <body> <form:form modelAttribute="user" method="post" action="formatter.html"> <form:errors path="*"/> <p>userId:<input type="text" name="userId"/></p> <p>username:<input type="text" name="username"/></p> <p>password:<input type="password" name="password"/></p> <form:errors path="balance"/> <p>balance:<input type="text" name="balance"/></p> <form:errors path="registerDate"/> <p>registerDate:<input type="text" name="registerDate"/></p> <button type="submit">Login</button> </form:form> <img src="<c:url value="/test/test.jpeg" />"/> </body> </html>
注意几个重点即可:
1、使用标签库
2、使用<form:from>的标签然后定义这个提交的modelAttribute名称。
3、将使用标签<form:error path="相应的属性">path属性可以使用通配符*代表输出全部错误。
4、在controller的处理方法中在user对象的入参中打上annotation @ModelAttribute,如下:
@RequestMapping("/formatter.html") public ModelAndView userDetail(@ModelAttribute("user") @Valid User user, BindingResult bindingResult) { ModelAndView modelAndView = new ModelAndView(); if (bindingResult.hasErrors()) { modelAndView.setViewName("user/login"); } else { modelAndView.addObject("user", user); modelAndView.setViewName("user/main"); } return modelAndView; }
然后我们尝试进行方法这个页面,并输入无法通过验证的表单数据:
然后我们希望可以输出的是中文,需要使用国际化,Spring也支持这一操作,只要添加一个bean:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basename="conf/i18n/messages"></bean>
这里bean有一个basename属性,这个属性就是相应的国际化配置文件位置,以下是配置文件的内容[文件位置:conf/i18n/messages.properties]:
DecimalMin.user.balance=请输入大于等于1000的数 DecimalMax.user.balance=请输入小于等于2000的数
可以看到格式是<验证的annotation名称>.<modelAttribute名称>.<验证参数名称>=相应的错误提示。
然后当再次测试时就会发现输出的是中文的了。
最后说两句:其实我们没有必要在Spring中输出这些错误提示,因为一般情况下这些验证都会又前段JS完成,而且现在也有angularJS这种强大的JS框架足够完成验证工作,我们的验证目的是避免有用户没有经过JS验证直接提交参数,从业务安全性去考虑使用服务器验证,而不是为了在界面显示这写验证提示信息。而且现在也比较少直接提交form表单了,基本上大部分都是依赖于ajax。而且angularJS那种单页面应用程序也受到很多开发的青睐,所以说我们最终服务器验证是作为一个最后防线,从而提供安全可靠的服务。
--------------------- 作者:TONY Yan 来源:CSDN 原文:https://blog.csdn.net/tony308001970/article/details/72677969?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!