SpringMVC 坑路6 -> 数据类型转换

32 篇文章 0 订阅
13 篇文章 1 订阅

如何实现数据类型转换

1.类型转换:首先表单数据(全部是字符串)通过 WebDataBinder 进行绑定到命令对象,内部通过 Converter SPI 实现。
2.数据验证:使用 JSR-303 验证框架进行验证
3.格式化显示:在表单页面可以通过如下方式展示通过内部通过 Converter SPI 格式化的数据和错误信息

数据类型转换架构

SpringMVC 数据转换包括两部分

一、类型转换器:提供类型转换的实现支持

1、Converter:类转换器,用于转换 S 类型到 T 类型,此接口的实现必须是线程安全的且可以被共享。
package org.springframework.core.convert.converter;
public interface Converter<S,T>{// S 是源类型 T 是目标类型
    T convert(S source); // 转换 S 类型的 source 到 T 目标类型的转换方法
}
2、GenericConverter 和 ConditionalGenericConverter:GenericConverter 接口实现能在多种类型之间进行转换,ConditionalGenericConverter 是有条件的在多种类型之间进行转换。

GenericConverter:

package org.springframework.core.convert.converter;
public interface GenericConverter{
    Set<ConvertiblePair> getConvertibleTypes();
    Object convert(Object source,TypeDescriptor sourceType,TypeDescriptor targetType);
}

getConvertibleTypes:指定了可以转换的目标类型对;
convert:在 sourceType 和 targetType 类型之间进行转换。

COnditionalGenericConverter:

package org.springframework.core.convert.converter;
public interface ConditionalGenericConverter extends GenericConverter{
    boolean matches(TypeDescriptor sourceTyoe,TypeDescriptor targetType);
}

matches:用于判断 sourceType 和 targetType 类型之间能否进行类型转换。

3、ConverterFactory:工厂模式的实现,用于选择将一种 S 源类型转换为 R 类型的子类型 T 的转换器的工厂接口。
package org.springframework.core.convert.converter;
public interface COnvertFactory<S,R>{
    <T extends R>Converter<S,T> getConverter(Class<T> targetType); // S:源类型;R:目标类型的父类型;T:目标类型,且是 R 类型的子类型;
}

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

1、ConverterRegistry:类型转换器注册支持,可以注册/删除相应的类型转换器。

package org.springframework.core.convert.converter;
public interface ConverterRegistry{
    void addConverter(Converter<?,?> converter);
    void addConverter(Class<?> sourceType,Class<?> targetType,COnverter<?,?>converter);
    void addConverter(GenericConverter converter);
    void addConverterFactory(ConverterFactory<?,?> converterFactory);
    void removeConvertible(Class<?> sourceType,Class<?> targetType);
}

可以注册:Converter 实现,GenericConverter 实现,ConverterFactory 实现。

2、ConversionService:运行时类型转换服务接口,提供运行期类型转换的支持。

package org.springframework.core.convert;
public interface ConversionService{
    boolean canConvert(Class<?> sourceType,Class<?> targetType);
    boolean canConvert(TypeDescriptor sourceType,TypeDescriptor targetType);
    <T> T convert(Object srouce,Class<T> targetType);
    Object convert(Object source,TypeDescriptor sourceType,TypeDescriptor targetType);
}

Spring提供了两个默认实现(其都实现了ConverterRegistry、ConversionService接口):

**DefaultConversionService:默认的类型转换服务实现;
DefaultFormattingConversionService:带数据格式化支持的类型转换服务实现,一般使用该服务实现即可。**

内建的类型转换器

