SpringMVC的类型转换器和数据格式化(九)中

简介: SpringMVC的类型转换器和数据格式化(九)

三. SpringMVC 的 类型转换接口。


三.一 SpringMVC 关于类型转换,共提供了三个接口。


1 . org.springframework.core.convert.converter.Converter


package org.springframework.core.convert.converter;
public abstract interface Converter<S, T>
{
  public abstract T convert(S paramS);
}


2 . org.springframework.core.convert.converter.ConverterFactory


package org.springframework.core.convert.converter;
public abstract interface ConverterFactory<S, R>
{
  public abstract <T extends R> Converter<S, T> getConverter(Class<T> paramClass);
}


3 . org.springframework.core.convert.converter.GenericConverter


定义了两个方法:


  public abstract Set<ConvertiblePair> getConvertibleTypes();  
  public abstract Object convert(Object paramObject, TypeDescriptor paramTypeDescriptor1, TypeDescriptor paramTypeDescriptor2);


这三个接口均在同一个包下。


20190902104505997.png


有一个support 包。 看看,支持哪些类型转换。


20190902104521377.png


这三个接口之间,有一些区别。


1 .Converter, 最简单的接口, 只是负责将一个 S 源类型 转换成 T 目标类型。


2 .ConverterFactory, 将一种类型的对象转换成另外一种类型及其子类型的对象。 比如,将String 转换成Number 以及 Number 的子类 Integer 和Double,需要定义一系列的转换器,就需要 将String 转换成 Integer的 StringToInteger 和String 转换成Double的 StringToDouble . 如果有一个Float, 那么还需要再写 一个StringToFloat.


SpringMVC 中提供了这么一个例子,可以看一下 StringToNumberConverterFactory


 final class StringToNumberConverterFactory
   implements ConverterFactory<String, Number>
{
  public <T extends Number> Converter<String, T> getConverter(Class<T> targetType)
   {
     return new StringToNumber(targetType);
   }
  private static final class StringToNumber<T extends Number> implements Converter<String, T>
   {
     private final Class<T> targetType;
     public StringToNumber(Class<T> targetType) {
       this.targetType = targetType;
    }
    public T convert(String source)
     {
       if (source.length() == 0) {
        return null;
       }
       return NumberUtils.parseNumber(source, targetType);
     }
   }
 }


如果想转换成 Integer, 可以 用 getConverter(Integer.class).convert(string字符串),


如果想转换成 Double, 可以用 getConverter(Double.class).convert(string字符串),


如果想转换成 Float, 可以用 getConverter(Float.class).convert(string字符串)


S 为源类型, R 为目标类型的基类, T 为目标类型基类的子类,也就是最终要转换的那个类。


这样的Factory 还有:


StringToEnumConverterFactory

CharacterToNumberFactory

NumberToNumberConverterFactory


可以方便的对有子类的 对象进行转换。


3 . GenericConverter Converter 只是将源类型转换成目标类型,并没有携带源类型和目标类型的信息,只能用于普通的转换,无法进行复杂的转换。 会根据源类型和目标类型对象的上下文信息进行类型转换。


GenericConverter接口中一共定义了两个方法,getConvertibleTypes()和convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType)。getConvertibleTypes方法用于返回这个GenericConverter能够转换的原类型和目标类型的这么一个组合;convert方法则是用于进行类型转换的,我们可以在这个方法里面实现我们自己的转换逻辑。之所以说GenericConverter是最复杂的是因为它的转换方法convert的参数类型TypeDescriptor是比较复杂的。TypeDescriptor对类型Type进行了一些封装,包括value、Field及其对应的真实类型等等。


一般用 Convert 就可以达到基本的要求了。


三.二 ConversionService 接口


为了方便的对上面的三个接口进行进行统一调用,所以定义了 ConversionService 接口。


package org.springframework.core.convert;
public abstract interface ConversionService
{
  //能否转换
  public abstract boolean canConvert(Class<?> paramClass1, Class<?> paramClass2);
  public abstract boolean canConvert(TypeDescriptor paramTypeDescriptor1, TypeDescriptor paramTypeDescriptor2);
  //转换
  public abstract <T> T convert(Object paramObject, Class<T> paramClass);
  public abstract Object convert(Object paramObject, TypeDescriptor paramTypeDescriptor1, TypeDescriptor paramTypeDescriptor2);
}


该接口的实现类


