前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot源码解析之Model和Map参数解析

springboot源码解析之Model和Map参数解析

作者头像
九转成圣
发布2024-04-10 16:44:09
1260
发布2024-04-10 16:44:09
举报
文章被收录于专栏:csdn

springboot源码解析之Model和Map参数解析

有需要互关的小伙伴,关注一下,有关必回关,争取今年认证早日拿到博客专家

标签:源码:springboot

测试代码

代码语言:javascript
复制
@Controller
public class HelloController {

    @RequestMapping("/helloModelAndMap")
    public String helloModelAndMap(HttpServletRequest request, Model model, Map<String, Object> map) {
        System.out.println(model.getClass().getSimpleName());
        System.out.println(map.getClass().getSimpleName());
        System.out.println(model == map);
        request.setAttribute("message", "Hello World!");
        model.addAttribute("name", "张三");
        map.put("age", 18);
        // 这里拿不到Model和Map中的值,转发后能拿到 在视图渲染阶段才会放到请求域中
        System.out.println("helloMapAndModel:" + request.getAttribute("name"));
        System.out.println("helloMapAndModel:" + request.getAttribute("age"));
        return "forward:/success";
    }

    @RequestMapping("/success")
    @ResponseBody
    public Object success(ServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        result.put("message", request.getAttribute("message"));
        result.put("name", request.getAttribute("name"));
        result.put("age", request.getAttribute("age"));
        return result;
    }

}

控制台输出

代码语言:javascript
复制
BindingAwareModelMap
BindingAwareModelMap
true
helloMapAndModel:null
helloMapAndModel:null

请求响应

代码语言:javascript
复制
{"name":"张三","message":"Hello World!","age":18}

结果分析

通过输出可以看到,这里传入的Model对象和Map对象都是BindingAwareModelMap类型,并且指向同一个对象,BindingAwareModelMap既是Model也是Map

ModelAndViewContainer

代码语言:javascript
复制
public class ModelAndViewContainer {

   // ...

   private final ModelMap defaultModel = new BindingAwareModelMap();

  
   public ModelMap getModel() {
      if (useDefaultModel()) {
         return this.defaultModel;
      }
      else {
         if (this.redirectModel == null) {
            this.redirectModel = new ModelMap();
         }
         return this.redirectModel;
      }
   }

   // ... 

}

MapMethodProcessor

Map是由MapMethodProcessor参数处理器处理的

代码语言:javascript
复制
public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

   @Override
   public boolean supportsParameter(MethodParameter parameter) {
       // 参数类型为Map,并且没有啥注解(所以如果想要用map接受前段传递的请求体里的参数,一定要不要忘记加上@RequestBody注解)
      return Map.class.isAssignableFrom(parameter.getParameterType()) &&
            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");
       // 解析参数 这里拿到了ModelAndViewContainer 里面的Model 也就是 BindingAwareModelMap
      return mavContainer.getModel();
   }

   @Override
   public boolean supportsReturnType(MethodParameter returnType) {
      return Map.class.isAssignableFrom(returnType.getParameterType());
   }

   @Override
   @SuppressWarnings({"rawtypes", "unchecked"})
   public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
         ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

      if (returnValue instanceof Map){
         mavContainer.addAllAttributes((Map) returnValue);
      }
      else if (returnValue != null) {
         // should not happen
         throw new UnsupportedOperationException("Unexpected return type: " +
               returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
      }
   }

}

ModelMethodProcessor

Model参数是由ModelMethodProcessor解析的

代码语言:javascript
复制
public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
        // 参数类型是model
		return Model.class.isAssignableFrom(parameter.getParameterType());
	}

	@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");
        // 解析参数 和 MapMethodProcessor 一样,拿到了同一个 BindingAwareModelMap 对象,这也就是为什么测试方法里面model 和 map指向同一个对象的原因
		return mavContainer.getModel();
	}

	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return Model.class.isAssignableFrom(returnType.getParameterType());
	}

	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		if (returnValue == null) {
			return;
		}
		else if (returnValue instanceof Model) {
			mavContainer.addAllAttributes(((Model) returnValue).asMap());
		}
		else {
			// should not happen
			throw new UnsupportedOperationException("Unexpected return type: " +
					returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
		}
	}

}

参数解析过程中只是拿到了 BindingAwareModelMap 对象,执行目标方法的时候只是将key和value设置到了 BindingAwareModelMap 对象里面,那么具体是在哪里将 BindingAwareModelMap 中的key和value设置到请求域中的呢?

AbstractView

org.springframework.web.servlet.view.AbstractView#exposeModelAsRequestAttributes

代码语言:javascript
复制
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
                                              HttpServletRequest request) throws Exception {

    model.forEach((name, value) -> {
        if (value != null) {
            // 这样就是为什么给model 和 map中方数据和给request放数据一样的原因
            request.setAttribute(name, value);
        }
        else {
            request.removeAttribute(name);
        }
    });
}

通过调用链我们可以发现是在渲染视图的过程中将BindingAwareModelMap 对象中的值设置到请求域中的

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • springboot源码解析之Model和Map参数解析
    • 标签:源码:springboot
    • 测试代码
    • 控制台输出
    • 请求响应
    • 结果分析
    • ModelAndViewContainer
    • MapMethodProcessor
    • ModelMethodProcessor
    • AbstractView
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档