开发第一个SpringMVC应用
SpirngMVC架构图
总结:
1、用法发起请求,到前端控制器(DispatchServlet)
2、前端控制器没有处理业务逻辑的能力,通过HandlerMapping查找Handler
3、返回执行链,包含了2部分内容,
a)Handler对象(模型对象)
b)拦截器(数组)
4、通过HandlerAdapter进行包装Handler
5、通过适配器执行Handler,进行业务逻辑的处理
6、业务逻辑处理完成,返回ModelAndView
a)Model Data(模型数据)
b)View(ViewName) 视图名称
7、将ModelAndView返回到前端控制器
8、前端控制器通过视图名称到 视图解析器中 查找视图对象
9、视图解析器返回真正视图对象
10、前端控制器通过模型数据和视图对象进行渲染
11、渲染完成产生响应返回
12、将响应返回给用户
开发第一个SpringMVC应用
创建SpringMVC工程
工程目录结构
导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.springmvc</groupId>
<artifactId>SpringMVCTest</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- 定义依赖版本号 -->
<properties>
<junit.version>4.10</junit.version>
<slf4j.version>1.6.4</slf4j.version>
<spring.version>4.1.3.RELEASE</spring.version>
<jstl.version>1.2</jstl.version>
<servlet-api.version>2.5</servlet-api.version>
<jsp-api.version>2.0</jsp-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- JSP相关 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-api.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 端口 -->
<port>80</port>
<!-- /:直接访问,无需加项目名 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置web.xml
在src/main/webapp下创建WEB-INF目录以及web.xml
配置DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>spingmvc</display-name>
<!-- 配置SpringMVC框架入口 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
tomcat启动时完成初始化
不配置,在第一次请求后完成初始化
-->
<load-on-startup>1</load-on-startup>
<!-- 加载springmvc配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
配置日志文件
在src/main/resources下创建log4j.properties
log4j.rootLogger=DEBUG,A1
log4j.logger.org.mybatis = DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
SpringMVC配置文件
在src/main/resources下创建springmvc-servlet.xml
SpringMVC默认从WEB-INF下读取servlet配置文件,文件的命名规则是:servletName-servlet.xml
如果要自定义servlet文件,需要在servlet定义时指定contextConfigLocation。
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定义执行器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 定义适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--定义模型对象 -->
<bean name="/hello.do" class="com.springmvc.handler.HelloHandler"/>
<!--
定义视图解析器(内部资源视图解析器)
Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
配置文件解析:
1、配置处理器映射器HandlerMapping
2、配置处理器适配器HandlerAdapter
3、配置模型Handler
4、配置视图解析器ViewResolver
HandlerMapping:
HandlerAdapter:
ViewResolver:
为什么要设计适配器?
Controller是多种类型的,如果没有适配器,在DispatcherServlet中调用Hadnler,需要判断Controller类型做调用,我们想去扩展自己的Controller,需要去改源码做判断调用。违反开闭(对扩展开放,对修改关闭)原则。
如果有了适配器,如果要扩展Controller,只需要写自己的Controller和实现适配器接口即可。
编写模型对象处理器
package com.springmvc.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloHandler implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 处理业务逻辑
ModelAndView mv = new ModelAndView();
mv.setViewName("hello");// 设置视图名称
mv.addObject("msg", "我的第一个SpringMVC应用!");// 设置模型数据
// request.setAttribute("msg", "xxxxx");
return mv;
}
}
启动Tomcat查看效果
测试:
DispatcherServlet源码解析
DispatcherServlet源码初始化过程
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); //文件上传组件
initLocaleResolver(context); //国际化
initThemeResolver(context);// 主题
initHandlerMappings(context);// HandlerMapping 处理器映射
initHandlerAdapters(context);// HandlerAdapter 适配器
initHandlerExceptionResolvers(context); //异常相关组件
initRequestToViewNameTranslator(context); // 转化
initViewResolvers(context); // ViewResolvers 视图解析器
initFlashMapManager(context); // 闪存
}
初始化映射器
初始化适配器
SpringMVC的默认配置文件
org.springframework.web.servlet.DispatcherServlet.properties
发现默认的配置文件中已经配置了默认的映射器和适配器,所以可以简化配置,无需配置映射器和适配器。
在DispatcherServlet中的doDispatch方法是SpringMVC的执行流程的控制方法,源码如下:
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);
// Determine handler for the current request.
// 获取执行链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 获取Handler的适配器
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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行链中拦截器的前置方法,如果返回false则终止执行。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
// 通过Handler适配器执行Handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
// 执行拦截器的后置方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 处理返回的结果,视图解析器的处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
使用注解方式开发SpringMVC应用
在第一个SpringMVC应用的基础上修改SpringMVC配置文件和编写模型对象处理器。
下面两个配置不是SpringMVC默认配置,所以不能省略。
SpringMVC配置文件
<!-- 定义注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 定义注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!-- 配置扫描器,使得@Controller生效 -->
<context:component-scan base-package="com.springmvc.handler" />
编写模型对象处理器
使用@RequestMapping映射请求URL
使用@Controller注解使HelloHandler 成为处理请求的控制器
package com.springmvc.handler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@RequestMapping("/show")
public ModelAndView show() {
// 处理业务逻辑
ModelAndView mv = new ModelAndView();
mv.setViewName("hello");// 设置视图名称
mv.addObject("msg", "我的第一个注解SpringMVC应用!");// 设置模型数据
return mv;
}
}
使用tomcat7启动后并测试
升级版注解驱动
作用:SpringMVC默认配置的升级版;
<mvc:annotation-driven />
对应的java类是:
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
使用<mvc:annotation-driven />后默认加入的HandlerMapping和Adapter有:
HandlerMapping有2个:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
Adapter有3个:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter