SpringMvc参数解析器源码分析(三)—数据类型转换

SpringMvc 参数解析的过程中需要进行数据类型的转换,如String变int,date变Long……,在类型转换的过程中还需要对数据的格式进行校验。

Java中的属性编辑器

PropertyEditor

PropertyEditor是属性编辑器的接口,它规定了将外部设置值转换为内部JavaBean属性值的转换接口方法。


public interface PropertyEditor {

    //设置属性的值,基本类型以包装类传入(自动装箱)
    void setValue(Object value);

    //返回属性的当前值。基本类型被封装成对应的包装类实例
    Object getValue();

    boolean isPaintable();

    void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box);

    String getJavaInitializationString();

    //----------------------------------------------------------------------
    //将属性对象用一个字符串表示,以便外部的属性编辑器能以可视化的方式显示。缺省返回null,表示该属性不能以字符串表示。
    String getAsText();

    //用给定的字符串设置属性值,如果格式不正确或者属性不是text则抛出异常
    void setAsText(String text) throws java.lang.IllegalArgumentException;

    //----------------------------------------------------------------------

    String[] getTags();

    //获取自定义属性编辑器
    java.awt.Component getCustomEditor();

   //是否支持自定义编辑器
    boolean supportsCustomEditor();

    void addPropertyChangeListener(PropertyChangeListener listener);


    void removePropertyChangeListener(PropertyChangeListener listener);

}
PropertyEditorSupport

  Java为PropertyEditor提供了一个方便的实现类:PropertyEditorSupport,该类实现了PropertyEditor接口并提供默认实现。
  


public String getAsText() {
    return (this.value != null)
            ? this.value.toString()
            : null;
}


public void setAsText(String text) throws java.lang.IllegalArgumentException {
    if (value instanceof String) {
        setValue(text);
        return;
    }
    throw new java.lang.IllegalArgumentException(text);
}

PropertyEditorSupport的实现只能是简单的String<——>Object之间转换,不能任意对象<——>任意类型之间的转换。Spring自己实现了各种类型的属性编辑器。

Spring的属性编辑器

Spring中有很多自定义的属性编辑器,都在spring-beans jar包下的
org.springframework.beans.propertyeditors包里。这些属性编辑器都继承自PropertyEditorSupport。

image

  1. 基本数据类型,如:boolean、byte、short、int等;
  2. 基本数据类型封装类,如:Long、Character、Integer等;
  3. 两个基本数据类型的数组,char[]和byte[];
  4. 时间类型 date、timezone
  5. 集合类Collection、Set、SortedSet、List和SortedMap
  6. 访问外部资源的常见类Class、Class[]、File、InputStream、Locale、Properties、Resource[]和URL

Spring数据类型转换

上面的属性编辑器中我们知道了Spring实现了各个类型的属性编辑器,因此Spring就有能力可以把各个种类的数据进行转换,下面我们看一下Spring是如何实现数据转换的。

属性编辑器注册
PropertyEditorRegistry接口
public interface PropertyEditorRegistry {

    void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);


    void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor);


    PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath);

}
PropertyEditorRegistrySupport——PropertyEditorRegistry接口的基础实现类

    private ConversionService conversionService;

    private boolean defaultEditorsActive = false;

    private boolean configValueEditorsActive = false;

    //默认属性编辑器集合
    private Map<Class<?>, PropertyEditor> defaultEditors;
    //重写的默认属性编辑器集合
    private Map<Class<?>, PropertyEditor> overriddenDefaultEditors;
    //自定义的属性编辑器集合
    private Map<Class<?>, PropertyEditor> customEditors;
    //自定义路径属性编辑器集合
    private Map<String, CustomEditorHolder> customEditorsForPath;
    //自定义属性编辑器缓存
    private Map<Class<?>, PropertyEditor> customEditorCache;
createDefaultEditors 添加默认属性编辑器

