SpringMVC框架学习笔记(六):数据格式化(即数据类型转换)、表单数据校验、以及表单中文乱码处理

1 数据格式化

1.1 基本介绍

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

基本数据类型可以和字符串之间自动完成转换,Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作。( 相互转换, 这里只列出部分)
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 ……

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

(1)特殊数据类型和字符串之间的转换使用注解(比如日期,规定格式的小数比如货币形式 等)

(2)对于日期和货币可以使用 @DateTimeFormat 和 @NumberFormat 注解. 把这两个注 解标记在字段上即可

例如:

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

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

2 验证及国际化

2.1 概述

  • 对输入的数据(比如表单数据),进行必要的验证,并给出相应的提示信息。
  • 对于验证表单数据,springMVC 提供了很多实用的注解, 这些注解由 JSR 303 验证框架提供.
  • 使用这些注解需要引入验证和国际化相关的 jar 包,这些jar包已发布在文章顶部

2.2 JSR 303 验证框架

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

(2)JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则, 并通过标准的验证接口对 Bean 进行验证

(3)JSR 303 提供的基本验证注解有: 

注解功能说明
@Null被注释的元素必须为null
@NotNull(message="不能为空")被注释的元素必须不为null。message为发生错误时会保存的错误信息,如果不写会保存默认信息
@AssertTrue被注释的元素必须为true
@AssertFalse被注释的元素必须为false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)被注释的元素的大小必须在指定的范围内
@Digits(integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@ Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式

2.3 Hibernate Validator 扩展注解

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

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

注解功能说明
@Email被注释的元素必须是电子邮箱地址
@Length(value)被注释的字符串的大小必须在指定的范围内
@NotEmpty(message="不能为空")被注释的字符串、集合 或 数组 的必须非空,message为发生错误时会保存的错误信息,如果不写会保存默认信息
@Range(min = 1,max = 100,message="该数字必须在规定的范围内")被注释的元素必须在合适的范围内,这里是1-100。min默认为0,max默认为一个很大的数

(3)maven 依赖

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.1.6.Final</version>
</dependency>

2.4 注解使用细节说明

(1)在需要验证的 Javabean/POJO 的字段上加上相应的验证注解.

(2)在目标方法上,在 JavaBean/POJO 类型的参数前, 添加 @Valid 注解. 告知 SpringMVC 该 bean 是需要验证的

(3)在 @Valid 注解之后, 添加一个 Errors 或 BindingResult 类型的参数, 可以获取到验证 的错误信息

(4)可以使用 <form:errors path="email"></form:errors> 标签来显示错误消息, 这个标签, 需要写在<form:form> 标签内生效.

(5)指定发生错误时返回的信息

配置spring容器配置文件xml文件

<!-- 配置国际化错误信息的资源处理bean -->
<bean id="messageSource" class=
        "org.springframework.context.support.ResourceBundleMessageSource">
    <!-- 配置国际化文件名字
        如果你这样配的话,表示messageSource回到 src/i18nXXX.properties去读取错误信息
     -->
    <property name="basename" value="i18n"></property>
</bean>

新建 i18n.properties 文件,指定错误信息,例如

NotEmpty.monster.name=\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a
typeMismatch.monster.age=\u5e74\u9f84\u8981\u6c42\u5728\u0031\u002d\u0031\u0035\u0030\u4e4b\u95f4
typeMismatch.monster.birthday=\u751f\u65e5\u683c\u5f0f\u4e0d\u6b63\u786e
typeMismatch.monster.salary=\u85aa\u6c34\u683c\u5f0f\u4e0d\u6b63\u786e
Range.monster.age=\u8fd9\u662f\u65b0\u7684\u9a8c\u8bc1\u9519\u8bef\u4fe1\u606f-\u5e74\u9f84\u57281-100\u4e4b\u95f4

格式: 验证规则.表单 modelAttribute .属性名=消息信息 

(5)错误消息的国际化文件是 i18n.properties , 中文需要是 Unicode 编码,使用工具转码.

(6)NotEmpty,NotNull,Range可直接通过message指定,而其他验证规则只能通过文件来配置错误信息

(6)注解@NotNull @NotEmpty 的区别说明

  • 源码 : @NotEmpty Asserts that the annotated string, collection, map or array is not {@code null} or empty.
  • @NotEmpty可以作用在 string, collection, map or array
  • 源码 : @NotNull * The annotated element must not be {@code null}.*Accepts any type.
  • @NotNull 可以作用在所有类型上
  • 如果是字符串验证空, 建议使用 @NotEmpty

3 取消某个属性的绑定

说明:在默认情况下,表单提交的数据都会和 pojo 类型的 javabean 属性绑定,如果
在开发中,希望取消某个属性的绑定,也就是说, 不希望接收到某个表单对应的属
性的值 ,则可以通过 @InitBinder 注解取消绑定 .
(1)编写一个方法 , 使用 @InitBinder 标识的该方法,可以对 WebDataBinder 对象进行初始
化。 WebDataBinder DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑
(2)@InitBinder 方法不能有返回值,它必须声明为 void
(3)@InitBinder 方法的参数通常是是 WebDataBinder

实际案例:

需求说明:不希望接收怪物的名字属性

在目标方法所在的类添加如下方法

//取消绑定 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
     *
     */
    webDataBinder.setDisallowedFields("name");
}

