ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面

总结:

找到解析器后,用解析器去解析参数,都使用了resolveArgument()中以下方法

mavContainer.getModel();

mavContainer:模型和视图容器

视图:页面请求要返回一个地方,这个地方的地址叫视图 。比如要到/sucess

模型:携带的数据称为模型

复杂参数

   Map Model  :会被放在request请求域中,相当于调用了request.setAttribute

  Errors/BindingRequest

RedirectAttributes   重定向携带数据

 ServletResponse

SessionStatus UriComponentBuilder 

ServletComponentBuilder

转发生效前提

    return  "forward:/success2";

该类必须标注  @Controller  而不是@RestController,标准后者只会输出原文

方法注解参数设定非必须

  value="msg2",required = false

@ResponseBody
@GetMapping("/success2")
public Map success2(@RequestAttribute(value="msg2",required = false) String msg2,
                    @RequestAttribute(value="code",required = false) Integer code,
                    HttpServletRequest request

                    ){

 给Request域中放数据 map   model  request   response

TestFuza(Map<String,Object> map,
                           Model model,
                           HttpServletRequest request,
                           HttpServletResponse response
                           )

@Controller
public class FuzaController {

@GetMapping("/fuza")
    public String TestFuza(Map<String,Object> map,
                           Model model,
                           HttpServletRequest request,
                           HttpServletResponse response
                           ) {
    map.put("hello","1234567");
   model.addAttribute("city","苏州");
   request.setAttribute("province","广东");
    Cookie cookie=new Cookie("cookie1","shanghai");
    cookie.setDomain("localhost");
   response.addCookie(cookie);
     return  "forward:/success2";

    }

    @ResponseBody
    @GetMapping("/success2")
    public Map success2(@RequestAttribute(value="msg2",required = false) String msg2,
                        @RequestAttribute(value="code",required = false) Integer code,
                        HttpServletRequest request

                        ){

    Object msg1=request.getAttribute("msg");
    Map<String,Object> map=new HashMap<>();
    Object hello=request.getAttribute("hello");
    Object city=request.getAttribute("city");
   Object province=request.getAttribute("province");
   map.put("请求注解",msg1);
   map.put("annotion注解2",msg2);
   map.put("hello",hello);
   map.put("city",city);
   map.put("province",province);
      return map;
    }
}

原理分析1-到获取所有4个请求参数值

Cookie cookie=new Cookie("cookie1","shanghai");设置断点,请求后

我们企图给浏览器设置cookie

 浏览器中就会保存这个cookie

 进入断点

一路到

 stepinto

 stepinto

 循环27个解析器

可以看到parameter里面包含请求的4个参数: Map,Model,

 也就是方法张的参数

public String TestFuza(Map<String,Object> map,
                       Model model,
                       HttpServletRequest request,
                       HttpServletResponse response
                       ) 

可以看到当前Receiver,进入下一循环

 因为第一个参数是map,所以一直到  MapMethodProcessor

进入,会查看当前请求参数是否为Map

放行到去解析

 进入

 放行到

 进入

 其中有mavContainer,全称 ModelAndViewContainer去getModel

 ctrl进入ModelAndViewContainer,看到defaultModel

private final ModelMap defaultModel = new BindingAwareModelMap();

下面还有ModelMap getModel(),返回 defaultModel

 也可以在本类中ctl+f12查看方法

 

 其中有一句

private final ModelMap defaultModel = new BindingAwareModelMap();

ctrl进入类 BindingAwareModelMap

ctrl进入父类 ExtendedModelMap

public class ExtendedModelMap extends ModelMap implements Model {

可以看出ExtendedModelMap 既是ModelMap 又是Model

一路返回

,这样就获取了第一个参数 

 第二个参数解析

第二个参数编号1,就是model

stepinto

 stepinto

stepinto进入遍历Resolvers

 一直循环到ModelMethodParameter

 stepinto,可以看到参数类型是Model即可支持

继续放行

 stepinto

在如下位置stepinto

可以看到调的是与解析参数0一样的方法    mavContainer.getModel();

 放行到

 发现已经获得的两个参数类型都是@7059,代表他们是同一个对象

 放行到获取全部参数

 

-------------------------------以上获取了全部4个参数---------------------------------------------------- 

原理分析2-

放行到

可以在controller里面打一个断点

 这样放行几步就会先来到上面controller文件

继续放行几步

 放行到发现returnValue已经获取  是 forward:/success2

 查看其mavContainer参数得到的default model

 如何将上文defaultmodel中的两个值放到请求域中

在如下位置this.setResponseStatus(webRequest);进入

 进入之后

 

    放行到this.returnValueHandlers.handleReturnValue

 

 其传入参数中包含了 mavContainer

,这是处理返回结果,controller里面返回结果是个string),

 stepinto   this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest); 获取返回结果类型