20190902104532685.png


故,类型转换时一般用 DefaultConversionService (默认注入到 mvc:annotation-driven 中)


类型格式化时用 DefaultFormattingConversionService.


三.三 ConverterRegistry 转换器注册接口


package org.springframework.core.convert.converter;
public abstract interface ConverterRegistry
{
  //添加 Converter 接口
  public abstract void addConverter(Converter<?, ?> paramConverter);
  public abstract void addConverter(Class<?> paramClass1, Class<?> paramClass2, Converter<?, ?> paramConverter);
   // 添加 GenericConverter 接口
  public abstract void addConverter(GenericConverter paramGenericConverter);
  // 添加 ConverterFactory 接口
  public abstract void addConverterFactory(ConverterFactory<?, ?> paramConverterFactory);
//移除转换器
  public abstract void removeConvertible(Class<?> paramClass1, Class<?> paramClass2);
}


用于 注册和移除转换器。


这儿用简单的 Convert 接口来进行讲解。


四. Convert 接口的使用


原始的错误类型转换。


四.一 前端代码


<body>
  <h2>两个蝴蝶飞,类型转换器使用</h2>
  <form:form commandName="user" action="login.action" method="post">
    <form:label path="name">姓名:</form:label>
    <form:input path="name"/><br/>
    <form:label path="birthday">日期:</form:label>
    <form:input path="birthday"/><br/>
    <form:button>提交</form:button>
  </form:form>
</body>


四.二 后端代码实现


@Controller
@RequestMapping(value="/user")
public class UserAction {
  //转到登录的页面
  @RequestMapping(value="toLogin")
  public String toLogin(Model model){
    model.addAttribute("user",new User());
    return "user/login";
  }
  //绑定到user对象。
  @RequestMapping(value="login") 
  public String login(User user){
    System.out.println("设置名称:"+user.getName());
    System.out.println("生日:"+user.getBirthday().toLocaleString());
    return "user/list";
  }
}


四.三 前端输入值,进行测试


20190902104556348.png


输入数值之后 ,点击提交,发生了错误。


20190902104546419.png


请求不通过,无法进行转换的原因。 也就是,没有默认提交 String 到Date 的转换。

进行重新构造,添加类型转换器,来达到StringToDate 的转换。


四.四 编写类型转换器 DateConvert


为了方便,将格式 pattern 改成注入的形式。


package com.yjl.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
public class DateConvert implements Converter<String,Date>{
  // 自定义转换格式
  private String pattern;
  @Override
  public Date convert(String dateStr) {
    SimpleDateFormat sdf=new SimpleDateFormat(this.pattern);
    try {
      return sdf.parse(dateStr);
    } catch (ParseException e) {
      // TODO 自动生成的 catch 块
      e.printStackTrace();
      System.out.println(dateStr+"日期转换失败");
      return null;
    }
  }
  public String getPattern() {
    return pattern;
  }
  public void setPattern(String pattern) {
    this.pattern = pattern;
  }
}


四.五 在springmvc.xml 配置文件中 配置类型转换


将:


<!--提供了内置的转换器-->
<mvc:annotation-driven></mvc:annotation-driven>


改成 新写的转换器。


  <!-- 添加转换器 -->
   <mvc:annotation-driven conversion-service="conversionService">
    </mvc:annotation-driven>
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
      <property name="converters">
        <list>
          <bean class="com.yjl.convert.DateConvert">
            <property name="pattern" value="yyyy-MM-dd"></property>
          </bean>
        </list>
      </property>
    </bean>


四.六 重启服务器,再次进行验证。


输入上面相同的值,再次提交,页面可以进行跳转。


控制台打印输出:


2019090210461433.png


说明,新的日期转换器是成功的。


四.七 注解型日期转换器 @DateTimeFormat


日期转换,是非常常用的转换器。 SpringMVC 虽然没有提供,但是却提供了注解的形式。 @DateTimeFormat


JDK1.8 之前,不包括JDK1.8, 需要添加 joda-time.jar 包, JDK1.8包括,之后,不需要这个jar包,可直接使用@DateTimeFormat注解。


老蝴蝶版本是 1.8,不需要添加额外的jar包。


1 . User.java 中 在birthday 属性上面添加注解,写明格式。


 //定义一个日期类
    @DateTimeFormat(pattern="yyyy年MM月dd日")
    private Date birthday;


