博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC源码解析系列4-HandleAdapter
阅读量:7049 次
发布时间:2019-06-28

本文共 21655 字,大约阅读时间需要 72 分钟。

SpringMVC源码解析系列3-HandleAdapter

HandleAdapter接口定义

定义: 根据HandlerMethod信息,对http请求进行参数解析,并完成调用

先看一下HandlerAdapter的接口定义

public interface HandlerAdapter {   //判断是否支持该handler类型的解析   boolean supports(Object handler);   //参数解析 并调用handler完成过程调用    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;   //用于处理http请求头中的last-modified   long getLastModified(HttpServletRequest request, Object handler);}复制代码

RequestMappingHandlerAdapter

以RequestMappingHandlerAdapter为例来讲,先看下继承关系

初始化过程

同RequestMappingHandlerMapping都有ApplicationContextAware,ServletContextAware,InitializingBean三个生命周期方法

这里我们就直接看InitializingBean了

#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overridepublic void afterPropertiesSet() { // 1.装载@ControllerAdvice注解的类 initControllerAdviceCache();// 2.装载ArgumentResolver(默认+自定义) if (this.argumentResolvers == null) {    List
resolvers = getDefaultArgumentResolvers(); //包装成一个Composite对象 this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 2.装载InitBinderArgumentResolvers(默认+自定义) if (this.initBinderArgumentResolvers == null) { List
resolvers = getDefaultInitBinderArgumentResolvers(); //包装成一个Composite对象 this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 3.装载ReturnValueHandlers(默认+自定义) if (this.returnValueHandlers == null) { List
handlers = getDefaultReturnValueHandlers(); //包装成一个Composite对象 this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); }}复制代码

过程概括:

  1. 装载带有ControllerAdvices注解的对象

