springMVC如何对输入数据校验实现代码
前言
数据的校验是交互式网站一个不可或缺的功能,数据验证分为客户端验证和服务器端验证。前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验;但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已,服务器端验证是整个应用阻止非法数据的最后防线,通过在应用中编程实现。
客户端验证在大多数情况下,使用 JavaScript 进行客户端验证的步骤如下:
- 编写验证函数。
- 在提交表单的事件中调用验证函数。
- 根据验证函数来判断是否进行表单提交。
服务器端验证对于系统的安全性、完整性、健壮性起到了至关重要的作用。服务器端验证Spring MVC 的 Converter 和 Formatter 在进行类型转换时是将输入数据转换成领域对象的属性值(一种 Java 类型),一旦成功,服务器端验证器就会介入。也就是说,在 Spring MVC 框架中先进行数据类型转换,再进行服务器端验证。在 Spring MVC 框架中可以利用 Spring 自带的验证框架验证数据,也可以利用 JSR 303 实现数据验证。
JSR303/JSR-349,hibernate validation,spring validation之间的关系
JSR303是一项标准,JSR-349是其的升级版本,添加了一些新特性,他们规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,他们位于javax.validation.constraints包下,只提供规范不提供实现。而hibernate validation是对这个规范的实践(不要将hibernate和数据库orm框架联系在一起),他提供了相应的实现,并增加了一些其他校验注解,如@Email,@Length,@Range等等,他们位于org.hibernate.validator.constraints包下。而万能的spring为了给开发者提供便捷,对hibernate validation进行了二次封装,显示校验validated bean时,你可以使用spring validation或者hibernate validation,而spring validation另一个特性,便是其在springmvc模块中添加了自动校验,并将校验信息封装进了特定的类中。这无疑便捷了我们的web开发。本文主要介绍在springmvc中自动校验的机制。
springMVC输入数据校验实现
首先在maven项目中引入相关jar包
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.0</version> </dependency>
开启spring的Valid功能
<mvc:annotation-driven />
创建需要被校验的实体类
import org.hibernate.validator.constraints.Length; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; //与数据库中users对应 public class UserInfo { private int id; @Pattern(regexp = Constants.USERNAMR, message = Constants.USERNAMRERROR) private String username; @NotBlank(message = Constants.NAMEERROR) private String name; @Email(message = Constants.EMAILERROR) private String email; @Length(min = 6, max = 16, message = Constants.PASSWORDERROR) private String password; @Pattern(regexp = Constants.PHONE, message = Constants.PHONEERROR) private String phoneNum; //...get/set方法 }
这些注解还是比较浅显易懂的,字段上的注解名称即可推断出校验内容,每一个注解都包含了message字段,用于校验失败时作为提示信息,特殊的校验注解,如Pattern(正则校验),还可以自己添加正则表达式。
JSR提供的校验注解: @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(regex=,flag=) 被注释的元素必须符合指定的正则表达式 Hibernate Validator提供的校验注解: @NotBlank(message =) 验证字符串非null,且长度必须大于0 @Email 被注释的元素必须是电子邮箱地址 @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内 @NotEmpty 被注释的字符串的必须非空 @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
我们将message错误信息放在一个Constants类中
public class Constants { public static final String PHONE = "^1[3|4|5|7|8][0-9]{9}$"; public static final String USERNAMR = "^NH[0-9]{7}$"; public static final String NAMEERROR = "用户名不能为空"; public static final String PHONEERROR = "请输入一个正确的电话号码"; public static final String EMAILERROR= "请输入一个正确的邮箱地址"; public static final String USERNAMRERROR = "请输入一个正确的用户编号"; public static final String PASSWORDERROR = "密码的长度为6~16位"; public static final String DATENOTNULL = "日期非空"; }
在@Controller中校验数据
@Valid 和 BindingResult 是一一对应的,如果有多个@Valid,那么每个@Valid后面跟着的BindingResult就是这个@Valid的验证结果,顺序不能乱
//用户添加 @RequestMapping("/save.do") //@PreAuthorize("authentication.principal.username == 'NH1905001'") @PreAuthorize("hasRole('ROLE_ADMIN')") public String save(@Valid @ModelAttribute(value="userInfo") UserInfo userInfo, BindingResult result) throws Exception { if(result.hasErrors()){ List<FieldError> errors = result.getFieldErrors(); for (FieldError fieldError : errors) { System.out.println("错误消息提示:" + fieldError.getDefaultMessage()); System.out.println("错误的字段是?" + fieldError.getField()); System.out.println(fieldError); System.out.println("------------------------"); } return "user-add"; }else { userService.save(userInfo); return "redirect:findAll.do"; } }
错误对象的代表者是 Errors 接口,存储和暴露关于数据绑定错误和验证错误相关信息的接口,提供了相关存储和获取错误消息的方法,具有如下几个实现类:
- BindingResult:代表数据绑定的结果,继承了 Errors 接口;
- BindException:代表数据绑定的异常,它继承 Exception,并实现了BindingResult,这是内部使用的错误对象;
Errors接口中的方法
void addAllErrors(Errors var1); boolean hasErrors(); int getErrorCount(); List<ObjectError> getAllErrors(); boolean hasGlobalErrors(); int getGlobalErrorCount(); List<ObjectError> getGlobalErrors(); @Nullable ObjectError getGlobalError(); boolean hasFieldErrors(); int getFieldErrorCount(); List<FieldError> getFieldErrors(); @Nullable FieldError getFieldError(); boolean hasFieldErrors(String var1); int getFieldErrorCount(String var1); List<FieldError> getFieldErrors(String var1); @Nullable FieldError getFieldError(String var1); @Nullable Object getFieldValue(String var1); @Nullable Class<?> getFieldType(String var1);
根据方法名字就可以知道方法的作用
输出的校验信息
错误消息提示:用户名不能为空 错误的字段是?name Field error in object 'userInfo' on field 'name': rejected value []; codes [NotBlank.userInfo.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.name,name]; arguments []; default message [name]]; default message [用户名不能为空] ------------------------ 错误消息提示:请输入一个正确的邮箱地址 错误的字段是?email Field error in object 'userInfo' on field 'email': rejected value [111]; codes [Email.userInfo.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.email,email]; arguments []; default message [email],[Ljavax.validation.constraints.Pattern$Flag;@462d227d,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@2a8eb300]; default message [请输入一个正确的邮箱地址] ------------------------ 错误消息提示:请输入一个正确的用户编号 错误的字段是?username Field error in object 'userInfo' on field 'username': rejected value []; codes [Pattern.userInfo.username,Pattern.username,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.username,username]; arguments []; default message [username],[Ljavax.validation.constraints.Pattern$Flag;@63f401ef,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@72436888]; default message [请输入一个正确的用户编号] ------------------------ 错误消息提示:请输入一个正确的电话号码 错误的字段是?phoneNum Field error in object 'userInfo' on field 'phoneNum': rejected value []; codes [Pattern.userInfo.phoneNum,Pattern.phoneNum,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.phoneNum,phoneNum]; arguments []; default message [phoneNum],[Ljavax.validation.constraints.Pattern$Flag;@63f401ef,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute@5d528277]; default message [请输入一个正确的电话号码] ------------------------ 错误消息提示:密码的长度为6~16位 错误的字段是?password Field error in object 'userInfo' on field 'password': rejected value []; codes [Length.userInfo.password,Length.password,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.password,password]; arguments []; default message [password],16,6]; default message [密码的长度为6~16位] ------------------------
数据校验错误信息回显
controller处理方法的形参pojo定义的对象与此类型同名 ,首字母小写,此时spring能自动将该对象名为key,此对象作为value,保存到request中。当然,也可以通过@Valid @ModelAttribute(value=“userInfo”) UserInfo userInfo自定义名称。
modelAttribute="userInfo"中userInfo与controller方法的形参pojo定义的对象同名 。
注意页面需要引入
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<form:form modelAttribute="userInfo" action="${pageContext.request.contextPath}/user/save.do" method="post"> <!-- 正文区域 --> <section class="content"> <!--产品信息--> <div class="panel panel-default"> <div class="panel-heading">用户信息</div> <div class="row data-type"> <div class="col-md-2 title">用户名称</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="username" placeholder="用户名称" value=""> </div> <div class="col-md-6 data"> <form:errors path="username" cssStyle="color:red"/> </div> <div class="col-md-2 title">姓名</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="name" placeholder="姓名" value=""> </div> <div class="col-md-6 data"> <form:errors path="name" cssStyle="color:red"/> </div> <div class="col-md-2 title">密码</div> <div class="col-md-4 data"> <input type="password" class="form-control" name="password" placeholder="密码" value=""> </div> <div class="col-md-6 data"> <form:errors path="password" cssStyle="color:red"/> </div> <div class="col-md-2 title">邮箱</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="email" placeholder="邮箱" value=""> </div> <div class="col-md-6 data"> <form:errors path="email" cssStyle="color:red"/> </div> <div class="col-md-2 title">联系电话</div> <div class="col-md-4 data"> <input type="text" class="form-control" name="phoneNum" placeholder="联系电话" value=""> </div> <div class="col-md-6 data"> <form:errors path="phoneNum" cssStyle="color:red"/> </div> <div class="col-md-2 title">用户状态</div> <div class="col-md-4 data"> <select class="form-control select2" style="width: 100%" name="status"> <option value="0" selected="selected">关闭</option> <option value="1">开启</option> </select> </div> </div> </div> <!--订单信息/--> <!--工具栏--> <div class="box-tools text-center"> <button type="submit" class="btn bg-maroon">保存</button> <button type="button" class="btn bg-default" onclick="history.back(-1);">返回</button> </div> <!--工具栏/--> </section> <!-- 正文区域 /--> </form:form>
数据校验错误信息回显方法2
通过model方式在request中存储指定key与value,如下:
//改变客户到公海 @RequestMapping("/transformClients.do") public String transformClientsById(@Valid @ModelAttribute("publicSea") PublicSea publicSea, BindingResult result, Model model) throws Exception { if(result.hasErrors()){ model.addAttribute("failueError",failueError.getDefaultMessage()); model.addAttribute("failueDesc",publicSea.getFailueDesc()); model.addAttribute("cNumber",publicSea.getcNumber()); return "publicSea-change"; }else { return "redirect:findAll.do"; } }
客户端代码
<form action="${pageContext.request.contextPath}/clients/transformClients.do" method="post"> <!-- 正文区域 --> <section class="content"> <!--产品信息--> <div class="panel panel-default"> <div class="panel-heading">跟踪失败原因</div> <div class="row data-type"> <input type="text" style="display:none" name="cNumber" placeholder="线索Id" value="${cNumber}"> <div class="col-md-2 title rowHeight2x">跟踪失败描述</div> <div class="col-md-10 data rowHeight2x"> <textarea class="form-control" rows="3" placeholder="跟踪失败描述" name="failueDesc">${failueDesc}</textarea> </div> <div class="col-md-12 data rowHeight2x"> <label>${failueError}</label> </div> </div> </div> <!--订单信息/--> <!--工具栏--> <div class="box-tools text-center"> <button type="submit" class="btn bg-maroon">保存</button> <button type="button" class="btn bg-default" onclick="history.back(-1);">返回</button> </div> <!--工具栏/--> </section> <!-- 正文区域 /--> </form>
分组校验
自定义校验
手动校验
基于方法校验
到此这篇关于springMVC如何对输入数据校验的文章就介绍到这了,更多相关springMVC数据校验内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!