2 .将springmvc.xml 配置文件仍然换成以前的样式,注释掉 四.五 中的内容。


重新换成:


<mvc:annotation-driven></mvc:annotation-driven>


3 . 重启服务器,进行验证。


前端输入值之后 ,页面可以正常的跳转。


20190902104624398.png


控制台打印输出


20190902104629510.png


注解 @DateTimeFormat 是可以使用的。


@DateTimeFormat 代码为:


支持 DATE,TIME,DATE_TIME,NONE 等多种形式。


 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.ANNOTATION_TYPE})
 public @interface DateTimeFormat
 {
  ISO iso() default ISO.NONE;
  String pattern() default "";
  public static enum ISO
   {
    DATE, 
   TIME, 
     DATE_TIME, 
     NONE;
     private ISO() {}
   }
}


四.八 原先的类型转换器可以正常使用吗?


用的是name, 接收的是 字符串类型, 现在添加一个age 字段,要转换成int,看后台 User 能否接收呢?


注意,此时 springmvc.xml 的配置文件,又换成了 四.五 中的配置,在User.java 中去掉了 @DateTimeFormat 注解。


1 . 前端页面


<form:form commandName="user" action="login.action" method="post">
    <form:label path="name">姓名:</form:label>
    <form:input path="name"/><br/>
    <form:label path="age">年龄:</form:label>
    <form:input path="age"/><br/>
    <form:label path="birthday">日期:</form:label>
    <form:input path="birthday"/><br/>
    <form:button>提交</form:button>
  </form:form>


2 .后端输出


@RequestMapping(value="login") 
  public String login(User user){
    System.out.println("设置名称:"+user.getName()+",年龄:"+user.getAge());
    System.out.println("生日:"+user.getBirthday().toLocaleString());
    return "user/list";
  }


3 .测试输入


20190902104721239.png


页面可以正常的进行跳转,控制台打印输出


201909021046596.png


可以发现,原先的类型转换器还是可以使用的。(不知道为什么)

相关文章
|
10月前
|
前端开发 Java Spring
springMVC--数据格式化
springMVC--数据格式化
63 0
|
前端开发 安全 Java
详细解读_SpringMvc类型转换&数据格式化&数据验证
详细解读_SpringMvc类型转换&数据格式化&数据验证
|
Java Spring
SpringMVC - 数据格式化(@DateTimeFormat & @NumberFormat)(一)
SpringMVC - 数据格式化(@DateTimeFormat & @NumberFormat)(一)
252 0
SpringMVC - 数据格式化(@DateTimeFormat & @NumberFormat)(一)
|
Java Spring
SpringMVC - 数据格式化(@DateTimeFormat & @NumberFormat)(二)
SpringMVC - 数据格式化(@DateTimeFormat & @NumberFormat)(二)
141 0
|
前端开发
SpringMVC的类型转换器和数据格式化(九)下
SpringMVC的类型转换器和数据格式化(九)
234 0
SpringMVC的类型转换器和数据格式化(九)下
SpringMVC的类型转换器和数据格式化(九)上
SpringMVC的类型转换器和数据格式化(九)
218 0
SpringMVC的类型转换器和数据格式化(九)上
|
XML JSON 前端开发
springmvc4整合AJAX使用@ResponseBody注解返回JSON数据格式
版权声明:本文为博主原创文章,如需转载,请标明出处。 https://blog.csdn.net/alan_liuyue/article/details/53433325   ...
1238 0
|
容器 前端开发
SpringMVC 中 数据格式化
FormattingConversionServiceFactoryBean内部已经注册了: - NumberFormatAnnotationFormatterFactroy:支持对数字类型的属性使用@NumberFormat注解。 - JodaDateTimeFormatAnnotationFormatterFactroy:支持对日期类型的属性使用@DataTime
1415 0
|
前端开发 Java Spring
springMVC4(11)使用注解完成数据格式化
<div class="markdown_views"> <h1 id="需求实例引入">需求实例引入</h1> <p>在实际开发中,我们会常常遇到需要对日期格式、数值格式进行转换的需求。在spring中,我们可以轻松通过注解的方式完成对数据的格式化处理,比如现在有个User POJO类: <br> package com.mvc.model;</p> <pre cla
2741 0
|
1月前
|
设计模式 前端开发 JavaScript
Spring MVC(一)【什么是Spring MVC】
Spring MVC(一)【什么是Spring MVC】