private void createDefaultEditors() {
    this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64);

    // Simple editors, without parameterization capabilities.
    // The JDK does not contain a default editor for any of these target types.
    this.defaultEditors.put(Charset.class, new CharsetEditor());
    this.defaultEditors.put(Class.class, new ClassEditor());
    this.defaultEditors.put(Class[].class, new ClassArrayEditor());
    this.defaultEditors.put(Currency.class, new CurrencyEditor());
    this.defaultEditors.put(File.class, new FileEditor());
    this.defaultEditors.put(InputStream.class, new InputStreamEditor());
    this.defaultEditors.put(InputSource.class, new InputSourceEditor());
    this.defaultEditors.put(Locale.class, new LocaleEditor());
    if (pathClass != null) {
        this.defaultEditors.put(pathClass, new PathEditor());
    }
    this.defaultEditors.put(Pattern.class, new PatternEditor());
    this.defaultEditors.put(Properties.class, new PropertiesEditor());
    this.defaultEditors.put(Reader.class, new ReaderEditor());
    this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
    this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
    this.defaultEditors.put(URI.class, new URIEditor());
    this.defaultEditors.put(URL.class, new URLEditor());
    this.defaultEditors.put(UUID.class, new UUIDEditor());
    if (zoneIdClass != null) {
        this.defaultEditors.put(zoneIdClass, new ZoneIdEditor());
    }

    // Default instances of collection editors.
    // Can be overridden by registering custom instances of those as custom editors.
    this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
    this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
    this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
    this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
    this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));

    // Default editors for primitive arrays.
    this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
    this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());

    // The JDK does not contain a default editor for char!
    this.defaultEditors.put(char.class, new CharacterEditor(false));
    this.defaultEditors.put(Character.class, new CharacterEditor(true));

    // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
    this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
    this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));

    // The JDK does not contain default editors for number wrapper types!
    // Override JDK primitive number editors with our own CustomNumberEditor.
    this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
    this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
    this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
    this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
    this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
    this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
    this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
    this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
    this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
    this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
    this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
    this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
    this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
    this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));

    // Only register config value editors if explicitly requested.
    if (this.configValueEditorsActive) {
        StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
        this.defaultEditors.put(String[].class, sae);
        this.defaultEditors.put(short[].class, sae);
        this.defaultEditors.put(int[].class, sae);
        this.defaultEditors.put(long[].class, sae);
    }
}
类型转换
TypeConverter接口

public interface TypeConverter {

    <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;

    <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
            throws TypeMismatchException;

    <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
            throws TypeMismatchException;

}
TypeConverterSupport:TypeConverter基础实现类,并继承了PropertyEditorRegistrySupport

public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {

    //类型转换委托类。具体的类型转换操作由此类完成。
    TypeConverterDelegate typeConverterDelegate;


    @Override
    public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException {
        return doConvert(value, requiredType, null, null);
    }

    @Override
    public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam)
            throws TypeMismatchException {

        return doConvert(value, requiredType, methodParam, null);
    }

    @Override
    public <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
            throws TypeMismatchException {

        return doConvert(value, requiredType, null, field);
    }

    private <T> T doConvert(Object value, Class<T> requiredType, MethodParameter methodParam, Field field)
            throws TypeMismatchException {
        try {
            if (field != null) {
                return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
            }
            else {
                return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
            }
        }
        catch (ConverterNotFoundException ex) {
            throw new ConversionNotSupportedException(value, requiredType, ex);
        }
        catch (ConversionException ex) {
            throw new TypeMismatchException(value, requiredType, ex);
        }
        catch (IllegalStateException ex) {
            throw new ConversionNotSupportedException(value, requiredType, ex);
        }
        catch (IllegalArgumentException ex) {
            throw new TypeMismatchException(value, requiredType, ex);
        }
    }

}
TypeConverterDelegate

数据的转换在TypeConverterDelegate里实现,下面看部分代码


class TypeConverterDelegate {

    //属性编辑器注册中心,持有各种Spring自定义的属性编辑器
    private final PropertyEditorRegistrySupport propertyEditorRegistry;

    private final Object targetObject;


public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {

        // 根据类型找到自定义的属性编辑器
        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);

        ConversionFailedException conversionAttemptEx = null;

