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 map,
                           Model model,
                           HttpServletRequest request,
                           HttpServletResponse response
                           )

@Controller
public class FuzaController {

@GetMapping("/fuza")
    public String TestFuza(Map 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 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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第1张图片

 浏览器中就会保存这个cookie

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

 进入断点

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第3张图片

一路到

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第4张图片 stepinto

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第5张图片

 stepinto

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第6张图片

 循环27个解析器

可以看到parameter里面包含请求的4个参数: Map,Model,ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第7张图片

 也就是方法张的参数

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

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

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第8张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第9张图片

放行到去解析

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

 进入

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第11张图片

 放行到

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第12张图片

 进入

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第13张图片

 其中有mavContainer,全称 ModelAndViewContainer去getModel

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第14张图片

 ctrl进入ModelAndViewContainer,看到defaultModel

private final ModelMap defaultModel = new BindingAwareModelMap();

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第15张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第16张图片

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

 

 其中有一句

private final ModelMap defaultModel = new BindingAwareModelMap();

ctrl进入类 BindingAwareModelMap

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第17张图片

ctrl进入父类 ExtendedModelMap

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第18张图片

public class ExtendedModelMap extends ModelMap implements Model {

可以看出ExtendedModelMap 既是ModelMap 又是Model

一路返回

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第19张图片

 第二个参数解析

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

stepinto

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第20张图片

 stepinto

stepinto进入遍历Resolvers

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第21张图片

 一直循环到ModelMethodParameter

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第22张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第23张图片

继续放行

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第24张图片

 stepinto

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第25张图片

在如下位置stepinto

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第26张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第27张图片 放行到

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第28张图片

 放行到获取全部参数

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第29张图片

 

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

原理分析2-

放行到

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第30张图片

可以在controller里面打一个断点

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第31张图片

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

继续放行几步

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第32张图片

 查看其mavContainer参数得到的default model

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第33张图片

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

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第34张图片

 进入之后

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第35张图片

 

    放行到this.returnValueHandlers.handleReturnValue

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第36张图片

 

 其传入参数中包含了 mavContainer

,这是处理返回结果,controller里面返回结果是个stringServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第37张图片),

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第38张图片

放行返回

   ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第39张图片

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

 

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第40张图片

 放行到本方法下面一句 

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第41张图片

 看到这个

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第42张图片

 可以看出把返回值变成字符串放到了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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第43张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第44张图片

 

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

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第45张图片

 继续放行,回到DispatcherServlet

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第46张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第47张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第48张图片

放行到

 ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第49张图片

 一路放行到

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第50张图片

 

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

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

stepinto 

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第51张图片

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

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第52张图片

 放行

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第53张图片

进入render()

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第54张图片

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

放行到

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第55张图片

对  mv.getModelInternal() 评估一下

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第56张图片

 

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

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第57张图片

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

 渲染要去的页面

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第58张图片

stepinto

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第59张图片

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

Map mergedModel = this.createMergedOutputModel(model, request, response);

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第60张图片

 stepinto 

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第61张图片

 放行到

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第62张图片

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第63张图片

继续放行,返回mergedModel

 

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第64张图片

放行,准备响应repareResponse

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第65张图片

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

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

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第66张图片

stepinto    getRequestToExpose拿到请求对象 

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第67张图片

 

放行回到

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第68张图片

 再次step into   renderMergedOutputModel,

ServletAPI 2-10复杂参数, 解析完的参数值都会放到 ModelAndViewContainer里面_第69张图片

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

this.exposeModelAsRequestAttributes(model, request);

 

 protected void renderMergedOutputModel(Map 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 model, HttpServletRequest request) throws Exception {
        model.forEach((name, value) -> {
            if (value != null) {
                request.setAttribute(name, value);
            } else {
                request.removeAttribute(name);
            }

        });
    }

你可能感兴趣的:(servlet)