springMvc-07 类型转换/格式化/数据校验

前端给后端传递数据进行数据绑定时,会经过类型转换,数据格式化,以及数据校验的过程。

1、类型转换

SpringMVC框架提供了一个通用的类型转换模块,该类型转换模块位于包org.springframework.core.convert中,可以在处理方法的参数绑定中使用他们进行数据转换。

SpringMVC框架中内置了很多的类型转换。

 

 3)自定义类型转换

默认类型转换器并不是可以将用户提交的内容,转换为用户需要的所有类型。此时 ,就需要自定义类型转换器了

例如:我们文本框里边要输入2021-01-01之后要让其转换为日期类型,则需要自定义类型转换器。

自定义类型转换器的方式有3三种:

1)Converter<S,T>:是SpringMVC最简单的一个转换器接口,可以实现任意类型间的相互转换,负责把S转为T

2)ConverterFactory<S,R>:将一种类型的对象转换成另一个类型及其子类型对象。其中S为转换的源类型,R为目标类型的基类,T为R的子类。

3)GenericConverter,转换方法参数中包含TypeDescriptor类型的参数,这个参数包含了上下文信息,能够根据上下文信息进行类型转换。

举例:

1)转换器实现

package rui.tool;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class StringToDateConverter implements Converter<String,Date> {
    //日期的格式,定义一个变量,允许配置Bean的时候动态的指定
    private String datePattern;
    public String getDatePattern() {
        return datePattern;
    }

    public void setDatePattern(String datePattern) {
        this.datePattern = datePattern;
    }

    @Override
    public Date convert(String s) {
        if(s==null || "".equals(s.trim())) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
        Date result = null;
        try {
            result = sdf.parse(s);
        }
        catch (ParseException e)
        {
            e.printStackTrace();
            System.out.println("转换失败");
        }
        return result;
    }
}

2)SpringMVC配置

 

    <!--开启自动注册处理器映射器和处理器适配器-->
    <!--开启Spring的valid功能 validator="validator" -->
    <mvc:annotation-driven validator="validator" conversion-service="formatService" />

    <!--配置类型转换和格式化-->
    <bean id="formatService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="rui.tool.StringToDateConverter">
                    <property name="datePattern" value="yyyy-MM-dd" />
                </bean>
            </list>
        </property>
    </bean>

 

 

 

2、数据格式化

从Spring3.0开始,引入了格式化转换框架,该框架位于Spring-context.jar包中。

Spring在格式化模块中定义了一个实现ConversionService接口的FormattingConversionService实现类,该类既具有类型转换功能,有具有格式化功能。

Formatter和Converter基本功能一样, 是将一种类型转换成另一种类型, 但是,Formatter的源类型必须是一个String, 目标类型是java类型.

通过FormattingConversionServiceFactoryBean即可以实现注册定义的转换器,也可以注册自定义的格式化器。

Spring内置了很多的格式化转换器,也允许我们自定义,例如定义了一个坐标类Point,内部包含x,y属性,如果表单上输入2,3之后,能够将其转换为Point对象,则需要自己编写数据格式化器。

1) 内置的格式化

名称 功能
NumberFormatter 实现Number与String之间的解析与格式化
CurrencyFormatter 实现Number与String之间的解析与格式化(带货币符号)
PercentFormatter 实现Number与String之间的解析与格式化(带百分数符号)
DateFormatter 实现Date与String之间的解析与格式化
NumberFormatAnnotationFormatterFactory @NumberFormat注解,实现Number与String之间的解析与格式化,可以通过指定style来指示要转换的格式(Style.Number/Style.Currency/Style.Percent),当然也可以指定pattern(如pattern=“#.##”(保留2位小数) ),这样pattern指定的格式会覆盖掉Style指定的格式
JodaDateTimeFormatAnnotationFormatterFactory @DateTimeFormat注解,实现日期类型与String之间的解析与格式化这里的日期类型包括Date、Calendar、Long以及Joda的日期类型。必须在项目中添加Joda-Time包

2)自定义格式化

举例:

1)格式化器实现

package rui.tool;

import org.springframework.format.Formatter;
import rui.db.Model.Point;

import java.text.ParseException;
import java.util.Locale;

public class StringToPointFormatter implements Formatter<Point> {

    @Override
    public Point parse(String s, Locale locale) throws ParseException {
        if(s==null || "".equals(s.trim())) {
            return null;
        }

        String[] array = s.split(",");
        if(array.length==2)
        {
            Point p = new Point();
            p.setX(Integer.parseInt(array[0]));
            p.setY(Integer.parseInt(array[1]));
            return p;
        }
        return null;
    }

    @Override
    public String print(Point point, Locale locale) {
        if(point!= null)
        {
            return  point.getX()+","+point.getY();
        }
        return "";
    }
}

2)SpringMvc配置

类型转换和格式化可以放在一个Bean中配置。

    <!--开启自动注册处理器映射器和处理器适配器-->
    <!--开启Spring的valid功能 validator="validator" -->
    <mvc:annotation-driven validator="validator" conversion-service="formatService" />

    <!--配置类型转换和格式化-->
    <bean id="formatService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <list>
                <bean class="rui.tool.StringToPointFormatter" />
            </list>
        </property>
    </bean>

3)基于注解的格式化

