开发第一个SpringMVC应用

开发第一个SpringMVC应用

    • SpirngMVC架构图
    • 开发第一个SpringMVC应用
      • 创建SpringMVC工程
      • 工程目录结构
      • 导入依赖
      • 配置web.xml
      • 配置日志文件
      • SpringMVC配置文件
        • 为什么要设计适配器?
      • 编写模型对象处理器
      • 启动Tomcat查看效果
    • DispatcherServlet源码解析
      • 在DispatcherServlet中的doDispatch方法是SpringMVC的执行流程的控制方法,源码如下:
    • 使用注解方式开发SpringMVC应用
      • SpringMVC配置文件
      • 编写模型对象处理器
      • 使用tomcat7启动后并测试
      • 升级版注解驱动
      • 改进后的注解SpringMVC配置

SpirngMVC架构图

开发第一个SpringMVC应用_第1张图片
总结:
1、用户发起请求,到前端控制器(DispatchServlet),会执行到(doDispatch)方法;
2、循环 HandlerMapping 查找 Handler,返回一个处理器执行链(HandlerExecutionChain);
HandlerExecutionChain 包含:
a)Handler对象
b) HandlerInterceptor[] 拦截器数组
4、通过HandlerAdapter进行包装Handler,返回一个HandlerAdapter对象;
5、循环执行处理器执行链中拦截器的前置方法;
6、通过适配器执行Handler,返回一个ModelAndView;
a)Model Data(模型数据)
b)View(ViewName) 视图名称
7、DispatcherServlet将ModelAndView传给ViewReslover视图解析器;
8、ViewReslover解析后返回具体View;
9、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中);
10、DispatcherServlet响应用户。

简单总结:
1、请求进入中央处理器(DispatcherServlet)
2、通过HandlerMapping查询业务逻辑类
3、通过HandlerAdapter执行业务逻辑
4、通过ViewReslover渲染视图
5、DispatcherServlet响应用户

为什么要设计适配器?
适配器是专门用来执行业务方法的,业务方法的Controller有很多种类型,如果没有适配器的话,在DispatcherServlet中调用Controller中业务方法的时,需要判断Controller类型后再调用;如果这是我们想扩展一个自己的Controller,是需要改源码做判断调用。违反扩展开放,修改关闭的原则。如果有个适配器,这时要扩展Contrller,只需要编写自己的Controller和实现适配器接口就可以了。

开发第一个SpringMVC应用

创建SpringMVC工程

开发第一个SpringMVC应用_第2张图片

工程目录结构

开发第一个SpringMVC应用_第3张图片

导入依赖

	<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.0modelVersion>
	<groupId>com.springmvcgroupId>
	<artifactId>SpringMVCTestartifactId>
	<version>1.0.0-SNAPSHOTversion>
	<packaging>warpackaging>
	
	<properties>
		<junit.version>4.10junit.version>
		<slf4j.version>1.6.4slf4j.version>
		<spring.version>4.1.3.RELEASEspring.version>
		<jstl.version>1.2jstl.version>
		<servlet-api.version>2.5servlet-api.version>
		<jsp-api.version>2.0jsp-api.version>
	properties>

	<dependencies>
		<dependency>
			<groupId>org.springframeworkgroupId>
			<artifactId>spring-webmvcartifactId>
			<version>${spring.version}version>
		dependency>
		<dependency>
			<groupId>org.slf4jgroupId>
			<artifactId>slf4j-log4j12artifactId>
			<version>${slf4j.version}version>
		dependency>
		
		<dependency>
			<groupId>jstlgroupId>
			<artifactId>jstlartifactId>
			<version>${jstl.version}version>
		dependency>
		<dependency>
			<groupId>javax.servletgroupId>
			<artifactId>servlet-apiartifactId>
			<version>${servlet-api.version}version>
			<scope>providedscope>
		dependency>
		<dependency>
			<groupId>javax.servletgroupId>
			<artifactId>jsp-apiartifactId>
			<version>${jsp-api.version}version>
			<scope>providedscope>
		dependency>
	dependencies>
	<build>
		<plugins>
			
			<plugin>
				<groupId>org.apache.tomcat.mavengroupId>
				<artifactId>tomcat7-maven-pluginartifactId>
				<configuration>
					
					<port>80port>
					
					<path>/path>
				configuration>
			plugin>
		plugins>
	build>
project>

配置web.xml

在src/main/webapp下创建WEB-INF目录以及web.xml
配置DispatcherServlet


<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>spingmvcdisplay-name>

	
	<servlet>
		<servlet-name>springmvcservlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
		
		<load-on-startup>1load-on-startup>
		
		<init-param>
			<param-name>contextConfigLocationparam-name>
			<param-value>classpath:springmvc-servlet.xmlparam-value>
		init-param>
	servlet>

	<servlet-mapping>
		<servlet-name>springmvcservlet-name>
		<url-pattern>*.dourl-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。


<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"/>
	
	
	<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:
开发第一个SpringMVC应用_第4张图片
HandlerAdapter:
开发第一个SpringMVC应用_第5张图片
ViewResolver:
开发第一个SpringMVC应用_第6张图片

为什么要设计适配器?

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查看效果

开发第一个SpringMVC应用_第7张图片
开发第一个SpringMVC应用_第8张图片
测试:
开发第一个SpringMVC应用_第9张图片

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应用_第10张图片
初始化适配器
开发第一个SpringMVC应用_第11张图片
SpringMVC的默认配置文件
org.springframework.web.servlet.DispatcherServlet.properties开发第一个SpringMVC应用_第12张图片

发现默认的配置文件中已经配置了默认的映射器和适配器,所以可以简化配置,无需配置映射器和适配器。
开发第一个SpringMVC应用_第13张图片

在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);
			}
		}
	}
// 1、定义执行处理器执行链(HandlerExecutionChain mappedHandler = null;)
// 2、获取处理器执行链(mappedHandler = getHandler(processedRequest);)
// 3、获取处理器适配器(HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());)
// 4、执行链中拦截器的前置方法,如果返回false则终止执行(if (!mappedHandler.applyPreHandle(processedRequest, response)))
// 5、通过适配器执行真正的业务处理器逻辑,并返回模型和视图对象(mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)
// 6、执行链中拦截器的后置方法(mappedHandler.applyPostHandle(processedRequest, response, mv);)
// 7、处理返回的结果,视图解析器的处理(processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);)
// 8、查找到视图后进行渲染,然后响应给请求端

使用注解方式开发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"/>

	
	<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应用_第14张图片

升级版注解驱动

作用:SpringMVC默认配置的升级版;

<mvc:annotation-driven />

对应的java类是:

org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser

使用后默认加入的HandlerMapping和Adapter有:
开发第一个SpringMVC应用_第15张图片

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

改进后的注解SpringMVC配置

开发第一个SpringMVC应用_第16张图片
开发第一个SpringMVC应用_第17张图片

你可能感兴趣的:(Spring)