100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > springmvc转换器converter的使用

springmvc转换器converter的使用

时间:2018-12-27 12:48:50

相关推荐

springmvc转换器converter的使用

1:写在前面

页面传递的参数都是string,而在控制器中接收参数类型是不确定的,对于基础数据类型,springmvc已经提供了类型转换器,对于不支持的目标类型,例如日期类型,自定义的对象类型,则可以通过实现接口org.springframework.core.convert.converter.Converter接口的方法来实现,该接口定义如下:

@FunctionalInterfacepublic interface Converter<S, T> {@NullableT convert(S source);}

其中的泛型<S, T>中的S代表的是页面参数的类型,一般是String,T代表控制器中接收参数的类型,方法convert(source)就是我们要实现的从S转换为T的方法。接下来我们实现一个通过字符串向自定义对象转换的小栗子。

2:定义接收参数对象

public class GoodsModel {private String goodsname;private double goodsprice;private int goodsnumber;...getter and setter...}

3:定义类型转换器

我们假定传递参数为英文逗号分割的字符串,通过字符串分割后可以获取构建GoodModel对象需要的值,则源码如下:

public class MyGoodsModelConverter implements Converter<String, GoodsModel> {public MyGoodsModelConverter() {System.out.println("MyGoodsModelConverter no args constructor invoked!!!");}@Overridepublic GoodsModel convert(String source) {String logHead = "MyGoodsModelConverter_convert";System.out.println(logHead + " begin, source is: " + source);// 创建一个Goods实例GoodsModel goods = new GoodsModel();// 以英文逗号,分隔String stringvalues[] = source.split(",");if (stringvalues != null && stringvalues.length == 3) {// 为Goods实例赋值goods.setGoodsname(stringvalues[0]);goods.setGoodsprice(Double.parseDouble(stringvalues[1]));goods.setGoodsnumber(Integer.parseInt(stringvalues[2]));System.out.println(logHead + " end, goods is: " + goods);return goods;} else {throw new IllegalArgumentException(String.format("类型转换失败, 需要格式'apple, 10.58,200 ',但格式是[% s ] ", source));}}}

4:注册类型转换器

从String自动转换为dongshi.converter.GoodsModel的转换器需要注意这里的转换器是属于MVC范畴的,所以一定要配置在springMVC的配置文件,即{dispatcher-servlet-name}-spring.xml文件中,如

<servlet><servlet-name>letsGO</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>...<!-- 值越小优先级越高 --><load-on-startup>1</load-on-startup></servlet>

则需要配置的配置文件是letsGO-servlet.xml,配置方式如下:

<bean id="myConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><property name="converters"><set><bean class="dongshi.converter.MyGoodsModelConverter"/></set></property></bean><mvc:annotation-driven conversion-service="myConversionService">...消息转换等配置,和自定义转换器配置没有关系...</mvc:annotation-driven>

5:controller

@RequestMapping("/mytest")@Controllerpublic class MyTestController {@RequestMapping("/testConverter")@ResponseBodypublic GoodsModel testConverter(@RequestParam("goods") GoodsModel testConverter) {System.out.println(testConverter);return testConverter;}}

6:测试

分别在转换器的return goods;和controler的return testConverter;打断点测试,通过curlcurl http://localhost:8080/Gradle___org_springframework___dongsir_testspringmvc_5_1_18_BUILD_SNAPSHOT_war__exploded_/mytest/testConverter?goods=3,4,5,转换器如下图:

继续走代码到controller断点,如下图:

执行后返回:

{"goodsname":"3","goodsprice":4.0,"goodsnumber":5}

7:springboot环境

如果是在springboot环境中,则只需要定义转换器为spring的bean就可以了,springboot会自动从容器中扫描并通过DefaultFormattingConversionService类完成注册,其中,自动注册部分源码如下:

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addFormatters@Overridepublic void addFormatters(FormatterRegistry registry) {ApplicationConversionService.addBeans(registry, this.beanFactory);}org.springframework.boot.convert.ApplicationConversionService#addBeanspublic static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {Set<Object> beans =new LinkedHashSet();// 注册自定义的GenericConverterbeans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());// 注册自定义Converter(本例重点)beans.addAll(beanFactory.getBeansOfType(Converter.class).values());// 忽略beans.addAll(beanFactory.getBeansOfType(Printer.class).values());// 忽略beans.addAll(beanFactory.getBeansOfType(Parser.class).values());...}

下面我们开始实例。

7.1:定义controller

@RestControllerpublic class HelloWorldController {@RequestMapping("/testSpringBootConverter")@ResponseBodypublic GoodsModel testSpringBootConverter(@RequestParam("springboot-goods") GoodsModel testConverter) {System.out.println(testConverter);return testConverter;}}

不注册自定义转换器访问测试:

7.2:定义转换器

注意添加@Component注册到spring的容器中,成为spring的bean:

public class MySpringBootGoodsModelConverter implements Converter<String, GoodsModel> {public MySpringBootGoodsModelConverter() {System.out.println("MyGoodsModelConverter no args constructor invoked!!!");}@Overridepublic GoodsModel convert(String source) {String logHead = "MyGoodsModelConverter_convert";System.out.println(logHead + " begin, source is: " + source);// 创建一个Goods实例GoodsModel goods = new GoodsModel();// 以英文逗号,分隔String stringvalues[] = source.split(",");if (stringvalues != null && stringvalues.length == 3) {// 为Goods实例赋值goods.setGoodsname(stringvalues[0]);goods.setGoodsprice(Double.parseDouble(stringvalues[1]));goods.setGoodsnumber(Integer.parseInt(stringvalues[2]));System.out.println(logHead + " end, goods is: " + goods);return goods;} else {throw new IllegalArgumentException(String.format("类型转换失败, 需要格式'apple, 10.58,200 ',但格式是[% s ] ", source));}}}

这样就可以了,springboot就会自动完成注册了,启动应用时debug如下:

debug位置org.springframework.boot.convert.ApplicationConversionService#addBeans

7.3:访问测试

8:GenericConverter

前面的Converter是一对一转化器接口,即转换的源和目标都是单一的对象,GenericConverter可以认为是对Converter的增强,支持一对多,源码如下:

public interface GenericConverter {@NullableObject convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);}

即控制器的参数可以是List类型的,在spring中已经提供了StringToCollectionConverter来默认提供String向集合转换,源码如下:

org.springframework.core.convert.support.StringToCollectionConverter#convert@Override@Nullablepublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {// 强转http中的字符串String string = (String) source;// 按照英文逗号分割为字符串数组(重点!!!)String[] fields = maDelimitedListToStringArray(string);// 获取http参数的类型描述器,这里一般都是字符串TypeDescriptor elementDesc = targetType.getElementTypeDescriptor();Collection<Object> target = CollectionFactory.createCollection(targetType.getType(),(elementDesc != null ? elementDesc.getType() : null), fields.length);// 一般不会进if,所以只看else逻辑if (elementDesc == null) {for (String field : fields) {target.add(field.trim());}}else {// 遍历每个字段值,调用convertionService,实际上就是GenericConversionService方法,该方法内部会通过// sourceType+targetType(elementDesc)组合的方式来寻找可进行转换的转换器进行转换,转换后添加到最终的结果集中for (String field : fields) {Object targetElement = this.conversionService.convert(field.trim(), sourceType, elementDesc);target.add(targetElement);}}// 返回结果集return target;}

该转换器是先通过切割字符串的方式获取字符串数组,然后对每个元素,在通过http原始类型+控制器中的元素类型匹配的方式获取对应的转换器再进行转换,因此,前面的例子,我们就可以定义一个List控制器参数,然后http参数通过逗号分割的方式,就可以进行多值传递了。

8.1:定义controller

@RequestMapping("/testSpringBootConverterWithList")@ResponseBodypublic List<GoodsModel> testSpringBootConverter(@RequestParam("springboot-goods-list") List<GoodsModel> testConverterList) {System.out.println(testConverterList);return testConverterList;}

8.2:改造转换器

因为我们前面的转换器也是通过英文逗号分割的,这里和StringToCollectionConverter冲突,所以我们改为使用_分割:

将:String stringvalues[] = source.split(",");改为:String stringvalues[] = source.split("_");

8.3:测试

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。