放行返回

   

再次 step into,进入handleReturnValue 方法,找到返回值处理器selectHandler

 

 放行到本方法下面一句 

handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

 看到这个

 可以看出把返回值变成字符串放到了mavContainer

视图是要求的网址,模型是携带的数据

returnValue是forward:/success2  
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        if (returnValue instanceof CharSequence) {
            String viewName = returnValue.toString();
            mavContainer.setViewName(viewName);
            if (this.isRedirectViewName(viewName)) {
                mavContainer.setRedirectModelScenario(true);
            }

现在mavContainer包含了 view和 default model

 继续放行,辛苦啊,终于找到   getModelAndView这个方法所在位置

 

 进入,注意这一句modelFactory.updateModel(webRequest, mavContainer);

从此之后都是modelFactory执行 更新Model,可以进入研究

 继续放行,回到DispatcherServlet

 放行到mappedHandler.applyPostHandle(processedRequest, response, mv);

它是mv = ha.handle()获取完参数并放到mavcontainer中之后怎么办的方法,进入

放行到

 

 一路放行到

this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

 

 Step3  处理派发结果,就是要去哪些页面

this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);

stepinto 

 继续放行到,注意这里mv的值,mv是对model and view的再次封装

ModelAndView [view="forward:/success2"; model={hello=1234567, city=苏州}]

 放行

进入render()

 其中有拿到视图名 String viewName = mv.getViewName();

放行到

对  mv.getModelInternal() 评估一下

 

Stepinto   view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);

来到了视图解析器流程,了解即可

 继续放行进入  view.render(mv.getModelInternal(), request, response);

 渲染要去的页面

stepinto

 放行到核心    创建要去的页面   createMergedOutputModel

Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);

 stepinto 

 放行到

mergedModel.putAll(this.staticAttributes);此时创建了mergedModel

 放行到,如果model不为空,那么就都放入 mergedModel

继续放行,返回mergedModel

 

放行,准备响应repareResponse

 放行,渲染合并输出的模型数据

this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);

stepinto    getRequestToExpose拿到请求对象 

 

放行回到

 再次step into   renderMergedOutputModel,

 其中有一句暴露model作为请求域的属性,属于类InternalResourceView

this.exposeModelAsRequestAttributes(model, request);

 

 protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        this.exposeModelAsRequestAttributes(model, request);
        this.exposeHelpers(request);
        String dispatcherPath = this.prepareForRendering(request, response);
        RequestDispatcher rd = this.getRequestDispatcher(request, dispatcherPath);
        if (rd == null) {
            throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!");
        } else {
            if (this.useInclude(request, response)) {
                response.setContentType(this.getContentType());
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Including [" + this.getUrl() + "]");
                }

                rd.include(request, response);
            } else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Forwarding to [" + this.getUrl() + "]");
                }

                rd.forward(request, response);
            }

        }
    }

以下方法循环遍历model,赋值给request

  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);
            }

        });
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值