复杂参数的请求处理的源码分析:
Dbug分析:Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)
//前面Dbug个模式省略,直接看一些重要的底层代码
//获取能够处理器Map model的解析器
@Override
public boolean supportsParameter(MethodParameter parameter){
parameter.getParameterAnnotations().length==0;
}
//解析器解析
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
return mavContainer.getModel();
}
public ModelMap getModel(){
if(useDefaultModel()){
retrun this.defaultModel;
}
省略后面源码...
}
private final ModeMap defaultModel = new BindingAwareModelMap();
//第二次循环Model的时候,也在底层调用了这个方法,说明Map和Model都会返回 BindingAwareModelMap
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
return mavContainer.getModel();
}
Dbug分析调试一些重要的参数
执行:invokeForRequest方法 ----------->doInvoke(args);
//真正执行目标反复噶
@Nullable
protected Object doInvoke(Object... args) throws Exception {
//执行源代码,就是你编写的代码(业务逻辑代码)
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
return getBridgedMethod().invoke(getBean(), args);
}
省略部分源码...
获取方法的返回值:returnValue ,获取请求准发的地址:"/table"
获取保存的属性值:mavContainer
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//returnValue可以获取到当前方法的处理结果:"/table"请求转发
//mavContainer可以获取到属性内保存的参数值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//设置响应状态
setResponseStatus(webRequest);
//省略部分源码...
//处理返回结果
//mavContainer保存属性和属性值
//Dbug调试
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
--------------------------------------------------------------------------
//处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//找到返回值的处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//继续深入源码,查看如何处理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
--------------------------------------------------------------------------
//处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//如果returnValue(里面保存里返回结果"/table")
//如果不存在返回结果,那么就将true保存在mvcContainer
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
//将当前的returnValue转化为ModelAndView
ModelAndView mav = (ModelAndView) returnValue;
if (mav.isReference()) {
String viewName = mav.getViewName(); //"/table"
mavContainer.setViewName(viewName); //将结果放入到mavContainer当中
...
}
目标方法执行结束之后,将所有的数据放在ModelAndViewContaioner;
包含要去的页面地址view,还有Modl数据
//模型工厂
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//更新Model
modelFactory.updateModel(webRequest, mavContainer);
//绑定策略
private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception {
List keyNames = new ArrayList<>(model.keySet());
for (String name : keyNames) {
Object value = model.get(name);
if (value != null && isBindingCandidate(name, value)) {
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;
if (!model.containsAttribute(bindingResultKey)) {
WebDataBinder dataBinder = this.dataBinderFactory.createBinder(request, value, name);
model.put(bindingResultKey, dataBinder.getBindingResult());
}
}
}
}
//再次封装
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
//model 保存的是当前对象的属性和值(k,v)
//再次封装为mav
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//判断当前数据是否为重定向数据
if (model instanceof RedirectAttributes) {
Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
//之后这个方法算是执行完毕,返回到RequestMappingHandlerAdapter.java
//mav = invokeHandlerMethod(request, response, handlerMethod);
//然后继续执行,返回到
//DispatcherServlet.java
//当前方法也执行完毕:(真正使用适配器执行目标方法也真正结束了)
//mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//继续进入下一个核心代码
//mappedHandler.applyPostHandle(processedRequest, response, mv);
DispatcherServlet.java
核心方法:mappedHandler.applyPostHandle(processedRequest, response, mv);
//执行拦截器方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
//省略部分源码...
//处理最终的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
//做错误处理性格的返回false,继续向下执行
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
//省略部分源码...
}
//省略部分源码...
// Did the handler return a view to render?
//当前mv保存了属性和属性值,以及请求地址"/table"
if (mv != null && !mv.wasCleared()) {
//要去那个页面,开始渲染
//Dbug调试,继续深入源码
render(mv, request, response);
//省略部分源码...
继续深入源码,看如何渲染页面的
//深入源码查看是如何渲染的
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
//获取视图名viewName="/table"
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
//解析视图
//Dbug调试mv.getModelInternal()
//结果为:参数和参数值 map map... model model...
//深入源码查看是如何解析的
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
//省略部分源码...
//进入视图解析器进行解析 @Nullable protected View resolveViewName(String viewName, @Nullable Mapmodel, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { //继续查看是如何解析的 View view = viewResolver.resolveViewName(viewName, locale); //省略部分源码...
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
//拿到请求域中的全部属性
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
//省略部分源码...
}
//省略部分源码...
//核心代码
View view = viewResolver.resolveViewName(viewName, locale);
MapmergedModel = createMergedOutputModel(model, request, response);、 //继续进入源码代码,继续查看 protected Map createMergedOutputModel(@Nullable Map model, HttpServletRequest request, HttpServletResponse response) { @SuppressWarnings("unchecked") Map pathVars = (this.exposePathVariables ? (Map ) request.getAttribute(View.PATH_VARIABLES) : null); // Consolidate static and dynamic model attributes. int size = this.staticAttributes.size(); size += (model != null ? model.size() : 0); size += (pathVars != null ? pathVars.size() : 0); //声明:mergedModel Map mergedModel = new linkedHashMap<>(size); mergedModel.putAll(this.staticAttributes); if (pathVars != null) { mergedModel.putAll(pathVars); } //如果当前数据不为空,将当前的数据转移的linkedHashMap if (model != null) { mergedModel.putAll(model); } // Expose RequestContext? if (this.requestContextAttribute != null) { mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel)); } //最终得到这个linkedHashMap return mergedModel; } //继续执行代码,跳转到AbstractView.java //Dbug调试mergedModel 里面保存的了方法的参数值 map map... model model... Map mergedModel = createMergedOutputModel(model, request, response); //准备响应 prepareResponse(request, response); //渲染合并输出的模型数据 //我们将model中的数据放入到mergedModel,然后有放入到了renderMergedOutputModel()方法里面 renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
@Override
protected void renderMergedOutputModel(
Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
//暴露模型作为请求域的属性
//Dbug调试,查看是如何将Map和Model放入的request作用域当中的
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including [" + getUrl() + "]");
}
rd.include(request, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to [" + getUrl() + "]");
}
rd.forward(request, response);
}
}
Dbug调试:如何将Model Map放入的request集合中去的
protected void exposeModelAsRequestAttributes(Mapmodel, HttpServletRequest request) throws Exception { model.forEach((name, value) -> { if (value != null) { request.setAttribute(name, value); } else { request.removeAttribute(name); } }); }



