SpringMVC的執行流程
1. Spring MVC 的視圖解析機制
Spring MVC 的核心職責之一是將數據綁定到視圖并呈現給用戶。它通過 視圖解析器(View Resolver) 來將邏輯視圖名稱解析為具體的視圖文件(如 HTML、JSP)。
核心流程
-
Controller 處理請求:
Controller
方法可以通過返回 邏輯視圖名稱 或ModelAndView
對象來決定視圖和數據。
-
視圖解析器解析視圖名稱:
- 視圖名稱由
ViewResolver
解析為實際視圖文件路徑。
- 視圖名稱由
-
模型數據綁定到視圖:
- 數據由
Model
或ModelAndView
提供,Spring MVC 會將數據傳遞給視圖引擎渲染。
- 數據由
常見視圖解析器
-
Thymeleaf 視圖解析器
- Spring Boot 默認集成了 Thymeleaf,只需配置模板路徑:
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
-
JSP 視圖解析器
- 通過
InternalResourceViewResolver
? 或者xml配置文件配置: -
@Bean public InternalResourceViewResolver jspViewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver; }
- 通過
2. Model
和 ModelAndView
的作用與區別
2.1 Model
的作用
- 職責:僅負責傳遞數據。
- 特點:
Model
是一個數據容器。- 不能直接設置視圖名稱。
- Spring 自動將
Model
中的數據綁定到視圖。
- 常用場景:
- 數據簡單,視圖名稱固定,返回視圖邏輯名稱。
@RequestMapping("/exampleModel")
public String example(Model model) {model.addAttribute("message", "Hello from Model");return "viewName"; // 返回邏輯視圖名稱
}
2.2 ModelAndView
的作用
- 職責:同時封裝視圖名稱和數據。
- 特點:
- 既可以設置視圖名稱,也可以傳遞數據。
- 可以動態調整視圖名稱和數據,靈活性更高。
- 常用場景:
- 視圖名稱需要動態確定,或者需要同時設置多個數據。
@RequestMapping("/exampleModelAndView")
public ModelAndView exampleModelAndView() {ModelAndView mav = new ModelAndView();mav.setViewName("viewName"); // 設置視圖名稱mav.addObject("message", "Hello from ModelAndView");return mav;
}
2.3 Model
與 ModelAndView
的對比
特性 | Model | ModelAndView |
---|---|---|
職責 | 傳遞數據 | 傳遞數據并設置視圖名稱 |
視圖名稱設置 | 通過返回值設置 | 通過 setViewName 設置 |
靈活性 | 較低 | 較高 |
適用場景 | 固定視圖名稱,數據傳遞較簡單的場景 | 動態視圖名稱或需要同時傳遞多個數據的場景 |
3. Model
和 ModelAndView
配合視圖解析的用法
以下分別說明 Thymeleaf 和 JSP 的用法。
3.1 配合 Thymeleaf
(1)使用 Model
通過 Model
傳遞數據,并返回視圖的邏輯名稱。
@RequestMapping("/thymeleaf/model")
public String useModel(Model model) {model.addAttribute("message", "Hello from Model");model.addAttribute("title", "Thymeleaf Example");return "example"; // 解析為 /templates/example.html
}
對應 Thymeleaf 模板文件 (example.html
):
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title th:text="${title}">Default Title</title>
</head>
<body><h1 th:text="${message}">Default Message</h1>
</body>
</html>
(2)使用 ModelAndView
通過 ModelAndView
同時設置視圖名稱和數據。
@RequestMapping("/thymeleaf/modelAndView")
public ModelAndView useModelAndView() {ModelAndView mav = new ModelAndView();mav.setViewName("example"); // 解析為 /templates/example.htmlmav.addObject("message", "Hello from ModelAndView");mav.addObject("title", "Thymeleaf Example with ModelAndView");return mav;
}
3.2 配合 JSP
(1)使用 Model
通過 Model
傳遞數據,并返回視圖的邏輯名稱。
@RequestMapping("/jsp/model")
public String useModel(Model model) {model.addAttribute("message", "Hello from Model");model.addAttribute("title", "JSP Example");return "example"; // 解析為 /WEB-INF/views/example.jsp
}
對應 JSP 文件 (example.jsp
):
<!DOCTYPE html>
<html>
<head><title>${title}</title>
</head>
<body><h1>${message}</h1>
</body>
</html>
(2)使用 ModelAndView
通過 ModelAndView
同時設置視圖名稱和數據。
@RequestMapping("/jsp/modelAndView")
public ModelAndView useModelAndView() {ModelAndView mav = new ModelAndView();mav.setViewName("example"); // 解析為 /WEB-INF/views/example.jspmav.addObject("message", "Hello from ModelAndView");mav.addObject("title", "JSP Example with ModelAndView");return mav;
}
3.3 總結
特性 | Thymeleaf | JSP |
---|---|---|
視圖路徑配置 | classpath:/templates/ | /WEB-INF/views/ |
支持數據傳遞 | 支持 Model 和 ModelAndView | 支持 Model 和 ModelAndView |
模板引擎風格 | 現代化 HTML5 | 傳統 Java 模板 |
性能 | 高效 | 較低 |
4. 綜合總結
4.1 Model
和 ModelAndView
的選擇
- 簡單場景:使用
Model
配合返回視圖邏輯名稱。 - 復雜場景:使用
ModelAndView
同時設置視圖名稱和數據。
4.2 配合視圖解析器
- Thymeleaf 和 JSP 均支持
Model
和ModelAndView
,用法完全一致。 - 如果是新項目,推薦使用 Thymeleaf。
4.3 推薦實踐
- 優先使用
Model
和邏輯視圖名稱返回方式,更簡潔清晰。 - 在需要動態調整視圖名稱或復雜數據傳遞時,使用
ModelAndView
。
過濾器、攔截器、路徑匹配規則與應用
以下是關于 過濾器(Filter) 和 攔截器(Interceptor) 的核心內容,以及路徑匹配中 /
、/*
和 /**
的使用規則和場景總結。
1. 過濾器(Filter)
1.1 定義
- 屬于 Servlet 規范的一部分,運行在 Servlet 容器中。
- 用于對所有 HTTP 請求和響應進行預處理和后處理。
1.2 特點
- 作用范圍廣:可以作用于動態資源(如 API 請求)和靜態資源(如 HTML、CSS、JS)。
- 生命周期:由 Servlet 容器管理,啟動時初始化過濾器,容器銷毀時釋放過濾器。
- 使用場景:適用于跨域處理、編碼設置、訪問日志記錄、請求參數過濾等基礎功能。
1.3 示例
- 典型實現:
@WebFilter("/*") public class MyFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("Filter: Before processing request");chain.doFilter(request, response); // 執行后續邏輯System.out.println("Filter: After processing request");} }
2. 攔截器(Interceptor)
2.1 定義
- 屬于 Spring 框架的一部分,運行在 Spring MVC 的
DispatcherServlet
內部。 - 用于攔截由 Spring 處理的動態資源(如控制器方法)。
2.2 特點
- 作用范圍窄:僅作用于 Spring MVC 控制的請求(動態資源)。
- 生命周期:由 Spring 容器管理,在 Spring 啟動時加載,關閉時銷毀。
- 使用場景:適用于業務權限校驗、登錄校驗、動態數據封裝等業務邏輯。
2.3 示例
-
典型實現:
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("Interceptor: Before handling request");return true; // 返回 false 會中斷請求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {System.out.println("Interceptor: After handling request");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("Interceptor: After rendering view");} }
-
攔截器注冊:
@Configuration public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/api/**") // 攔截所有 /api 的請求.excludePathPatterns("/static/**"); // 排除靜態資源} }
3. 過濾器與攔截器的區別
特性 | 過濾器(Filter) | 攔截器(Interceptor) |
---|---|---|
作用范圍 | 全局,包含靜態資源和動態資源 | 僅作用于 Spring MVC 處理的動態資源 |
觸發時機 | 在 DispatcherServlet 之前運行 | 在 DispatcherServlet 內部運行 |
適用場景 | 跨域、編碼設置、日志記錄、IP 限制等基礎功能 | 登錄校驗、權限校驗、業務邏輯處理等 |
生命周期管理 | 由 Servlet 容器管理 | 由 Spring 容器管理 |
實現方式 | 實現 Filter 接口 | 實現 HandlerInterceptor 接口 |
路徑匹配能力 | 通過 /* 等規則匹配所有請求路徑 | 支持 /** ,匹配所有路徑,包括多級子路徑 |
靜態資源支持 | 支持靜態資源(如 HTML、CSS、JS) | 不支持靜態資源,只作用于動態請求 |
4. 路徑匹配規則與應用
4.1 匹配規則
規則 | 匹配范圍 | 適用場景 |
---|---|---|
/ | 僅匹配根路徑 / | 網站首頁、主路徑請求 |
/* | 匹配當前路徑下的一級子路徑 | 靜態資源過濾、一級子路徑匹配 |
/** | 匹配當前路徑及其所有層級子路徑 | 攔截器配置、遞歸匹配所有子路徑 |
5. 綜合推薦
-
過濾器(Filter):
- 如果需要對所有請求(包括靜態資源)進行操作,使用
/*
。 - 常見場景:日志記錄、編碼設置、跨域處理。
- 如果需要對所有請求(包括靜態資源)進行操作,使用
-
攔截器(Interceptor):
- 如果需要對動態請求(如 API 請求)進行操作,使用
/**
。 - 常見場景:登錄校驗、權限控制、封裝業務邏輯。
- 如果需要對動態請求(如 API 請求)進行操作,使用
-
路徑匹配規則:
/
:適用于根路徑請求。/*
:適用于當前路徑的一級子路徑。/**
:適用于所有子路徑的遞歸匹配。