理解Spring Web MVC架構(gòu)
基礎(chǔ)架構(gòu):Servlet
- 特點(diǎn)
- 請(qǐng)求/響應(yīng)式(Request/Response)
- 屏蔽網(wǎng)絡(luò)通訊細(xì)節(jié)
- API特性
- 面向HTTP協(xié)議
- 完整生命周期
- 職責(zé)
- 處理請(qǐng)求
- 資源管理(數(shù)據(jù)庫(kù)連接况毅、消息連接、其他)
- 視圖渲染
核心架構(gòu):前端控制器(Front Controller)
- 資源 : http://www.corej2eepatterns.com/FrontController.htm
- 實(shí)現(xiàn) :Spring Web MVC DispatchServlet
Spring Web MVC 架構(gòu)
認(rèn)識(shí)Spring Web MVC
Spring Framework時(shí)代的一般認(rèn)識(shí)
實(shí)現(xiàn)Controller
@Controller
public class HelloWorldController {
@RequestMapping("")
public String index() {
return "index";
}
}
配置 Web MVC 組件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.imooc.web"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
部署DispatchServlet
<web-app>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
使用可執(zhí)行 Tomcat Maven 插件
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>tomcat-run</id>
<goals>
<goal>exec-war-only</goal>
</goals>
<phase>package</phase>
<configuration>
<!-- ServletContext path -->
<path>/</path>
</configuration>
</execution>
</executions>
</plugin>
Spring Framework時(shí)代的重新認(rèn)識(shí)
Web MVC 核心組件
組件 Bean 類型 | 說(shuō)明 |
---|---|
HandlerMapping | 映射請(qǐng)求(Request)到處理器(Handler)加上其關(guān)聯(lián)的攔截器 (HandlerInterceptor)列表尔艇,其映射關(guān)系基于不同的 HandlerMapping 實(shí)現(xiàn)的一些 標(biāo)準(zhǔn)細(xì)節(jié)尔许。其中兩種主要 HandlerMapping 實(shí)現(xiàn), RequestMappingHandlerMapping 支持標(biāo)注 @RequestMapping 的方法终娃, SimpleUrlHandlerMapping 維護(hù)精確的URI 路徑與處理器的映射母债。 |
HandlerAdapter | 幫助 DispatcherServlet 調(diào)用請(qǐng)求處理器(Handler),無(wú)需關(guān)注其中實(shí)際的調(diào)用 細(xì)節(jié)尝抖。比如,調(diào)用注解實(shí)現(xiàn)的 Controller 需要解析其關(guān)聯(lián)的注解. HandlerAdapter 的主要目的是為了屏蔽與 DispatcherServlet 之間的諸多細(xì)節(jié)迅皇。 |
HandlerExceptionResolver | 解析異常昧辽,可能策略是將異常處理映射到其他處理器(Handlers) 、或到某個(gè) HTML 錯(cuò)誤頁(yè)面登颓,或者其他搅荞。 |
ViewResolver | 從處理器(Handler)返回字符類型的邏輯視圖名稱解析出實(shí)際的 View 對(duì)象,該對(duì) 象將渲染后的內(nèi)容輸出到HTTP 響應(yīng)中框咙。 |
LocaleResolver咕痛, LocaleContextResolver | 從客戶端解析出 Locale ,為其實(shí)現(xiàn)國(guó)際化視圖喇嘱。 |
MultipartResolver | 解析多部分請(qǐng)求(如 Web 瀏覽器文件上傳)的抽象實(shí)現(xiàn) |
交互流程
MVC 注解驅(qū)動(dòng)
-
版本依賴
- Spring Framework3.1+
-
基本配置步驟
- 注解配置:
@Configuration
(Spring 范氏注解) - 組件激活:
@EnableWebMvc
(Spring模塊裝配) - 自定義組件:
WebMvcConfigurer
(Spring Bean)
- 注解配置:
重構(gòu)代碼:
@ComponentScan(basePackages = "com.imooc.web")
public class DispatchServletConfig {
}
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("攔截中....");
return true;
}
});
}
}
- 常用注解
- 注冊(cè)模型屬性:
@ModelAttribute
- 讀取請(qǐng)求頭:
@RequestHeader
- 讀取Cookie:
@CookieValue
- 校驗(yàn)參數(shù):
@Valid
茉贡、@Validated
- 注冊(cè)模型屬性:
@Controller
public class HelloWorldController {
@RequestMapping
public String index(@RequestHeader("Accept-Language")String acceptLanguage,@CookieValue("JSESSIONID")String jsessionId, Model model){
// model.addAttribute("acceptLanguage",acceptLanguage);
// model.addAttribute("jsessionId",jsessionId);
// model.addAttribute("message","hello,world");
return "index";
}
}
@ControllerAdvice(assignableTypes = HelloWorldController.class)
public class HelloWorldControllerAdvice {
@ModelAttribute("acceptLanguage")
public String acceptLanguage(@RequestHeader("Accept-Language")String acceptLanguage){
return acceptLanguage;
}
@ModelAttribute("jsessionId")
public String jsessionId(@CookieValue("JSESSIONID")String jsessionId){
return jsessionId;
}
@ModelAttribute("message")
public String message(){
return "hello,world";
}
@ExceptionHandler(Throwable.class)
public ResponseEntity<String> onException(Throwable throwable){
return ResponseEntity.ok(throwable.getMessage());
}
}
自動(dòng)裝配
- 版本依賴
- Spring Framework3.1+
- Servlet 3.0+
Servlet SPI
-
ServletContainerInitializer
,參考Servlet3.0 規(guī)范 - 配合
@HandlesTypes
Spring 適配
org.springframework.web.SpringServletContainerInitializer
Spring SPI
- 基礎(chǔ)接口:
org.springframework.web.WebApplicationInitializer
- 編程驅(qū)動(dòng):
org.springframework.web.servlet.support.AbstractDispatcherServletInitializer
- 注解驅(qū)動(dòng):
org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer
public class DefaultAnnotationConfigDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
//web.xml
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
//dispatchServlet
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{DispatchServletConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Spring Boot 時(shí)代簡(jiǎn)化Spring Web MVC
完全自動(dòng)裝配
- 自動(dòng)裝配
DispatcherServlet
:org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
- 裝配條件:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
@EnableConfigurationProperties(ServerProperties.class)
- 替換@
EnableWebMvc
:org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
- 裝配條件:
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
-
Servlet
容器:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
理解自動(dòng)裝配順序性
- 絕對(duì)順序:
@AutoConfigureOrder
- 相對(duì)順序:
@AutoConfigureAfter
裝配條件
Web類型判斷(@ConditionalOnWebApplication
)
- WebApplicationType
- Servlet類型:
WebApplicationType.SERVLET
- Servlet類型:
API判斷(@ConditionalOnClass
)
- Servlet
- Servlet
- Spring Web MVC
org.springframework.web.servlet.DispatcherServlet
org.springframework.web.servlet.config.annotation.WebMvcConfigurer
Bean判斷(@ConditionalOnMissingBean
、@ConditionalOnBean
)
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
外部化配置
Web MVC配置
org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
spring.mvc.view.prefix = /WEB-INF/jsp/
spring.mvc.view.suffix = .jsp
Spring Boot JSP依賴
<!-- Provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>