SpringMVC系列:DispatcherServlet的小秘密
SpringMVC系列:DispatcherServlet的小秘密
DispatcherServlet详解
常规解释
DispatcherServlet
HandlerMapping
HandlerAdapter
Handler
ViewResolver
View
源码解析
初始化onRefresh
调用
代码演示
controller实现方式,目前流程方式
通过实现Controller重写handlerRequest方式
通过实现HttpRequestHandler重写handleRequest方式
配置拦截器
异常处理的方式
实现HandlerExceptionResolver接口
通过@ControllerAdvice、 @ExceptionHandler注解
常见面试题
1.SpringMVC是什么
2.@ResponseBody的作用
3.Springmvc 怎么样设定重定向和转发的
4.过滤器与拦截器的区别
代码下载:https://codechina.csdn.net/ljcc122/cc
常规解释
DispatcherServlet
DispatcherServlet 前端控制器框架实现,处理请求处理响应结果。
HandlerMapping
HandlerMapping管理映射器,框架实现,依据请求找到具体Adapter。
HandlerAdapter
HandlerAdapter管理适配器,框架实现,调用具体的Handler(Controller)。
Handler
Handler 后端处理器,由程序员实现。接收用户请求,处理具体业务【MVC-之C】
ViewResolver
ViewResolver 视图解析器,框架实现。
View
View具体视图,程序员实现。将数据展现给用户。
源码解析
初始化onRefresh
SpringMVC源码:https://github.com/spring-projects/spring-framework/tags
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
//本次仅分析个人认为重点方法
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
//处理器映射器(url和Controller方法的映射)//三大组件HandlerMappings
initHandlerMappings(context);
//处理器适配器(实际执行Controller方法)//三大组件HandlerAdapters
initHandlerAdapters(context);
//处理器异常解析器
initHandlerExceptionResolvers(context);
//RequestToViewName解析器
initRequestToViewNameTranslator(context);
//视图解析器(视图的匹配和渲染) //三大组件ViewResolvers
initViewResolvers(context);
initFlashMapManager(context);
}
//initHandlerAdapters,initViewResolvers,initHandlerExceptionResolvers同理
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// 在ApplicationContext中找到所有HandlerMappings,包括父类上下文。
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// 我们将HandlerMappings保持在已排序的顺序中
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
}
}
//通过注册确保至少有一个HandlerMapping如果未找到其他映射,则为默认的HandlerMapping。
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
调用
doGet、doPost、doPost等最终都会调用到doService方法,而doService方法最终调用到doDispathc方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//处理器执行链
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//异步请求管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;//模型与视图
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
mappedHandler = getHandler(processedRequest);//获取当前请求的处理程序
if (mappedHandler == null) {//没有处理器
noHandlerFound(processedRequest, response);//返回404或者抛出异常
return;
}
// 获取当前请求的处理程序适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//执行拦截器的PreHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;//拦截器返回false 退出调用
}
//调用具体的handler即controller业务,包含参数解析
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;//并发处理
}
applyDefaultViewName(processedRequest, mv);
//执行拦截器PostHandle 方法 可以修改ModelAndView
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {//记录异常
dispatchException = ex;
} catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//处理请求的结果 如果有异常,会执行相关异常方法 ,同时也会执行拦截器的AfterCompletion方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
代码演示
controller实现方式,目前流程方式
@Controller
@RequestMapping(value = "/user")
public class UserController {
@RequestMapping(value = "/getUserById",produces="text/html;charset=UTF-8;")
public String getUserById(String userId){
if(userId == null || "".equals(userId)) {
System.out.println("缺少用户id,请检查参数!");
}
int uId = Integer.parseInt(userId);
System.out.println(1/uId);
User user = new User("cc百川", uId);
System.out.println(user.toString());
return "success";
}
@ResponseBody
@RequestMapping(value = "/getUserByIds",produces="text/html;charset=UTF-8;")
public String getUserByIds(String userId, String userName){
if(userId == null || "".equals(userId)) {
System.out.println("缺少用户id,请检查参数!");
}
User user = new User("cc百川", Integer.parseInt(userId));
System.out.println(user.toString());
return JSON.toJSONString(user);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
通过实现Controller重写handlerRequest方式
注意都需要配置mvc扫描
public class UseImplController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("---->UseImplController---->handleRequest---->");
ModelAndView mv = new ModelAndView();
mv.setViewName("success2");
mv.addObject("hello","cc百川");
return mv;
}
}
1
2
3
4
5
6
7
8
9
10
11
通过实现HttpRequestHandler重写handleRequest方式
public class UseImplHttpRequestHandler implements HttpRequestHandler {
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("---->进入CcRequestHandler---->handleRequest方法---->");
request.getRequestDispatcher("/WEB-INF/pages/success3.jsp").forward(request,response);
return;
}
}
1
2
3
4
5
6
7
配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="cutonInterceptor" class="com.cc.interceptors.CustInterceptor"></bean> <!--我们自定义的Interceptor -->
</mvc:interceptor>
</mvc:interceptors>
1
2
3
4
5
6
public class CustInterceptor implements HandlerInterceptor {
//执行handler之前,返回false不执行handler
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置连接器");
String uri = request.getRequestURI();
System.out.println(request.getRequestURL()+":"+uri);;
if(uri.indexOf("getUserById")!=-1) {
String param = request.getParameter("userId")+"";
return "1".equals(param.trim()) || "0".equals(param.trim());
}
return true;
}
//只是handler之后,视图返回返回之前,可以动态的修改视图
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后置拦截器");
}
//创建视图后,渲染视图之前,已经不能修改视图
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("最终拦截器");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
异常处理的方式
实现HandlerExceptionResolver接口
public class CustomExc implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
System.out.println("===============>统一异常拦截机制 ");
System.out.println(o.toString()+":"+e.getMessage());
ModelAndView m = new ModelAndView();
m.setViewName("error");
return m;
}
}
1
2
3
4
5
6
7
8
9
10
11
需要配置加载bean
<bean id="CustomExc" class="com.cc.exception.CustomExc"/>
1
通过@ControllerAdvice、 @ExceptionHandler注解
public class CustomExcAnn {
@ExceptionHandler(Throwable.class)
@ResponseBody
public ModelAndView error(Throwable error, HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView();
System.out.println("===========>异常拦截");
mv.setViewName("error");
System.out.println(error.getMessage());
return mv;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
常见面试题
1.SpringMVC是什么
Spring Web MVC 框架提供 模型-视图-控制器 架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序
2.@ResponseBody的作用
把数据填充到http的response中
3.Springmvc 怎么样设定重定向和转发的
在返回值前面加"forward:“就可以让结果转发(默认),在返回值前面加"redirect:“就可以让返回值重定向
重定向与转发的区别
转发 重定向
一次请求 两次请求
地址不变 地址栏发生改变
数据共享 两次请求数据不共享
只能在站点内跳转 可以重定向到任何URL
服务端行为 客户端行为
效率高 效率低
4.过滤器与拦截器的区别
4.1过滤器是servlet层面的,而拦截器是框架层面。
4.2过滤器在拦截器之前执行。
4.3拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
4.4拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4.5拦截器是基于java的反射机制的,而过滤器是基于函数回调。
4.6拦截器可以获取IOC容器中的各个bean,而过滤器就不行
1
2
3
4
5
6
望指导,持续更新中。。。
————————————————
版权声明:本文为CSDN博主「cc百川」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ljcc122/article/details/115907286