定義: 根據HandlerMethod信息,對http請求進行參數解析,並完成調用java
先看一下HandlerAdapter的接口定義web
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爲例來說,先看下繼承關係spring
同RequestMappingHandlerMapping都有ApplicationContextAware,ServletContextAware,InitializingBean三個生命週期方法json
這裏咱們就直接看InitializingBean了瀏覽器
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
public void afterPropertiesSet() {
// 1.裝載@ControllerAdvice註解的類
initControllerAdviceCache();
// 2.裝載ArgumentResolver(默認+自定義)
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
//包裝成一個Composite對象
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 2.裝載InitBinderArgumentResolvers(默認+自定義)
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
//包裝成一個Composite對象
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 3.裝載ReturnValueHandlers(默認+自定義)
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
//包裝成一個Composite對象
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
複製代碼
過程歸納:緩存
裝載帶有ControllerAdvices註解的對象bash
private void initControllerAdviceCache() {
//從容器中獲取全部帶有ControllerAdvices註解的類名 幷包裝成ControllerAdviceBean
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
OrderComparator.sort(beans);
List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
for (ControllerAdviceBean bean : beans) {
//篩選出帶有@ModelAttribute且不帶@RequestMapping註解的方法
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
//保存到modelAttributeAdviceCache中
this.modelAttributeAdviceCache.put(bean, attrMethods);
}
//篩選出帶InitBinder註解的方法 添加到initBinderAdviceCache中
Set<Method> 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);
}
}
複製代碼
裝載ArgumentResolvers(默認+自定義)session
裝載InitBinderArgumentResolvers(默認+自定義)mvc
裝載ReturnValueHandlers(默認+自定義)app
自定義拓展方式放後面說
如下爲HandlerAdapter默認解析器
//參數解析器
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;
}
複製代碼
//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());
複製代碼
過程總結:
調用support()方法判斷是否支持改handler的解析
#org.springframework.web.servlet.DispatcherServlet
//在doDispatch()方法中調用了getHandlerAdapter(Object)方法來獲得一個HandlerAdapter
protected 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解析
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return true;
}
複製代碼
若是是Get或Head請求 調用getLastModified()獲取上次更新時間
若是小於瀏覽器緩存更新時間 則直接返回 瀏覽器使用本地緩存
#org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return -1;
}
複製代碼
調用handler()方法完成過程調用(參數解析 返回值解析)
#org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter
@Override
public 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
@Override
protected 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解析參數 並完成過程調用獲得一個ModelAndView
private 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種狀況:
同步調用: 過程比較簡單,直接進行參數解析和返回值轉化就行了
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
複製代碼
異步調用:
再分爲兩種狀況:
異步處理中(已開始,還沒有完成)
//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);
//對invocableMethod進行參數解析,過程調用(調用AsyncWebRequest.startAsync()執行異步過程),返回值轉化
//並將結果存到mavContainer中
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//若是異步處理正在執行(已經開始,還沒有結束) 馬上返回
//同時DispatcherServlet也直接返回
return null;
#org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
...
}
//等待AsyncWebRequest.dispatch()被調用 而後再次進入doDispatch()方法
複製代碼
異步執行完成,再次進入doDispatch()流程
//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);
//異步處理完成 獲取異步執行結果
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是個什麼東東
HandlerMethod:保存了處理過程方法
InvocableHandlerMethod: 對HandlerMethod的裝飾,增長了參數解析的功能
ServletInvocableHandlerMethod:對HandlerMethod的裝飾,增長了返回值轉化的功能
invocableMethod.invokeAndHandle(webRequest, mavContainer);
#org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod
public 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.InvocableHandlerMethod
public 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;
}
複製代碼
包裝ModelAndView getModelAndView(mavContainer, modelFactory, webRequest);
//從mavContainer取出結果 包裝成ModelAndView
private 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<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
複製代碼
到此 HandlerAdapter.handler的調用過程算分析完了
WebDataBinder:數據(對象屬性)綁定器,用於對對象的屬性進行轉化(Formatter)和校驗(Validator)
InitBinder: @InitBinder註解用於在參數解析前初始化WebDataBinder.簡單來講就是能夠對WebDataBinder增長Validator和屬性轉化器Formatter
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InitBinder {
//在哪些屬性上發生做用
String[] value() default {};
}
複製代碼
示例
@InitBinder
protected 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<Method> 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<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
//將全局@InitBinder方法包裝成InvocableHandlerMethod,添加到initBinderMethods
for (Entry<ControllerAdviceBean, Set<Method>> 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<InvocableHandlerMethod> 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
@Override
public 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
@Override
public 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<String, Object> 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進行了屬性綁定和屬性校驗