全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-18 10 分钟 ✍️ juanwangdev

数据绑定与类型转换

SpringMVC提供强大的数据绑定和类型转换机制,自动将请求参数转换为目标类型。

DataBinder核心类

基本结构

Java
public class DataBinder {
    private final Object target; // 目标对象
    private final String objectName; // 对象名称
    private BindingResult bindingResult; // 绑定结果

    // 绑定属性值
    public void bind(PropertyValues pvs) {
        doBind(pvs);
    }

    // 执行绑定
    protected void doBind(MutablePropertyValues mpvs) {
        checkAllowedFields(mpvs);
        checkRequiredFields(mpvs);
        applyPropertyValues(mpvs);
    }
}

WebDataBinder扩展

Java
public class WebDataBinder extends DataBinder {
    // 从HttpServletRequest绑定参数
    public void bind(HttpServletRequest request) {
        MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
        doBind(mpvs);
    }

    // 处理 multipart 请求
    protected void bindMultipart(Map<String, List<MultipartFile>> multipartFiles,
            MutablePropertyValues mpvs) {
        for (Map.Entry<String, List<MultipartFile>> entry : multipartFiles.entrySet()) {
            String key = entry.getKey();
            List<MultipartFile> files = entry.getValue();
            if (files.size() == 1) {
                mpvs.add(key, files.get(0));
            } else {
                mpvs.add(key, files.toArray(new MultipartFile[0]));
            }
        }
    }
}

ConversionService接口

核心接口

Java
public interface ConversionService {
    boolean canConvert(Class<?> sourceType, Class<?> targetType);
    boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
    <T> T convert(Object source, Class<T> targetType);
    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}

DefaultConversionService

Java
// Spring内置转换器
public class DefaultConversionService extends GenericConversionService {

    public static void addDefaultConverters(ConverterRegistry registry) {
        // 数值转换
        addNumberConverters(registry);
        // 字符串转换
        addStringConverters(registry);
        // 集合转换
        addCollectionConverters(registry);
        // 日期转换
        addDateConverters(registry);
        // 其他转换
        addScalarConverters(registry);
    }
}

Converter接口

核心接口

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

内置转换器示例

Java
// String -> Integer
final class StringToIntegerConverter implements Converter<String, Integer> {
    @Override
    public Integer convert(String source) {
        return Integer.parseInt(source.trim());
    }
}

// String -> Boolean
final class StringToBooleanConverter implements Converter<String, Boolean> {
    @Override
    public Boolean convert(String source) {
        String value = source.trim().toLowerCase();
        if ("true".equals(value) || "on".equals(value) || "yes".equals(value) || "1".equals(value)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }
}

自定义转换器

基本实现

Java
public class StringToDateConverter implements Converter<String, Date> {
    private final String datePattern;

    public StringToDateConverter(String datePattern) {
        this.datePattern = datePattern;
    }

    @Override
    public Date convert(String source) {
        try {
            SimpleDateFormat format = new SimpleDateFormat(datePattern);
            return format.parse(source.trim());
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期格式错误: " + source);
        }
    }
}

注册转换器

Java
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 注册Converter
        registry.addConverter(new StringToDateConverter("yyyy-MM-dd"));
        registry.addConverter(new StringToEnumConverter());

        // 注册Formatter(支持Locale)
        registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
    }
}

ConditionalConverter

Java
// 条件转换器 - 根据条件决定是否转换
public interface ConditionalConverter {
    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}

// 示例:仅当目标类有特定注解时转换
public class AnnotationDrivenConverter
        implements Converter<String, Object>, ConditionalConverter {

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return targetType.hasAnnotation(JsonFormat.class);
    }

    @Override
    public Object convert(String source) {
        // 自定义转换逻辑
        return null;
    }
}

ConverterFactory

Java
// 批量创建转换器(如所有枚举类型)
public interface ConverterFactory<S, R> {
    <T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

// String到枚举的转换工厂
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

    @Override
    public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
        return new StringToEnumConverter<>(targetType);
    }

    private static class StringToEnumConverter<T extends Enum>
            implements Converter<String, T> {

        private final Class<T> enumType;

        public StringToEnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        @Override
        public T convert(String source) {
            return (T) Enum.valueOf(this.enumType, source.trim().toUpperCase());
        }
    }
}

