SpringMVC-数据格式化、验证以及国际化

  |   0 评论   |   0 浏览

SpringMVC-数据格式化、验证以及国际化

SpirngMVC数据格式化

1.基本介绍

说明: 在我们提交数据(比如表单时)SpringMVC 怎样对提交的数据进行转换和处理的

  1. 基本数据类型可以和字符串之间自动完成转换,比如: Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。[相互转换, 这里只列出部分]

  2. ConversionService converters = java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@f874ca

    java.lang.Character -> java.lang.Number : CharacterToNumberFactory@f004c9

    java.lang.Character -> java.lang.String : ObjectToStringConverter@68a961

    java.lang.Enum -> java.lang.String : EnumToStringConverter@12f060a

    java.lang.Number -> java.lang.Character : NumberToCharacterConverter@1482ac5

    java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory@126c6f

    java.lang.Number -> java.lang.String : ObjectToStringConverter@14888e8

    java.lang.String -> java.lang.Boolean : StringToBooleanConverter@1ca6626

    java.lang.String -> java.lang.Character : StringToCharacterConverter@1143800

    java.lang.String -> java.lang.Enum : StringToEnumConverterFactory@1bba86e

    java.lang.String -> java.lang.Number : StringToNumberConverterFactory@18d2c12

    java.lang.String -> java.util.Locale : StringToLocaleConverter@3598e1

    java.lang.String -> java.util.Properties : StringToPropertiesConverter@c90828

    java.lang.String -> java.util.UUID : StringToUUIDConverter@a42f23

    java.util.Locale -> java.lang.String : ObjectToStringConverter@c7e20a

    java.util.Properties -> java.lang.String : PropertiesToStringConverter@367a7f

    java.util.UUID -> java.lang.String : ObjectToStringConverter@112b07f ……

2.基本数据类型和字符串自动转换

1.应用实例 -页面演示方式

● 说明: 基本数据类型可以和字符串之间自动完成转换

image-20220616232455421

image-20220616232524496

1.创建java Bean

public class Monster {
    private Integer id;

    private String email;

    private Integer age;

    private String name;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    @NumberFormat(pattern = "###,###.##")
    private Float salary;

