org.springframework.validation

Class DataBinder

at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.beans.BeanWrapperImpl$BeanPropertyHandler.setValue(BeanWrapperImpl.java:344)
at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:452)
at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:95)
at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:810)
at org.springframework.validation.DataBinder.doBind(DataBinder.java:706)
at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:189)
at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:106)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:150)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:110)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:799)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:728)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.global.filter.AddExtraToParamsFilter.doFilter(AddExtraToParamsFilter.java:27)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
- locked <0x14a4> (a org.apache.tomcat.util.net.NioChannel)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

增加的就是第110行

1 binder.setFieldDefaultPrefix(parameter.getParameterName() + "!");

parameter.getParameterName()返回的是你@Controller里2RequestMapping方法参数的名字

"!"是我区分成员域与对象名的分解符...这个可以自己设置.你想设置成.也可以!也可以#也OK

只要自己能区分就行了.

测试

URL:

1 http://localhost:8080/quick-start/test18?context!stateCode=91&a!name=hehe&context!exception.message=error&a!stateCode=84

后台打印参数:

1 com.labofjet.web.ContextDTO@9344568[stateCode=91,data=<null>,exception=com.labofjet.exception.BaseException: error]
2 com.labofjet.dto.ADTO@814d736[id=<null>,name=hehe,age=<null>,value=<null>,b=0,stateCode=84]

Controller的方法签名:

1     @RequestMapping("/test18")
2 public Object index18(ContextDTO context, ADTO a) throws IOException {
3 System.out.println(context);
4 System.out.println(a);
5 return null;
6 }

原理

先简明说下原理..具体的理论我想后面等我整理下思路,介绍RequestMappingHandlerAdapter的时候再讲(反正没人看...)

SpringMVC里@Controller里的各种参数由各种argumentsResolver来解析.

解析自定义的这种DTO的argumentsResolver是ServletModelAttributeMethodProcessor这个类.

收到参数以后他怎么解析呢?

很简单呀.在我测试例子中,比如我要初始化一个context对象,SpringMVC就先把context包装成BeanWrapperImpl对象..然后把Request里的各种key-value包装成MutablePropertyValues..然后set进去就可以了.利用的是反射的知识,你有一个key,那我就看BeanWrapperImpl warp的那个对象有没有对应的属性.有就设置进去.

既然原理是这样,那怎么达到我们的目的呢?

这里又有至少2种方法:

第一种就是像我那样: binder.setFieldDefaultPrefix(parameter.getParameterName() + "!"); 这样在解析MutablePropertyValues的时候会去掉你set进去的Feild的Prefix.

第二种方法: ServletRequestDataBinder在绑定的参数的时候需要先把request转化成MutablePropertyValues,做法是:

1     public void bind(ServletRequest request) {
2 MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
3 MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
4 if (multipartRequest != null) {
5 bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
6 }
7 addBindValues(mpvs, request);
8 doBind(mpvs);
9 }

也就是说:

1 MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);

而MutablePropertyValues 其实还有一种构造方法:

1     public ServletRequestParameterPropertyValues(ServletRequest request, String prefix) {
2 this(request, prefix, DEFAULT_PREFIX_SEPARATOR);
3 }

这种方法允许你填入一个prefix...那原理和前面是一样的..

但是这种方法需要改很多类...所以没有方法一简单....

为什么不使用继承

可能会有朋友想问.改进的ArgumentResolver和原本Spring自带的基本一样,只是多了一步,为什么不继承自原本的ServletModelAttributeMethodProcessor? 毕竟修改源码方案不太好.

原因有很多,主要有2个原因:

原因1:

ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor

resolveArgument在ModelAttributeMethodProcessor里的定义是:

public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
...........
}

是final啊!final!!!!!!!!!!!

所以我修改不了.

原因2:

一般父类定义了一个处理流程的话不能修改的话,会在子类给我们留一个扩展接口...

没错,那就是:

1     @Override
2 protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
3 ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
4 ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
5 servletBinder.bind(servletRequest);
6 }

这个是在ServletModelAttributeMethodProcessor里覆盖了父类的方法,我们可以继承ServletModelAttributeMethodProcessor再覆盖这个bindRequestParameters方法..

但是......

这里只有2个参数啊!!!!我们需要的@Controller的参数名称的信息不在这里....我们需要这个变量:

1 public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
2 NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
3 .............
4 }

参数的信息都在这里里面..可是bindRequestParameters方法里没有传入这个参数...所以坑爹的是我们在bindRequestParameters里并不能知道@Controller里参数的名字到底是什么...

所以我们没有办法设置一个通用的绑定方法...

方法:利用其它的HandlerMethodArgumentResolver

具体方法

不改源码最简单的方法可能是不自己写ArgumentResolver,而是利用SpringMVC原有的Resolver了吧..

我们可以利用RequestResponseBodyMethodProcessor这个ArgumentResolver..

具体请参考我的另外一篇文章:

http://www.cnblogs.com/abcwt112/p/5169250.html

原理就是利用HttpMessageConverter和其它的json转化工具将request里的参数转化成java bean.这也是很简单的.

基本只要在参数前加一个@RequestBody...

