使用线程安全的spring类型转换器ConversionService VS TypeConverter

此文翻译源:http://www.theserverside.com/tip/Spring-Converters-and-Formatters。部分无用的部分有删除

1 类型转换接口

在spring3.0之前,如果要自己实现一个从字符串到其它对象的转换,那么就需要实现PropertyEditor接口。PropertyEditor是遵循javaBean规范的属性处理器,其通过set方法设置属性值,通过get方法获取属性值,相应的转换逻辑就隐藏于其中。这个接口惟一的问题在于,他们不是线程安全的.并且只能实现从字符串到其它对象的转换。

在spring3.0,提供了一个更简单的类型转换器接口。在spring mvc中,可以使用内置的或者自己实现的接口来实现从请求参数到对象之间的转换。其相应的接口定义如下:

public interface Converter<S,T> {
    public T convert(S source);
}

即通过一个S类型的对象,将其转换为T类型的对象。其中S类型并不局限于字符串,可以是任何类型。这是与PropertyEditor的主要区别。

如下是一个从加密的密钥转换为银行账号的实现器,参考如下:

public class EncryptedKeyToBankAccountConverter implements Converter<String, BankAccount> {
public BankAccount convert(String key) {
	if (key == null) {
		throw IllegalArgumentException();
	}
	String decryptedKey = Decryptor.decrypt(key);
	if (decryptedKey == null) {
		throw InvalidKeyException(); // Custom Exception from your application
	}
	return new BankAccount(decryptedKey);
}
}

在具体实现中,很重要的一点就是:保证你的实现是无状态的,同时保证返回值不能为null。对于null返回的场景,更应该通过抛出IllegalArgumentException来表示参数错误,

2 使用ConversionService及自定义转换器

如果只是使用spring自带的的转换器,只需要如下配置即可:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"/>

如果需要注册自己实现的转换器,则需要通过以下方式进行配置:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="converters">
		<list>
			<bean class="com.serverside.EncryptedKeyToBankAccountConverter" />
		</list>
	</property>
</bean>

如上配置之后,使用conversionService即可以转换自己想要转换的S和T。如下的代码所示:

//bean 对象
public class BankCustomer {
	BankAccount checkingAccount;

	public void setCheckingAccount(BankAccount checkingAccount) {
		this.checkingAccount = checkingAccount;
	}
}
<bean id="bankCustomer" class="com.serverside.convertertips.BankCustomer" scope="session">
	<property name="checkingAccount" value="67dsdh8673hnkluye3nd38dn4j78vbn3"/>
</bean>

以上的配置,在获取bankCustomerBean时即可通过conversionService将字符串转换为bankAccount对象。

附原文(同样描述了如何在spring mvc中使用转换器)

1) Converter interface

Before Spring 3.0, to convert String values in your Spring configuration file to an Object type in your classes that weren't built into either the JDK or Spring, you had to implement your own PropertyEditors. The great thing about PropertyEditors are that they are defined by the JavaBean specification and can be reused anywhere that uses PropertyEditors. The problem with PropertyEditors were that they are stateful and therefore not thread-safe. They also can only convert to and from String to Object types. And if you also wanted to use them in Spring MVC, you had to bind them in all your Controllers.

Spring 3.0 now introduces a simple Converter interface that you can implement and reuse anywhere in Spring. And you can use them in Spring MVC to convert request String values to Controller method parameter values of any Object type that you can write a Converter for.

The Converter interface is rather simple:

public interface Converter<S,T> {
	public T convert(S source);
}

By implementing this interface the S source object can be converted to the T return type.This means you are not bound to convert to and from Strings only.

public class EncryptedKeyToBankAccountConverter implements Converter<String, BankAccount> {
public BankAccount convert(String key) {
	if (key == null) {
		throw IllegalArgumentException();
	}
	String decryptedKey = Decryptor.decrypt(key);
	if (decryptedKey == null) {
		throw InvalidKeyException(); // Custom Exception from your application
	}
	return new BankAccount(decryptedKey);
}
}

It is important that you keep your Converter stateless, and guarantee that the convert method never returns null. If an invalid parameter value is passed, throw an IllegalArgumentException. And instead of ever returning null throw another Exception.

2) Using converters and registering your custom converters

The only Spring configuration requirement is to create a bean of type ConversionService.

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"/>

and register your converters via the "converters" property of ConversionServiceFactoryBean.

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="converters">
		<list>
			<bean class="com.serverside.EncryptedKeyToBankAccountConverter" />
		</list>
	</property>
</bean>

Now Spring will use your converters to convert String configuration values to the correct Object type.

public class BankCustomer {
	BankAccount checkingAccount;

	public void setCheckingAccount(BankAccount checkingAccount) {
		this.checkingAccount = checkingAccount;
	}
}
<bean id="bankCustomer" class="com.serverside.convertertips.BankCustomer" scope="session">
	<property name="checkingAccount" value="67dsdh8673hnkluye3nd38dn4j78vbn3"/>
</bean>

Here the BankCustomer bean will get a BankAccount injected into it via converting the value string into a BankAcount object.Normally a BankCustomer and BankAccount object wouldn't be used as beans, since they seem to be domain objects.

And if you want to use them in your Spring MVC application, just refer to your conversionService bean via the new mvc namespace.

<mvc:annotation-driven conversion-service="conversionService"/>

If your web page encrypts the BankAccount number/key in the client side and sends it to the server side to your Controller method. Spring will call your converter which will decrypt the String, create a BankAccount object and pass it in as the value of the bankAccount parameter value.

@Controller
public class BankAccountController {

	@Autowired
	BankAccountService bankAccountService;

	@RequestMapping(value="/depositList", method=RequestMethod.GET)
	public String getListOfDeposits(@RequestParam("accountKey")BankAccount bankAccount, ModelMap model) {
		List<Deposit> deposits = bankAccountService.getListOfDeposits(bankAccount);
		model.addObject(deposits);
		return "depositList";
	}
}

Spring has also introduced a Formatter API which can convert types of objects via formats. This means that a date formatted MM/DD/YYYY can be converted to one type of Joda DateTime object, but if it is formatted DD/MM/YYYY it can be converted to a different Joda DateTime object.In most cases, the issue comes when you have different formats for the same type of data. This could be because of internationalization.

Spring's new Expression Language can also leverage Converters.

Converters combined with Spring's new Formatter API and Spring Expression Language goes well beyond the capabilities of PropertyEditors, and greatly reduces the amount of code necessary prior to Spring 3.0.This is a welcome addition and after using it a few times I think you will find it extremely powerful and easy to create and use.

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201502100001.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

电子邮件地址不会被公开。 必填项已用*标注