    public Monster(Integer id, String email, Integer age, String name, Date birthday, Float salary) {
        this.id = id;
        this.email = email;
        this.age = age;
        this.name = name;
        this.birthday = birthday;
        this.salary = salary;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Float getSalary() {
        return salary;
    }

    public void setSalary(Float salary) {
        this.salary = salary;
    }

    public Monster() {
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Monster{" +
                "id=" + id +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", salary=" + salary +
                '}';
    }
}

2.创建 \web\data_valid.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC[数据格式/验证等]</title>
</head>
<body>
<h1>SpringMVC[数据格式/验证等]</h1>
<hr>
<a href="<%=request.getContextPath()%>/addMonsterUI">添加妖怪</a>
</body>
</body>
</html>

3.创 建 \datavalid\MonsterHandler.java

/**
 * 显示添加monster的界面
 * 1. 这里Map<String, Object> map
 * 2. 当我们向map添加的数据时,会默认存放到request域
 *
 * @param map
 * @return
 */
@RequestMapping(value = "/addMonsterUI")
public String addMonsterUI(Map<String, Object> map) {
    /**
     1. 这里的表单,我们使用springMVC的标签来完成
     2. SpringMVC 表单标签在显示之前必须在 request 中有一个 bean, 该 bean 的属性和表单标签的字段要对应!
     request 中的 key 为: form 标签的 modelAttrite 属性值, 比如这里的monster
     3. SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB 应用的根目录.
     4. <form:form action="?" method="POST" modelAttribute="monster">
     //这里需要给request增加一个 monster,因为jsp 页面 的modelAttribute="monster"需要
     //这是springMVC的内部的检测机制  即使是一个空的也需要,否则报错.
     */
    //如果跳转的页面使用springmvc标签
    //就需要准备一个对象,放入request域中,这个对象的属性名 monster, 对于
    //springmvc表单标签的 modelAttribute="monster"
    map.put("monster", new Monster());
    return "datavalid/monster_addUI";
}

4.创建\web\WEB-INF\pages\datavalid\monster_addUI.jsp

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>添加妖怪</title>
</head>
<body>
<h3>添加妖怪</h3>
<!-- 这里的表单,我们使用springMVC的标签来完成
特别说明几点:
1. SpringMVC 表单标签在显示之前必须在 request 中有一个 bean, 该 bean 的属性和表单标签的字段要对应!
request 中的 key 为: form 标签的 modelAttribute 属性值, 比如这里的monsters
2. SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB 应用的根目录.
3. 这里使用springmvc的标签的主要的目的是方便提示信息回显
-->
<form:form action="save" method="post" modelAttribute="monster">
    妖怪名字: <form:input path="name"/> <form:errors path="name"/>  <br><br>
    妖怪年龄~: <form:input path="age"/> <form:errors path="age"/> <br><br>
    电子邮件: <form:input path="email"/> <form:errors path="email"/>  <br><br>
    妖怪生日: <form:input path="birthday"/> <form:errors path="birthday"/> 要求以"9999-11-11"的形式<br><br>
    妖怪薪水: <form:input path="salary"/> <form:errors path="salary"/> 要求以"123,890.12"的形式<br><br>
    <input type="submit" value="添加妖怪"/>
</form:form>
</body>
</html>

5.创建 \web\WEB-INF\pages\datavalid\success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>添加成功</title>
</head>
<body>
<h1>恭喜, 添加成功~</h1>
</body>
</html>

6.修改\datavalid\MonsterHandler.java

/**
     *编写方法,处理添加妖怪
     *1. springmvc可以将提交的数据,按照参数名和对象的属性名匹配
     *2. 直接封装到对象中
     * @param monster
     * @return
     */
    @RequestMapping(value = "/save",method = RequestMethod.POST)
    public String save(Monster monster){
        System.out.println("monster = "+monster);
        return "datavalid/success";
    }

7.测试

成功

image-20220618145903470

失败

Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat java.util.Date] for value '1999-11-101'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [1999-11-101]]]

2.特殊数据类型和字符串间的转换

  1. 特殊数据类型和字符串之间的转换使用注解(比如日期,规定格式的小数比如货币形式 等)
  2. 对于日期和货币可以使用 @DateTimeFormat 和 @NumberFormat 注解. 把这两个注 解标记在字段上即可.

SpringMVC验证以及国际化

1.概述

● 概述

  1. 对输入的数据(比如表单数据),进行必要的验证,并给出相应的提示信息。
  2. 对于验证表单数据,springMVC 提供了很多实用的注解, 这些注解由 JSR 303 验证框架提供

● JSR 303 验证框架

1.JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 中

  1. JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则, 并通过标准的验证接口对 Bean 进行验证
  2. JSR 303 提供的基本验证注解有:

空检查
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

Booelan检查
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false

长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.

日期检查
@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。

数值检查
建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为”“,Integer为null
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) 被指定的元素必须在合适的范围内
@Range(min=10000,max=50000,message=”range.bean.wage”)
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)

● Hibernate Validator 扩展注解

  1. Hibernate Validator 和 Hibernate 没有关系,只是 JSR 303 实现的一个扩展.

  2. Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支 持以下的扩展注解:

    1. 扩展注解有如下

image-20220618170242629

2.应用实例

● 应用实例-需求说明

image-20220618170327755

● 应用实例-代码实现

  1. 引入验证和国际化相关的 jar 包

image-20220618170509761

​ 2.修改 Monster.java

public class Monster {
    private Integer id;

    private String email;

    @Range(min = 1,max = 100)
    private Integer age;

    @NotEmpty
    private String name;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    @NumberFormat(pattern = "###,###.##")
    private Float salary;

