本文是學習 Spring Boot 的一些准備知識.
Spring Web MVC
Spring Web MVC 的兩個Context
如下圖所示, 基於 Servlet 的 Spring Web MVC 啟動時會創建兩個上下文, 即 Servlet WebApplicationContext 和 Root WebApplicationContext.
前者是 DispatcherServlet引導創建的, 后者由 ServletContextListener 創建, 包含服務,數據庫操作等非 Web 相關的組件.

DispatcherServlet
DispatcherServlet 是前端控制器, Spring MVC 遵循前端控制器模式(具體參看<Java EE 核心模式>一書). 前端控制器是 MVC 模式中 C 的一部分, 除此之外, C 還包括我們定義的 Controller 等應用控制器類.
HandlerMapping
- 傳統 Servlet 的請求 url 模式
Servlet規范中描述了 Servlet 和 Filter 的 URL 匹配模式. 如下;
- 精確匹配, 如
/index - 擴展名匹配, 如
*.jsp - 路徑匹配, 如
/hive/
優先級按精確匹配 > 最長路徑匹配 > 擴展名匹配.
- Spring MVC 中的
HandlerMapping
DispatcherServlet
Spring boot 中使用自動裝配來實例化和啟動 DispatcherServlet. 類名為 DispatcherServletAutoConfiguration, 路徑默認為 "" 或 "/" . 可以修改配置, 對應的配置類為 WebMvcProperties , 對應的配置為 spring.mvc.servlet.path=/
從中可以看到 Spring 配置的一般規律, 其他的配置項也可以從配置類中找到依據.
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
...
@Configuration
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
protected static class DispatcherServletConfiguration {
}
}
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
...
private final Servlet servlet = new Servlet();
...
}
public static class Servlet {
/**
* Path of the dispatcher servlet.
*/
private String path = "/";
}
HandlerMapping
用來找到 URL 匹配的 Handler 方法, 這些方法正是我們定義的 Controller 中的方法. 這些方法被 @RequestMapping 標記. 這個注解還有一些變體(CRUD): GetMapping , PostMapping, PutMapping, DeleteMapping等.
可以使用實現接口
HandlerInterceptor攔截器來驗證 handler 的本質. 其中一個方法的簽名是boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler). 注意handler定義的類型是Object, 說明handler的類型可能不止是HandlerMethod.
異常處理
Servlet 規范
規范中定義了異常處理相關的返回信息應該包含什么內容. 如: javax.servlet.error.stauts_code 定義了錯誤碼; javax.servlet.error.message 定義了錯誤信息; javax.servlet.error.exception 定義了異常.
Servlet 實現
web.xml 的配置如下:
<servlet>
<servlet-name>PageNotFoundServlet</servlet-name>
<servlet-class>com.xlx.servlet.PageNotFoundServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PageNotFoundServlet</servlet-name>
<url-pattern>/404.html</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
PageNotFoundServlet 實現:
public class PageNotFoundServlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,Exception{
// 此處驗證request中設置的錯誤碼.
request.getAttribute("javax.servlet.error.stauts_code");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.println("page not found...");
}
}
MVC 實現
通過 RestControllerAdvicer.
@RestConstrollerAdvice
public class RestControllerAdvicer{
@ExceptionHandler(NohandlerFoundException.class)
public Object pageNotFound(HttpStatus status,HttpServletRequest request,Throwable throwable){
Map<String,Object> errors = new HashMap<>();
errors.put("stauts_code",request.getAttribute("javax.servlet.error.stauts_code"));
errors.put("stauts_uri",request.getAttribute("javax.servlet.error.request_uri"));
return error;
}
}
Spring Boot 實現
通過實現 ErrorPageRegistrar 注冊錯誤頁面.
public class Application implements ErrorPageRegistrar{
@Override
public void registerErrorPages(ErrorPageRegistry registry){
registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,"404.html"));
}
}
....
@GetMapping("/404.html")
public Object handle404(){
// 實現錯誤處理
}
更多參看相關的那篇文章.
視圖
View
接口 View 定義了一個 void render(@Nullable Map<String, ?> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception; 方法, 用來渲染視圖.
ViewReslover
接口 ViewReslover 定義解析視圖名稱的方法 @Nullable View resolveViewName(String var1, Locale var2) throws Exception; 用來尋找對應的view對象名稱.
view 名稱: prefix + viewname + suffix
前綴 prefix 和 后綴 suffix 同樣可以配置
spring.mvc.view.suffix=.jsp
Thymeleaf
ThymeleafAutoConfiguration 同樣可以找到對應的配置類 ThymeleafProperties.
ContentNegotiationViewResolver內容協調處理器, 處理多個 viewResolver 的情況.
國際化(i18n)
- 理解
MessageSource抽象.