        // 没有自定义的属性编辑器但是有指定的conversionService
        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
        if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
            TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
            if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                try {
                    return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                }
                catch (ConversionFailedException ex) {
                    // fallback to default conversion logic below
                    conversionAttemptEx = ex;
                }
            }
        }

        Object convertedValue = newValue;

        // 值不是需要的类型
        if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
            //需要collection类型
            if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
                    convertedValue instanceof String) {
                TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
                if (elementTypeDesc != null) {
                    Class<?> elementType = elementTypeDesc.getType();
                    if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                    }
                }
            }
            //没有自定义的属性编辑器,则使用默认的属性编辑器
            if (editor == null) {
                editor = findDefaultEditor(requiredType);
            }
            //根据给定的属性编辑器将数据类型转换
            convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
        }

        boolean standardConversion = false;

        if (requiredType != null) {
            // 根据需要,按类型的标准进行转换

            if (convertedValue != null) {
                //需要转换成Object类型,结果直接返回
                if (Object.class == requiredType) {
                    return (T) convertedValue;
                }
                //需要Array类型,进行相应转换
                else if (requiredType.isArray()) {
                    // Array required -> apply appropriate conversion of elements.
                    if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                    }
                    return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
                }
                //转换成相应的collection类型
                else if (convertedValue instanceof Collection) {
                    // Convert elements to target type, if determined.
                    convertedValue = convertToTypedCollection(
                            (Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }
                //转换成相应的map类型
                else if (convertedValue instanceof Map) {
                    // Convert keys and values to respective target type, if determined.
                    convertedValue = convertToTypedMap(
                            (Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }
                if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
                    convertedValue = Array.get(convertedValue, 0);
                    standardConversion = true;
                }
                if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
                    // We can stringify any primitive value...
                    return (T) convertedValue.toString();
                }
                else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
                    if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                        try {
                            Constructor<T> strCtor = requiredType.getConstructor(String.class);
                            return BeanUtils.instantiateClass(strCtor, convertedValue);
                        }
                        catch (NoSuchMethodException ex) {
                            // proceed with field lookup
                            if (logger.isTraceEnabled()) {
                                logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
                            }
                        }
                        catch (Exception ex) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
                            }
                        }
                    }
                    String trimmedValue = ((String) convertedValue).trim();
                    if (requiredType.isEnum() && "".equals(trimmedValue)) {
                        // It's an empty enum identifier: reset the enum value to null.
                        return null;
                    }
                    convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
                    standardConversion = true;
                }
                //number类型的数据转换成需要的int、short等类型
                else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
                    convertedValue = NumberUtils.convertNumberToTargetClass(
                            (Number) convertedValue, (Class<Number>) requiredType);
                    standardConversion = true;
                }
            }
            else {
                // convertedValue == null
                if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
                    convertedValue = javaUtilOptionalEmpty;
                }
            }

            if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
                if (conversionAttemptEx != null) {
                    // Original exception from former ConversionService call above...
                    throw conversionAttemptEx;
                }
                else if (conversionService != null) {
                    // ConversionService not tried before, probably custom editor found
                    // but editor couldn't produce the required type...
                    TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
                    if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                        return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                    }
                }

                // Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
                StringBuilder msg = new StringBuilder();
                msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
                msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
                if (propertyName != null) {
                    msg.append(" for property '").append(propertyName).append("'");
                }
                if (editor != null) {
                    msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
                            "] returned inappropriate value of type '").append(
                            ClassUtils.getDescriptiveType(convertedValue)).append("'");
                    throw new IllegalArgumentException(msg.toString());
                }
                else {
                    msg.append(": no matching editors or conversion strategy found");
                    throw new IllegalStateException(msg.toString());
                }
            }
        }

        if (conversionAttemptEx != null) {
            if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
                throw conversionAttemptEx;
            }
            logger.debug("Original ConversionService attempt failed - ignored since " +
                    "PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
        }

        return (T) convertedValue;
    }


}

JavaBean类型转换

PropertyAccessor接口

对类中属性操作的接口。


 public interface PropertyAccessor {


    String NESTED_PROPERTY_SEPARATOR = ".";
    char NESTED_PROPERTY_SEPARATOR_CHAR = '.';


    String PROPERTY_KEY_PREFIX = "[";
    char PROPERTY_KEY_PREFIX_CHAR = '[';


    String PROPERTY_KEY_SUFFIX = "]";
    char PROPERTY_KEY_SUFFIX_CHAR = ']';



    boolean isReadableProperty(String propertyName);


    boolean isWritableProperty(String propertyName);


    Class<?> getPropertyType(String propertyName) throws BeansException;


    TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;

    Object getPropertyValue(String propertyName) throws BeansException;


    void setPropertyValue(String propertyName, Object value) throws BeansException;


    void setPropertyValue(PropertyValue pv) throws BeansException;


    void setPropertyValues(Map<?, ?> map) throws BeansException;

    void setPropertyValues(PropertyValues pvs) throws BeansException;


    void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
            throws BeansException;


    void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
            throws BeansException;

}
BeanWrapper接口