4 综合案例

需求说明:对表单数据进行数据类型转换和校验

3.1 创建 data_valid.jsp, 通过该页面将请求发送给指定的handler,由handler将请求转发给表单

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

 3.2 创建bean类 Monster.java,在该类中对字段添加相应的校验注解,创建handler类 MonsterHandler.java,转发请求到表单页面

package com.web.datavalid.entity;

import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;

import javax.validation.constraints.NotNull;
import java.util.Date;

public class Monster {
    private Integer id;

    //email是string,使用@NotEmpty
    @NotEmpty
    private String email;

    //@NotNull 表示接收的age值不为空
    //@Range(min = 1,max = 100) 表示接收的age值,在 1-100之间
    @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
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    @NotNull(message = "薪水不能为空")
    @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 +
                '}';
    }
}
package com.web.datavalid;

import com.web.datavalid.entity.Monster;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;

/**
 * MonsterHandler 处理器响应用户提交数据
 * @Scope(value = "prototype") 表示每次请求MonsterHandler会生成一个新的对象
 */
@Controller
@Scope(value = "prototype")
public class MonsterHandler {


    /**
     * 显示添加monster的界面
     * 1. 这里Map<String, Object> map‘当我们向map添加的数据时,会默认存放到request域
     */
    @RequestMapping(value = "/addMonsterUI")
    public String addMonsterUI(Map<String, Object> map) {
        /**
         1. SpringMVC 表单标签在显示之前必须在 request 中有一个 bean, 该 bean 的属性和表单标签的字段要对应!
         2. request 中的 key 为: form 标签的 modelAttribute 属性值, 比如这里的monster
         3. <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";
    }

}

3.3 创建表单页面monster_addUI.jsp 和 表单提交成功页面 success.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 属性值, 比如这里的monster
2. SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB 应用的根目录.
-->
<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>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>添加成功</title>
</head>
<body>
<h1>恭喜, 添加成功~</h1>
</body>
</html>

3.4 在MonsterHandler.java中添加方法,对提交的表单数据进行校验,如果发生错误,就进行错误回显

/**
 * 编写方法,处理添加妖怪
 * 1. springmvc可以将提交的数据,按照参数名和对象的属性名匹配,直接封装到对象中
 * String => Integer
 * 2. @Valid Monster monster :表示对monster接收的数据进行校验
 * 4. Errors errors 表示如果校验出现错误,将校验的错误信息保存在 errors
 * 5. Map<String, Object> map  表示如果校验出现错误, 将校验的错误信息保存到 map 同时保存monster对象
 * 6. 校验发生的时机: 在springmvc底层,反射调用目标方法时,会接收到http请求的数据,然后根据注解来进行验证
 * , 在验证过程中,如果出现了错误,就把错误信息填充errors 和 map
 */
@RequestMapping(value = "/save")
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";
}

3.5 在springmvc配置文件中错误信息信息,并创建文件il8n.properties

<!-- 配置国际化错误信息的资源处理bean -->
<bean id="messageSource" class=
        "org.springframework.context.support.ResourceBundleMessageSource">
    <!-- 配置国际化文件名字
        如果你这样配的话,表示messageSource回到 src/i18nXXX.properties去读取错误信息
     -->
    <property name="basename" value="i18n"></property>
</bean>
NotEmpty.monster.name=\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a
typeMismatch.monster.age=\u5e74\u9f84\u8981\u6c42\u5728\u0031\u002d\u0031\u0035\u0030\u4e4b\u95f4
typeMismatch.monster.birthday=\u751f\u65e5\u683c\u5f0f\u4e0d\u6b63\u786e
typeMismatch.monster.salary=\u85aa\u6c34\u683c\u5f0f\u4e0d\u6b63\u786e
#Range.monster.age=\u8fd9\u662f\u65b0\u7684\u9a8c\u8bc1\u9519\u8bef\u4fe1\u606f-\u5e74\u9f84\u57281-100\u4e4b\u95f4

3.6 启动tomcat服务器,查看效果

中文乱码处理

说明: 当表单提交数据为中文时,会出现乱码,我们来解决一下

乱码现象如下:

5.1 自定义中文乱码过滤器

5.1.1 创建MyCharacterFilter.java类

package com.web.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * 编写自定义过滤器,处理中文乱码问题
 */
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() {

    }
}

5.1.2 配置 web.xml 文件,配置自定义过滤器

<!--
1.配置中文乱码过滤,拦截所有请求,处理编码
2.放在其他过滤器的前面,让服务器先执行这个过滤器
-->
<filter>
    <filter-name>MyCharacterFilter</filter-name>
    <filter-class>com.web.filter.MyCharacterFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyCharacterFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

5.1.3 处理效果如下,乱码问题解决

 

5.2 Spring 提供的过滤器处理中文

5.2.1 修改 web.xml , 换成 Spring 提供的过滤器,处理中文乱码(注销前面自定义的过滤器)

<!--配置spring提供的过滤器,解决中文乱码问题-->
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--enconding 参数表示编码方式-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

5.2.2 测试效果,成功解决乱码

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值