【实训邦@腾讯课堂】Java核⼼⾯试之SpringMVC⾯试解析SpringMVC简介
SpringMVC是⼀种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使⽤了MVC架构模式的思想,将web层进⾏职责解耦,并管理应⽤所需对象的⽣命周期,为简化⽇常开发,提供了很⼤便利。
SpringMVC提供了总开关——前端控制器(DispatcherServlet);请求处理映射器(Handler Mapping)和处理适配器(Handler Adapter),视图解析器(View Resolver)进⾏视图管理;动作处理器Controller接⼝(包含ModelAndView,以及处理请求响应对象request和response),配置灵活,⽀持⽂件上传,数据简单转化等强⼤功能。
Spring MVC 的⼯作流程是什么?
典型回答
⽤户发送请求到后端,后端前端控制器接收后根据请求URL到映射器查处理器和执⾏链并返回,前端控制器通过适配器执⾏处理器,然后接收处理器返回的ModelAndView对象,前端控制器调⽤视图解析器解析ModelAndView,根据返回的结果去响应⽤户请求或渲染视图。
详细流程
⾸先:加载l配置
1. ⽤户向服务器发送请求,请求被Spring 前端控制器(DispatcherServlet)捕获;
2. DispatcherServlet对请求URL进⾏解析,得到请求资源标识符(URI)。然后根据该URI,调⽤处理器映射器(HandlerMapping)获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的处理器(Handler),选择⼀个合适的HandlerAdapter(处理器适配器) [适配器模式]。(附注:如果成功获得HandlerAdapter后,此时将开始执⾏的preHandler(...)⽅法)
4. 提取Request中的模型数据,填充Handler⼊参,开始执⾏Handler(Controller)。在填充Handler的⼊参过程中,根据你的配置,Spring将帮你做⼀些额外的⼯作:
HttpMessageConveter:将请求消息(如Json、xml等数据)转换成⼀个对象,将对象转换为指定的响应信息
springmvc的注解有哪些数据转换:对请求消息进⾏数据转换。如String转换成Integer、Double等
数据格式化:对请求消息进⾏数据格式化。如将字符串转换成格式化数字或格式化⽇期等
数据验证(如果有):验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. 处理器(Handler)执⾏完成后,向前端控制器(DispatcherServlet)返回⼀个ModelAndView对象;
6. 根据返回的ModelAndView,选择⼀个适合的视图解析器(ViewResolver)(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. 视图解析器(ViewResolver)结合 Model 和 View,来渲染视图(View)
8. 将渲染结果返回给客户端。
DisptacherServlet代码分析
DisptacherServlet 实现了 Servlet 接⼝。
下⾯展⽰了HttpServlet定义的⼀下⽅法
当然,⽗类 HttpServlet 只是给出了定义,直接调⽤⽗类这些⽅法将会报错,所以 FrameworkServlet 将它们覆盖重写了处理逻辑:
protected final voiddoGet(HttpServletRequest request, HttpServletResponse response) {
//注解 10. 具体调⽤的是 processRequest ⽅法 processRequest(request, response);
}
protected final void doPost(HttpServletRequest request,HttpServletResponse response) {
processRequest(request, response);
processRequest(request, response);
}
可以看到 doGet 、doPost 这些⽅法,底层调⽤的都是 processRequest ⽅法进⾏处理,关键⽅法是委托给⼦类DispatcherServlet 的 doServie() ⽅法
DispatcherServlet#doService
protected voiddoService(HttpServletRequest request, HttpServletResponse response) throwsException { logRequest(request);
// 暂存请求参数
Map attributesSnapshot = null;
// 经过前⾯的准备(属性、辅助变量),进⼊请求处理过程 doDispatch(request,response);
}
请求分发和处理逻辑的核⼼是在 doDispatch(request,
response) ⽅法中。
DispatcherServlet#doDispatch
protected voiddoDispatch(HttpServletRequest request, HttpServletResponse response) { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler =null;
// 注释 10. 检查是否 MultipartContent 类型
processedRequest = checkMultipart(request);
// 根据 request 信息寻对应的
Handler mappedHandler =getHandler(processedRequest); if(mappedHandler == null) {
/
/ 没有到 handler,通过 response 向⽤户返回错误信息 noHandlerFound(processedRequest, response); return;
}
// 根据当前的 handler 到对应的 HandlerAdapter 适配器 HandlerAdapter ha
=Handler());
// 如果当前 handler ⽀持 last-modified 头处理
String method = Method();
boolean isGet = "GET".equals(method);
if (isGet ||"HEAD".equals(method)) {
if (isGet ||"HEAD".equals(method)) {
long lastModified = ha.getLastModified(Handler());
if (new ServletWebRequest(request,response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 的 preHandler ⽅法的调⽤
if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; }
// 真正激活 handler 进⾏处理,并返回视图
mv = ha.handle(processedRequest, response, Handler());
if(asyncManager.isConcurrentHandlingStarted()) { return; } //视图名称转换(有可能需要加上前后缀)applyDefaultViewName(processedRequest,mv);
// 应⽤所有的 postHandle ⽅法 mappedHandler.applyPostHandle(processedRequest,response, mv);
// 处理分发的结果(如果有 mv,进⾏视图渲染和跳转) processDispatchResult(processedRequest,r
esponse, mappedHandler, mv, dispatchException);
}
知识拓展
1. Spring MVC的主要组件?
(1)DispatcherServlet(前端控制器):从图中我们可以看出DispatcherServlet是整个流程的核⼼,⽤来控制其他组件的执⾏,统⼀调度,降低组件之间的耦合度,⽅便后期扩展。
(2)Handler(处理器):直接对应着MVC中的C也就是Controller层,它的具体表现形式有很多,可以是类,也可以是⽅法,也可以是其他表现形式,它的类型是Object。例如我们可以将@RequestMapping的所有⽅法都看成是⼀个Handler。总的来说只要可以实际处理请求就可以是Handler。
(3)HandleMapping(处理器映射器):对于每⼀个请求都需要⼀个Handler来处理,那么我们怎么知道需要通过哪个Handler来处理呢?这就是HandleMapping的⼯作,它会根据request请求来到具体处理请求的Handler。
(4)HandlerAdapter(处理器适配器): 上⾯说过Handler可以是任意的形式,只要能处理请求就OK,但是Servlet需要的处理⽅法的结构确实固定的,都是以request和response为参数的⽅法(如doservic⽅法)。怎么让固定的servlet处理⽅法调⽤灵活的Handler来进⾏处理,这就是HandlerAdaper要做的事情。通过HandlerAdapter对处理器进⾏执⾏,这是适配器模式的应⽤,通过扩展适配器可以对更多类型的处理器进⾏执⾏。(DispatcherServlte会根据HandlerMapping 传过来的controller与已经注册好了的HandlerAdapter⼀⼀匹配,看哪⼀种HandlerAdapter是⽀持该controller类型的,如果到了其中⼀种HandlerAdapter是⽀持传过来的controller类型,那么该HandlerAdapter会调⽤⾃⼰的handle⽅法,handle⽅法运⽤Java的反射机制执⾏controller的具体⽅法来获得ModelAndView)
通俗的讲就是Handler是⽤来⼲活的⼯具,HandlerMapping则是⽤于需要⼲的活到相应的⼯具,HandlerAdapter是使⽤⼯具⼲活的⼈。
(5)View(视图):View是⼀个接⼝,实现类⽀持不同的View类型(jsp、freemarker、pdf…)
(6)ViewResolver(视图解析器):作⽤:进⾏视图解析,根据逻辑视图名解析成真正的视图(view)。ViewResolver负责将处理结果⽣成View视图,View Resolver⾸先根据逻辑视图名解析成物理视图名即具体的页⾯地
址,再⽣成View视图对象,最后对View进⾏渲染将处理结果通过页⾯展⽰给⽤户。 springmvc框架提
供了很多的View 视图类型,包括:jstlView、freemarkerView、pdfView等。
⼀般情况下需要通过页⾯标签或页⾯模版技术将模型数据通过页⾯展⽰给⽤户,需要由⼯程师根据业务需求开发具体的页⾯。(View和View Resolver的原理与Handler和HandlerMapping的原理类似,View是⽤来展⽰数据的,⽽View Resolver是⽤来查View的)
2. SpringMVC常⽤的注解有哪些?
@Controller
使⽤它标记的类就是⼀个SpringMVC Controller 对象,也可以使⽤@RestController,@RestController注解相当于
@ResponseBody+ @Controller。
@RequestMapping
⽤于处理请求 url 映射的注解,可⽤于类或⽅法上。⽤于类上,则表⽰类中的所有响应请求的⽅法都是以该地址作为⽗路径。
@RequestMapping(value="/new",method = RequestMethod.GET)
// 简写
@GetMapping(value="/new")
// 其他请求⽅法
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@PathVariable
⽤于对应 RESTful 风格 url 中的参数
// url:/happy/1
@RequestMapping(value="/happy/{dayid}") findPet(@PathVariable
String dayid) // dayid == 1
@RequestParam
将请求的参数绑定到⽅法中的参数上
// Url:x?name=steven
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论