0060 Spring MVC的数据类型转换--ConversionService--局部PropertyEditor--全局WebBindingInitializer

浏览器向服务器提交的数据,多是字符串形式,而有些时候,浏览器需要Date、Integer等类型的数据,这时候就需要数据类型的转换器

使用Spring的ConversionService及转换器接口

下面以字符串转Date为例:

<!DOCTYPE html>
<html>
<head>
    <title>Spring MVC的数据类型转换</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="resources/jquery-3.1.0.js"></script>
    <script type="text/javascript" src="resources/json2.js"></script>
    
</head>
    <body>
        <form action="register" method="post">
            姓名:<input type="text" name="name" /> <br><br>
            生日:<input type="text" name="birth" /> <br><br> <!-- 浏览器提交的数据是表示日期的字符串,比如1980-2-3 -->
                <input type="submit" value="提交" />
        </form>
    </body>
</html>

下面是实体类User

package net.sonng.mvcdemo.entity;

import java.util.Date;

public class User {
    private String name;
    private Date birth;   //注意这个birth是Date,而不是String类型
    //.......
}

下面是controller

package net.sonng.mvcdemo.controller;

import net.sonng.mvcdemo.entity.User;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {
    @RequestMapping("/register")
    public String register(User user,Model model){
        model.addAttribute("user", user);
        return "result";
    }
}

部署运行,然后会出现400错误:The request sent by the client was syntactically incorrect.

接下来写个转换器:

package net.sonng.mvcdemo.converter;

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

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

public class StringToDateConverter implements Converter<String,Date>{   //实现Converter接口
    private String datePattern;
    public void setDatePattern(String pattern){
        this.datePattern=pattern;
    }
    @Override
    public Date convert(String date){
        try{
            SimpleDateFormat dateFormat=new SimpleDateFormat(this.datePattern);
            return dateFormat.parse(date);
        }catch(Exception ex){
            ex.printStackTrace();
            System.out.println("日期转换失败");
            return null;
        }
    }
}

将其配置到applicationContext.xml中:

<mvc:annotation-driven conversion-service="conversionService"  />
    
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" >
        <property name="converters" >
            <list> <!-- 这里可以配置多个转换器 -->
                <bean class="net.sonng.mvcdemo.converter.StringToDateConverter" p:datePattern="yyyy-MM-dd" />
            </list>
        </property>
    </bean>

重新部署访问,成功

几个接口

  • ConversionService:
    • 这是Spring 类型转换体系的核心接口
  • ConversionServiceFactoryBean
    • 这个相当于是类型转换器的容器,里面可以配置很多个转换器
  • 转换器接口:
    • Converter<S,T>:最简单的转换器接口,将S类型转为T类型
    • ConverterFactory<S,R>:将S类型转换为另一种类型T及其子类型R的转换器接口。将相同系列多个Converter封装到一起
    • GenericConverter:相对于Converter接口,该接口会根据源类型与目标类型的上下文信息进行转换

使用局部的java.beans.PropertyEditor接口

该接口是Java SE中的接口,其核心功能是将字符串转为Java对象,只能用与字符串和Java对象的转换,不能识别到源类型及目标类型的上下文信息,不能实现高级转换逻辑

写一个转换类继承PropertyEditorSupport,该类实现了PropertyEditor接口

package net.sonng.mvcdemo.converter;

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

public class DateEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text){
        SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
        try{
            Date date=dateFormat.parse(text);
            setValue(date);
        }catch(ParseException e){
            e.printStackTrace();
        }
    }
}

再在Controller中添加一个方法:

package net.sonng.mvcdemo.controller;

import java.util.Date;

import net.sonng.mvcdemo.converter.DateEditor;
import net.sonng.mvcdemo.entity.User;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {
    
    @InitBinder /*该注解会在该Controller初始化的时候注册一个转换器(属性编辑器)*/
    public void initBinder(WebDataBinder binder){ /*WebDataBinder是Spring提供的支持*/
        binder.registerCustomEditor(Date.class, new DateEditor()); /*表示DateEditor的目标类型是Date*/
    }
    
    @RequestMapping("/register")
    public String register(User user,Model model){
        model.addAttribute("user", user);
        return "result";
    }
}

部署访问,ok

使用全局的PropertyEditor

上面一个示例中,用@InitBinder注解只是让自定义的PropertyEditor在当前Controller范围内使用,如果要在全局范围内使用,则需要写个类实现WebBindingInitializer接口,再将自定义的PropertyEditor注册在其中,再到applicationContext.xml中进行装配

写个WebBindingInitializer的实现类

package net.sonng.mvcdemo.converter;

import java.util.Date;

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest;

public class DateBindingInitializer implements WebBindingInitializer {  //实现该接口

    @Override
    public void initBinder(WebDataBinder binder, WebRequest request) {
        binder.registerCustomEditor(Date.class,new DateEditor());       //注册自定义的PropertyEditor
    }
}

applicationContext.xml中配置该实现类

    <!-- 《Spring MVC + MyBatis 企业应用实战》里面用的AnnotationMethodHandlerAdapter,实际测试下来无效,得用RequestMappingHandlerAdapter;并且要将<mvc:annotation-driven />写在下方,写在上面无效 -->
    <!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> --> 
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" >
        <property name="webBindingInitializer">
            <bean class="net.sonng.mvcdemo.converter.DateBindingInitializer" />
        </property>
        <property name="cacheSeconds" value="0" />
    </bean>
    
    <mvc:annotation-driven  />  <!-- 特别注意,这条配置要写在下方,写在上方无效 -->

这里参考:webBindingInitializer 在XML中无效

三者优先级

  1. @InitBinder
  2. ConversionService
  3. WebBindingInitializer

总结

这里写了三种配置转换器的方法:
----全局的ConversionService,实现三个转换器接口之一,再在xml中配置
----局部的PropertyEditor,在Controller中写个注册方法,再用@InitBinder注释
----全局的PropertyEditor,写个类实现 WebBindingInitializer接口,将写好的转换器注册到其中,然后到xml中配置,配置要特别注意用RequestMappingHandlerAdapter,并且要把<mvc:annotation-driven />写在下方

posted @ 2017-04-02 13:28  sonng  阅读(1434)  评论(0编辑  收藏  举报