理解Spring Web MVC架构
基础架构:Servlet
- 特点
- 请求/响应式(Request/Response)
- 屏蔽网络通讯细节
- API特性
- 面向HTTP协议
- 完整生命周期
- 职责
- 处理请求
- 资源管理(数据库连接、消息连接、其他)
- 视图渲染
核心架构:前端控制器(Front Controller)
- 资源 : http://www.corej2eepatterns.com/FrontController.htm
- 实现 :Spring Web MVC DispatchServlet
Spring Web MVC 架构
认识Spring Web MVC
Spring Framework时代的一般认识
实现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>
使用可执行 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时代的重新认识
Web MVC 核心组件
组件 Bean 类型 | 说明 |
---|---|
HandlerMapping | 映射请求(Request)到处理器(Handler)加上其关联的拦截器 (HandlerInterceptor)列表,其映射关系基于不同的 HandlerMapping 实现的一些 标准细节。其中两种主要 HandlerMapping 实现, RequestMappingHandlerMapping 支持标注 @RequestMapping 的方法, SimpleUrlHandlerMapping 维护精确的URI 路径与处理器的映射。 |
HandlerAdapter | 帮助 DispatcherServlet 调用请求处理器(Handler),无需关注其中实际的调用 细节。比如,调用注解实现的 Controller 需要解析其关联的注解. HandlerAdapter 的主要目的是为了屏蔽与 DispatcherServlet 之间的诸多细节。 |
HandlerExceptionResolver | 解析异常,可能策略是将异常处理映射到其他处理器(Handlers) 、或到某个 HTML 错误页面,或者其他。 |
ViewResolver | 从处理器(Handler)返回字符类型的逻辑视图名称解析出实际的 View 对象,该对 象将渲染后的内容输出到HTTP 响应中。 |
LocaleResolver, LocaleContextResolver | 从客户端解析出 Locale ,为其实现国际化视图。 |
MultipartResolver | 解析多部分请求(如 Web 浏览器文件上传)的抽象实现 |
交互流程
MVC 注解驱动
-
版本依赖
- Spring Framework3.1+
-
基本配置步骤
- 注解配置:
@Configuration
(Spring 范氏注解) - 组件激活:
@EnableWebMvc
(Spring模块装配) - 自定义组件:
WebMvcConfigurer
(Spring Bean)
- 注解配置:
-
重构代码:
@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;
}
});
}
}
- 常用注解
- 注册模型属性:
@ModelAttribute
- 读取请求头:
@RequestHeader
- 读取Cookie:
@CookieValue
- 校验参数:
@Valid
、@Validated
- 注册模型属性:
@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());
}
}
自动装配
- 版本依赖
- Spring Framework3.1+
- Servlet 3.0+
Servlet SPI
-
ServletContainerInitializer
,参考Servlet3.0 规范 - 配合
@HandlesTypes
Spring 适配
org.springframework.web.SpringServletContainerInitializer
Spring SPI
- 基础接口:
org.springframework.web.WebApplicationInitializer
- 编程驱动:
org.springframework.web.servlet.support.AbstractDispatcherServletInitializer
- 注解驱动:
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 时代简化Spring Web MVC
完全自动装配
- 自动装配
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
理解自动装配顺序性
- 绝对顺序:
@AutoConfigureOrder
- 相对顺序:
@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>
网友评论