一、标量转换器
类名说明
StringToBooleanConverterString —-> Boolean
true:true/on/yes/1;
false:false/off/no/0
ObjectToStringConverterObject —-> String
调用 toString 方法转换
StringToNumberConverterFactoryString —-> Number
(如 Integer、Long 等)
NumberToNumberConverterFactoryNumber 子类型(Integer、Long、Double 等)<—> Number 子类型(Integer、Long、Double 等)
StringToCharacterConverterString —-> java.lang.Character
取字符串第一个字符
NumberToCharacterConverterjava.lang.Character —-> Number子类型(Integer、Long、Double等)
StringToEnumConverterFactoryString —-> enum 类型
通过 Enum.valueOf 将字符串转换为需要的 enum 类型
EnumToStringConverterenum 类型 —-> String
返回 enum 对象的 name()
StringToLocaleConverterString —-> java.util.Local
PropertiesToStringConverterjava.util.Properties —-> String
默认通过 ISO-8859-1 解码
StringToPropertiesConverterString —-> java.util.Properties
默认使用 ISO-8859-1 编码
二、集合、数组相关转换器
类名说明
ArrayToCollectionConverter任意 S 数组 —-> 任意 T 集合(List、Set)
ColleactionToArrayConverter任意 T 集合(List、Set) —-> 任意 S 数组
ArrayToArrayConverter任意 S 数组 <–> 任意 T 数组
CollectionToCollectionConverter任意 T 集合(List、Set) <–> 任意 T 集合(List、Set)
即集合之间的类型转换
MapToMapConverterMap <–> Map 之间的转换
ArrayToStringConverter任意 S 数组 —-> String 类型
StringToArrayConverterString —-> 数组
默认通过”,”分割,且去除字符串的两边空格(trim)
ArrayToObjectConverter任意 S 数组 —-> 任意 Object 的转换
(如果目标类型和源类型兼容,直接返回源对象;否则返回 S 数组的第一个元素并进行类型转换)
ObjectToArrayConverterObject —-> 单元素数组
ColleactionToStringConverter任意 T 集合(List、Set) —-> String 类型
StringToCollectionConverterString —-> 集合(List、Set)
默认通过”,”分割,且去除字符串的两边空格(trim)
CollectionToObjectConverter任意 T 集合 —-> 任意 Object 的转换
(如果目标类型和源类型兼容,直接返回源对象;否则返回 S 数组的第一个元素并进行类转换)
ObjectToCollectionConverterObject —-> 单元素集合

自定义转换类

一、StringToDateConverter:自定义 String 类型转 Date 类型的转换类;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT;

import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;

public class StringToDateConverter implements Converter<String,Date>{
    private final SimpleDateFormat DATE_FORMAT_PATTERN = new SimpleDateFormat("yyyy-MM-dd");
    private final SimpleDateFormat DATETIME_FORMAT_PATTERN = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public Date convert(String source) {
        Date date = null;
        if(!StringUtils.hasLength(source)) {
            return date; // 原始字符串为空
        }
        if(source.contains("-")) { // 处理日期类型
            try {
                date = DATE_FORMAT_PATTERN.parse(source);

            }catch(ParseException e) {
                throw new IllegalArgumentException(
                        String.format("类型转换失败,期望的格式是[yyyy-MM-dd],但是原始格式为[%s]", source));
            }
        }else if(source.contains("-") && source.contains(":") && 19 == source.length()) { // 处理时间类型
            try {
                date = DATETIME_FORMAT_PATTERN.parse(source);
            }catch(ParseException e) {
                throw new IllegalArgumentException(
                        String.format("类型转换失败,期望的格式是[yyyy-MM-dd HH:mm:ss],但是原始格式为[%s]", source));
            }
        }else {
            throw new IllegalArgumentException(
                    String.format("类型转换失败,期望的格式是[yyyy-MM-dd]或[yyyy-MM-dd HH:mm:ss],但是原始格式为[%s]", source));
        }
        return date;
    }
}
二、StringToPhoneNumberConverter:自定义 String 类型转 PhoneNumberModel 类型的转换类
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;


class PhoneNumberModel{
    private String areaCode;
    private String phoneNumber;
    public String getAreaCode() {
        return areaCode;
    }
    public void setAreaCode(String areaCode) {
        this.areaCode = areaCode;
    }
    public String getPhoneNumber() {
        return phoneNumber;
    }
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
}
public class StringToPhoneNumberConverter implements Converter<String,PhoneNumberModel>{
    private final Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d(7,8))$");
    @Override
    public PhoneNumberModel convert(String source) {
        if(!StringUtils.hasLength(source)) {
            return null; // 原始字符串为空
        }
        Matcher matcher = pattern.matcher(source);
        if(matcher.matches()) {
            PhoneNumberModel phoneNumberModel = new PhoneNumberModel();
            phoneNumberModel.setAreaCode(matcher.group(1));
            phoneNumberModel.setPhoneNumber(matcher.group(2));
            return phoneNumberModel;
        }else {
            throw new IllegalArgumentException(String.format("类型转换失败,需要格式[000-00000000],但格式是[%s]", source));
        }
    }
}
配置自定义类型转换器
1、注册ConversionService 实现和自定义的类型转换器
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="全限定类名" />
            <!-- 例如:
            <bean class="xxx.xxx.converters.StringToPhoneNumberConverter"/>
            -->
        </list>
    </property>
</bean>
2、通过 ConfigurableWebBindingInitializer 注册 ConversionService
<bean id="webBindingInitializer" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
    <property name="conversionService" ref="conversionService">
</bean>
3、注册 ConfigurableWebBindingInitializer 到 RequestMappingHandlerAdapter
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer" ref="webBindingInitializer">
</bean>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值