Map、Model原理

本篇内容与参数解析原理域对象数据共享 有较多重复,就算是复习吧,夯实基础。

首先,新建spring项目:demo4。

然后,java目录下创建控制器类Demo4Controller。

package com.example.boot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

@Controller
public class Demo4Controller {
    @GetMapping("/params")
    public String getParams(Map<String,Object> map,
                            Model model,
                            HttpServletRequest request,
                            HttpServletResponse response){
        map.put("hello","world666");
        model.addAttribute("world","hello666");
        request.setAttribute("message","helloworld");
        Cookie cookie = new Cookie("message2","helloworld2");
        response.addCookie(cookie);
        return "forward:/success";
    }

    @GetMapping("/success")
    @ResponseBody
    public Map success(HttpServletRequest request){
        Map<String,Object> map = new HashMap<>();
        Object hello = request.getAttribute("hello");
        Object world = request.getAttribute("world");
        Object message = request.getAttribute("message");
        map.put("hello",hello);
        map.put("world",world);
        map.put("message",message);
        return map;
    }
}

注意哈:Demo4Controller类上的注解是@Controller,不是@RestController
Demo4Controller#success()方法上的注解有@ResponseBody

并在resources.static目录下新建静态页index.html。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <a href="/params">getParams</a>
</body>
</html>

启动应用,进行调试,具体调试过程如下。
在这里插入图片描述

  • MapMethodProcessor#resolveArgument
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();
}
  • ModelAndViewContainer
public class ModelAndViewContainer {
	//...
    private final ModelMap defaultModel = new BindingAwareModelMap();
    //...
    public ModelMap getModel() {
        if (this.useDefaultModel()) {
            return this.defaultModel;
        } else {
            if (this.redirectModel == null) {
                this.redirectModel = new ModelMap();
            }

            return this.redirectModel;
        }
    }
    //...
}
//BindingAwareModelMap
public class BindingAwareModelMap extends ExtendedModelMap {}

//ExtendedModelMap
public class ExtendedModelMap extends ModelMap implements Model {}

//ModelMap
public class ModelMap extends LinkedHashMap<String, Object> {}

//LinkedHashMap
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{}

//HashMap
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {}

//Map
public interface Map<K,V> {}

//Model
public interface Model {}

在这里插入图片描述

解析请求参数:Map和Model时,调用MapMethodProcessor#resolveArgument(),将返回BindingAwareModelMap类型实例,且为同一个实例。
另外,从继承层次来看,BindingAwareModelMap类既为Map,也为Model。

Map或Model,可实现将数据放到request域中,相当于request.setAttribute。不妨调试一下,如下。
在这里插入图片描述

  • org.springframework.web.servlet.DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//...
	HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
	//...
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	//...
	this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
	//...
}
  • org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return this.handleInternal(request, response, (HandlerMethod)handler);
}
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	//...
	mav = this.invokeHandlerMethod(request, response, handlerMethod);
	//...
	return mav;
}
  • org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	//...
	invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
	//...
	var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
	//...
	return var15;
}
  • org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }

    return this.doInvoke(args);
}
  • org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
	//...
     Object[] args = new Object[parameters.length];

     for(int i = 0; i < parameters.length; ++i) {
		//...
         if (args[i] == null) {
             if (!this.resolvers.supportsParameter(parameter)) {
                 throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
             }

             try {
                 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
             } catch (Exception var10) {
             //...
             }
         }
     }

     return args;
}
  • org.springframework.web.method.annotation.MapMethodProcessor#resolveArgument
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();
}
  • org.springframework.web.servlet.DispatcherServlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
	//...
	this.render(mv, request, response);
	//...
}
  • org.springframework.web.servlet.DispatcherServlet#render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	//...
	view.render(mv.getModelInternal(), request, response);
	//...
}
  • org.springframework.web.servlet.view.AbstractView#render
public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
	//...
     this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);
 }
  • org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    this.exposeModelAsRequestAttributes(model, request);
    //...
}
  • org.springframework.web.servlet.view.AbstractView#exposeModelAsRequestAttributes
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
    model.forEach((name, value) -> {
        if (value != null) {
            request.setAttribute(name, value);
        } else {
            request.removeAttribute(name);
        }

    });
}

如上,Map或者Model中的数据,最终在AbstractView#exposeModelAsRequestAttributes方法中通过request.setAttribute()保存在request域中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值