`

第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC数据格式化——跟着开涛学SpringMVC

阅读更多

7.3、数据格式化

在如Web /客户端项目中,通常需要将数据转换为具有某种格式的字符串进行展示,因此上节我们学习的数据类型转换系统核心作用不是完成这个需求,因此Spring3引入了格式化转换器(Formatter SPI) 和格式化服务API(FormattingConversionService)从而支持这种需求。在Spring中它和PropertyEditor功能类似,可以替代PropertyEditor来进行对象的解析和格式化,而且支持细粒度的字段级别的格式化/解析。

 

Formatter SPI核心是完成解析和格式化转换逻辑,在如Web应用/客户端项目中,需要解析、打印/展示本地化的对象值时使用,如根据Locale信息将java.util.Date---->java.lang.String打印/展示、java.lang.String---->java.util.Date等。

 

该格式化转换系统是Spring通用的,其定义在org.springframework.format包中,不仅仅在Spring Web MVC场景下。

 

7.3.1、架构

1、格式化转换器:提供格式化转换的实现支持。


 

一共有如下两组四个接口:

(1、Printer接口:格式化显示接口,将T类型的对象根据Locale信息以某种格式进行打印显示(即返回字符串形式);

Java代码  收藏代码
  1. package org.springframework.format;  
  2. public interface Printer<T> {  
  3.     String print(T object, Locale locale);   
  4. }  

(2、Parser接口:解析接口,根据Locale信息解析字符串到T类型的对象;

Java代码  收藏代码
  1. package org.springframework.format;  
  2. public interface Parser<T> {  
  3.     T parse(String text, Locale locale) throws ParseException;  
  4. }  

解析失败可以抛出java.text.ParseException或IllegalArgumentException异常即可。

 

(3、Formatter接口:格式化SPI接口,继承Printer和Parser接口,完成T类型对象的格式化和解析功能;

Java代码  收藏代码
  1. package org.springframework.format;  
  2. public interface Formatter<T> extends Printer<T>, Parser<T> {  
  3. }  

(4、AnnotationFormatterFactory接口:注解驱动的字段格式化工厂,用于创建带注解的对象字段的Printer和Parser,即用于格式化和解析带注解的对象字段。

Java代码  收藏代码
  1. package org.springframework.format;  
  2. public interface AnnotationFormatterFactory<A extends Annotation> {//①可以识别的注解类型  
  3.     Set<Class<?>> getFieldTypes();//②可以被A注解类型注解的字段类型集合  
  4.     Printer<?> getPrinter(A annotation, Class<?> fieldType);//③根据A注解类型和fieldType类型获取Printer  
  5.     Parser<?> getParser(A annotation, Class<?> fieldType);//④根据A注解类型和fieldType类型获取Parser  
  6.   
  7. }  

返回用于格式化和解析被A注解类型注解的字段值的Printer和Parser。如JodaDateTimeFormatAnnotationFormatterFactory可以为带有@DateTimeFormat注解的java.util.Date字段类型创建相应的Printer和Parser进行格式化和解析。

 

2、格式化转换器注册器、格式化服务:提供类型转换器注册支持,运行时类型转换API支持。

 

 


一个有如下两种接口:

(1、FormatterRegistry:格式化转换器注册器,用于注册格式化转换器(Formatter、Printer和Parser、AnnotationFormatterFactory);

 

 

Java代码  收藏代码
  1. package org.springframework.format;  
  2. public interface FormatterRegistry extends ConverterRegistry {  
  3.     //①添加格式化转换器(Spring3.1 新增API)  
  4.     void addFormatter(Formatter<?> formatter);  
  5.     //②为指定的字段类型添加格式化转换器  
  6.     void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);  
  7.     //③为指定的字段类型添加Printer和Parser  
  8.     void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);  
  9.     //④添加注解驱动的字段格式化工厂AnnotationFormatterFactory  
  10.     void addFormatterForFieldAnnotation(  
  11.                 AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);  
  12. }   

(2、FormattingConversionService:继承自ConversionService,运行时类型转换和格式化服务接口,提供运行期类型转换和格式化的支持。

 

 

FormattingConversionService内部实现如下图所示:


我们可以看到FormattingConversionService内部实现如上所示,当你调用convert方法时:

⑴若是S类型----->String:调用私有的静态内部类PrinterConverter,其又调用相应的Printer的实现进行格式化;

⑵若是String----->T类型:调用私有的静态内部类ParserConverter,其又调用相应的Parser的实现进行解析;

⑶若是A注解类型注解的S类型----->String:调用私有的静态内部类AnnotationPrinterConverter,其又调用相应的AnnotationFormatterFactory的getPrinter获取Printer的实现进行格式化;

⑷若是String----->A注解类型注解的T类型:调用私有的静态内部类AnnotationParserConverter,其又调用相应的AnnotationFormatterFactory的getParser获取Parser的实现进行解析。

 

注:S类型表示源类型,T类型表示目标类型,A表示注解类型。

 

此处可以可以看出之前的Converter SPI完成任意Object与Object之间的类型转换,而Formatter SPI完成任意Object与String之间的类型转换(即格式化和解析,与PropertyEditor类似)。

 

7.3.2、Spring内建的格式化转换器如下所示:

类名

说明

DateFormatter

java.util.Date<---->String

实现日期的格式化/解析

NumberFormatter

java.lang.Number<---->String

实现通用样式的格式化/解析

CurrencyFormatter

java.lang.BigDecimal<---->String

实现货币样式的格式化/解析

PercentFormatter

java.lang.Number<---->String

实现百分数样式的格式化/解析

NumberFormatAnnotationFormatterFactory

@NumberFormat注解类型的数字字段类型<---->String

①通过@NumberFormat指定格式化/解析格式

②可以格式化/解析的数字类型:Short、Integer、Long、Float、Double、BigDecimal、BigInteger

JodaDateTimeFormatAnnotationFormatterFactory

@DateTimeFormat注解类型的日期字段类型<---->String

①通过@DateTimeFormat指定格式化/解析格式

②可以格式化/解析的日期类型:

joda中的日期类型(org.joda.time包中的):LocalDate、LocalDateTime、LocalTime、ReadableInstant

java内置的日期类型:Date、Calendar、Long

 

classpath中必须有Joda-Time类库,否则无法格式化日期类型

NumberFormatAnnotationFormatterFactory和JodaDateTimeFormatAnnotationFormatterFactory(如果classpath提供了Joda-Time类库)在使用格式化服务实现DefaultFormattingConversionService时会自动注册。

 

7.3.3、示例

在示例之前,我们需要到http://joda-time.sourceforge.net/下载Joda-Time类库,本书使用的是joda-time-2.1版本,将如下jar包添加到classpath:

Java代码  收藏代码
  1. joda-time-2.1.jar  

 

 

7.3.3.1、类型级别的解析/格式化

一、直接使用Formatter SPI进行解析/格式化

Java代码  收藏代码
  1. //二、CurrencyFormatter:实现货币样式的格式化/解析  
  2. CurrencyFormatter currencyFormatter = new CurrencyFormatter();  
  3. currencyFormatter.setFractionDigits(2);//保留小数点后几位  
  4. currencyFormatter.setRoundingMode(RoundingMode.CEILING);//舍入模式(ceilling表示四舍五入)  
  5.   
  6. //1、将带货币符号的字符串“$123.125”转换为BigDecimal("123.00")  
  7. Assert.assertEquals(new BigDecimal("123.13"), currencyFormatter.parse("$123.125", Locale.US));  
  8. //2、将BigDecimal("123")格式化为字符串“$123.00”展示  
  9. Assert.assertEquals("$123.00", currencyFormatter.print(new BigDecimal("123"), Locale.US));  
  10. Assert.assertEquals("¥123.00", currencyFormatter.print(new BigDecimal("123"), Locale.CHINA));  
  11. Assert.assertEquals("¥123.00", currencyFormatter.print(new BigDecimal("123"), Locale.JAPAN));  
  12.            

parse方法:将带格式的字符串根据Locale信息解析为相应的BigDecimal类型数据;

print方法:BigDecimal类型数据根据Locale信息格式化为字符串数据进行展示。

 

不同于Convert SPI,Formatter SPI可以根据本地化(Locale)信息进行解析/格式化。

 

其他测试用例请参考cn.javass.chapter7.web.controller.support.formatter.InnerFormatterTest的testNumber测试方法和testDate测试方法。

Java代码  收藏代码
  1. @Test  
  2. public void testWithDefaultFormattingConversionService() {  
  3.     DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();  
  4.     //默认不自动注册任何Formatter  
  5.     CurrencyFormatter currencyFormatter = new CurrencyFormatter();  
  6.     currencyFormatter.setFractionDigits(2);//保留小数点后几位  
  7.     currencyFormatter.setRoundingMode(RoundingMode.CEILING);//舍入模式(ceilling表示四舍五入)  
  8.     //注册Formatter SPI实现  
  9.     conversionService.addFormatter(currencyFormatter);  
  10.           
  11.     //绑定Locale信息到ThreadLocal  
  12.     //FormattingConversionService内部自动获取作为Locale信息,如果不设值默认是 Locale.getDefault()  
  13.     LocaleContextHolder.setLocale(Locale.US);  
  14.     Assert.assertEquals("$1,234.13", conversionService.convert(new BigDecimal("1234.128"), String.class));  
  15.     LocaleContextHolder.setLocale(null);  
  16.       
  17.         LocaleContextHolder.setLocale(Locale.CHINA);  
  18.         Assert.assertEquals("¥1,234.13", conversionService.convert(new BigDecimal("1234.128"), String.class));  
  19.     Assert.assertEquals(new BigDecimal("1234.13"), conversionService.convert("¥1,234.13", BigDecimal.class));  
  20.     LocaleContextHolder.setLocale(null);}   

DefaultFormattingConversionService带数据格式化功能的类型转换服务实现;

conversionService.addFormatter()注册Formatter SPI实现;

conversionService.convert(new BigDecimal("1234.128"), String.class)用于将BigDecimal类型数据格式化为字符串类型,此处根据“LocaleContextHolder.setLocale(locale)”设置的本地化信息进行格式化;

conversionService.convert("1,234.13", BigDecimal.class)用于将字符串类型数据解析为BigDecimal类型数据,此处也是根据“LocaleContextHolder.setLocale(locale)”设置的本地化信息进行解;

LocaleContextHolder.setLocale(locale)设置本地化信息到ThreadLocal,以便Formatter SPI根据本地化信息进行解析/格式化;

 

具体测试代码请参考cn.javass.chapter7.web.controller.support.formatter.InnerFormatterTest的testWithDefaultFormattingConversionService测试方法。

 

三、自定义Formatter进行解析/格式化

此处以解析/格式化PhoneNumberModel为例。

 

(1、定义Formatter SPI实现 

 

Java代码  收藏代码
  1. package cn.javass.chapter7.web.controller.support.formatter;  
  2. //省略import  
  3. public class PhoneNumberFormatter implements Formatter<PhoneNumberModel> {  
  4.     Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");  
  5.     @Override  
  6.     public String print(PhoneNumberModel phoneNumber, Locale locale) {//①格式化  
  7.         if(phoneNumber == null) {  
  8.             return "";  
  9.         }  
  10.         return new StringBuilder().append(phoneNumber.getAreaCode()).append("-")  
  11.                                   .append(phoneNumber.getPhoneNumber()).toString();  
  12.     }  
  13.   
  14.     @Override  
  15.     public PhoneNumberModel parse(String text, Locale locale) throws ParseException {//②解析  
  16.         if(!StringUtils.hasLength(text)) {  
  17.             //①如果source为空 返回null  
  18.             return null;  
  19.         }  
  20.         Matcher matcher = pattern.matcher(text);  
  21.         if(matcher.matches()) {  
  22.             //②如果匹配 进行转换  
  23.             PhoneNumberModel phoneNumber = new PhoneNumberModel();  
  24.             phoneNumber.setAreaCode(matcher.group(1));  
  25.             phoneNumber.setPhoneNumber(matcher.group(2));  
  26.             return phoneNumber;  
  27.         } else {  
  28.             //③如果不匹配 转换失败  
  29.             throw new IllegalArgumentException(String.format("类型转换失败,需要格式[010-12345678],但格式是[%s]", text));  
  30.         }  
  31.     }  
  32. }  

 类似于Convert SPI实现,只是此处的相应方法会传入Locale本地化信息,这样可以为不同地区进行解析/格式化数据。

 

(2、测试用例:

Java代码  收藏代码
  1. package cn.javass.chapter7.web.controller.support.formatter;  
  2. //省略import  
  3. public class CustomerFormatterTest {  
  4.     @Test  
  5.     public void test() {  
  6.         DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();  
  7.         conversionService.addFormatter(new PhoneNumberFormatter());  
  8.   
  9.         PhoneNumberModel phoneNumber = new PhoneNumberModel("010""12345678");  
  10.         Assert.assertEquals("010-12345678", conversionService.convert(phoneNumber, String.class));  
  11.           
  12.         Assert.assertEquals("010", conversionService.convert("010-12345678", PhoneNumberModel.class).getAreaCode());  
  13.     }  
  14. }  

通过PhoneNumberFormatter可以解析String--->PhoneNumberModel和格式化PhoneNumberModel--->String。

 

到此,类型级别的解析/格式化我们就介绍完了,从测试用例可以看出类型级别的是对项目中的整个类型实施相同的解析/格式化逻辑。

 

有的同学可能需要在不同的类的字段实施不同的解析/格式化逻辑,如用户模型类的注册日期字段只需要如“2012-05-02”格式进行解析/格式化即可,而订单模型类的下订单日期字段可能需要如“2012-05-02 20:13:13”格式进行展示。

 

接下来我们学习一下如何进行字段级别的解析/格式化吧。

 

7.3.3.2、字段级别的解析/格式化

一、使用内置的注解进行字段级别的解析/格式化:

(1、测试模型类准备:

Java代码  收藏代码
  1. package cn.javass.chapter7.model;  
  2. public class FormatterModel {  
  3.     @NumberFormat(style=Style.NUMBER, pattern="#,###")  
  4.     private int totalCount;  
  5.     @NumberFormat(style=Style.PERCENT)  
  6.     private double discount;  
  7.     @NumberFormat(style=Style.CURRENCY)  
  8.     private double sumMoney;  
  9.       
  10.     @DateTimeFormat(iso=ISO.DATE)   
  11.     private Date registerDate;  
  12.       
  13.     @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")   
  14.     private Date orderDate;  
  15.   
  16.     //省略getter/setter  
  17. }   

此处我们使用了Spring字段级别解析/格式化的两个内置注解:

 

@Number:定义数字相关的解析/格式化元数据(通用样式、货币样式、百分数样式),参数如下:

    style:用于指定样式类型,包括三种:Style.NUMBER(通用样式) Style.CURRENCY(货币样式) Style.PERCENT(百分数样式),默认Style.NUMBER;

    pattern:自定义样式,如patter="#,###"

 

@DateTimeFormat定义日期相关的解析/格式化元数据,参数如下:

    pattern:指定解析/格式化字段数据的模式,如”yyyy-MM-dd HH:mm:ss”

iso:指定解析/格式化字段数据的ISO模式,包括四种:ISO.NONE(不使用)  ISO.DATE(yyyy-MM-dd) ISO.TIME(hh:mm:ss.SSSZ)  ISO.DATE_TIME(yyyy-MM-dd hh:mm:ss.SSSZ),默认ISO.NONE;

    style:指定用于格式化的样式模式,默认“SS”,具体使用请参考Joda-Time类库的org.joda.time.format.DateTimeFormat的forStyle的javadoc;

优先级: pattern 大于 iso 大于 style

 

(2、测试用例:

Java代码  收藏代码
  1. @Test  
  2. public void test() throws SecurityException, NoSuchFieldException {  
  3.     //默认自动注册对@NumberFormat和@DateTimeFormat的支持  
  4.     DefaultFormattingConversionService conversionService =   
  5.                                 new DefaultFormattingConversionService();  
  6.       
  7.     //准备测试模型对象  
  8.     FormatterModel model = new FormatterModel();  
  9.     model.setTotalCount(10000);  
  10.     model.setDiscount(0.51);  
  11.     model.setSumMoney(10000.13);  
  12.     model.setRegisterDate(new Date(2012-190041));  
  13.     model.setOrderDate(new Date(2012-190041201818));  
  14.        
  15.     //获取类型信息  
  16.     TypeDescriptor descriptor =   
  17.             new TypeDescriptor(FormatterModel.class.getDeclaredField("totalCount"));          
  18.     TypeDescriptor stringDescriptor = TypeDescriptor.valueOf(String.class);  
  19.           
  20.     Assert.assertEquals("10,000", conversionService.convert(model.getTotalCount(), descriptor, stringDescriptor));  
  21.     Assert.assertEquals(model.getTotalCount(), conversionService.convert("10,000", stringDescriptor, descriptor));  
  22.   
  23. }  

 TypeDescriptor拥有类型信息的上下文,用于Spring3类型转换系统获取类型信息的(可以包含类、字段、方法参数、属性信息);通过TypeDescriptor,我们就可以获取(类、字段、方法参数、属性)的各种信息,如注解类型信息;

conversionService.convert(model.getTotalCount(), descriptor, stringDescriptor):将totalCount格式化为字符串类型,此处会根据totalCount字段的注解信息(通过descriptor对象获取)来进行格式化;

conversionService.convert("10,000", stringDescriptor, descriptor)将字符串“10,000”解析为totalCount字段类型,此处会根据totalCount字段的注解信息(通过descriptor对象获取)来进行解析。

 

3、通过为不同的字段指定不同的注解信息进行字段级别的细粒度数据解析/格式化

 

Java代码  收藏代码
  1. descriptor = new TypeDescriptor(FormatterModel.class.getDeclaredField("registerDate"));  
  2. Assert.assertEquals("2012-05-01", conversionService.convert(model.getRegisterDate(), descriptor, stringDescriptor));  
  3. Assert.assertEquals(model.getRegisterDate(), conversionService.convert("2012-05-01", stringDescriptor, descriptor));  
  4.           
  5. descriptor = new TypeDescriptor(FormatterModel.class.getDeclaredField("orderDate"));  
  6. Assert.assertEquals("2012-05-01 20:18:18", conversionService.convert(model.getOrderDate(), descriptor, stringDescriptor));  
  7. Assert.assertEquals(model.getOrderDate(), conversionService.convert("2012-05-01 20:18:18", stringDescriptor, descriptor));  

 通过如上测试可以看出,我们可以通过字段注解方式实现细粒度的数据解析/格式化控制,但是必须使用TypeDescriptor来指定类型的上下文信息,即编程实现字段的数据解析/格式化比较麻烦。

 

其他测试用例请参考cn.javass.chapter7.web.controller.support.formatter.InnerFieldFormatterTest的test测试方法。

 

二、自定义注解进行字段级别的解析/格式化:

此处以解析/格式化PhoneNumberModel字段为例。

(1、定义解析/格式化字段的注解类型:

Java代码  收藏代码
  1. package cn.javass.chapter7.web.controller.support.formatter;  
  2. //省略import  
  3. @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})  
  4. @Retention(RetentionPolicy.RUNTIME)  
  5. public @interface PhoneNumber {  
  6. }  

 (2、实现AnnotationFormatterFactory注解格式化工厂:

 

Java代码  收藏代码
  1. package cn.javass.chapter7.web.controller.support.formatter;  
  2. //省略import  
  3. public class PhoneNumberFormatAnnotationFormatterFactory  
  4.     implements AnnotationFormatterFactory<PhoneNumber> {//①指定可以解析/格式化的字段注解类型  
  5.   
  6.     private final Set<Class<?>> fieldTypes;  
  7.     private final PhoneNumberFormatter formatter;  
  8.     public PhoneNumberFormatAnnotationFormatterFactory() {  
  9.         Set<Class<?>> set = new HashSet<Class<?>>();  
  10.         set.add(PhoneNumberModel.class);  
  11.         this.fieldTypes = set;  
  12.         this.formatter = new PhoneNumberFormatter();//此处使用之前定义的Formatter实现  
  13.     }  
  14.     //②指定可以被解析/格式化的字段类型集合  
  15.     @Override  
  16.     public Set<Class<?>> getFieldTypes() {  
  17.         return fieldTypes;  
  18.     }  
  19.     //③根据注解信息和字段类型获取解析器  
  20.     @Override  
  21.     public Parser<?> getParser(PhoneNumber annotation, Class<?> fieldType) {  
  22.         return formatter;  
  23.     }  
  24.     //④根据注解信息和字段类型获取格式化器  
  25.     @Override     
  26.     public Printer<?> getPrinter(PhoneNumber annotation, Class<?> fieldType) {  
  27.         return formatter;  
  28.     }  
  29. }   

AnnotationFormatterFactory实现会根据注解信息和字段类型获取相应的解析器/格式化器。

 

(3、修改FormatterModel添加如下代码:

Java代码  收藏代码
  1. @PhoneNumber  
  2. private PhoneNumberModel phoneNumber;   

(4、测试用例

Java代码  收藏代码
  1. @Test  
  2. ublic void test() throws SecurityException, NoSuchFieldException {  
  3. DefaultFormattingConversionService conversionService =   
  4.                                     new DefaultFormattingConversionService();//创建格式化服务  
  5. conversionService.addFormatterForFieldAnnotation(  
  6.                 new PhoneNumberFormatAnnotationFormatterFactory());//添加自定义的注解格式化工厂  
  7.       
  8. FormatterModel model = new FormatterModel();  
  9. TypeDescriptor descriptor =   
  10.         new TypeDescriptor(FormatterModel.class.getDeclaredField("phoneNumber"));  
  11. TypeDescriptor stringDescriptor = TypeDescriptor.valueOf(String.class);  
  12.   
  13. PhoneNumberModel value = (PhoneNumberModel) conversionService.convert("010-12345678", stringDescriptor, descriptor); //解析字符串"010-12345678"--> PhoneNumberModel  
  14. model.setPhoneNumber(value);  
  15.       
  16. Assert.assertEquals("010-12345678", conversionService.convert(model.getPhoneNumber(), descriptor, stringDescriptor));//格式化PhoneNumberModel-->"010-12345678"  
  17.    

 

此处使用DefaultFormattingConversionServiceaddFormatterForFieldAnnotation注册自定义的注解格式化工厂PhoneNumberFormatAnnotationFormatterFactory

 

到此,编程进行数据的格式化/解析我们就完成了,使用起来还是比较麻烦,接下来我们将其集成到Spring Web MVC环境中。

7.3.4、集成到Spring Web MVC环境

一、注册FormattingConversionService实现和自定义格式化转换器:

 

Java代码  收藏代码
  1. <bean id="conversionService"   
  2. class="org.springframework.format.support.FormattingConversionServiceFactoryBean">  
  3.   <!—此处省略之前注册的自定义类型转换器-->  
  4.   <property name="formatters">  
  5.       <list>  
  6.           <bean class="cn.javass.chapter7.web.controller.support.formatter.  
  7.                                                   PhoneNumberFormatAnnotationFormatterFactory"/>  
  8.       </list>  
  9.   </property>  
  10. </bean>  

 其他配置和之前学习7.2.2.4一节一样。

 

二、示例:

(1、模型对象字段的数据解析/格式化:

 

Java代码  收藏代码
  1. @RequestMapping(value = "/format1")  
  2. public String test1(@ModelAttribute("model") FormatterModel formatModel) {  
  3.     return "format/success";  
  4. }   
Java代码  收藏代码
  1. totalCount:<spring:bind path="model.totalCount">${status.value}</spring:bind><br/>  
  2. discount:<spring:bind path="model.discount">${status.value}</spring:bind><br/>  
  3. sumMoney:<spring:bind path="model.sumMoney">${status.value}</spring:bind><br/>  
  4. phoneNumber:<spring:bind path="model.phoneNumber">${status.value}</spring:bind><br/>  
  5. <!-- 如果没有配置org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor将会报错 -->  
  6. phoneNumber:<spring:eval expression="model.phoneNumber"></spring:eval><br/>  
  7.   
  8. <br/><br/>  
  9. <form:form commandName="model">  
  10.     <form:input path="phoneNumber"/><br/>  
  11.     <form:input path="sumMoney"/>  
  12. </form:form>  

 

在浏览器输入测试URL:

http://localhost:9080/springmvc-chapter7/format1?totalCount=100000&discount=0.51&sumMoney=100000.128&phoneNumber=010-12345678

 

数据会正确绑定到我们的formatModel,即请求参数能被正确的解析并绑定到我们的命令对象上,而且在JSP页面也能正确的显示格式化后的数据(即正确的被格式化显示)。

 

(2、功能处理方法参数级别的数据解析:

Java代码  收藏代码
  1. @RequestMapping(value = "/format2")  
  2. public String test2(  
  3.         @PhoneNumber @RequestParam("phoneNumber") PhoneNumberModel phoneNumber,   
  4.         @DateTimeFormat(pattern="yyyy-MM-dd"@RequestParam("date") Date date) {  
  5.         System.out.println(phoneNumber);  
  6.         System.out.println(date);  
  7.         return "format/success2";  
  8. }   

此处我们可以直接在功能处理方法的参数上使用格式化注解类型进行注解,Spring Web MVC能根据此注解信息对请求参数进行解析并正确的绑定。

 

在浏览器输入测试URL:

http://localhost:9080/springmvc-chapter7/format2?phoneNumber=010-12345678&date=2012-05-01

 

数据会正确的绑定到我们的phoneNumberdate上,即请求的参数能被正确的解析并绑定到我们的参数上。

 

控制器代码位于cn.javass.chapter7.web.controller.DataFormatTestController中。

 

如果我们请求参数数据不能被正确解析并绑定或输入的数据不合法等该怎么处理呢?接下来的一节我们来学习下绑定失败处理和数据验证相关知识。

 

原文地址:http://jinnianshilongnian.iteye.com/blog/1729739

原作者:开涛

如有侵权请通知我删除!!!

JAVA技术交流群 532101200

分享到:
评论

相关推荐

    springmvc注解式控制器的数据验证、类型转换及格式化 SpringMVC数据验证

    springmvc注解式控制器的数据验证、类型转换及格式化 SpringMVC数据验证 参数传递

    跟我学SpringMVC 教程

    第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC数据类型转换 第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC数据格式化 第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC...

    跟我学SpringMVC

    第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC数据类型转换 第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC数据格式化 第七章 注解式控制器的数据验证、类型转换及格式化 SpringMVC数据...

    SpringMvc开涛.rar

    PDF,源代码 开涛学SpringMVC 第一章源代码下载 第二章 Spring MVC入门 源代码下载 第四章 Controller接口控制器详解 源代码下载 第五章 处理器拦截器详解——跟着...第七章 注解式控制器的数据验证、类型转换及格式化

    SpringMVC数据类型转换超详细介绍

    SpringMVC数据类型转换超详细介绍,注解式控制器的数据验证、类型转换及格式化

    SpringMVC学习文档

    SpringMVC入门、Controller接口详解、注解详解、数据验证、类型转换及格式化等等

    SpringMVC示例

    员工信息、RESTRUL_CRUD_添加操作&表单标签、RESTRUL_CRUD_删除操作&处理静态资源、RESTRUL_CRUD_修改操作、自定义类型转换器、annotation-driven配置、InitBinder注解、数据的格式化、JSR 303数据校验、错误消息的...

    Spring MVC通过添加自定义注解格式化数据的方法

    主要给大家介绍了关于Spring MVC通过添加自定义注解格式化数据的方法,文中先对springmvc 自定义注解 以及自定义注解的解析进行了详细的介绍,相信会对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    SpringMVC大威天龙.docx

    SpringMVC是Spring提供的一个强大而灵活的Web框架 借助于注解 SpringMVC提供了几乎是POJO的开发模式 使得控制器的开发和测试更加简单 二 SpringMVC优点 1. 角色划分清晰 2. 分工明确 而且扩展相当灵活 3. 和Spring...

    SpringMVC Employee Demo

    driven配置、InitBinder注解、数据的格式化、JSR303数据校验、错误消息的显示及国际化、Ajax返回JSON、使用HttpMessageConverter、国际化_通过超链接切换中英文、文件上传、自定义的拦截器、拦截器的零Xml配置、异常...

    Spring、SpringMVC和Mybatis框架整合包

    手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis 博客地址:http://blog.csdn.net/qq598535550/article/details/51703190 我们看招聘信息的时候,经常会看到这一点,需要具备SSH框架的技能;而且在大...

    spring杂谈 作者zhang KaiTao

    1. spring杂谈[原创] 1.1 Spring事务处理时自我调用的解决方案及一些实现方式的风险 ...1.32 Spring3 Web MVC下的数据类型转换(第一篇)——《跟我学Spring3 Web MVC》抢先看 1.33 Spring 注入集合类型

    Spring MVC 3.0实战指南.ppt

    4、数据转换、格式化、校验 5、数据模型控制 6、视图及解析器 7、其它 目录: Spring MVC 3.0新特性 Spring MVC框架结构 Spring MVC框架结构 框架的实现者 目录 HTTP请求映射原理 Spring MVC进行映射的依据 通过URL...

    Spring3_MVC注解教程.ppt

    支持REST风格的URL 添加更多注解,可完全注解驱动 引入HTTP输入输出转换器...和数据转换、格式化、验证框架无缝集成 对静态资源处理提供特殊支持 更加灵活的控制器方法签名,可完全独立于Servlet API

    spring-mvc-learn:spring-mvc学习代码源码-mvc source code

    转换器(转换器)和格式化(Formatter) 转炉 实现转换器接口 在spring-mvc的配置文件中添加bean:org.springframework.context.support.ConversionServiceFactoryBean,注册转换器,添加注释驱动的转换服务属性 ...

    spring mvc 3.2 参考文档

    Spring的视图解析也非常灵活,控制器通常负责准备含有数据的model Map并选择一种视图名称,当然,它也可以直接直接写响应流,并完成该请求。视图名称解析可以根据文件扩展名或者Accept头内容类型协商,通过bean的...

    server-api:SERVER-API 是一个gui的web接口管理工具,基于 swagger-ui 的后台API开源项目,采用SpringMvc+Maven3+Jdk1.7+Tomcat7

    api 是一个GUI的WEB接口管理工具,基于 的后台API开源项目,采用SpringMvc+Maven3+Jdk1.7+Tomcat7,该项目的初衷是为了更好的去发展Swagger-ui与SpringMvc的结合,希望能够更加灵活,轻量化的根据后台不同的数据源...

    report 开源的访问层中间件,基于java平台

    可用于接口的调试及性能的展示,以及访问控制层的使用,简化控制层的繁琐代码,简化spring mvc的配置,剥离的请求前的一系列操作,耦合性低,report是请求通道采用责任链模式设计,轻便可控、扩展性强。report的测试...

    SSM入门到精通项目实战(附源码)

    掌握SpringMVC的项目整合配置,@Controller,@RequestMapping,@Resource,@PathVariable,@ResponseBody,@ModelAttribute,@CookieValue,@Transactional等注解的使用,json数据传值,国际化,拦截器,权限控制,...

    java猜数字源码-eweb4j-framework:简单的Java网络框架

    声明式事务、事务模板、事务嵌套 丰富的DAO封装类 多数据源、表关联 简单的 IOC 容器 MVC、ORM、IOC 可控开关 键值对配置文件支持 国际化支持 让我们看看它是如何做到的。 == 1. 独具特色的 RESTful 路由 == 讨厌 _...

Global site tag (gtag.js) - Google Analytics