你的位置:首页 > Java教程

[Java教程]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优先级更高.