spring类型自动转换——@InitBinder和Converter

spring有2种类型转换器,一种是propertyEditor,一种是Converter.虽然都是类型转换,但是还是有细微差别.

所以这里以一个例子的形式来分析一下这2种类型转换的使用场景和差别.

平常的应用中应该有很多这样的情况,一个po中有一个字段是status,这个status=0时代表成功,status=1时代表失败...虽然这个status可以定义为Integer的类型,但是有时候可能为了方便管理和更面向对象,直接定义了一个TypeStatus的类来表示这个status字段.这个TypeStatus的实现可能如下,当然这只是个demo不要当真:

public class TypeStatus {

    private Integer value;
    private String msg;

    public TypeStatus(Integer value, String msg) {
        this.value = value;
        this.msg = msg;
    }
    public static TypeStatus toBean(Integer value){
        if(value==0){
            return new TypeStatus(0,"成功");
        }else if(value==1){
            return new TypeStatus(1,"失败");
        }else{
            return null;
        }
    }
    public Integer getValue() {
        return value;
    }
    public String getMsg() {
        return msg;
    }
}

然后问题来了,虽然这样封装了一下后那个status字段变得更生动了..但是我们从前端页面中传过来一个0,到controller中spring如何把0转成一个TypeStatus类型呢?假设含有这个status字段的po如下:

public class PoDemo {
    TypeStatus status;
}

controller如下:

public class DemoController {
    
    public String testEditor(PoDemo po){
        return "ok";
    }

}

从一种类型到另一个类型,这肯定需要用到类型转换,我们先看第一种propertyEditor的实现,在controller中增加如下方法:

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(TypeStatus.class, "status", new TypeStatusEditor());
    }

方法registerCustomEditor的第二个参数为字段名,标识字段名为status,类型为TypeStatus的属性将会应用此类型转换,如果我们的PoDemo有另一个字段statusToo也为TypeStatus类型,那么将不会应用此类型转换.如果想把所有的TypeStatus类型字段都应用此类型转换,则第二个参数可以设置为null.

TypeStatusEditor的实现如下:

public class TypeStatusEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        TypeStatus ts = (TypeStatus) getValue();
        return String.valueOf(ts.getValue());
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        TypeStatus ts = TypeStatus.toBean(Integer.parseInt(text));
        setValue(ts);
    }        

}

PropertyEditor的使用此处不做讨论.从代码中也大体能看出实际是一个String到类型的过程,这个恰恰是propertyEditor和Converter的一个区别所在.PropertyEditor主要应用场景为String到类型的转换.从Editor提供的get和set方法也可以看出,必经过String.一般前台页面传过来的值大多是String类型,此时用PropertyEditor来转换再合适不过了.
ProertyEditor是String到类型,这只是一种特殊情况的转换,而说到最通用的肯定是类型到类型.此时就是Converter的应用了.
还是PoDemo和Controller:

public class PoDemo {
    byte[] img;
}
public class DemoController {
    
    public String testEditor(PoDemo po){
        return "ok";
    }

}

比如我们向数据库中存一个图片,那么数据库中是以blob类型存储的,而java类中对应的类型实际是byte[],那么问题又来了,我前台上传一张图片实际上以MultipartFile类型传到Controller中的,spring如何将MultipartFile转换成byte[]自动封装成PoDemo类呢?此时PropertyEditor显然不行了.这已经是类型到类型转换,只能用Converter.

实现如下:

public class MultipartFileToByteArrayEditor implements  Converter<CommonsMultipartFile,byte[]> {

    @Override
    public byte[] convert(CommonsMultipartFile source) {
        return source.getBytes();
    }    
    
}

然后我们还需要在spring的配置文件中注册一下:

<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>
<bean id="conversionService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
          <property name="converters">
            <list>
                <bean class="xx.xx.MultipartFileToByteArrayEditor"/>  
            </list>
         </property>
    </bean>

这里使用的系统提供的FormattingConversionServiceFactoryBean来注册我们的类型转换器类MultipartFileToByteArrayEditor,实际也可以用ConversionServiceFactoryBean来注册.

都配置好后,spring就可以自动将MultipartFile转换成byte[]并封装成PoDemo了.

可能有人想到Converter实际上是包含PropertyEditor的,那么如果2种转换器都适用,那么究竟会适用哪种呢?Spring默认是首先查找PropertyEditor,然后再查找Converter.

总结:PropertyEditor适用于String到类型,而Converter更加通用用于类型到类型.PropertyEditor优先级更高.

 

posted on 2016-02-22 23:01  蓝萝卜blu  阅读(4308)  评论(1编辑  收藏  举报

导航