为地图 and/or 嵌套对象自定义 Spring @RequestParam 反序列化

Customize Spring @RequestParam Deserialization for Maps and/or Nested Objects

@RestController
class MyController {
     @RequestMapping(...)
     public void test(Container container) { ... }
}

Spring 默认使用 Dot-Notation 反序列化嵌套的 @RequestParam:

class Container {
    A a;
}

class A {
    String val;
}

适用于:

http://.../myController?a.val=foo

但对于地图,它使用方括号表示法:

class Container {
    Map<String, String> a;
}

适用于:

http://.../myController?a[val]=foo

当使用 JavaScript 时,HashMap 和嵌套对象之间当然没有区别,因此所有内容都将使用点 方括号进行序列化。


问题:

我如何/在哪里可以告诉 Spring(或 Spring Boot,如果这样更容易)为 both 使用圆点表示法(或方括号) , 嵌套对象 and Maps?

或者为什么 Spring 会在这些类型之间产生差异?

Spring 由于其自定义 DataBinder 子类 RelaxedDataBinder,Boot 支持使用点分隔路径来绑定映射。好消息是,它也是一个 DataBinder,在 Spring MVC 中用于执行请求参数绑定。坏消息是插入您自己的活页夹并不简单,它需要是 WebDataBinder。您可以通过声明您自己的名为 requestMappingHandlerAdapterRequestMappingHandlerAdapter bean 来插入一个。例如:

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdpter() {
    return new RequestMappingHandlerAdapter() {

        @Override
        protected InitBinderDataBinderFactory createDataBinderFactory(
                List<InvocableHandlerMethod> binderMethods)
                throws Exception {
            return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer()) {

                @Override
                protected ServletRequestDataBinder createBinderInstance(
                        final Object target, String objectName,
                        NativeWebRequest request) {

                    return new ServletRequestDataBinder(target) {

                        private RelaxedDataBinder relaxedBinder = new RelaxedDataBinder(target);

                        @Override
                        protected void doBind(MutablePropertyValues mpvs) {
                            this.relaxedBinder.bind(mpvs);
                        }
                    };
                }
            };
        }   
    };
}

您可能希望重构它以避免使用多重嵌套匿名内部 类,但它有望说明一般方法。

@InitBinder
private void initBinder(WebDataBinder binder, ServletRequest request) {
    new RelaxedDataBinder(binder.getTarget()).bind(new ServletRequestParameterPropertyValues(request));
}

这就是我逃脱惩罚的方式;控制器中委托给 RelaxedDataBinder.

的方法