SpringMVC
2015年12月23日
1 目标:基于Spring的WebMVC集成实现。
相较SSH,Spring框架实现Structs的功能。
2 原理:Spring框架中集成的Controller功能。
使用DispatcherServlet代替Structs控制器功能,将请求进行过滤,配置@RequestMapping实现请求与具体的Bean映射。
使用@Controller标记为响应Bean,并返回逻辑View(仅仅是个请求的URL)。
使用ViewResolver将逻辑View与实际的URL映射,渲染生成返回View。
参考:http://www.cnblogs.com/crazy-fox/archive/2012/02/18/2357675.html
3 流程:创建WebApp,配置Spring的控制器DispatcherServlet,配置Spring的响应Bean,创建响应类,创建页面。
3.1 创建WebApp:Dynamic Web Application
3.1.1安装Spring库:下载Spring,解压,将libs和depends下的库都copy到工程的lib目录。配置BuildPath,将lib下的jar全部加入buildpath。
3.1.2安装JSTL库:下载JSTL-1.2.jar到工程的lib目录,加入BuildPath。
参考:http://stackoverflow.com/questions/25678610/spring-mvc-java-tutorial-issues
3.2 配置Spring的控制器DispatcherServlet
注意:servlet的name将导致spring的配置文件默认名称为name-servlet.xml(位于web-inf目录)
//web.xml
<?xmlversion="1.0" encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID"version="3.1">
<display-name>SpringWebMVCDemo</display-name>
<!-- Spring MVC配置 -->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.3 配置Spring的响应Bean:@Controller的POJO
配置注释支持:添加后可以使用@Controller等注释。
<mvc:annotation-driven/>
添加响应Bean:只有添加Bean后才会扫描注释。
添加View解析器:将返回的View名称重新组织跳转。
//mvc-servlet.xml
<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd ">
<mvc:annotation-driven />
<beanclass="lee.HelloWorldController"/>
<!-- ViewResolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="viewClass"
value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix"value="/WEB-INF/jsp/" />
<property name="suffix"value=".jsp" />
</bean>
</beans>
3.4 创建响应类并配置为Bean:实现Controller接口,返回页面跳转数据
@Controller标记为响应Bean。
@RequestMapping标记为请求的URL。
返回的Model为键值对Map,可以被View处理。
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public classHelloWorldController{
@RequestMapping("/hello")
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponse resp) throwsException {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message","Hello World!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
3.5 创建前面页面:可以接收传递的数据。
//hello.jsp
<%@ pagelanguage="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE htmlPUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>HelloWorld</title>
</head>
<body>
${message}
</body>
</html>
结果:前面jsp能够正常跳转,得到controller的数据。
4 流程(非注释方法,已废弃):创建WebApp,配置Spring的控制器DispatcherServlet,配置Spring的响应Bean,创建响应类,创建页面。
参考:http://jinnianshilongnian.iteye.com/blog/1594806
4.1 创建WebApp:Dynamic Web Application
4.2 配置Spring的控制器DispatcherServlet
注意:servlet的name将导致spring的配置文件默认名称为name-servlet.xml(位于web-inf目录)
//web.xml
<?xmlversion="1.0" encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID"version="3.1">
<display-name>SpringWebMVCDemo</display-name>
<!-- Spring MVC配置 -->
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4.3 配置Spring的响应Bean:Controller接口的实现类
映射过程基本不需要参与,而且不好理解,在Spring3中已经改善。
BeanNameUrlHandlerMapping:将URL映射为Handler(什么是Handler?可能是一种Filter)。
SimpleControllerHandlerAdapter:将Handler映射为Controller。
//mvc-servlet.xml
<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="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"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- HandlerMapping -->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- HandlerAdapter -->
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- ViewResolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="viewClass"
value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix"value="/WEB-INF/jsp/" />
<property name="suffix"value=".jsp" />
</bean>
<!-- 处理器 -->
<bean name="/hello"class="lee.HelloWorldController" />
</beans>
4.4 创建响应类并配置为Bean:实现Controller接口,返回页面跳转数据
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
importorg.springframework.web.servlet.mvc.Controller;
public classHelloWorldController implements Controller {
@Override
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponse resp) throwsException {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message", "HelloWorld!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
4.5 创建前面页面
//hello.jsp
<%@ pagelanguage="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE htmlPUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>HelloWorld</title>
</head>
<body>
${message}
</body>
</html>
结果:前面jsp能够正常跳转,得到controller的数据。
5 方法:标记,返回值
5.1 标记
参考:http://haohaoxuexi.iteye.com/blog/1343761
详见:
5.1.1响应类标记@Controller:任何POJO都可以标记,目标是配置为Bean成为Spring控制器的响应类。
5.1.2请求映射标记@RequestMapping:可以是响应类或响应类的方法,目标是请求的控制策略。
5.1.2.1 控制请求的url:value,指定请求的url相同时则使用本类或方法响应。
类与方法构成URL树。
value是默认参数,如果仅有此参数,可以忽略参数名。
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="xx")
public classHelloWorldController{
@RequestMapping("hello")
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponse resp) throwsException {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message","Hello World!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
结果:请求为http://localhost:8080/SpringWebMVCDemo/xx/hello
5.1.2.2 控制请求的方法:Method,可以指定允许访问的方法,默认是GET和POST都允许。
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="xx")
public classHelloWorldController{
@RequestMapping(value="hello",method=RequestMethod.POST)
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponse resp) throwsException {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message","Hello World!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
结果:GET请求http://localhost:8080/SpringWebMVCDemo/xx/hello 返回错误405,不支持GET。
5.1.2.3 控制请求头策略:headers,指定可以处理的请求头的类型。
参考:http://blog.youkuaiyun.com/hongjun1847/article/details/20555477
HTTP请求头中包括Host,User-Agent,Accept等,设置能够接受的类型。只要在头中设置Key-value,后台解析时能够接受就处理,否则不处理。
为了便于请求、响应设置,增加了@Consumes(设置可以接受的请求头),@Prouduces(设置需要生产的响应头)标记。
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="xx")
public classHelloWorldController{
@RequestMapping(value="hello",method=RequestMethod.GET,headers="Accept-Language=jp")
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponse resp) throwsException {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message","Hello World!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
5.1.2.4 控制请求参数策略:params,指定参数规则。
可以指定必须具有的参数,必须具有的参数和值,必须不含有参数(!参数名)等。
示例:必须具有参数p1,且值必须为v1。
//HelloWorldController.java
package lee;
import javax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="xx")
public classHelloWorldController{
@RequestMapping(value="hello",method=RequestMethod.GET,params="p1=v1")
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponse resp) throwsException {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message","Hello World!");
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
结果:http://192.168.41.134:8080/SpringWebMVCDemo/xx/hello?p1=v1 能够正常访问,
http://192.168.41.134:8080/SpringWebMVCDemo/xx/hello?p1=v2 不能访问。
5.1.3参数传递:@PathVariable,@RequestParam
详见:http://blog.youkuaiyun.com/hongjun1847/article/details/20559771
http://blog.youkuaiyun.com/hongjun1847/article/details/20560515
5.1.3.1 获取请求的路径中的参数:@PathVariable,需要在请求映射中设置{参数名},在响应函数中标记此参数名。
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.PathVariable;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="xx")
public classHelloWorldController{
@RequestMapping(value="hello/{user}",method=RequestMethod.GET)
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp,@PathVariable("user")String user) throws Exception {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message", "HelloWorld!"+user);
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
结果:http://192.168.41.134:8080/SpringWebMVCDemo/xx/hello/xiaoming
输出Hello World!xiaoming
5.1.3.2 获取请求头中的参数:@RequestParam。
默认取请求参数,相当于request.getParameter("参数名")方法。
//HelloWorldController.java
package lee;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.bind.annotation.RequestParam;
importorg.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="xx")
public classHelloWorldController{
@RequestMapping(value="hello",method=RequestMethod.GET)
public ModelAndViewhandleRequest(HttpServletRequest req, HttpServletResponseresp,@RequestParam("user") String user) throws Exception {
ModelAndView mv = new ModelAndView();
// 添加模型数据 可以是任意的POJO对象
mv.addObject("message","Hello World!"+user);
// 设置逻辑视图名,视图解析器会根据该名字解析到具体的视图页面
mv.setViewName("hello");
return mv;
}
}
结果:http://192.168.41.134:8080/SpringWebMVCDemo/xx/hello?user=xx
输出Hello World!xx
5.2 返回值:返回页面和数据。
参考:http://haohaoxuexi.iteye.com/blog/1343761
View:逻辑View(名字)。
Model:键值对数据和默认的逻辑View。
ModelAndView:键值对数据和逻辑View。
其它对象:对象类名=对象值的数据。
无返回:无返回。可以在HttpResponse中直接操作返回内容。