方法:利用@InitBinder注解

具体:

请大家看这篇文章:

http://jinnianshilongnian.iteye.com/blog/1888474

缺点:

1.原理和方法:改源码是差不多的....都是通过修改binder设置额外属性来达到目的的,但是没传入MethodParameter parameter,所以还是不知道你的@Controller里的参数名字..只能手动指定前缀

2.貌似要绑定的时候每个Controller里都要写@InitBinder,稍微有点麻烦..当然好处是更灵活...

方法N:自己实现HandlerMethodArgumentResolver

这个方法就太多了......

请参考:

http://jinnianshilongnian.iteye.com/blog/1717180

简单总结

方法有太多太多了..不同方法可能适合不同场景,但是我觉得最简单的还是@InitBinder和@RequestBody这2种方案.

http://www.cnblogs.com/abcwt112/p/5302469.html

org.springframework.web.bind.ServletRequestDataBinde的更多相关文章

  1. 使用ControllerAdvice注意事项,Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]

    前言 ControllerAdvice非常好用,可以把系统内部的异常统一处理.用起来也很简单.比如,http://www.cnblogs.com/woshimrf/p/spring-web-400.h ...

  2. org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'xxxx' is not present

    org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'xxx ...

  3. Java-API-Package:org.springframework.web.bind.annotation

    ylbtech-Java-API-Package:org.springframework.web.bind.annotation 1.返回顶部 1. @NonNullApi @NonNullField ...

  4. Java-Class-@I:org.springframework.web.bind.annotation.PostMapping

    ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.PostMapping 1.返回顶部   2.返回顶部 1. package ...

  5. Java-Class-@I:org.springframework.web.bind.annotation.RestController

    ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.RestController 1.返回顶部   2.返回顶部 1. pack ...

  6. Java-Class-@I:org.springframework.web.bind.annotation.RequestMapping

    ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.RequestMapping 1.返回顶部   2.返回顶部 1. pack ...

  7. Java-Class-@I:org.springframework.web.bind.annotation.RequestBody

    ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.RequestBody 1.返回顶部   2.返回顶部 1. package ...

  8. org.springframework.web.bind.annotation重定向的问题

    @RequestMapping(value="/redir/authcode") public ModelAndView getAuthCode(){ String authUrl ...

  9. spring org.springframework.web.bind.annotation 常用注解

    开发中常用的注解记录,查缺补漏 Request注解 @RequestBody @RequestHeader @RequestMapping @RequestParam @RequestPart @Co ...

随机推荐

  1. HTML DOM对象

    HTML DOM对象 Document对象每个载入浏览器的HTML文档都会成为Document对象Document对象让我们可以从javascript中操作文档中的所有元素Document对象是win ...

  2. Ajax.Utility.RegisterTypeForAjax(typeof(_Default)) 的使用

    语句的作用:页面注册方法的作用. Ajax.Utility.RegisterTypeForAjax(typeof(命名空间.类名)); 首先要在配置文件里配置 <httpHandlers> ...

  3. UML类图细节

    类图表述的是类和类之间的关系,是前期用来推演代码设计,后期用来优化代码的结构,寻找设计不合理之处.网上解释类图和类图的画法,往往表述的十分晦涩,或者例子呆板,很难具体的操作. 类图一般在详细设计过程中 ...

  4. 【JAVA错误笔记】 - 【Could not open ServletContext resource [/WEB-INF/applicationContext.xml]解决方法】

    错误描述: Could not open ServletContext resource [/WEB-INF/applicationContext.xml] 原因分析: 问题主要由于加载spring的 ...

  5. 再跟SQL谈一谈--基础篇

    1.简介 2.DDL & DML 3.SELECT ①DISTINCT ②WHERE ③AND & OR ④ORDER BY 4.INSERT 5.UPDATE 6.DELETE 1. ...

  6. 2013年10月13日学习:SQL通过命令语句来创建表

    优点:操作简单,不容易出错,易于调试 缺点:需要记住命令.命令多了就容易混淆,是吧!但是熟悉了时间长了就OK了! step 1. 新建数据库,命名为Test 点击图形化界面中的新建查询,此时就可以输入 ...

  7. 堆排序算法(C#实现)

    在软件设计相关领域,“堆(Heap)”的概念主要涉及到两个方面: 一种是数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆). 另一种是垃圾收集存储区,是软件系统可以编程的内存区域. 本文 ...

  8. oracle 11g卸载方法

    在网上查看了很多卸载oracle11g的方法,但是感觉都太复杂了,没有使用,最后查看了很多资料,得到一种比较简单,而且能完全卸载的方法: 在根目录下运行c:\app\Administrator\pro ...

  9. 怎样区分JQuery对象和Dom对象 常用的写法

    第一步,http://www.k99k.com/jQuery_getting_started.html 第二步,新手先仔细得全部看一遍jQuery的选择器,很重要!!! (http://shawphy ...

  10. Block中的引用循环

    原文地址:http://www.cnblogs.com/lujianwenance/p/5910490.html Block在实际的开发中非常的常用,事件回调.传值.封装成代码块调用等等.很多人都对b ...