Formatter接口

Java
// Formatter支持Locale(国际化)
public interface Formatter<T> extends Printer<T>, Parser<T> {
    String print(T object, Locale locale);
    T parse(String text, Locale locale) throws ParseException;
}

// 日期格式化器
public class DateFormatter implements Formatter<Date> {
    private String pattern;

    public DateFormatter(String pattern) {
        this.pattern = pattern;
    }

    @Override
    public String print(Date date, Locale locale) {
        return getDateFormat(locale).format(date);
    }

    @Override
    public Date parse(String text, Locale locale) throws ParseException {
        return getDateFormat(locale).parse(text);
    }

    protected DateFormat getDateFormat(Locale locale) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, locale);
        dateFormat.setLenient(false);
        return dateFormat;
    }
}

数据绑定流程

ServletModelAttributeMethodProcessor

Java
public class ServletModelAttributeMethodProcessor
        extends ModelAttributeMethodProcessor {

    public Object resolveArgument(MethodParameter parameter,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) {

        String name = ModelAttribute.getNameForParameter(parameter);
        Object attribute = mavContainer.getAttribute(name);

        if (attribute == null) {
            // 创建目标对象
            attribute = createAttribute(name, parameter, binderFactory, webRequest);
        }

        // 创建DataBinder并绑定
        WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
        bindRequestParameters(binder, webRequest);

        // 校验(如有@Valid)
        validateIfApplicable(binder, parameter);

        return binder.getTarget();
    }
}

WebDataBinderFactory

Java
public class DefaultDataBinderFactory implements WebDataBinderFactory {

    private final List<WebBindingInitializer> bindingInitializers;

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

        WebDataBinder binder = createBinderInstance(target, objectName);

        // 应用初始化器
        if (this.bindingInitializers != null) {
            for (WebBindingInitializer initializer : bindingInitializers) {
                initializer.initBinder(binder, webRequest);
            }
        }

        return binder;
    }
}

类型转换流程图

Java
请求参数(String)
        ↓
HandlerMethodArgumentResolver
        ↓
WebDataBinder.bind()
        ↓
PropertyValues → applyPropertyValues()
        ↓
BeanWrapper.setPropertyValue()
        ↓
TypeConverterDelegate.convertIfNecessary()
        ↓
ConversionService.convert()
        ↓
Converter/Formatter实现类
        ↓
目标类型属性

WebBindingInitializer

Java
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void initBinder(WebDataBinder binder, WebRequest request) {
        // 设置允许的字段
        binder.setAllowedFields("name", "age", "email");

        // 设置必填字段
        binder.setRequiredFields("name", "age");

        // 设置字段标记
        binder.setFieldMarkerPrefix("_");

        // 注册自定义编辑器
        binder.registerCustomEditor(Date.class,
            new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    }
}

类型转换性能优化

text
// ConversionService缓存
public class GenericConversionService implements ConversionService {

    private final Map<ConverterCacheKey, Converter<?, ?>> converterCache =
        new ConcurrentHashMap<>(64);

    public <T> T convert(Object source, Class<T> targetType) {
        TypeDescriptor sourceType = TypeDescriptor.forObject(source);
        TypeDescriptor targetDescriptor = TypeDescriptor.valueOf(targetType);

        // 从缓存获取Converter
        Converter<?, ?> converter = getConverter(sourceType, targetDescriptor);
        return (T) converter.convert(source);
    }
}

数据绑定通过BeanWrapper实现属性赋值,ConversionService负责类型转换,支持自定义扩展。

要点总结

  1. DataBinder负责将PropertyValues绑定到目标对象
  2. ConversionService统一管理类型转换
  3. Converter适用于单向转换,Formatter支持国际化格式化
  4. ConverterFactory批量创建同类型转换器
  5. WebBindingInitializer配置DataBinder初始参数

jwdev/articles/SPRINGMVC/专家/容器级WEB组件扩展/容器级WEB组件扩展/数据绑定与类型转换.md

📝 发现内容有误?点击此处直接编辑

← 上一篇 拦截器与过滤器扩展机制
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库