org.springframework.web.bind.ServletRequestDataBinde
Class DataBinder
- java.lang.Object
- org.springframework.validation.DataBinder
- All Implemented Interfaces:
- PropertyEditorRegistry, TypeConverter
- Direct Known Subclasses:
- WebDataBinder
public class DataBinder
extends Object
implements PropertyEditorRegistry, TypeConverterBinder that allows for setting property values onto a target object, including support for validation and binding result analysis. The binding process can be customized through specifying allowed fields, required fields, custom editors, etc.Note that there are potential security implications in failing to set an array of allowed fields. In the case of HTTP form POST data for example, malicious clients can attempt to subvert an application by supplying values for fields or properties that do not exist on the form. In some cases this could lead to illegal data being set on command objects or their nested objects. For this reason, it is highly recommended to specify the
allowedFieldsproperty on the DataBinder.The binding results can be examined via the
BindingResultinterface, extending theErrorsinterface: see thegetBindingResult()method. Missing fields and property access exceptions will be converted toFieldErrors, collected in the Errors instance, using the following error codes:- Missing field error: "required"
- Type mismatch error: "typeMismatch"
- Method invocation error: "methodInvocation"
By default, binding errors get resolved through the
BindingErrorProcessorstrategy, processing for missing fields and property access exceptions: see thesetBindingErrorProcessor(org.springframework.validation.BindingErrorProcessor)method. You can override the default strategy if needed, for example to generate different error codes.Custom validation errors can be added afterwards. You will typically want to resolve such error codes into proper user-visible error messages; this can be achieved through resolving each error via a
MessageSource, which is able to resolve anObjectError/FieldErrorthrough itsMessageSource.getMessage(org.springframework.context.MessageSourceResolvable, java.util.Locale)method. The list of message codes can be customized through theMessageCodesResolverstrategy: see thesetMessageCodesResolver(org.springframework.validation.MessageCodesResolver)method.DefaultMessageCodesResolver's javadoc states details on the default resolution rules.This generic data binder can be used in any kind of environment. It is typically used by Spring web MVC controllers, via the web-specific subclasses
ServletRequestDataBinderandPortletRequestDataBinder.- Author:
- Rod Johnson, Juergen Hoeller, Rob Harrop, Stephane Nicoll
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的更多相关文章
- 使用ControllerAdvice注意事项,Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]
前言 ControllerAdvice非常好用,可以把系统内部的异常统一处理.用起来也很简单.比如,http://www.cnblogs.com/woshimrf/p/spring-web-400.h ...
- org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'xxxx' is not present
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'xxx ...
- Java-API-Package:org.springframework.web.bind.annotation
ylbtech-Java-API-Package:org.springframework.web.bind.annotation 1.返回顶部 1. @NonNullApi @NonNullField ...
- Java-Class-@I:org.springframework.web.bind.annotation.PostMapping
ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.PostMapping 1.返回顶部 2.返回顶部 1. package ...
- Java-Class-@I:org.springframework.web.bind.annotation.RestController
ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.RestController 1.返回顶部 2.返回顶部 1. pack ...
- Java-Class-@I:org.springframework.web.bind.annotation.RequestMapping
ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.RequestMapping 1.返回顶部 2.返回顶部 1. pack ...
- Java-Class-@I:org.springframework.web.bind.annotation.RequestBody
ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.RequestBody 1.返回顶部 2.返回顶部 1. package ...
- org.springframework.web.bind.annotation重定向的问题
@RequestMapping(value="/redir/authcode") public ModelAndView getAuthCode(){ String authUrl ...
- spring org.springframework.web.bind.annotation 常用注解
开发中常用的注解记录,查缺补漏 Request注解 @RequestBody @RequestHeader @RequestMapping @RequestParam @RequestPart @Co ...
随机推荐
- Apache 80 端口被占用无法重启解决办法
原文出处 Apache 80 端口被占用无法重启解决办法 www.111cn.net 编辑:tiger 来源:转载使用WEB服务器的朋友都知道80端口是一个用来对外让用户访问的一个端口了,像apach ...
- Java集合和PHP的对比
这里突然感觉到在java中的集合,和php的数组非常相似 .
- WebView组件的应用
1.什么是WebView? WebView(网络视图)能加载显示网页,可以将其视为一个浏览器,它使用了WebKit渲染引擎加载显示网页. <?xml version="1.0" ...
- window redis 安装配置
1 下载 https://github.com/MSOpenTech/redis/releases 当前最新版本为 redis-2.8.21 下载的为zip包,下载连接为:https://gith ...
- redis 在windows上运行
参考自:https://github.com/ServiceStack/redis-windows 1.用vagrant 运行redis的最后版本 1.1在windows上安装vagrant http ...
- MongoDB源码编译
MongoDB源码编译 本人编译的版本编译的版本为mongodb2.6分支,目前MongoDB3.0已经发布,编译步骤和2.6的差不多,不过3.0版本要求编译器支持c++11标准,所以如果是在Linu ...
- 九度OJ 1082 代理服务器 -- 贪心算法
题目地址:http://ac.jobdu.com/problem.php?pid=1082 题目描述: 使用代理服务器能够在一定程度上隐藏客户端信息,从而保护用户在互联网上的隐私.我们知道n个代理服务 ...
- 【原创】Android多个xml文件的使用
Android中经常会使用多个xml文件,但在Mainactivity中使用的setContentView(R.layout.main)只加载main.xml文件,其他xml文件不加载进当前视图,当我 ...
- u-boot和linux的机器码
先看u-boot的机器码和linux的机器码是在什么地方决定的. 1. u-boot的机器码是在u-boot的board/fs2410/fs2410.c文件里决定的: /* arch numb ...
- php PHP_EOL 常量
换行符 unix系列用 \n windows系列用 \r\n mac用 \r PHP中可以用PHP_EOL来替代,以提高代码的源代码级可移植性 <?php echo PHP_EOL; //win ...