    public Monster(Integer id, String email, Integer age, String name, Date birthday, Float salary) {
        this.id = id;
        this.email = email;
        this.age = age;
        this.name = name;
        this.birthday = birthday;
        this.salary = salary;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Float getSalary() {
        return salary;
    }

    public void setSalary(Float salary) {
        this.salary = salary;
    }

    public Monster() {
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Monster{" +
                "id=" + id +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", salary=" + salary +
                '}';
    }
}

3.修改MonsterHandler.java

/**
 * 编写方法,处理添加妖怪
 * 1. springmvc可以将提交的数据,按照参数名和对象的属性名匹配
 * 2. 直接封装到对象中
 * String => Integer
 * 3. @Valid Monster monster :表示对monster接收的数据进行校验
 * 4. Errors errors 表示如果校验出现错误,将校验的错误信息保存 errors
 * 5. Map<String, Object> map  表示如果校验出现错误, 将校验的错误信息保存 map 同时保存monster对象
 * 6. 校验发生的时机: 在springmvc底层,反射调用目标方法时,会接收到http请求的数据,然后根据注解来进行验证
 * , 在验证过程中,如果出现了错误,就把错误信息填充errors 和 map
 * @param monster
 * @return
 */
@RequestMapping(value = "/save",method = RequestMethod.POST)
public String save(@Valid Monster monster, Errors errors,Map<String,Object> map){
    System.out.println("----monster---" + monster);
    //我们为了看到验证的情况,我们输出map 和 errors
    System.out.println("===== map ======");
    for (Map.Entry<String, Object> entry : map.entrySet()) {
        System.out.println("key= " + entry.getKey() + " value=" + entry.getValue());
    }

    System.out.println("===== errors ======");
    if (errors.hasErrors()) {//判断是否有错误
        List<ObjectError> allErrors = errors.getAllErrors();
        for (ObjectError error : allErrors) {
            System.out.println("error=" + error);
        }
        return "datavalid/monster_addUI";
    }
    return "datavalid/success";
}
  1. 配置国际化文件 springDispatcherServlet-servlet.xml
<!-- 配置国际化错误信息的资源处理bean -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- 配置国际化文件名字,如果你这样配的话,表示messageSource回到 src/i18nXXX.properties去读取错误信息-->
   <property name="basename" value="i18n"></property>
</bean>

​ 5.创建国际化文件 \src\i18n.properties

NotEmpty.monster.name=用户名不能为空
typeMismatch.monster.age=年龄要求在1-150之间
typeMismatch.monster.birthday=生日格式不正确
typeMismatch.monster.salary=薪水格式不正确
Range.monster.age=这是新的验证错误信息-年龄在1-100之间

​ 6.完成测试

image-20220618222953667

3.细节说明和注意事项

  1. 在需要验证的 Javabean/POJO 的字段上加上相应的验证注解.
  2. 目标方法上,在 JavaBean/POJO 类型的参数前, 添加 @Valid 注解. 告知 SpringMVC 该 bean 是需要验证的
  3. 在 @Valid 注解之后, 添加一个 Errors 或 BindingResult 类型的参数, 可以获取到验证 的错误信息
  4. 需要使用 <form:errors path="email">< /form:errors> 标签来显示错误消息, 这个标签, 需要写在< form:form> 标签内生效.
  5. 错误消息的国际化文件 i18n.properties , 中文需要是 Unicode 编码,使用工具转码. √ 格式: 验证规则.表单 modelAttribute 值.属性名=消息信息 √ NotEmpty.monster.name=\u540D\u5B57\u4E0D\u80FD\u4E3A\u7A7A √ typeMismatch.monster.age=\u7C7B\u578B\u4E0D\u5339\u914D
  6. 注解@NotNull 和 @NotEmpty 的区别说明

​ (1)查看源码可以知道 : @NotEmpty Asserts that the annotated string, collection, map or array is not {@code null} or empty.

​ (2)查看源码可以知道 : @NotNull * The annotated element must not be {@code null}.*Accepts any type.

​ (3) 如果是字符串验证空, 建议使用 @NotEmpty

  1. SpingMVC 验证时,会根据不同的验证错误, 返回对应的信息

3.注解的结合使用

先看一个问题

● 问题提出, age 没有, 是空的,提交确是成功了

这里age我们设置了范围,但是没有填写也提交成功了

image-20220618223453711

image-20220618223505464

解决方案 注解组合使用

解决问题

  1. 使用@NotNull + @Range 组合使用解决
  2. 具体代码

修改Monster.java

@NotNull(message = "age不能为空")
@Range(min = 1,max = 100)
private Integer age;
//@NotEmpty 表示name不能为空
//Asserts that the annotated string, collection, map or array is not {@code null} or empty.
//@NotEmpty
private String name;

@NotNull(message = "生日不能为空")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;

@NotNull(message = "薪水不能为空")
@NumberFormat(pattern = "###,###.##")
private Float salary;

​ 3.测试(页面方式),这时 age 不能为空,同时必须是 1-100, (也不能输入 haha, hello 等不 能转成数字的内容)

我们在使用这些注解时,要注意注解适用于哪些类型的字段,针对性的使用

image-20220618224056459

4.数据类型转换校验核心类-DataBinder

● DataBinder 工作机制-了解

图例 Spring MVC 通过反射机制对目标方法进行解析,将请求消息绑定到处理方法的入参中。+ 数据绑定的核心部件是 DataBinder,运行机制如下

image-20220618224311354

5.取消某个属性的绑定

使用实例

● 说明 在默认情况下,表单提交的数据都会和 pojo 类型的 javabean 属性绑定,如果 程序员在开发中,希望取消某个属性的绑定,也就是说,不希望接收到某个表单对应的属 性的值,则可以通过 @InitBinder 注解取消绑定.

  1. 编写一个方法, 使用@InitBinder 标识的该方法,可以对 WebDataBinder 对象进行初始 化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑 定
  2. @InitBinder 方法不能有返回值,它必须声明为 void。
  3. @InitBinder 方法的参数通常是是 WebDataBinder

● 案例-不希望接收怪物的名字属性

​ 1. 修改 MonsterHandler.java , 增加方法

//取消绑定 monster的name表单提交的值给monster.name属性
@InitBinder
public void initBinder(WebDataBinder webDataBinder) {
    /**
     * 1. 方法上需要标注 @InitBinder  springmvc底层会初始化 WebDataBinder
     * 2. 调用 webDataBinder.setDisallowedFields("name") 表示取消指定属性的绑定
     *    即:当表单提交字段为 name时, 就不在把接收到的name值,填充到model数据monster的name属性
     * 3. 机制:springmvc 在底层通过反射调用目标方法时, 接收到http请求的参数和值,使用反射+注解技术
     *    取消对指定属性的填充
     * 4. setDisallowedFields支持可变参数,可以填写多个字段
     * 5. 如果我们取消某个属性绑定,验证就没有意义了,应当把验证的注解去掉, name属性会使用默认值null
     *  //@NotEmpty
     *  private String name;
     *
     */
    webDataBinder.setDisallowedFields("name");
}

image-20220618230745620

测试

image-20220618230921961

image-20220618231153464

SpringMVC中文乱码处理

1.自定义中文乱码过滤器

● 说明 当表单提交数据为中文时,会出现乱码

自定义中文乱码过滤器

public class MyCharacterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //这里加入对编码的处理
        servletRequest.setCharacterEncoding("utf-8");
        //方向请求
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

配置web.xml

<!--
    1.配置中文乱码过滤器
    2.过滤器配置顺序需要考量,将重要的过滤器配置在前面(过滤器链根据先后顺序执行)
    -->
<filter>
    <filter-name>myCharacterFilter</filter-name>
    <filter-class>com.llp.web.filter.MyCharacterFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>myCharacterFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.Spring提供的过滤器处理中文

<!--在使用springmvc过程中接收客户端的请求参数时有时会出现中文乱码,这是因为springmvc并没有对象请求参数进行编码控制,如果需要控制需要自行指定-->
<filter>
    <filter-name>charset</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>charset</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

image-20220618231938568


标题:SpringMVC-数据格式化、验证以及国际化
作者:llp
地址:https://llinp.cn/articles/2022/06/18/1655565348882.html