@DateTimeFormat可以对Date和Calendar等时间类型的属性进行标准。

  • DateTimeFormat.ISO.DATE: 格式yyyy-MM-dd
  • DateTimeFormat.ISO.DATE_TIME: 格式yyyy-MM-dd HH:mm:ss .SSSZ
  • DateTimeFormat.ISO.TIME: 格式HH:mm:ss .SSSZ
  • DateTimeFormat.ISO.NONE: 表示不使用ISO格式的时间。

该标准拥有两个属性:

  • pattern。类型为String,使用自定义的时间格式化字符串。
  • style。类型为String,通过样式指定日期时间的格式,由两位字符组成,第1位表示日期的样式,第2位表示时间的格式:
    • S: 短日期/时间的样式;
    • M: 中日期/时间的样式;
    • L: 长日期/时间的样式;
    • F: 完整日期/时间的样式;
    • -: 忽略日期/时间的样式;

@NumberFormat可对类似数字类型的属性进行标准,它拥有两个互斥的属性。

  • pattern。类型为String,使用自定义的数字格式化字符串,"##,###.##"。
  • style。类型为NumberFormat.Style,常用值:
    • Style.NUMBER正常数字类型
    • Style.PERCENT百分数类型
    • Style.CURRENCY 货币类型

例子代码:

// 域对象,实现序列化接口
public class User implements Serializable{
    
    // 日期类型
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date birthday;
    // 正常数字类型
    @NumberFormat(style=Style.NUMBER, pattern="#,###")  
    private int total;  
    // 百分数类型
    @NumberFormat(style=Style.PERCENT)  
    private double discount;  
    // 货币类型
    @NumberFormat(style=Style.CURRENCY)  
    private double money;  
    
}

填写数据和展示效果:

3、数据校验

SpringMVC提供了强大的数据验证功能,其中有两种方法可以验证输入

1)利用Spring自定的validation校验框架。

2)利用JSR303(Java验证规范)实现验证功能

这里极少JSR303的使用方法。

3.1、导入需要的包

        <!--JSR3.0校验-->
        <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>7.0.0.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.3.2.Final</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml/classmate -->
        <dependency>
            <groupId>com.fasterxml</groupId>
            <artifactId>classmate</artifactId>
            <version>1.5.1</version>
        </dependency>

3.2、springmvc.xml注册校验器

    <!--开启自动注册处理器映射器和处理器适配器-->
    <!--开启Spring的valid功能 validator="validator" -->
    <mvc:annotation-driven validator="validator" conversion-service="formatService" />

    <!--配置验证器-->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
    </bean>

3.3、常用验证特性

注解功能
@Null 对象必须为null
@NotNull 对象必须不为null,无法检查长度为0的字符串
@NotBlank 字符串必须不为Null,且去掉前后空格长度必须大于0
@AssertTrue 对象必须为true
@AssertFalse 对象必须为false
@Max(Value) 必须为数字,且小于或等于Value
@Min(Value) 必须为数字,且大于或等于Value
@DecimalMax(Value) 必须为数字( BigDecimal ),且小于或等于Value。小数存在精度
@DecimalMin(Value) 必须为数字( BigDecimal ),且大于或等于Value。小数存在精度
@Digits(integer,fraction) 必须为数字( BigDecimal ),integer整数精度,fraction小数精度
@Size(min,max) 对象(Array、Collection、Map、String)长度必须在给定范围
@Range(min,max) 验证数字是否介入min和max之间
@Email 字符串必须是合法邮件地址
@Past Date和Calendar对象必须在当前时间之前
@Future Date和Calendar对象必须在当前时间之后
@Pattern(regexp=“正则”) String对象必须符合正则表达式
@Url 验证是否合法的Url地址
@CreditCardNumber 信用卡校验

 

3.4、例子

1)在模型类上增加标准

2)控制器内判断验证是否有问题

  • 给模型类前边增加@Valid标准,代表User对象绑定时会检查验证规则。
  • BindResult参数必须紧跟在有@Valid参数的后边,用来获取绑定之后的错误信息
  • 如果有验证错误,则重新返回到填写界面,需要把界面需要的数据都携带上。
   //用户注册提交
    @RequestMapping(value = "register", method = RequestMethod.POST)
    public String register(Model model, @Valid User user, BindingResult bindResult,
                           List<MultipartFile> headImgUpload,
                           HttpServletRequest request
    ) {
        System.out.println("执行TestController==2");
        System.out.println(bindResult.toString());

        //验证不通过
        if (bindResult.getFieldErrorCount() > 0) {

            //获取所有的错误
            List<ObjectError> errList = bindResult.getAllErrors();
            for(ObjectError err:errList)
            {
                System.out.println(err.toString());
            }

            model.addAttribute("user", user);
            model.addAttribute("sexList", rui.tool.listHelper.getSex());
            model.addAttribute("deptList", rui.tool.listHelper.getSex());
            model.addAttribute("loveList", rui.tool.listHelper.getLove());
            return "/test/register";
        }
        
        model.addAttribute("user", user);
        return "forward:/test/showInfo";
    }

3)前端JSP页面显示错误

<div>用户账号:<f:input path="loginId" data-id="123" /><f:errors path="loginId"/> </div>

如果是前后端分离的,需要自己获取错误描述信息,并通过JSON返回。

 

posted @ 2022-02-12 19:17  草莓爸  阅读(158)  评论(0编辑  收藏  举报