    private void initControllerAdviceCache() {  //从容器中获取所有带有ControllerAdvices注解的类名 并包装成ControllerAdviceBean  List
    beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); OrderComparator.sort(beans); List
    responseBodyAdviceBeans = new ArrayList(); for (ControllerAdviceBean bean : beans) { //筛选出带有@ModelAttribute且不带@RequestMapping注解的方法 Set
    attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { //保存到modelAttributeAdviceCache中 this.modelAttributeAdviceCache.put(bean, attrMethods); } //筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中 Set
    binderMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(bean, binderMethods); } //筛选实现RequestBodyAdvice接口 添加到requestResponseBodyAdviceBeans中 if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); if (logger.isInfoEnabled()) { logger.info("Detected RequestBodyAdvice bean in " + bean); } } //筛选实现ResponseBodyAdvice接口 添加到requestResponseBodyAdviceBeans中 if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) { requestResponseBodyAdviceBeans.add(bean); if (logger.isInfoEnabled()) { logger.info("Detected ResponseBodyAdvice bean in " + bean); } } } //保存到全局变量 if (!responseBodyAdviceBeans.isEmpty()) { this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans); }}复制代码
    • 筛选出带有@ModelAttribute且不带@RequestMapping注解的方法
    • 筛选出带InitBinder注解的方法 添加到initBinderAdviceCache中
    • 筛选实现RequestBodyAdvice接口 添加到responseBodyAdvice中
    • 筛选实现ResponseBodyAdvice接口 添加到responseBodyAdvice中
  2. 装载ArgumentResolvers(默认+自定义)

  3. 装载InitBinderArgumentResolvers(默认+自定义)

  4. 装载ReturnValueHandlers(默认+自定义)

自定义拓展方式放后面说

以下为HandlerAdapter默认解析器

HandlerMethodReturnValueHandler,HandlerMethodArgumentResolver

//参数解析器public interface HandlerMethodArgumentResolver {  //判断是否支持该参数的解析(根据类型,注解等)   boolean supportsParameter(MethodParameter parameter);  //对参数进行解析 得到解析结果   Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,         NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;}//返回值解析器public interface HandlerMethodReturnValueHandler {  //判断是否支持该返回值的解析(根据类型,注解等)	boolean supportsReturnType(MethodParameter returnType);  //对返回值进行解析	void handleReturnValue(Object returnValue, MethodParameter returnType,			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;}复制代码

DispatcherServlet调用HandlerAdapter过程

//1.调用support()方法判断是否支持HandlerMethod的解析HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 如果是Get或Head请求 调用getLastModified()获取上次更新时间 String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {   long lastModified = ha.getLastModified(request, mappedHandler.getHandler());   if (logger.isDebugEnabled()) {      logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);   }  //如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存   if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {      return;   }}if (!mappedHandler.applyPreHandle(processedRequest, response)) {   return;}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());复制代码

过程总结:

  1. 调用support()方法判断是否支持改handler的解析

    #org.springframework.web.servlet.DispatcherServlet//在doDispatch()方法中调用了getHandlerAdapter(Object)方法来得到一个HandlerAdapterprotected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {    //调用HandlerAdapter.support()方法 判断是否支持该handler对象的解析   for (HandlerAdapter ha : this.handlerAdapters) {        ...      if (ha.supports(handler)) {         return ha;      }   }  ...}#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter//根据handler对象判断是否支持handler解析@Overridepublic final boolean supports(Object handler) {	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));}#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overrideprotected boolean supportsInternal(HandlerMethod handlerMethod) {	return true;}复制代码

  2. 如果是Get或Head请求 调用getLastModified()获取上次更新时间

    如果小于浏览器缓存更新时间 则直接返回 浏览器使用本地缓存

    #org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overrideprotected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {   return -1;}复制代码

  3. 调用handler()方法完成过程调用(参数解析 返回值解析)

    #org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter@Overridepublic final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)      throws Exception {   return handleInternal(request, response, (HandlerMethod) handler);}#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@Overrideprotected ModelAndView handleInternal(HttpServletRequest request,		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {	//对http协议缓存方面的请求头的处理(expire,cache-control)	if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {		checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);	}else {		checkAndPrepare(request, response, true);	}	//是否使用session锁	if (this.synchronizeOnSession) {		HttpSession session = request.getSession(false);		if (session != null) {          	//得到互斥量			Object mutex = WebUtils.getSessionMutex(session);			synchronized (mutex) {//执行过程调用				return invokeHandleMethod(request, response, handlerMethod);			}		}	}	//执行过程调用(参数解析 过程调用)	return invokeHandleMethod(request, response, handlerMethod);}复制代码

参数解析,过程调用流程分析

//根据HandlerMethod解析参数 并完成过程调用得到一个ModelAndViewprivate ModelAndView invokeHandleMethod(HttpServletRequest request,                 HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  ServletWebRequest webRequest = new ServletWebRequest(request, response);  try {    //对@InitBinder的处理 主要是聚合了@InitBinder的所有处理方法    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);    //@ModelAttribute的处理    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);	//对HandlerMethod的装饰,主要是增加了参数解析和返回值转化的功能    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);    //提供对参数解析的支持    invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);    //提供对返回值解析的支持    invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);    //提供对@InitBinder处理的支持    invocableMethod.setDataBinderFactory(binderFactory);    //TODO 尚不明功能    invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);	    //可以看做handler()过程的上下文    ModelAndViewContainer mavContainer = new ModelAndViewContainer();    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));    modelFactory.initModel(webRequest, mavContainer, invocableMethod);    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);==========================异步处理分割线=============		//AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务    AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);    asyncWebRequest.setTimeout(this.asyncRequestTimeout);	//异步处理Manager    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);    //设置异步执行线程池    asyncManager.setTaskExecutor(this.taskExecutor);    //提供对异步处理的支持    asyncManager.setAsyncWebRequest(asyncWebRequest);    //异步调用拦截器    asyncManager.registerCallableInterceptors(this.callableInterceptors);    asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);	//如果异步处理完成    if (asyncManager.hasConcurrentResult()) {      //获取异步执行结果      Object result = asyncManager.getConcurrentResult();      mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];      asyncManager.clearConcurrentResult();      ...      //替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果)      invocableMethod = invocableMethod.wrapConcurrentResult(result);    }	//对invocableMethod进行参数解析,过程调用,返回值转化    //并将结果存到mavContainer中    invocableMethod.invokeAndHandle(webRequest, mavContainer);    //如果异步处理正在执行(已经开始,尚未结束) 立刻返回    //同时DispatcherServlet也直接返回 等待AsyncContext.dispatch()调用再次进入doDispatch()方法    if (asyncManager.isConcurrentHandlingStarted()) {      return null;    }	//从mavContainer捞出结果    return getModelAndView(mavContainer, modelFactory, webRequest);  }  finally {    webRequest.requestCompleted();  }}复制代码

以上是invokeHandleMethod()的完整过程

但在调用过程中实际从异步处理分割线开始分为2种情况:

  1. 同步调用: 过程比较简单,直接进行参数解析和返回值转化就好了

    invocableMethod.invokeAndHandle(webRequest, mavContainer);return getModelAndView(mavContainer, modelFactory, webRequest);复制代码
  2. 异步调用:

    再分为两种情况:

    1. 异步处理中(已开始,尚未完成)

      //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);//异步处理ManagerWebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);//设置异步执行线程池asyncManager.setTaskExecutor(this.taskExecutor);//提供对异步处理的支持asyncManager.setAsyncWebRequest(asyncWebRequest);//异步调用拦截器asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);//对invocableMethod进行参数解析,过程调用(调用AsyncWebRequest.startAsync()执行异步过程),返回值转化//并将结果存到mavContainer中invocableMethod.invokeAndHandle(webRequest, mavContainer);//如果异步处理正在执行(已经开始,尚未结束) 立刻返回//同时DispatcherServlet也直接返回 return null;#org.springframework.web.servlet.DispatcherServletprotected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  ...  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  if (asyncManager.isConcurrentHandlingStarted()) {    return;  }  ...}//等待AsyncWebRequest.dispatch()被调用 然后再次进入doDispatch()方法复制代码
    2. 异步执行完成,再次进入doDispatch()流程

      //AsyncWebRequest内部持有AsyncContext 可以通过其开启异步任务AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);//异步处理ManagerWebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);//设置异步执行线程池asyncManager.setTaskExecutor(this.taskExecutor);//提供对异步处理的支持asyncManager.setAsyncWebRequest(asyncWebRequest);//异步调用拦截器asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);//异步处理完成 获取异步执行结果Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();//替换invocableMethod(原先异步处理的方法返回值是Callable现在直接返回结果)invocableMethod = invocableMethod.wrapConcurrentResult(result);//对invocableMethod进行参数解析,过程调用,返回值转化//并将结果存到mavContainer中invocableMethod.invokeAndHandle(webRequest, mavContainer);//从mavContainer捞出结果return getModelAndView(mavContainer, modelFactory, webRequest);复制代码

ServletInvocableHandlerMethod

先看一下ServletInvocableHandlerMethod是个什么东东

HandlerMethod:保存了处理过程方法

InvocableHandlerMethod: 对HandlerMethod的装饰,增加了参数解析的功能

ServletInvocableHandlerMethod:对HandlerMethod的装饰,增加了返回值转化的功能

同步流程

  1. invocableMethod.invokeAndHandle(webRequest, mavContainer);

    #org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethodpublic void invokeAndHandle(ServletWebRequest webRequest,                    ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  // 1.1 参数解析 并完成过程调用  Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);  setResponseStatus(webRequest);  ...    try {      //1.2 使用returnValueHandlers对返回结果进行处理 讲结果塞到mavContainer中 过程类似参数解析      this.returnValueHandlers.handleReturnValue(        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);    }}#org.springframework.web.method.support.InvocableHandlerMethodpublic Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,                                       Object... providedArgs) throws Exception {  //1.1.1 参数解析并得到绑定的结果  Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);  ...    //1.1.2 反射完成过程调用     Object returnValue = doInvoke(args);  ...    return returnValue;}private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,                                         Object... providedArgs) throws Exception {  //参数信息  MethodParameter[] parameters = getMethodParameters();  Object[] args = new Object[parameters.length];  for (int i = 0; i < parameters.length; i++) {    //调用HandlerMethodArgumentResolver#supportsParameter判断是否支持该参数的解析    if (this.argumentResolvers.supportsParameter(parameter)) {      try {        //调用HandlerMethodArgumentResolver#resolveArgument进行解析        args[i] = this.argumentResolvers.resolveArgument(          parameter, mavContainer, request, this.dataBinderFactory);        continue;      }      ...    }    ...  }  return args;}复制代码

  2. 包装ModelAndView getModelAndView(mavContainer, modelFactory, webRequest);

    //从mavContainer取出结果 包装成ModelAndViewprivate ModelAndView getModelAndView(ModelAndViewContainer mavContainer,                                     ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {  modelFactory.updateModel(webRequest, mavContainer);  if (mavContainer.isRequestHandled()) {    return null;  }  ModelMap model = mavContainer.getModel();  ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);  if (!mavContainer.isViewReference()) {    mav.setView((View) mavContainer.getView());  }  //如果是redirect请求  if (model instanceof RedirectAttributes) {    Map
    flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav;}复制代码

到此 HandlerAdapter.handler的调用过程算分析完了

@InitBinder的处理

WebDataBinder:数据(对象属性)绑定器,用于对对象的属性进行转化(Formatter)和校验(Validator)

InitBinder: @InitBinder注解用于在参数解析前初始化WebDataBinder.简单来说就是可以对WebDataBinder增加Validator和属性转化器Formatter

@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface InitBinder {	//在哪些属性上发生作用	String[] value() default {};}复制代码

示例

@InitBinderprotected void initBinder(WebDataBinder binder) { //添加自定义Data类型Formatter  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  dateFormat.setLenient(false);  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));}复制代码

@InitBinder方法分为两种:

  • 全局@InitBinder:定义在注解有@ControllerAdvices的类中,装载发生在HandlerAdapter初始化调用initControllerAdviceCache()过程中(见上文初始化过程分析)

  • 局部@InitBinder:定义在注解有@Controller的类中,装载发生在HandlerAdapter.handler()调用getDataBinderFactory()过程中

    private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {  //获取处理方法所在的类  Class
    handlerType = handlerMethod.getBeanType(); //从保存的全局缓存中找属于该类的局部@InitBinder方法 Set
    methods = this.initBinderCache.get(handlerType); if (methods == null) {
    //如果没找到 说明该类不是一个@ControllerAdvices注解的类(只有@Controller没有@ControllerAdvices) //得到该类中所有@InitBinder注解的方法 methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS); //将局部@InitBinder方法缓存到initBinderCache中 this.initBinderCache.put(handlerType, methods); } List
    initBinderMethods = new ArrayList
    (); //将全局@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods for (Entry
    > entry : this.initBinderAdviceCache.entrySet()) { if (entry.getKey().isApplicableToBeanType(handlerType)) { Object bean = entry.getKey().resolveBean(); for (Method method : entry.getValue()) { initBinderMethods.add(createInitBinderMethod(bean, method)); } } } //将局部@InitBinder方法包装成InvocableHandlerMethod,添加到initBinderMethods for (Method method : methods) { Object bean = handlerMethod.getBean(); initBinderMethods.add(createInitBinderMethod(bean, method)); } //使用initBinderMethods对象(局部+全局),包装成WebDataBinderFactory对象 return createDataBinderFactory(initBinderMethods);}protected InitBinderDataBinderFactory createDataBinderFactory(List
    binderMethods) throws Exception { return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());}复制代码

看完了了@InitBinder的装载过程,来看下@InitBinder方法是怎样被处理的

处理过程

this.argumentResolvers.resolveArgument(          parameter, mavContainer, request, this.dataBinderFactory);复制代码

可以看到在使用argumentResolvers.resolveArgument()进行参数解析时将dataBinderFactory作为参数传递了过去

分别来看RequestParamMapMethodArgumentResolver,RequestResponseBodyMethodProcessor,ModelAttributeMethodProcessor三个参数解析器是如何处理@InitBinder方法的

  • RequestParamMapMethodArgumentResolver

    @Override	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {      // 完全没使用binderFactory      ...	}}复制代码

    因为说过@InitBinder是用来初始化WebDataBinder的,而RequestParamMapMethodArgumentResolver是处理表单属性的(不是对象),所以完全没用

  • RequestResponseBodyMethodProcessor

    @Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {  parameter = parameter.nestedIfOptional(); //使用binderFactory创建对象解析器  WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);  if (arg != null) {    //使用对象解析进行参数校验    validateIfApplicable(binder, parameter);    //如果参数校验异常,且目标方法参数列表中没有BindingResult类型参数,则直接抛出参数解析异常    if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) 	{    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());    }  }  //将参数解析结果存到mavContainer上下文中  mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());  return adaptArgumentIfNecessary(arg, parameter);}复制代码

    因为RequestResponseBodyMethodProcessor将属性绑定委托给了json解析器,所以这里WebDataBinder只负责参数校验

  • ModelAttributeMethodProcessor

    @Overridepublic final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer 		mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {  String name = ModelFactory.getNameForParameter(parameter);  Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :                      createAttribute(name, parameter, binderFactory, webRequest));	...  WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);  if (binder.getTarget() != null) {    //使用binder进行属性绑定    if (!mavContainer.isBindingDisabled(name)) {      bindRequestParameters(binder, webRequest);    }    //使用binder进行属性校验    validateIfApplicable(binder, parameter);    if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {      throw new BindException(binder.getBindingResult());    }  }  // Add resolved attribute and BindingResult at the end of the model  Map
    bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);}protected Object createAttribute(String attributeName, MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { return BeanUtils.instantiateClass(methodParam.getParameterType());}protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) { ((WebRequestDataBinder) binder).bind(request);}复制代码

    使用WebDataBinder进行了属性绑定和属性校验

转载地址:http://cepol.baihongyu.com/

你可能感兴趣的文章
Hibernate连接DB2的问题(已解决)
查看>>
I.MX6 dts 在哪里、怎么编译
查看>>
第 44 章 Chart 图表
查看>>
JQuery ztree 异步加载实践
查看>>
XOR算法的原理和实现
查看>>
EF架构~一个规范,两个实现(续)~性能可以接受的批量增删改操作
查看>>
tensorflow笔记:多层LSTM代码分析
查看>>
Selenium2(WebDriver)总结(一)---启动浏览器、设置profile&加载插件
查看>>
iOS - C 基本语法
查看>>
我的软件测试之旅:(8)困难——没有现成的测试工具
查看>>
“智慧城市”建设风生水起
查看>>
楼宇对讲防盗报警系统两大特点
查看>>
使用“伪造”数据是消除大数据隐私问题的关键
查看>>
浅谈信息安全与数据中心安全的关系
查看>>
《PostgreSQL服务器编程》一一2.7 小结
查看>>
Oracle Database 12.2新特性详解
查看>>
IBM:量子计算现在跟1940年代电脑差不多 更看重长远目标
查看>>
研究机构称独角兽更易获得融资 明后年或有大量企业IPO
查看>>
三星将斥资80亿美元收购美国哈曼国际
查看>>
纷享销客变“逍”客 缘何战略一再调整?
查看>>