zoukankan      html  css  js  c++  java
  • SpringMVC数据校验

    29.1 类型转换

    form表单提交的数据都是String类型,例如在Servlet中我们是通过String filedName=request.getParameter(“…”)方法来获取相应的字段值。如果需要的是int类型,在 Servlet中我们也必须进行类型转换,如int age=Integer.parseInt(…)。但是在SpringMVC中,我们并不需要关心类型的转换,例如:

    复制
    1. @RequestMapping(value = "/requestWithREST/{id}",
    2. method = RequestMethod.POST)
    3. public String requestWithRestAdd(@PathVariable("id") Integer id)
    4. {
    5. System.out.println("增加时需要的id:" + id);
    6. return "success";
    7. }

    SpringMVC可以直接将form表单中的id字段值转为Integer类型,并传递给requestWithRestAdd()方法中的参数id。这是因为SpringMVC中存在着一些内置的类型转换器,可以自动实现大多数的类型转换。

    除此以外,我们还可以根据需求来自定义类型转换器。例如,现在需要将form表单传来的字符串1-张三-23解析成学号为1、姓名为张三、年龄为23,并将这些值封装到一个学生对象之中,也就是说需要将字符串1-张三-23转换为Student对象类型。

    以下是具体的实现步骤:

    ①创建自定义类型转换器

    创建基于SpringMVC的自定义类型转换器,需要新建一个类,并实现SpringMVC提供的Converter接口,如下,

    自定义类型转换器,用于将字符串转换为Student类型 : StudentConverter.java

    复制
    1. import org.springframework.core.convert.converter.Converter;
    2. public class StudentConverter
    3. implements Converter<String, Student>
    4. {
    5. @Override
    6. public Student convert(String source)
    7. {
    8. //source值就是前端form传来的"1-张三-23"
    9. if (source != null)
    10. {
    11. //解析出source中的学号、姓名、年龄
    12. String[] vals = source.split("-");
    13. int stuNo = Integer.parseInt(vals[0]);
    14. String stuName = vals[1];
    15. int stuAge = Integer.parseInt(vals[2]);
    16. //将解析出的学号、姓名、年龄封装到Student对象之中
    17. Student student = new Student();
    18. student.setStuNo(stuNo);
    19. student.setStuAge(stuAge);
    20. student.setStuName(stuName);
    21. return student;
    22. }
    23. return null;
    24. }
    25. }

    ②注册自定义类型转换器

    springmvc.xml:将自定义的类型转换器注册到SpringMVC之中,共三步

    复制
    1. <beans>
    2. <!-- ①将自定义的类型转换器加入SpringIOC容器 -->
    3. <bean id="studentConverter"
    4. class="org.lanqiao.converter.StudentConverter"></bean>
    5. <!-- ②将自定义的类型转换器注册到 SpringMVC提供的
    6. ConversionServiceFactoryBean中-->
    7. <bean id="conversionService"
    8. class="org.springframework.context
    9. .support.ConversionServiceFactoryBean">
    10. <property name="converters">
    11. <set>
    12. <ref bean="studentConverter"/>
    13. </set>
    14. </property>
    15. </bean>
    16. <!--③ 将自定义的类型转换器所在的ConversionServiceFactoryBean,
    17. 注册到annotation-driven之中 -->
    18. <mvc:annotation-driven
    19. conversion-service="conversionService">
    20. </mvc:annotation-driven>
    21. </beans>

    至此就完成了自定义类型转化器的编写及配置工作。以下,对配置完成的类型转换器StudentConverter进行测试。

    ③请求处理方法

    FirstSpringDemo.java

    复制
    1. @Controller
    2. @RequestMapping(value = "/FirstSpringDemo")
    3. public class FirstSpringDemo
    4. {
    5. @RequestMapping("/testConversionServiceConverer")
    6. public String testConversionServiceConverer
    7. (@RequestParam("studentInfo") Student student)
    8. {
    9. System.out.println("学号:"+student.getStuNo()
    10. +",姓名:"+student.getStuName()+",年龄:"
    11. +student.getStuAge());
    12. return "success";
    13. }
    14. }

    ④测试

    index.jsp

    复制
    1. <form action="FirstSpringDemo/testConversionServiceConverer">
    2. 学生信息: <input type="text" name="studentInfo"/>
    3. <input type="submit" value="增加"/>
    4. </form>

    输入学生信息“1-张三-23”,如图,

    图29-01

    点击“增加”后,可在控制台得到以下结果:

    图29-02

    通过自定义类型转换器StudentConverter,成功的将前端传来的字符串1-张三-23转为了请求处理方法参数中的Student类型。

    29.2 格式化数据

    有时候需要对于日期、数字等类型进行格式化操作,例如:规定日期的格式必须为yyyy-MM-dd。

    使用SpringMVC实现数据的格式化,只需要简单的两步操作:

    在需要格式化的属性前加上格式化注解,如@DateTimeFormat;

    在springmvc.xml中加入<mvc:annotation-driven></mvc:annotation-driven>和SpringMVC提供的FormattingConversionServiceFactoryBean,如下:

    springmvc.xml

    复制
    1. <beans>
    2. <bean id="conversionService"
    3. class="org.springframework.format.
    4. support.FormattingConversionServiceFactoryBean">
    5. </bean>
    6. </beans>

    说明:

    通过类的名字可知,FormattingConversionServiceFactoryBean既提供了格式化需要的Formatting,又提供了类型转换需要的Conversion。因此,之前配置类型转换时使用的ConversionServiceFactoryBean,也可以使用FormattingConversionServiceFactoryBean来替代。也就是说,使用以下配置既可以实现自定义的类型转换,也可以实现格式化数据:

    复制
    1. <bean id="conversionService"
    2. class="org.springframework.
    3. format.support.FormattingConversionServiceFactoryBean">
    4. <property name="converters">
    5. <set>
    6. <ref bean="studentConverter"/>
    7. </set>
    8. </property>
    9. </bean>

    例如,以下指定Date类型的birthday属性的输入格式必须为yyyy-MM-dd。

    Student.java

    复制
    1. public class Student
    2. {
    3. private int stuNo;
    4. private String stuName;
    5. @DateTimeFormat(pattern="yyyy-MM-dd")
    6. private Date birthday ;
    7. //setter、getter
    8. }

    通过注解@DateTimeFormat(pattern="yyyy-MM-dd")指定birthday属性的输入格式必须为yyyy-MM-dd。以下是测试格式化的操作:

    请求处理方法:FirstSpringDemo.java

    复制
    1. @Controller
    2. @RequestMapping(value = "/FirstSpringDemo")
    3. public class FirstSpringDemo
    4. {
    5. @RequestMapping("/testDateTimeFormat")
    6. public String testDateTimeFormat(Student student){
    7. System.out.println("学号:"+student.getStuNo()
    8. +",姓名:"+student.getStuName()+",生日"
    9. +student.getBirthday());
    10. return "success";
    11. }
    12. }

    请求页index.jsp

    复制
    1. <form action="FirstSpringDemo/testDateTimeFormat">
    2. 姓名:<input type="text" name="stuName"/><br>
    3. 年龄:<input type="text" name="stuAge"/><br>
    4. 生日:<input type="text" name="birthday"/><br>
    5. <input type="submit" value="提交"/>
    6. </form>

    如果表单中输入的日期格式符合“yyyy-MM-dd”,如“2015-05-16”,如图,

    图29-03

    就会将日期赋值给birthday属性,并可以在控制台得到输出结果:

    图29-04

    而如果输入的日期格式不符合“yyyy-MM-dd”格式,如输入“2015年05月16日”,点击“提交”后JSP页面就会显示HTTP Status 400,如图,

    图29-05

    但控制台并没有任何异常信息的输出,很不利于开发人员排查错误。为此,我们可以给请求处理方法加入一个BindingResult类型的参数,此参数就包含了格式化数据失败时的异常信息,如下:

    FirstSpringDemo.java

    复制
    1. @Controller
    2. @RequestMapping(value = "/FirstSpringDemo")
    3. public class FirstSpringDemo
    4. {
    5. @RequestMapping("/testDateTimeFormat")
    6. public String testDateTimeFormat(Student student,
    7. BindingResult result)
    8. {
    9. //如果有错误信息
    10. if (result.getErrorCount() > 0)
    11. {
    12. //循环遍历所有错误信息
    13. for (FieldError error : result.getFieldErrors())
    14. {
    15. System.out.println(error.getField() + ":"
    16. + error.getDefaultMessage());
    17. }
    18. }
    19. return "success";
    20. }
    21. }

    此时再输入不符合格式的日期“2015年05月16日”,就能既在JSP页面显示HTTP Status 400异常,又能在控制台得到具体的异常信息,如下:

    控制台输出:

    复制
    1. birthday:Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property 'birthday'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@javax.validation.constraints.Past @org.springframework.format.annotation.DateTimeFormat java.util.Date] for value '2015年05月16日';
    2. nested exception is java.lang.IllegalArgumentException:
    3. Unable to parse '2015年05月16日'

    除了用于格式化日期的注解@DateTimeFormat以外,SpringMVC还提供了用于格式化数字的注解@NumberFormat,例如,可以使用@NumberFormat指定以下int类型的属性count的输入格式为“#,###”(其中#代表数字)

    复制
    1. public class ClassName
    2. {
    3. @NumberFormat(pattern="#,###")
    4. private int count;
    5. //setter、getter
    6. }

    通过form表单中的input字段来映射count属性时,合法输入:如1,234;不合法的输入:如12,34。

    29.3 数据校验

    除了使用JS、正则表达式以外,还可以使用JSR 303-Bean Validation(简称JSR 303)来实现数据的校验。例如:用户名不能为空,email必须是一个合法地址,某个日期时间必须在当前时间之前等众多校验,都可以使用JSR 303-Bean Validation非常方便的实现。

    JSR 303通过在实体类的属性上标注类@NotNull、@Max等注解指定校验规则,并通过与注解相对应的验证接口(JSR303内置提供)对属性值进行验证。

    JSR 303提供的标准注解如下:

    注解 简介
    @Null 被注释的元素必须为 null。
    @NotNull 被注释的元素必须不为 null。
    @AssertTrue 被注释的元素必须为 true。
    @AssertFalse 被注释的元素必须为 false。
    @Min(value) 被注释的元素必须是一个数字,其值必须大于或等于value。
    @Max(value) 被注释的元素必须是一个数字,其值必须小于或等于value。
    @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于或等于value。
    @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于或等于value。
    @Size(max, min) 被注释的元素的取值范围必须是介于min和max之间。
    @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内。
    @Past 被注释的元素必须是一个过去的日期。
    @Future 被注释的元素必须是一个将来的日期。
    @Pattern(value) 被注释的元素必须符合指定的正则表达式。

    Hibernate Validator 是JSR 303的扩展。Hibernate Validator 提供了 JSR 303中所有内置的注解,以及自身扩展的4个注解,如下:

    注解 简介
    @Email 被注释的元素值必须是合法的电子邮箱地址。
    @Length 被注释的字符串的长度必须在指定的范围内。
    @NotEmpty 被注释的字符串的必须非空。
    @Range 被注释的元素必须在合适的范围内。

    以下是使用Spring整合Hibernate Validator实现数据校验的步骤:

    ①导入JAR包:

    Spring整合Hibernate Validator共需要导入以下5个JAR包:

    hibernate-validator-5.0.0.CR2.jar classmate-0.8.0.jar jboss-logging-3.1.1.GA.jar
    validation-api-1.1.0.CR1.jar hibernate-validator-annotation-processor-5.0.0.CR2.jar

    ②加入<mvc:annotation-driven/>

    Spring提供了一个LocalValidatorFactoryBean类,这个类既实现了Spring的校验接口,也实现了JSR303的校验接口。因此,Spring整合Hibernate Validator时,需要在Spring容器中定义了一个LocalValidatorFactoryBean。方便的是,<mvc:annotation-driven/>就会自动给Spring容器装配一个LocalValidatorFactoryBean,因此只需要在springmvc.xml中配置上<mvc:annotation-driven/>即可。

    ③使用JSR303或Hibernate Validator校验注解,标识实体类的属性:

    本次使用JSR303提供的@Past注解,以及Hibernate Validator提供的@Email注解进行输入校验,如下:

    Student.java

    复制
    1. public class Student
    2. {
    3. @Past
    4. @DateTimeFormat(pattern="yyyy-MM-dd")
    5. private Date birthday ;
    6. @Email
    7. private String email;
    8. //setter、getter
    9. }

    规定birthday必须在当天之前、email必须符合邮箱格式。

    ④在请求处理方法对应的实体类参数前,增加@Valid注解

    SpringMVC会对标有@Valid注解的实体类参数进行校验,并且可以通过BindingResult类型的参数来存储校验失败时的信息,如下:

    请求处理类:FirstSpringDemo.java

    复制
    1. @Controller
    2. @RequestMapping(value = "/FirstSpringDemo")
    3. public class FirstSpringDemo
    4. {
    5. @RequestMapping("/testValid")
    6. public String testValid(@Valid Student student,
    7. BindingResult result)
    8. {
    9. if (result.getErrorCount() > 0)
    10. {
    11. //循环遍历所有错误信息
    12. for (FieldError error : result.getFieldErrors())
    13. {
    14. System.out.println(error.getField() + ":"
    15. + error.getDefaultMessage());
    16. }
    17. }
    18. return "success";
    19. }
    20. }

    ⑤测试

    index.jsp

    复制
    1. <form action="FirstSpringDemo/testValid">
    2. 用户名:<input type="text" name="stuName"/><br>
    3. 生日:<input type="text" name="birthday"/><br>
    4. 邮箱:<input type="text" name="email"/><br>
    5. <input type="submit" value="提交"/>
    6. </form>

    如果输入的数据不符合要求,如下:

    图29-06

    点击提交后,就会在控制台得到校验失败的信息(错误信息是JSR303/Hibernate Validator框架提供的,无需开发人员编写):

    图29-07

    如果希望校验失败后,跳转到错误提示页面(error.jsp),可以通过以下方式实现:

    请求处理类:FirstSpringDemo.java

    复制
    1. @Controller
    2. @RequestMapping(value = "/FirstSpringDemo")
    3. public class FirstSpringDemo
    4. {
    5. @RequestMapping("/testValid")
    6. public String testValid(@Valid Student student,
    7. BindingResult result, Map<String, Object> map)
    8. {
    9. if (result.getErrorCount() > 0)
    10. {
    11. //将错误信息通过map放入request作用域之中
    12. map.put ("errors",result.getFieldErrors());
    13. return "error";
    14. }
    15. return "success";
    16. }
    17. }

    错误提示页:error.jsp

    复制
    1. <c:forEach items="${errors }" var="error">
    2. ${error.getDefaultMessage() }、
    3. </c:forEach>

    再次在index.jsp中输入错误的信息(生日2021-11-11,邮箱yanqun),点击“提交”后得到以下error.jsp页面:

    图29-08

    说明:

    需要注意的是:在请求处理方法的参数中,实体类参数和存储错误信息的BindingResult参数必须书写在一起,它们之间不能掺杂任何其它参数。

    例如,可以写成:

    复制
    1. public String testValid(@Valid Student student, BindingResult result, Map<String, Object> map)

    但不能写成:

    复制
    1. public String testValid(@Valid Student student, Map<String, Object> map, BindingResult result)
  • 相关阅读:
    drf3
    字典的操作方法
    列表的操作方法
    字符串的操作方法
    while循环和基本运算符
    初识数据类型
    USDT相关
    带团队
    CentOS7更改时区及同步网络时间
    mac胡刷新dns
  • 原文地址:https://www.cnblogs.com/gu-bin/p/10545201.html
Copyright © 2011-2022 走看看