admin管理员组文章数量:1794759
Spring MVC代码实例系列
超级通道 :Spring MVC代码实例系列-绪论
本章主要记录,如何在Spring MVC中添加Hibernate-Validator以及自定义校验注解。本章主要涉及的技术点有:
##1.目录结构
src \\---main \\---java | \\---pers | \\---hanchao | \\---hespringmvc | \\---validation | \\---InsertGroup.java | \\---UpdateGroup.java | \\---Student.java | \\---JsonResult.java | \\---StudentManageController.java \\---webapp \\---message.properties \\---webapp \\---validation | \\---student.jsp \\---WEB-INF | \\---spring-mvc-servlet.xml | \\---web.xml \\---index.jsp##2.pom.xml引入相关jar包
<hibernate-validator.version>5.4.1.Final</hibernate-validator.version> <!-- 验证的jar --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate-validator.version}</version> </dependency>##3.spring-mvc-servlet.xml配置校验驱动
<!--注册校验驱动--> <mvc:annotation-driven validator="validator"/> <!--校验工厂--> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> <property name="validationMessageSource" ref="messageSource"/> </bean> <!--validation message 校验消--> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="message"/> <property name="defaultEncoding" value="utf-8"/> <property name="useCodeAsDefaultMessage" value="false"/> <property name="cacheSeconds" value="60"/> </bean>##4.Student.java设置校验规则 先看两个分组接口
package pers.hanchao.hespringmvc.validation; public interface InsertGroup {} package pers.hanchao.hespringmvc.validation; public interface UpdateGroup {}再看被校验的实体类:
package pers.hanchao.hespringmvc.validation; import org.hibernate.validator.constraints.CreditCardNumber; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Range; import org.hibernate.validator.constraints.URL; import pers.hanchao.hespringmvc.validation.custom.annotation.CustomLength; import javax.validation.GroupSequence; import javax.validation.constraints.*; import java.util.Date; /** * <p>javax.validation校验、hibernate.validator校验、分组校验、@GroupSequence分组顺序校验</p> * @author hanchao 2018/1/20 14:58 **/ @GroupSequence({InsertGroup.class,UpdateGroup.class,Student.class}) public class Student { /javax.validation/ //添加学生时,id必为空;修改学生时,id必须有值 @Null(groups = InsertGroup.class,message = "{Null.student.id}") @NotNull(groups = UpdateGroup.class,message = "{NotNull.student.id}") private String id; @Size(min = 2,max = 16,message = "{Size.student.name}",groups = {InsertGroup.class,UpdateGroup.class}) private String name;//名字 @AssertTrue(groups = InsertGroup.class, message = "{AssertTrue.student.newRegister}") @AssertFalse(groups = UpdateGroup.class, message = "{AssertTrue.student.newRegister}") private boolean newRegister;//是否新注册 @Max(value = 100, message = "{Max.student.score}",groups = {InsertGroup.class,UpdateGroup.class}) @Min(value = 0, message = "{Min.student.score}",groups = {InsertGroup.class,UpdateGroup.class}) private int score;//分数[0-100] @DecimalMax(value = "30",inclusive = true, message = "{student.age}",groups = {InsertGroup.class,UpdateGroup.class}) @DecimalMin(value = "19",inclusive = false, message = "{student.age}",groups = {InsertGroup.class,UpdateGroup.class}) private String age;//年龄范围[20-30] @Digits(integer = 3,fraction = 2, message = "{Digits.student.weight}",groups = {InsertGroup.class,UpdateGroup.class}) private float weight;//体重格式[xxx.yy] @Past(message = "{Past.student.entrance}",groups = {InsertGroup.class,UpdateGroup.class}) private Date entrance;//入学时间 @Future(message = "{Future.student.graduation}",groups = {InsertGroup.class,UpdateGroup.class}) private Date graduation;//毕业时间 @Pattern(regexp = "^S2018[0-9]{4}$",flags = Pattern.Flag.CASE_INSENSITIVE, message = "{Pattern.student.number}",groups = {InsertGroup.class,UpdateGroup.class}) private String number;//学号形式 S20180000-S20189999 大小写敏感 /hibernate.validator/ @URL(message = "{URL.student.blog}",groups = {InsertGroup.class,UpdateGroup.class}) private String blog;//个人学生主页 @Length(min = 1000,max = 5000 ,message = "{Length.student.bonus}",groups = {InsertGroup.class,UpdateGroup.class}) private String tuition;//学费 @Range(min = 2000L,max = 4000L,message = "{Rang.student.bonus}",groups = {InsertGroup.class,UpdateGroup.class}) private String bonus;//奖金 @CreditCardNumber(message = "{CreditCardNumber}",groups = {InsertGroup.class,UpdateGroup.class}) private String creditCard;//银行账号 //toString() //setter and getter }校验规则说明:
@URL、@Length、@Range、 @CreditCardNumber属于hibernate.validator,其他的都属于javax.validation。
groups = InsertGroup.class表名此字段只在InsertGroup分组被校验。
groups = {InsertGroup.class,UpdateGroup.class}表面此字段在InsertGroup和UpdateGroup分组都被校验。
一个字段可以被多种校验规则注解,如
@Max(value = 100, message = "{Max.student.score}",groups = {InsertGroup.class,UpdateGroup.class}) @Min(value = 0, message = "{Min.student.score}",groups = {InsertGroup.class,UpdateGroup.class}) private int score;//分数[0-100]@GroupSequence({InsertGroup.class,UpdateGroup.class,Student.class})表明了InsertGroup和UpdateGroup分组的校验顺序,即:如果InsertGroup分组的校验有错误,则不再进行UpdateGroup分组的校验,直接返回。
@GroupSequence({InsertGroup.class,UpdateGroup.class,Student.class})一定要注意不要忘了把当前实体类Student.class写入其中。
message = "{Length.student.bonus}""是通过message.properties读取校验提示信的方式。
多种校验规则可以共用同样的校验提示信,如:
@DecimalMax(value = "30",inclusive = true, message = "{student.age}",groups = {InsertGroup.class,UpdateGroup.class}) @DecimalMin(value = "19",inclusive = false, message = "{student.age}",groups = {InsertGroup.class,UpdateGroup.class}) private String age;//年龄范围[20-30]##5.message.properties设置校验提示信
Null.student.id = 学生id必须为空! NotNull.student.id = 学生id必须不为空! Size.student.name = 姓名应该在2至16个汉字之间! CustomLength.student.name = 姓名应该在2至16个字符之间! AssertTrue.student.newRegister = 必须是新注册的学生! AssertFalse.student.newRegister = 必须是已经注册的学生! Max.student.score = 分数必须小于等于100! Min.student.score = 分数必须大于等于0! student.age = 年龄必须处于20~30之间! Digits.student.weight = 体重必须是xxx.yy的格式,如101.52! Past.student.entrance = 入学时间必须早于今天! Future.student.graduation = 毕业时间必须晚于今天! Pattern.student.number = 学号格式必须位于S20180000-S20189999之间! URL.student.blog = 学生个人主页必须错误! Length.student.bonus = 学费必须在1000-5000之间! Rang.student.bonus = 奖金必须在2000-4000之间! CreditCardNumber = 银行账号不合法!校验提示信说明:
##6.StudentManageController.java控制类对实体进行校验
package pers.hanchao.hespringmvc.validation; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; /** * <p>简单的bean validation和hibernate validator的例子</p> * @author hanchao 2018/1/20 14:47 **/ @Controller @RequestMapping("validation") public class StudentManageController { /** * <p>注册学生信</p> * @author hanchao 2018/1/20 14:47 **/ @PostMapping("/insert") @ResponseBody public JsonResult insert(@Validated(InsertGroup.class) @RequestBody Student student, BindingResult bindingResult){ JsonResult jsonResult = new JsonResult(); validate(bindingResult, jsonResult); System.out.println(jsonResult.toString()); return jsonResult; } /** * <p>修改学生信</p> * @author hanchao 2018/1/20 14:47 **/ @PostMapping("/update") @ResponseBody public JsonResult update(@Validated(UpdateGroup.class) @RequestBody Student student, BindingResult bindingResult){ JsonResult jsonResult = new JsonResult(); validate(bindingResult, jsonResult); System.out.println(jsonResult.toString()); return jsonResult; } /** * <p>对bindingResult进行校验</p> * @author hanchao 2018/1/20 14:46 **/ private void validate(BindingResult bindingResult, JsonResult jsonResult) { if (bindingResult.hasErrors()){ StringBuffer errors = new StringBuffer(); List<ObjectError> allErrors = bindingResult.getAllErrors(); for (ObjectError objectError : allErrors){ errors.append(objectError.getDefaultMessage() + "<br/>"); } jsonResult.setCodeAndMessage("0",errors.toString()); } } }说明:
##7.student.jsp页面
<%-- Created by IntelliJ IDEA. User: hanchao Date: 2018/1/17 Time: 21:14 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>学生信管理页面</title> <script type="text/javascript" src="../static/jquery-3.2.1.min.js"></script> <style> table, td, th{border:1px solid green;background-color: lemonchiffon;text-align:center} </style> </head> <body> <p id="errorString"/> <form> <table> <tr> <td><label>姓名</label></td> <td><input name="name" type="text"></td> </tr> <tr> <td><label>是否新注册用户</label></td> <td><input name="newRegister" type="text"></td> </tr> <tr> <td><label>学分</label></td> <td><input name="score" type="text"></td> </tr> <tr> <td><label>年龄</label></td> <td><input name="age" type="text"></td> </tr> <tr> <td><label>姓名</label></td> <td><input name="name" type="text"></td> </tr> <tr> <td><label>体重(kg)</label></td> <td><input name="weight" type="text"></td> </tr> <tr> <td><label>入学时间</label></td> <td><input name="entrance" type="text"></td> </tr> <tr> <td><label>毕业时间</label></td> <td><input name="graduation" type="text"></td> </tr> <tr> <td><label>学号</label></td> <td><input name="number" type="text"></td> </tr> <tr> <td><label>个人学生主页</label></td> <td><input name="blog" type="text"></td> </tr> <tr> <td><label>学费</label></td> <td><input name="tuition" type="text"></td> </tr> <tr> <td><label>奖金</label></td> <td><input name="bonus" type="text"></td> </tr> <tr> <td><label>银行卡号</label></td> <td><input name="creditCard" type="text"></td> </tr> <tr> <td><input type="button" value="注册" οnclick="insert()"/></td> <td><input type="button" value="查询" οnclick="update()"/></td> </tr> </table> </form> </body> <script type="text/javascript"> //插入一条学生信 function insert() { $.ajax({ type:"POST", url:"/validation/insert", data:JSON.stringify({ name:$('input[name="name"]').val(), newRegister:$('input[name="newRegister"]').val(), score:$('input[name="score"]').val(), age:$('input[name="age"]').val(), weight:$('input[name="weight"]').val(), entrance:$('input[name="entrance"]').val(), graduation:$('input[name="graduation"]').val(), number:$('input[name="number"]').val(), reward:$('input[name="reward"]').val(), opinion:$('input[name="opinion"]').val(), email:$('input[name="email"]').val(), blog:$('input[name="blog"]').val(), tuition:$('input[name="tuition"]').val(), bonus:$('input[name="bonus"]').val(), creditCard:$('input[name="creditCard"]').val() }), contentType:'application/json;charset=utf-8', dataType:'json', success:function (jsonResult) { console.log(jsonResult); $("#errorString").html(jsonResult.message); } }) } //更新学生信 function update() { $.ajax({ type:"POST", url:"/validation/update", data:JSON.stringify({ name:$('input[name="name"]').val(), newRegister:$('input[name="newRegister"]').val(), score:$('input[name="score"]').val(), age:$('input[name="age"]').val(), weight:$('input[name="weight"]').val(), entrance:$('input[name="entrance"]').val(), graduation:$('input[name="graduation"]').val(), number:$('input[name="number"]').val(), reward:$('input[name="reward"]').val(), opinion:$('input[name="opinion"]').val(), email:$('input[name="email"]').val(), blog:$('input[name="blog"]').val(), tuition:$('input[name="tuition"]').val(), bonus:$('input[name="bonus"]').val(), creditCard:$('input[name="creditCard"]').val() }), contentType:'application/json;charset=utf-8', dataType:'json', success:function (jsonResult) { console.log(jsonResult); $("#errorString").html(jsonResult.message); } }) } </script> </html>###8.result
##9.自定义注解校验 场景(假设情况…):
- @Length校验的是输入字符的个数,例如你好的长度是2
- 如果name字段的校验规则为(min = 2,max = 4),在mysql中name字段的长度设计为varchar(4)。
- 这种校验应用在mysql 5.0以后是没问题的,因为Mysql 5.0以后varchar存储的就是字符数,name字段最多可以存储4个汉字。
- 但是这种校验应用在Mysql 4.0数据库中是有问题的,因为Mysql 4.0存储的是字节数,name组多存储1个UTF-8汉字或者2个GBG汉字。
- 如果前台传过来的name=张三丰,虽然校验不报错,但是插入mysql时,肯定会报错。
这里引入了自定义校验注解的概念,需要设计一个新的注解实现以下功能:
为了完成这个自定义注解,下面分两步进行: 目录结构(续接之前的目录结构):
\\---validation \\---custom \\---annotation \\---CustomLength.java \\---validator \\---CustomLengthValidator.java###9.1.CustomLength.java自定义校验注解
package pers.hanchao.hespringmvc.validation.custom.annotation; import pers.hanchao.hespringmvc.validation.custom.validator.CustomLengthValidator; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * <p>校验字符串长度,中文按照charset进行计算</p> * @author hanchao 2018/1/20 15:40 **/ @Target( { METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = CustomLengthValidator.class) @Documented public @interface CustomLength { long min() default 0; long max() default Integer.MAX_VALUE; String charset() default "gbk"; String message() default "length must be between {min} and {max}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }###9.2.CustomLengthValidator自定义校验规则类
package pers.hanchao.hespringmvc.validation.custom.validator; import java.io.UnsupportedEncodingException; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import org.hibernate.validator.internal.util.logging.Log; import org.hibernate.validator.internal.util.logging.LoggerFactory; import pers.hanchao.hespringmvc.validation.custom.annotation.CustomLength; /** * <p>自定义校验规则诶</p> * @author hanchao 2018/1/20 17:04 **/ public class CustomLengthValidator implements ConstraintValidator<CustomLength, String> { private static final Log log = LoggerFactory.make(); private long min; private long max; private String charset; @Override public void initialize(CustomLength parameters) { //do nothing this.min = parameters.min(); this.max = parameters.max(); this.charset = parameters.charset(); validateParameters(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if(null == value){ value = ""; } long length = 0; try { length = ((String)value).getBytes(charset).length; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } boolean result = (length >= min) && (length <= max); log.info("CustomLength.validator:[value:" + (String)value + ",min:" + min + ",max:" + max + ",length:" + length + "],result:" + result); return (length >= min) && (length <= max); } private void validateParameters() { if (this.min < 0) { throw log.getMinCannotBeNegativeException(); } if (this.max < 0) { throw log.getMaxCannotBeNegativeException(); } if (this.max < this.min) throw log.getLengthCannotBeNegativeException(); } }以上,自定义校验注解CustomLenght定义完毕,下面进行实践。 ###9.3.修改Student.java 为了方便演示,注释掉了其他校验
// @Size(min = 2,max = 4,message = "{Size.student.name}",groups = {InsertGroup.class,UpdateGroup.class}) @CustomLength(min = 2,max = 4,charset = "utf-8",message = "{CustomLength.student.name}",groups = {InsertGroup.class,UpdateGroup.class}) private String name;//名字##9.4.修改message.properties 添加提示信
CustomLength.student.name = 姓名应该在2至4个字节之间!###9.5.result
版权声明:本文标题:Spring MVC代码实例系列 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686612429a86081.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论