Spring底层JavaBeans基础结构的核心接口。继承ConfigurablePropertyAccessor(ConfigurablePropertyAccessor继承PropertyAccessor、PropertyEditorRegistry、TypeConverter接口)。

public interface BeanWrapper extends ConfigurablePropertyAccessor {
    //省略方法
}

public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter {
    //省略方法

}
BeanWrapperImpl类

BeanWrapper接口的默认实现类,TypeConverterSupport是它的父类,可以进行类型转换,可以进行属性设置。

convertForProperty

给定的值按照特定的属性进行转换。

public Object convertForProperty(Object value, String propertyName) throws TypeMismatchException {
    CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
    PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
    if (pd == null) {
        throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
                "No property '" + propertyName + "' found");
    }
    TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
    if (td == null) {
        td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
    }
    return convertForProperty(propertyName, null, value, td);
}

AbstractNestablePropertyAccessor中的转换方法

具体的转换工作是由TypeConverterDelegate来完成的。


public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter {

    TypeConverterDelegate typeConverterDelegate;

    //省略不少代码

    protected Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td)
                throws TypeMismatchException {

        return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
    }

    private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType,
            TypeDescriptor td) throws TypeMismatchException {
        try {
            return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
        }
        catch (ConverterNotFoundException ex) {
            PropertyChangeEvent pce =
                    new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
            throw new ConversionNotSupportedException(pce, td.getType(), ex);
        }
        catch (ConversionException ex) {
            PropertyChangeEvent pce =
                    new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
            throw new TypeMismatchException(pce, requiredType, ex);
        }
        catch (IllegalStateException ex) {
            PropertyChangeEvent pce =
                    new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
            throw new ConversionNotSupportedException(pce, requiredType, ex);
        }
        catch (IllegalArgumentException ex) {
            PropertyChangeEvent pce =
                    new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, newValue);
            throw new TypeMismatchException(pce, requiredType, ex);
        }
    }

}

数据绑定

DataBinder

 实现PropertyEditorRegistry、TypeConverter的类。支持类型转换,参数验证,数据绑定等功能。
 
 

public class DataBinder implements PropertyEditorRegistry, TypeConverter {

    //绑定数据的目标对象
    private final Object target;

    private final String objectName;

    //
    private AbstractPropertyBindingResult bindingResult;

    //绑定器SimpleTypeConverter
    private SimpleTypeConverter typeConverter;


}
参数绑定
protected void doBind(MutablePropertyValues mpvs) {
    checkAllowedFields(mpvs);
    checkRequiredFields(mpvs);
    applyPropertyValues(mpvs);
}


protected void applyPropertyValues(MutablePropertyValues mpvs) {
    try {
        // Bind request parameters onto target object.
        getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
    }
    catch (PropertyBatchUpdateException ex) {
        // Use bind error processor to create FieldErrors.
        for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
            getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
        }
    }
}

//获取BeanWrapperImpl对象
protected ConfigurablePropertyAccessor getPropertyAccessor() {
    return getInternalBindingResult().getPropertyAccessor();
}

参数赋值的具体操作在AbstractPropertyAccessor#setPropertyValues方法。

WebDataBinder

DataBinder的子类,主要是针对Web请求的数据绑定。

WebDataBinder的工厂方法创建
public class DefaultDataBinderFactory implements WebDataBinderFactory {


    public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
            throws Exception {

        WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
        if (this.initializer != null) {
            this.initializer.initBinder(dataBinder, webRequest);
        }
        initBinder(dataBinder, webRequest);
        return dataBinder;
    }

    protected WebDataBinder createBinderInstance(Object target, String objectName, NativeWebRequest webRequest)
            throws Exception {

        return new WebRequestDataBinder(target, objectName);
    }


}
WebRequestDataBinder

WebDataBinder的子类,将request中的参数进行绑定操作;同时也可对多文件上传进行绑定操作。


public class WebRequestDataBinder extends WebDataBinder {


    public void bind(WebRequest request) {
        MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap());
        if (isMultipartRequest(request) && request instanceof NativeWebRequest) {
            MultipartRequest multipartRequest = ((NativeWebRequest) request).getNativeRequest(MultipartRequest.class);
            if (multipartRequest != null) {
                bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
            }
            else if (servlet3Parts) {
                HttpServletRequest serlvetRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
                new Servlet3MultipartHelper(isBindEmptyMultipartFiles()).bindParts(serlvetRequest, mpvs);
            }
        }
        doBind(mpvs);
    }



}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值