Spring MVC 1.简介 Spring MVC是一个和Spring完美结合的Web框架。我先前学过Struts2,再学Spring MVC,觉得Spring MVC更为简约、高效和优雅,它有不少东西借鉴自Struts2,如依赖注入等。它功能完整,推荐在新项目中替代Struts2,至于Struts,直接秒杀。
下面的配置均采用Spring 3版本,Spring MVC基于Java Servlet技术规范,主要处理流程图: 来自浏览器的请求URL由DispatcherServlet统一处理(除了css、js、图片等静态文件),它符合Java Servlet规范。在web.xml文件中配置哪些URL由该Servlet处理。
DispatcherServlet根据配置(通常由注解或xml文件配置)将URL请求发往相应的Controller处理,
这个过程会带上服务器端传递过来的参数并自动装载给Controller。
Controller接收到参数后,调用相应的方法处理之,
方法里可以调用业务层接口或数据层接口等,
然后将处理结果打包到一个ModelAndView对象中并返 回。
DispatcherServlet将ModelAndView对象发往视图解析器viewResolver处理。
视图解析器根据ModelAndView对象中指定的视图模板位置和携带的数据渲染模板文件为html文件,返回渲染后的文件。
DispatcherServlet将html文件(有时候是纯文本或多媒体文件)返回给浏览器。
很好的教程:点击 2.安装及配置文件 建议使用eclipse或netbeans编写程式,只需要导入Spring和Spring Web的所有jar包即可。
按照习惯,Spring的xml配置文件统一放在classpath根目录下并遵循applicationContext-*.xml的命名规范;
web.xml配置css、js、图片文件为静态文件,靠后缀识别,其它URL由DispatcherServlet处理。
web.xml配置文件如下:
不要使用/js/*作为静态文件的url-pattern,这样可以直接访问WEB-INF下的文件。
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">
<!--解决乱码问题-->
<filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter. CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf8</param-value> </init-param> <init-param> <param- name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url -pattern>/*</url-pattern> </filter-mapping>
<!--配置静态文件-->
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>* .css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping > <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default< /servlet-name> <url-pattern>*.jpeg</url-pattern></servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png </url-pattern></servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern></servlet-mapping> < servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.bmp</url-pattern> </servlet-mapping>
<!-- Spring MVC Servlet配置-->
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name>
< !--如果有多个spring配置文件,用逗号隔开-->
<param-value>classpath:applicationContext-*.xml</param-value> </init-param> <load-on-startup>1 </load-on-startup></servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern></servlet-mapping> <welcome- file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
Tomcat, Jetty, JBoss, and GlassFish默认Servlet的名字– “default” Google App Engine默认Servlet的名字– “_ah_default” Resin默认Servlet的名字– “resin-file” WebLogic默认Servlet的名字– “FileServlet” WebSphere默认Servlet的名字– “SimpleFileServlet” classpath下关于Spring Web的配置文件: applicationContext-web .xml <?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0. xsd">
<!-- 【注意】这里设置所有Controller所在的包位置,该包中所有使用annotation的类都会自动加载-->
<context:component-scan base-package="springmvc.web" />
<!-- 视图解析器,由DispatcherServlet控制,根据Controller返回值选择对应的模板具体:Controller返回modelAndView或String对象,由对象name前面加上prefix,后面加上subfix形成文件的真实地址 -->
< bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value =".jsp" />
</bean>
<!--上传文件-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
</beans>
3.编写Controller之Hello World
3.1编写Controller Controller可以是任意一个普通类,不需要继承或实现任何东西。
Controller类必须放在配置文件applicationContext-web.xml中指定的注解包下,
如springmvc.web,应根据实际情况修改。
HelloWorldController.java package springmvc.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;
//通过注解使得该类变成Controller类 @Controller //根目录,默认是"/",指定后为"/hello"
@RequestMapping("hello") public class HelloWorldController {
//该方法对应的URL,即访问"/hello/hello_world"将调用该方法
@RequestMapping("hello_world") public ModelAndView handleRequest() {
// modelAndView的名称将会结合viewResolver配置的prefix和suffix合成一个页面的路径
ModelAndView modelAndView = new ModelAndView("hello_world");
// modelAndView对象携带的信息modelAndView.addObject("message", "hello_world MVC!"); return modelAndView; }
//一个类中可以写很多这样的方法,名称自取,使用注解映射到不同的URL
//如果没有附带数据,也可以直接返回String类型的名称} 关于其它bean依赖注入,
比如业务层或数据层的对象,使用注解可以让Spring完成自动注入:
@Autowiredprivate CommonDao commonDao;
注意:ModelAndView的类不是org.springframework. web.portlet.ModelAndView
3.2编写jsp页面 当请求链接”/hello/hello_world”发送到DispatcherServlet,转发到HelloWorldController的handlerRequest方法,
该方法返回modelAndView对象,根据该对象的名称hello_world和配置文件中的prefix和suffix组合成物理jsp地址位置:
/WEB-INF/jsp/hello_world.jsp
现在创建该jsp页面:hello_world.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<p>
这是Controller传过来的数据message: ${message}
</p>
</body>
</html>
modelAndView对象中附带的message字符串将被渲染到jsp页面中。
部署该标准Java Web项目到tomcat服务器上,本机访问http://127.0.0.1:8080/spring_mvc/hello/hello_world就可以看到网页,
其中spring_mvc是我在eclipse中的项目名称,
默认是这样: 这是Controller传过来的数据message:hello_world MVC!
4.获得来自浏览器的参数及环境变量
4.1 GET或POST传递的参数 Spring MVC采用控制反转的思想进行依赖注入,
假设HTML页面需要传递参数name和age,
则HTML页面有个form:
<form action="/some/url">
Name: <input type="text" name="name"/><br />
Age: <input type="text" name ="age"/><br />
</form>
这种提交形式是POST,也可以等同地使用GET方式提交:/some/url?name=pugwoo&age=24
然后Controller中对应的方法只需要在参数上加上对应名称和类型的参数:
@RequestMapping("/some/url")
public ModelAndView handleRequest(String name, Integer age) {
//此时name和age已经拥有服务器端传过来的值
//类型也会自动转换,比如从String转成Integer
//接下来,做你想做的事情
}
如果想指定采用GET或POST方式,在@RequestMapping中指定method即可:
@RequestMapping(value = "/url", method = RequestMethod.GET)
或 @RequestMapping(value = "/url", method = RequestMethod.POST)
注:我不喜欢Spring 2.0使用Spring MVC标签来写HTML页面的方式。
虽然它提供了参数验证功能,但这个由自己写的js来做更好,这样有利于开发的解耦。
类Struts2的OGNL传参形式 当页面的变量很多时,
可以采用OGNL方式传递变量,加入有类Car,Car有属性String name和String model并提供对应的getter和setter方法,
则HTML的<input>名称可以写为:”name”和”model”,
然后在Controller的对应方法的参数中只写Car car,Spring MVC会将该对象及其值构建好。
注意:<input>的name属性不是填“car.name”,而是“name”。
Date类型的参数传递问题 页面传递过来的数据均是String类型,
尔后Spring将其转化成对应类型。有些类型不是Spring默认可以转换的,如Date。
只需要在Controller.java代码中加入一个binder方法即可:
@InitBinder public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor (dateFormat, true)); }
其中日期格式按照实际需要进行设置,如“yyyy-MM-dd HH:mm:ss”等。
4.2获得Cookie的值 在Controller对应的方法的参数使用@CookieValue注解获得:
@RequestMapping("/some/url")
public ModelAndView handleRequest(@CookieValue("name") String name) {
//接下来,做你想做的事情
}
4.3上传文件 首先是HTML上传页面的form表格:
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="myfile " />
<input type="submit" />
</form>
然后编写Controller,注意一定要加上@RequestParam,原因未明: UploadController.java package springmvc.web;
import java.io.IOException;import org.springframework .stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet .ModelAndView;
@Controller public class UploadController {
@RequestMapping("upload") //一定要加上@RequestParam
public ModelAndView uploadFile(@RequestParam MultipartFile myfile) throws IOException{
ModelAndView modelAndView = new ModelAndView("result"); //显示文件内容
StringBuilder sb = new StringBuilder(); //判断文件是否已上传
if (!myfile.isEmpty()) { sb.append("文件名 称: " + myfile.getOriginalFilename() + "<br/>") ;
String content = new String(myfile.getBytes());
content = content.replace("\n", "<br/>");
sb.append(content); } else {sb.append("没有选择文件"); }
modelAndView.addObject("result", sb.toString());
return modelAndView; }}
然后新建一个/WEB-INF/result.jsp文件: result.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html >
<body>
<p>上传的文件信息:</p>
<p>${result}</p>
</body>
</html>
如果出现java.lang.NoClassDefFoundError: org/apache/commons/io /output/DeferredFileOutputStream异常,加上org.apache.commons.io包即可。
4.4获得环境变量标准的Servlet规范中,有HttpServletRequest和HttpServletResponse等环节变量(关于这些变量的用途,请参见标准Servlet编程),Spring MVC可以很轻松地获得,只需要像上面获得参数一样在方法参数中写即可:
@RequestMapping("/some/url")
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) {
//你已获得HttpServletRequest和HttpServletResponse对象,比Struts2实现***Aware接口还简单
//接下来,做你想做的事情
}
5. REST形式的URL REST形式的URL对搜索引擎友好,看起来也很简洁漂亮。
Spring MVC实现REST形式URL很简单,例子: /** *在RequestMapping中,变量用{}括起来 *然后在处理方法中用@PathVariable获取,名称要一致 * @PathVariable里面也可以加上value=" xxx",名称可以不一致 */ @RequestMapping("/{name}/page/{p}") public void handleRequest(Writer writer, @PathVariable String name, @PathVariable Integer p) throws IOException{ writer.write("you are reading " + name +"'s page " + p); } URL中的数值会被作为变量传入到方法中,如name和p,同样是依赖注入的思想,类型会自动转换,访问下面的URL查看效果:http://127.0.0.1:8080/spring_mvc/pugwoo/page/1
http://127.0.0.1:8080/spring_mvc/pugwoo/page/2
http://127.0.0.1:8080/spring_mvc/ nick/page/99
6.其它技巧输出纯文本例子,支持中文:
@RequestMapping("test") public void test(HttpServletResponse resp) throws IOException {
resp.setContentType("text/plain;charset=utf-8") ;
resp.getWriter().write("Test测试中文"); }
该方法适合做cgi接口,输出json等格式的数据。
客户端跳转设定Controller对应的方法返回名称“redirect:hello_world”即可跳转到对应的页面,如hello_world。
浏览器的地址栏会变化。服务器端跳转设定Controller对应的方法返回名称“forward:hello_world”即可跳转到对应的页面,如hello_world。
forward并不能将变量通过modelAndView传递给新的URL,只能通过将变量放在request或session里面来完成。
而对于redirect,变量只能放在session里面,不能放在request里。
jsp页面标签jstl 导入标签:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
直接获取 某个变量的值:${message}或${car.name}等循环遍历容器,假如有类Car,Car有属性name并且提供getter方法,
对象数组ArrayList<Car> cars,
则java语句:for(Car car : cars) { System.out.println (car.getName()); }
等同于
<c:forEach items="${cars}" var="car">
${car.name} <br />
</c:forEach>
乱码问题上面的web .xml中已经解决了POST数据的乱码问题,但是GET方式传递数据仍有乱码,这是URL编码的问题,需要在服务器容器端设置,以Tomcat为例,
修改conf/server.xml文件对应位置新增“URIEncoding”:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/>
修订日志
<body>
<p>上传的文件信息:</p>
<p>${result}</p>
</body>
</html>
如果出现java.lang.NoClassDefFoundError: org/apache/commons/io/ output/DeferredFileOutputStream异常,加上org.apache.commons.io包即可。
4.4获得环境变量标准的Servlet规范中,有HttpServletRequest和HttpServletResponse等环节变量(关于这些变量的用途,请参见标准Servlet编程),Spring MVC可以很轻松地获得,只需要像上面获得参数一样在方法参数中写即可:@RequestMapping("/some/url") public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { //你已获得HttpServletRequest和HttpServletResponse对象,比Struts2实现***Aware接口还简单//接下来,做你想做的事情}
5. REST形式的URLREST形式的URL对搜索引擎友好,看起来也很简洁漂亮。Spring MVC实现REST形式URL很简单,例子:/** *在RequestMapping中,变量用{}括起来*然后在处理方法中用@PathVariable获取,名称要一致* @PathVariable里面也可以加上value=" xxx",名称可以不一致*/ @RequestMapping("/{name}/page/{p}") public void handleRequest(Writer writer, @PathVariable String name, @PathVariable Integer p) throws IOException{writer.write("you are reading " + name +"'s page " + p); } URL中的数值会被作为变量传入到方法中,如name和p,同样是依赖注入的思想,类型会自动转换,访问下面的URL查看效果:http://127.0.0.1:8080/spring_mvc/pugwoo/page/1
http://127.0.0.1:8080/spring_mvc/pugwoo/page/2
http://127.0.0.1:8080/spring_mvc/ nick/page/99
6.其它技巧输出纯文本例子,支持中文:
@RequestMapping("test")
public void test(HttpServletResponse resp) throws IOException {
resp.setContentType("text/plain;charset=utf-8") ;
resp.getWriter().write("Test测试中文");
}
该方法适合做cgi接口,输出json等格式的数据。
客户端跳转设定Controller对应的方法返回名称“redirect:hello_world”即可跳转到对应的页面,如hello_world。
浏览器的地址栏会变化。服务器端跳转设定Controller对应的方法返回名称“forward:hello_world”即可跳转到对应的页面,如hello_world。
forward并不能将变量通过modelAndView传递给新的URL,只能通过将变量放在request或session里面来完成。
而对于redirect,变量只能放在session里面,不能放在request里。
jsp页面标签jstl 导入标签:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 直接获取
某个变量的值:${message}或${car.name}等循环遍历容器,假如有类Car,Car有属性name并且提供getter方法,
对象数组ArrayList<Car> cars,
则java语句:for(Car car : cars) { System.out.println (car.getName()); }
等同于
<c:forEach items="${cars}" var="car"> ${car.name} <br /> </c:forEach>
乱码问题上面的web .xml中已经解决了POST数据的乱码问题,但是GET方式传递数据仍有乱码,
这是URL编码的问题,需要在服务器容器端设置,以Tomcat为例,修改conf/server.xml文件对应位置新增“URIEncoding”:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/>
修订日志
<body>
<p>上传的文件信息:</p>
<p>${result}</p>
</body>
</html>
如果出现java.lang.NoClassDefFoundError: org/apache/commons/io/ output/DeferredFileOutputStream异常,加上org.apache.commons.io包即可。
4.4获得环境变量 标准的Servlet规范中,有HttpServletRequest和HttpServletResponse等环节变量(关于这些变量的用途,请参见标准Servlet编程),Spring MVC可以很轻松地获得,只需要像上面获得参数一样在方法参数中写即可:
@RequestMapping("/some/url")
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) {
//你已获得HttpServletRequest和HttpServletResponse对象,比Struts2实现***Aware接口还简单 //接下来,做你想做的事情 }
5. REST形式的URL REST形式的URL对搜索引擎友好,看起来也很简洁漂亮。Spring MVC实现REST形式URL很简单,例子: /** *在RequestMapping中,变量用{}括起来 *然后在处理方法中用@PathVariable获取,名称要一致 * @PathVariable里面也可以加上value=" xxx",名称可以不一致 */@RequestMapping("/{name}/page/{p}") public void handleRequest(Writer writer, @PathVariable String name,@PathVariable Integer p) throws IOException{ writer.write("you are reading " + name +"'s page " + p); } URL中的数值会被作为变量传入到方法中,如name和p,同样是依赖注入的思想,类型会自动转换,访问下面的URL查看效果: http://127.0.0.1:8080/spring_mvc/pugwoo/page/1
http://127.0.0.1:8080/spring_mvc/pugwoo/page/2
http://127.0.0.1:8080/spring_mvc/ nick/page/99
6.其它技巧 输出纯文本 例子,支持中文:@RequestMapping("test") public void test(HttpServletResponse resp) throws IOException {resp.setContentType("text/plain;charset=utf-8") ; resp.getWriter().write("Test测试中文"); } 该方法适合做cgi接口,输出json等格式的数据。
客户端跳转 设定Controller对应的方法返回名称“redirect:hello_world”即可跳转到对应的页面,如hello_world。浏览器的地址栏会变化。 服务器端跳转 设定Controller对应的方法返回名称“forward:hello_world”即可跳转到对应的页面,如hello_world。
forward并不能将变量通过modelAndView传递给新的URL,只能通过将变量放在request或session里面来完成。而对于redirect,变量只能放在session里面,不能放在request里。
jsp页面标签jstl 导入标签: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 直接获取 某个变量的值:${message}或${car.name}等 循环遍历容器,假如有类Car,Car有属性name并且提供getter方法,对象数组ArrayList<Car> cars,则java语句:
for(Car car : cars) { System.out.println (car.getName()); } 等同于 <c:forEach items="${cars}" var="car"> ${car.name} <br /> </c:forEach> 乱码问题 上面的web .xml中已经解决了POST数据的乱码问题,但是GET方式传递数据仍有乱码,这是URL编码的问题,需要在服务器容器端设置,以Tomcat为例,修改conf/server.xml文件对应位置新增“URIEncoding”: <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/> 修订日志
PS:修改时间2012年12月31日 周一
自我感觉:很坑爹,如果你耐着性子看完了,那么还是会有收获的!