前一段时间由于项目的需要,接触了springMVC(这里主要是讲3.1版,以下内容也是围绕这个版本展开),发觉其MVC模式真的很强大,也简单易用,完全是基于注解实现其优雅的路径配置的。想想以前接手的项目,是用原生的servlet,一个功能块就得在web.xml上配置一个servlet信息,那个蛋疼,现在那个项目就单配置文件都快达到1万行了。当然,现在是SSH横行的年代,strust2.0也是许多企业的选择,是一个稳定、成熟的框架。但是我们选择springMVC是因为其具有几个突出的特性:1.轻量、2控制反转、3.面向切面、4.容器。这里可以参考这篇文章:
http://developer.51cto.com/art/200610/33580.htm
1 springMVC简介
1.1 度娘有话
度娘说:SpringMVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还可以是 Struts 这样的 Web 框架。通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术、Velocity、Tiles、iText 和POI。Spring MVC 框架并不知道使用的视图,所以不会强迫您只使用 JSP 技术。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
1.2 处理流程图:
1.3 流程解释:
Spring MVC中前端的控制器就是DispatcherServlet这个Servlet来掌管着用户的请求及最后的系统回应。这个DispatcherServlet同具体的业务逻辑一点都不着边,而是把所有的事情委派给控制器去做(Controller),当然DispatcherServlet是知道该把当前的事情交个那个控制器去做,这个后面会讲;然后当控制器把事情都做完了后,这个时候轮到视图(View)上场了,简单的理解好比我们做PPT,那么这里的视图好比PPT里面的模板,它可以把数据以不同的展现形式交给客户,可以是jsp、xml、json等等。
springMVC提供完全基于注解方式的控制反转机制,基本的POJO添加一些注解后即可变成控制层(C)、处理层(M)、组件或其他功能的类。
2 配置讲解
2.1 在web.xml上的配置:
<?xml version="1.0"encoding="UTF-8"?>
<web-app version="2.5"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/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/ spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
说明:上面说到前端控制器是DispatcherServlet这个Servlet,那很显然需要在web.xml中加入一个servlet,然后把用户的请求都让DispatcherServlet去处理。这里有个地方就是contextConfigLocation,这个是个初始化参数(init-param),在servlet进行初始化的时候可以设置它的值,而这个值定义了spring应用上下文(context—上下文,指的是一种环境,主要是各种bean,可以理解为各种component)的配置文件(XML格式)的位置,这个上下文会被DispatcherServlet加载进来,这样Dispatcher工作起来时会依照这个上下文的内容进行分配任务。
2.2 在spring-mvc.xml上的配置:
按上面的web.xml我们需要在/WEB-INF/目录下新建一个servlet-context.xml配置文件,进行springMVC的上下文配置,几个常用的配置内容如下:
<?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/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsd"> <!-- 自动扫描, 并保证@Required、@Autowired的属性被注入,指定要扫描的包 -->
<context:component-scanbase-package="keyingbo.spring.learn">
<context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
</context:component-scan> <mvc:annotation-driven>
<mvc:message-converters>
<!—重写字符过滤类,处理中文乱码 -->
<bean class="keyingbo.spring.learn.common.UTF8StringHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler/>
<!-- 定义视图层文件(这里用了默认的视图处理类)prefix 指定视图文件的目录,suffix指定后缀名-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Configure the multipart resolver 文件上传-->
<bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes-->
<property name="maxUploadSize"value="104857600"/>
</bean>
</beans>
3 几个简单的例子
3.1 显示helloWord
这里涉及到几个文件:
IndexCtronller.java:
package keyingbo.spring.learn.controller; importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
/**
* @Description: hello World例子
* @Company : 广东全通教育股份有限公司
* @author 柯颖波
* @date Sep 22, 2013 4:23:19 PM
* @version v1.0
*/
@Controller
@RequestMapping("/hello")
public class IndexCtronller {
@RequestMapping(method= RequestMethod.GET )
publicString index() {
return"index";
}
}
index.jsp:
<%@ page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
hello World. welcome to springMVC! <br>
</body>
</html>
这里讲解一下基本的处理流程:当项目跑起来时,假设前缀为:http://localhost:8080/
项目加载过程中会去扫描IndexCtronller.java这个类并进行映射存储,因为该类带有一个@ Controller的注解。前客户端请求:http://localhost:8080/hello时,springMVC的DispatcherServlet类进行过滤处理,去寻找相应的控制器,发现IndexCtronller这个类中的@ RequestMapping("/hello")带有”hello”(其实,这里不能说“发现”,应该是个映身的过程),所以调用这个类的某个方法进行请求处理(这里的方法中还可以带路径匹配的,这个例子简单化而没加),IndexCtronller进行处理完后,返回一个字符串“index”,DispatcherServlet会根据前面配置好的视图处理类及相关的路径设置(视图处理类配了默认,路径设在/WEB-INF/views/,后缀为.jsp)将/WEB-INF/views/index.jsp文件找出,并进行渲染呈现给客户端。以下例子的处理流程基本跟这个一致,只是中间加多业务逻辑的处理。
3.2 传递参数:
要与客户端交互,传递参数到服务器是必不可少的。下面的例子就是基于这个需求:
PostParaController.java:
packagekeyingbo.spring.learn.controller; importkeyingbo.spring.learn.entity.JavaBean; importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.PathVariable;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.bind.annotation.ResponseBody; /**
* @Description: 传递参数
* @Company : 广东全通教育股份有限公司
* @author 柯颖波
* @date Sep 22,2013 4:52:51 PM
* @version v1.0
*/
@Controller
@RequestMapping("/postPara")
public classPostParaController {
//单值
@RequestMapping(value="param",method=RequestMethod.GET)
public @ResponseBody StringwithParam(@RequestParam String param) {
return "取得 'param' 查询参数:" +param + "'";
}
//多值(值要与JavaBean的格式对应)
@RequestMapping(value="group",method=RequestMethod.GET)
public @ResponseBody StringwithParamGroup(JavaBean bean) {
return "取得 'param' 查询参数: "+ bean;
}
//REST形式的参数
@RequestMapping(value="path/{param}",method=RequestMethod.GET)
public @ResponseBody StringwithPathVariable(@PathVariable String param) {
return "取得 'param' 查询参数: '"+ param + "'";
} //还有其他方式
}
解释:如果只是传递单值,页面上传过来的参数名要与方法名一致,如果是集合,则有另外的处理方式,这里略过,可以参考其他资料。当然我们也可以传递HttpServletRequest对象进行处理。
3.3 页面数据绑定:
当我们从数据库中取出数据,需要进行页面绑定时,可以先将数据存入容器中,让springMVC的视图处理层进行解析填充。
JstlViewController.java
package keyingbo.spring.learn.controller; importkeyingbo.spring.learn.entity.JavaBean; importorg.springframework.stereotype.Controller;
import org.springframework.ui.Model;
importorg.springframework.web.bind.annotation.RequestMapping; /**
* @Description: 使用系统设定的ViewResolver进行页面渲染(这里的例子用到了jstl)
* @Company : 广东全通教育股份有限公司
* @author 柯颖波
* @date Sep 22, 2013 4:55:06 PM
* @version v1.0
*/
@Controller
@RequestMapping("/jstl")
public class JstlViewController {
@RequestMapping(value="")
publicString chooseView(Model model) {
JavaBeanjavaBean = new JavaBean();
javaBean.setParam1("keyingbo");
javaBean.setParam2("11111111");
javaBean.setParam3("柯颖波");
model.addAttribute("name","keyingbo");
model.addAttribute("javaBean",javaBean);
return"jstl";
}
}
jstl.jsp:
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"prefix="c" %>
<%@ page session="false"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My HTML View</title>
</head>
<body>
<div>
<h3>name:"${name}"</h3>
<h3>javaBean.param1:"${javaBean.param1}"</h3>
<h3>javaBean.param2:"${javaBean.param2}"</h3>
<h3>javaBean.param3:"${javaBean.param3}"</h3>
</div>
</body>
</html>
<script>
$(document).ready(function() {
base = new Base();
base.dynLoadCss( "${ctx}/resource/js/asyncbox/skins/Chrome/asyncbox.css");
base.dynLoadJs( "${ctx}/resource/js/asyncbox/AsyncBox.v1.4.5.js");
}
</script>
解释:JstlViewController将需要绑定的数据放入Model中(其实是一个map),然后视图处理器会根据jstl.jsp文件中的语句进行填充,比如${name}则是将model中的属性名为“name”的值进行替换,${javaBean.param1}则是将属性名为javaBean的对象的param1的属性值进行替换,其他亦然(这里只是简单的操作,jstl还有很多语法,具体查看相关的资料)
3.4 直接返回响应流形式(即不通过视图层处理直接反回流):
有时我们如果想做接口,或者用ajax进行页面取数据的时候,常常只需要服务器返回相应的数据列表(json或者xml)即可。
ResponseBodyController.java
packagekeyingbo.spring.learn.controller; importkeyingbo.spring.learn.entity.JavaBean; importorg.springframework.http.MediaType;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.ResponseBody; /**
* @Description: 直接返回响应流形式(多应用于ajax请求等)
* @Company : 广东全通教育股份有限公司
* @author 柯颖波
* @date Sep 22,2013 4:52:51 PM
* @version v1.0
*/
@Controller
@RequestMapping("/responseBody")
public classResponseBodyController { @RequestMapping(value="/string",method=RequestMethod.GET)
public @ResponseBody StringresponseString() {
return "response aString!!";
}
// 返回json形式的数据
@RequestMapping(value="/json",method=RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody JavaBeanresponseJson() {
JavaBean javaBean = newJavaBean();
javaBean.setParam1("keyingbo");
javaBean.setParam2("11111111");
javaBean.setParam3("22222222");
return javaBean;
} // 返回xml形式的数据
@RequestMapping(value="/xml",method=RequestMethod.GET,produces=MediaType.APPLICATION_XML_VALUE)
public @ResponseBody JavaBeanresponseXml() {
JavaBean javaBean = newJavaBean();
javaBean.setParam1("keyingbo");
javaBean.setParam2("11111111");
javaBean.setParam3("22222222");
return javaBean;
}
}
解释:注解@ResponseBody说明是直接返回数据流。可以通过
@RequestMapping(….,produces=MediaType.APPLICATION_XML_VALUE)设定返回流的类型。
备注:以上例子均可以在资源http://download.csdn.net/detail/keyingbo2008/6373279中下载,项目运行后,可以打开http://localhost:8080/(即首页,根据容器的配置来输入地址)进行查看。