SpringMVC简介
Web开发是Java的一个很常见的应用场景,在企业级开发中基于Web的应用程序也是大多数Java开发者主要的关注点。我们都知道在Web开发中,状态管理、工作流以及数据验证都是需要解决的重要特性。而HTTP协议的无状态性决定了这些问题都不太好解决,而Spring的Web框架就是为了解决这些关注点而设计的。
在介绍SpringMVC之前我们先来简单提一下MVC模式,MVC是很经典的一个架构模式,早在桌面时代就已经存在了,使用MVC模式我们能够开发出来一个松耦合的应用,让应用分为模型 - 控制器 - 视图。想必各位都对MVC很熟悉了,也都知道MVC有两种模式,分别为MVC1和MVC2,如下:
MVC1通常用于桌面程序,MVC2则多用于Web程序,而SpringMVC则是基于MVC2模式实现的。Spring MVC属Spring FrameWork的后续产品,已经融合在Spring Web Flow里面。SpringMVC能帮我们构建像Spring框架那样灵活、松耦合基于MVC模式的Web应用程序。
不过MVC框架不止SpringMVC一种,例如Struts就是老牌的MVC框架,目前Struts2结合了Webwork,也是非常优秀的MVC框架,优点非常多比如良好的结构,拦截器的思想,丰富的功能。但缺点是Struts2由于采用了值栈、OGNL表达式、Struts2标签库等等,会导致应用的性能下降,启动个服务器都要半天。Struts2的多层拦截器、多实例Action性能都很好。但正是因为拦截器太多,使得Struts2变得更加复杂,让人使用起来感觉很重不够轻量。
而SpringMVC是一个典型的教科书式的MVC构架,不像Struts等都是变种或者不是完全基于MVC系统的框架,对于初学者或者想了解MVC的人来说我觉得 SpringMVC 是最好的。第二它Ttapestry一样是一个纯正的Servlet系统,这也是它和Tapestry相比 Struts所具有的优势。而且框架本身有代码,看起来容易理解,使用简单,学习成本低,学习难度要小于Struts2。所以使得SpringMVC成为现在最主流的MVC框架。
简单介绍完SpringMVC后,我们来看看请求是如何从客户端发起,经过SpringMVC中的组件,最终再返回到客户端的。
跟踪SpringMVC的请求:
每当用户在web页面中,点击链接或者点击提交表单的按钮时,就会有请求发送到服务器 ,请求会将用户输入的数据带到服务端。当服务端使用了SpringMVC时,请求一般会经历如下几个站点:
请求经历的第一站是DispatcherServlet,使用了SpringMVC后,所有的请求都会通过这个作为前端控制器(front controller)的Servlet,这一点与大多数基于Java的Web框架一样。DispatcherServlet就是SpringMVC中的前端控制器,DispatcherServlet本质上也是一个Servlet,所以它是单例的。
DispatcherServlet的任务是将请求发送给SpringMVC控制器,控制器是一个用于处理请求的Spring组件。在典型的应用程序中可能会有多个控制器,所以DispatcherServlet需要知道应该将请求发送给哪个控制器,它就会去查询一个或多个处理器映射来确定请求的下一站在哪里,也就是要将请求发送给哪个控制器,而处理器映射会根据请求所携带的URL信息来进行决策发送到哪个控制器。
一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器。请求到了控制器后,会卸下用户提交的数据。而控制器会把这些数据交给服务对象进行处理,如果该控制器设计得良好的话。
控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器页面上显示出来。这些信息被称为模型,不过我们不能直接返回这些原始数据,这些数据需要以用户友好的方式返回,例如渲染成html格式进行返回。所以,这些数据还需要发送给视图,通常会是JSP。
控制器所做的最后一件事就是将模型数据打包,并且标示出用于渲染输出的视图名。它接下来会将请求连同模型和视图名称发送回DispatcherServlet。
这样控制器不会与特定的视图相耦合,因为传递给DispatcherServlet的视图名并不直接表示某个特定的JSP。实际上,它甚至不能确定视图就是JSP。它仅仅传递了一个名称,这个名称将会用来查找产生结果的真正视图,所以DispatcherServlet将会使用视图解析器来将逻辑视图名称匹配为一个特定的视图实现。
既然DispatcherServlet已经知道由哪个视图来渲染结果数据,那请求的任务基本上也就完成了。它的最后一站是视图的实现,在这里它交付模型数据。请求的任务就完成了。视图渲染模型数据并进行输出,这个输出会通过响应对象传递给客户端。
可以看到,请求要经过很多步骤,最终才能形成返回客户端的响应。大多数的步骤都是在SpringMVC框架内部完成的。
在web工程里配置SpringMVC
首先创建一个Maven的Web工程:
在pom.xml文件里配置如下依赖:
代码语言:javascript复制 <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
然后在resource目录下创建spring的配置文件,配置内容如下:
代码语言:javascript复制<?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"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config/>
<context:component-scan base-package="org.zero01.test"/>
<mvc:annotation-driven/>
</beans>
接着就是配置SpringMVC的前端控制器:DispatcherServlet,这个Servlet需要在web.xml中配置,配置内容如下:
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 配置DispatcherServlet在服务器启动时加载,以及其初始化参数 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 注意,这里不能写/*,不然会把jsp给匹配了,导致无法访问jsp -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
最后编写一个测试类,用于测试SpringMVC是否能够正常把请求传递到控制器上:
代码语言:javascript复制package org.zero01.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
// 控制器注解,声明这是一个控制器
@Controller
public class Test {
// 处理器映射注解,映射URL访问名称
@RequestMapping("/test.do")
public void method(){
System.out.println("This is a test output");
}
}
在浏览器里访问 http://localhost:8080/test.do 后,控制台输出内容如下:
代码语言:javascript复制This is a test output
除了以上这种通过web.xml文件配置SpringMVC之外,我们还可以通过Java类来进行配置,不过这种配置方式要求Web3.0以上的版本才行。以下简单介绍一下这种基于Java类的配置方式:
首先把之前在web.xml里配置的内容注释掉,然后创建一个Java类:
代码语言:javascript复制package org.zero01.test;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitial extends AbstractAnnotationConfigDispatcherServletInitializer{
protected Class<?>[] getRootConfigClasses() {
// 指定根配置类
return new Class[]{RootConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
// 指定配置类
return new Class[]{WebConfig.class};
}
protected String[] getServletMappings() {
// 将DispatcherServlet映射到 "/" 上
return new String[]{"/"};
}
}
编写配置类:
代码语言:javascript复制package org.zero01.test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc // 启动SpringMVC
@ComponentScan("org.zero01.test") // 启动组件扫描
public class WebConfig extends WebMvcConfigurerAdapter{
}
编写根配置类:
代码语言:javascript复制package org.zero01.test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan(basePackages = {"org.zero01.test"}, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)
})
public class RootConfig {
}
控制器类和之前一样,重启服务器访问 http://localhost:8080/test.do 后,控制台输出内容如下:
代码语言:javascript复制This is a test output
如上,介绍了两种配置SpringMVC的方式,不过这样我们只能算是完成了最基本、最简单的配置,其中还有视图、视图解析器等还没有进行配置,这些留到下一篇再进行介绍。