1. Spring web mvc介绍
Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来:
2. Web mvc
1、 用户发起request请求至控制器
2、 控制器通过模型准备数据
3、 控制器将模型数据在视图中展示
4、 控制器将视图响应给用户
3. Sping web mvc 架构
1、 用户发送请求至前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器
5、 HandlerAdapter经过适配(通过反射)调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、 ViewReslover解析后返回具体View
10、 DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中,数据为map类型通用性强)。
11、 DispatcherServlet响应用户
重点:
DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。
ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。
4. 开发环境准备
本教程使用Eclipse+tomcat7开发
5. 第一个springmvc工程
第一步:建立一个Web项目
在eclipse下创建动态web工程springmvc_01。
第二步:导入sping3.1.4的jar包
第三步:前端控制器配置
在WEB-INF\web.xml中配置前端控制器,
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
load-on-startup:表示servlet随服务启动;
url-pattern:*.action的请交给DispatcherServlet处理。
contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加
载WEB-INF/[DispatcherServlet的Servlet 名字]-servlet.xml。
第四步:配置处理器映射器
在springmvc-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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">
<!-- HandlerMapping -->
<beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾。
第五步:配置处理器适配器
在springmvc-servlet.xml文件配置如下:
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为
Springmvc的后端控制器。
第六步:配置视图解析器
在springmvc-servlet.xml文件配置如下:
<!-- ViewResolver -->
<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
InternalResourceViewResolver:支持JSP视图解析
viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,所以classpath中必须包含jstl的相关jar 包;
prefix 和suffix:查找视图页面的前缀和后缀,最终视图的址为:
前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址 “WEB-INF/jsp/hello.jsp”
第七步:后端控制器开发
后端控制器即controller,也有称为action。
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 HelloWorldControllerimplements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp)throws
Exception {
ModelAndView mv = new ModelAndView();
//添加模型数据
mv.addObject("message", "Hello World!");
//设置逻辑视图名,最终视图地址=前缀+逻辑视图名+后缀
mv.setViewName("hello");
return mv;
}
}
org.springframework.web.servlet.mvc.Controller:处理器必须实现Controller 接口。
ModelAndView:包含了模型数据及逻辑视图名
第八步:后端控制器配置
在springmvc-servlet.xml文件配置如下:
<!-- 处理器-->
<beanname="/hello.action"
class="springmvc.action.HelloWorldController"/>
name="/hello.action":前边配置的BeanNameUrlHandlerMapping,表示如过请求的URL 为“上下文/hello.action”,则将会
交给该Bean进行处理。
第九步:视图开发
创建 /WEB-INF/jsp/hello.jsp视图页面:
<%@ pagelanguage="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPEhtml PUBLIC "-//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>Hello World</title>
</head>
<body>
${message}
</body>
</html>
${message}:表示显示由HelloWorldController处理器传过来的模型数据。
第十步:部署在tomcat测试
通过请求:http://localhost:8080/springmvc_01/hello.action,如果页面输出“Hello World! ”就表明我们成功了!
总结:
主要进行如下操作:
1、前端控制器DispatcherServlet配置
2、HandlerMapping配置
3、HandlerAdapter配置
4、ViewResolver配置
5、后端控制器编写
6、后端控制器配置
7、视图编写
从上边的步骤可以看出,通常情况下我们只需要编写后端控制器和视图。
6. HandlerMapping处理器映射器
HandlerMapping 给前端控制器返回一个HandlerExecutionChain对象(包含一个Handler (后端控制器)对象、多个HandlerInterceptor 拦截器)对象。
BeanNameUrlHandlerMapping
beanName Url映射器
<!—beanName Url映射器 -->
<beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
将后端控制器的bean name作为请求的url。
SimpleUrlHandlerMapping
<!—简单url映射 -->
<beanclass="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<propertyname="mappings">
<props>
<propkey="/hello1.action">hello_controller</prop>
<propkey="/hello2.action">hello_controller</prop>
</props>
</property>
</bean>
可定义多个url映射至一个后端控制器。
7. HandlerAdapter处理器适配器
HandlerAdapter会把后端控制器包装为一个适配器,支持多种类型的控制器开发,这里使用了适配器设计模式。
SimpleControllerHandlerAdapter
简单控制器处理器适配器
所有实现了org.springframework.web.servlet.mvc.Controller接口的Bean作为
Springmvc的后端控制器。
适配器配置如下:
<beanclass="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
HttpRequestHandlerAdapter
HTTP请求处理器适配器
HTTP请求处理器适配器将http请求封装成HttpServletResquest 和HttpServletResponse对象,和servlet接口类似。
适配器配置如下:
<beanclass="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
Controller实现如下:
public class HelloWorldController2 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException,IOException {
request.setAttribute("message","HelloWorld!");
request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(request, response);
}
}
从上边可以看出此适配器器的controller方法没有返回ModelAndView,可通过response修改定义响应内容。
8. Controller控制器
ParameterizableViewController(参数控制器)
参数化视图控制器,不进行功能处理(即静态视图),根据参数的逻辑视图名直接选择需要展示的视图。
<beanname="/success.action"
class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<propertyname="viewName"value="success"/>
</bean>
AbstractCommandController(命令控制器)
该控制器能把请求参数封装到一个命令对象(模型对象)中。
public class MyCommandController extendsAbstractCommandController{
/**
* 通过构造函数设置命令对象
*/
public MyCommandController(){
this.setCommandClass(Student.class);
this.setCommandName("student");//不是必须设置
}
@Override
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors)
throws Exception {
Student student = (Student)command;
System.out.println(student);
return null;
}
/**
* 字符串转换为日期属性编辑器
*/
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinderbinder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
}
public class Student {
public Student() {
}
public Student(String name) {
this.name = name;
}
private Stringname;//姓名
private Integerage;//年龄
private Datebirthday;//生日
private Stringaddress;//地址
….get/set方法省略
Controller配置;
<beanid="command_controller" name="/command.action"
class="springmvc.action.MyCommandController"/>
SimpleFormController(表单控制器)
表单控制器可以实现通用的表单显示及表单提交操作。
public class MyFormController extendsSimpleFormController{
public MyFormController(){
this.setCommandClass(Student.class);
this.setCommandName("student");
}
/**
* 注册属性编辑器(字符串转日期)
*/
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
/**
* 表单显示
*/
@Override
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors, MapcontrolModel)
throws Exception {
// TODO Auto-generatedmethod stub
return super.showForm(request, response, errors, controlModel);
}
/**
* 表单提交
*/
@Override
protected void doSubmitAction(Object command) throws Exception {
System.out.println(command);
super.doSubmitAction(command);
}
}
Controller配置:
<beanid="from_controller"name="/form.action"class="springmvc.action.MyFormController">
<!-- 表单视图 -->
<propertyname="formView"value="student"/><!--逻辑视图名 -->
<!-- 成功视图 -->
<propertyname="successView"value="success"/><!--逻辑视图名 -->
</bean>
问题解决
日期格式化
在controller注册属性编辑器:
/**
* 注册属性编辑器(字符串转换为日期)
*/
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
Post时中文乱码
在web.xml中加入:
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
9. 注解开发
第一个例子
创建工程的步骤同第一个springmvc工程,注解开发需要修改handlermapper和handlMapperAdapter,如下:
在springmvc-servlet.xml中配置:
<!-- 注解映射器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 注解适配器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
注意:
Spring3.1 之前版本,开启注解式处理器为:DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter。
Spring3.1 之后的版本,开启注解式处理器为:RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
HelloWorldController编写:
@Controller
public class HelloWorldController {
@RequestMapping(value="/hello")
public String hello(Model model)throws Exception{
model.addAttribute("message","HelloWorld!");
return"hello";
}
}
注解描述:
@Controller:用于标识是处理器类
@RequestMapping:请求到处理器功能方法的映射规则
Controller配置
在springmvc-servlet.xml中配置定义的controller:
<!-- controller -->
<bean class="springmvc.action.HelloWorldController"/>
组件扫描
<context:component-scanbase-package="springmvc.action" />
扫描@component、@controller、@service、@repository的注解
注意:如果使用组件扫描则controller不需要在springmvc-servlet.xml中配置
@Controller
标识该类为控制器类,@controller、@service、@repository分别对应了web应用三层架构的组件即控制器、服务接口、数据访问接口。
@RequestMapping
URL路径映射
@RequestMapping(value="/user")或@RequestMapping("/user")
根路径+子路径
根路径:
@RequestMapping放在类名上边,如下:
@Controller
@RequestMapping("/user")
子路径:
@RequestMapping放在方法名上边,如下:
@RequestMapping("/useradd")
public String useradd(….
URI 模板模式映射
@RequestMapping(value="/useredit/{userId}"):{×××}占位符, 请求的URL可以是“/useredit/001”或“/useredit/abc”,通过在方法中使用@PathVariable获取{×××}中的×××变量。
@RequestMapping("/useredit/{userid}")
public String useredit(@PathVariable String userid,Modelmodel)throws Exception{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute("userid", userid);
return"/user/useredit";
}
多个占位符:
@RequestMapping("/useredit/{groupid}/{userid}")
public String useredit(@PathVariable Stringgroupid,@PathVariable Stringuserid,Model model)throwsException{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute("groupid",groupid);
model.addAttribute("userid", userid);
return"/user/useredit";
}
正则表达式url映射
限制只允许输入数字:
RequestMapping(value="/useredit/{userid:\\d+}")
限制只允许输入数字、英文字符:
RequestMapping(value="/useredit/{userid:[A-Za-z0-9]+}")
请求方法限定
限定GET方法
@RequestMapping(method = RequestMethod.GET)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'POST' notsupported
例如:
@RequestMapping(value="/useredit/{userid}",method=RequestMethod.GET)
限定POST方法
@RequestMapping(method = RequestMethod.POST)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'GET' notsupported
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
请求数据绑定
默认支持的参数类型
HttpServletRequest
通过request对象获取请求信息
HttpServletResponse
通过response处理响应信息
HttpSession
通过session对象得到session中存放的对象
Model、Map、ModelMap
通过model、map及modelMap向页面传递数据,如下:
modelMap.put("user1", new User("张三"));
model.addAttribute("user2", new User("李四"));
map.put("user3",new User("王五"));
命令/表单对象
自动将请求参数绑定到功能处理方法的命令/表单对象上。
Java基本数据类型
布尔型:
页面如下:
<tr>
<td>是否好学生:</td>
<td>
<inputtype="radio"name="isgood"value="true"/>
<inputtype="radio"name="isgood"value="false"/></td>
</tr>
<tr>
日期型需要添加属性编辑器:
@InitBinder
public void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
Pojo对象
页面上以pojo对象中属性名称命名:
将pojo对象中的属性名于传递进来的属性名对应,对应上的将值设置在pojo对象中
页面定义如下;
<inputtype="text" name="age"/>
<inputtype="text" name="birthday"/>
页面上以pojo对象名点 属性名命名:
需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
包装对象定义如下:
public class UserVo {
private Useruser;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
页面定义:
<inputtype="text" name="user.height" />
字符串数组
页面传递逗号分隔的字符串,springmvc中以String[]接收。
List
List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。
List中对象:
成绩对象
public classStudentScore {
private Stringcoursename;//课程名称
private Floatscore;//成绩
public String getCoursename(){
return coursename;
}
public void setCoursename(Stringcoursename) {
this.coursename = coursename;
}
public Float getScore() {
return score;
}
public void setScore(Float score) {
this.score = score;
}
}
包装类中定义List对象,并添加get/set方法如下:
private List<StudentScore> scores;//成绩
页面:
<tr>
<td>兴趣课程:</td>
<td>
课程名:<inputtype="text"name="scores[0].coursename"/>成绩:<inputtype="text"name="scores[0].score"/><br/>
课程名:<inputtype="text"name="scores[1].coursename"/>成绩:<inputtype="text"name="scores[1].score"/><br/>
课程名:<inputtype="text"name="scores[2].coursename"/>成绩:<inputtype="text"name="scores[2].score"/><br/>
</td>
</tr>
Map
在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:
private Map<String, Object>userinfo = new HashMap<String, Object>();
页面定义如下:
<tr>
<td>学生详细信息:</td>
<td>
地址:<inputtype="text"name="userinfo['address']"/>
朋友:<inputtype="text"name="userinfo['firend']"/>
</td>
</tr>
@RequestParam绑定单个请求参数
value:参数名字,即入参的请求参数名字,如value=“studentid”表示请求的参数区中的名字为studentid的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
@PathVariable 绑定URI 模板变量值
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上
@RequestMapping(value="/useredit/{groupid}/{userid}",method={RequestMethod.GET,RequestMethod.POST})
public String useredit(@PathVariable String groupid,@PathVariable Stringuserid,Model model)throwsException{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute("groupid", groupid);
model.addAttribute("userid", userid);
return"/user/useredit";
}
如请求的 URL 为“控制器URL/useredit/1/admin.action”,则自动将URL 中模板变量{groupid}和{userid}绑定到@PathVariable注解的同名参数上,即入参后groupid=“1”、userid=“admin”
@RequestBody @ResponseBody实现json数据交互
@RequestBody
作用:
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。
本例子应用:
@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象
@ResponseBody
作用:
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
本例子应用:
@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端
请求json,响应json实现:
环境准备
Springmvc默认用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson的包,如下:
配置:
在注解适配器中加入messageConverters
<!-- 注解适配器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<propertyname="messageConverters">
<list>
<beanclass="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
controller编写
/**
* 请求json单个对象,返回json单个对象
* @param user
* @return
* @throws Exception
*/
@RequestMapping("/requestjson")
//@RequestBody接收json串自动转为user对象,@ResponseBody将user转为json数据响应给客户端
public @ResponseBody User requestjson(@RequestBody User user)throws Exception{
System.out.println(user);
return user;
}
页面js方法编写:
function request_json(){
var user =JSON.stringify({name:"张三", age: 3});
alert(user);
$.ajax(
{
type:'post',
url:'${pageContext.request.contextPath}/requestjson.action',
contentType:'application/json;charset=utf-8', //请求内容为json
data:user,
success:function(data){
alert(data.name);
}
}
)
}
测试结果:
从上图可以看出请求的数据是json格式
从上图可以看出响应的数据也是json格式,json数据的内容是从User对象转换得来。
Form提交,响应json实现:
采用form提交是最常用的作法,通常有post和get两种方法,响应json数据是为了方便客户端处理,实现如下:
环境准备
同第一个例子
controller编写
/**
* 客户端提交表单,服务端返回json
* @param user
* @return
* @throws Exception
*/
@RequestMapping("/formsubmit")
public @ResponseBody Userformsubmit(User user)throws Exception{
System.out.println(user);
return user;
}
页面js方法编写:
function formsubmit(){
var user ="name=张三&age=3";
alert(user);
$.ajax(
{
type:'post',//这里改为get也可以正常执行
url:'${pageContext.request.contextPath}/formsubmit.action',
//ContentType没指定将默认为:application/x-www-form-urlencoded
data:user,
success:function(data){
alert(data.name);
}
}
)
}
从上边的js代码看出,已去年ContentType的定义,ContentType默认为:application/x-www-form-urlencoded格式。
测试结果:
从上图可以看出请求的数据是标准的key/value格式。
从上图可以看出响应的数据也是json格式,json数据的内容是从User对象转换得来。
简化配置:
注解映射器和注解适配器可以使用<mvc:annotation-driven />代替。
<mvc:annotation-driven />默认注册了注解映射器和注解适配器等bean。
如下:
以下配置可用<mvc:annotation-driven />代替:
<!-- 注解映射器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 注解适配器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<propertyname="messageConverters">
<list>
<beanclass="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
10. 拦截器
定义
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
拦截器定义
实现HandlerInterceptor接口,如下:
public class HandlerInterceptor1 implements HandlerInterceptor{
/**
*controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generatedmethod stub
return false;
}
/**
*controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generatedmethod stub
}
/**
* controller执行后且视图返回后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exceptionex)
throws Exception {
// TODO Auto-generatedmethod stub
}
}
拦截器配置
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<propertyname="interceptors">
<list>
<refbean="handlerInterceptor1"/>
<refbean="handlerInterceptor2"/>
</list>
</property>
</bean>
<beanid="handlerInterceptor1"class="springmvc.intercapter.HandlerInterceptor1"/>
<beanid="handlerInterceptor2"class="springmvc.intercapter.HandlerInterceptor2"/>
正常流程测试
代码:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2,每个拦截器的preHandler方法都返回true。
运行流程
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
中断流程测试
代码:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2。
运行流程
HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:
HandlerInterceptor1..preHandle..
从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且controller也不执行了。
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了。
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
拦截器应用
用户身份认证
public class LoginInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//如果是登录页面则放行
if(request.getRequestURI().indexOf("login.action")>=0){
return true;
}
HttpSession session = request.getSession();
//如果用户已登录也放行
if(session.getAttribute("user")!=null){
return true;
}
//用户没有登录挑战到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
1. Spring web mvc介绍
Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来:
2. Web mvc
1、 用户发起request请求至控制器
2、 控制器通过模型准备数据
3、 控制器将模型数据在视图中展示
4、 控制器将视图响应给用户
3. Sping web mvc 架构
1、 用户发送请求至前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器
5、 HandlerAdapter经过适配(通过反射)调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、 ViewReslover解析后返回具体View
10、 DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中,数据为map类型通用性强)。
11、 DispatcherServlet响应用户
重点:
DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。
ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。
4. 开发环境准备
本教程使用Eclipse+tomcat7开发
5. 第一个springmvc工程
第一步:建立一个Web项目
在eclipse下创建动态web工程springmvc_01。
第二步:导入sping3.1.4的jar包
第三步:前端控制器配置
在WEB-INF\web.xml中配置前端控制器,
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
load-on-startup:表示servlet随服务启动;
url-pattern:*.action的请交给DispatcherServlet处理。
contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加
载WEB-INF/[DispatcherServlet的Servlet 名字]-servlet.xml。
第四步:配置处理器映射器
在springmvc-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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">
<!-- HandlerMapping -->
<beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾。
第五步:配置处理器适配器
在springmvc-servlet.xml文件配置如下:
<!-- HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
SimpleControllerHandlerAdapter:即简单控制器处理适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为
Springmvc的后端控制器。
第六步:配置视图解析器
在springmvc-servlet.xml文件配置如下:
<!-- ViewResolver -->
<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
InternalResourceViewResolver:支持JSP视图解析
viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,所以classpath中必须包含jstl的相关jar 包;
prefix 和suffix:查找视图页面的前缀和后缀,最终视图的址为:
前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址 “WEB-INF/jsp/hello.jsp”
第七步:后端控制器开发
后端控制器即controller,也有称为action。
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 HelloWorldControllerimplements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest req,HttpServletResponse resp)throws
Exception {
ModelAndView mv = new ModelAndView();
//添加模型数据
mv.addObject("message", "Hello World!");
//设置逻辑视图名,最终视图地址=前缀+逻辑视图名+后缀
mv.setViewName("hello");
return mv;
}
}
org.springframework.web.servlet.mvc.Controller:处理器必须实现Controller 接口。
ModelAndView:包含了模型数据及逻辑视图名
第八步:后端控制器配置
在springmvc-servlet.xml文件配置如下:
<!-- 处理器-->
<beanname="/hello.action"
class="springmvc.action.HelloWorldController"/>
name="/hello.action":前边配置的BeanNameUrlHandlerMapping,表示如过请求的URL 为“上下文/hello.action”,则将会
交给该Bean进行处理。
第九步:视图开发
创建 /WEB-INF/jsp/hello.jsp视图页面:
<%@ pagelanguage="java"contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPEhtml PUBLIC "-//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>Hello World</title>
</head>
<body>
${message}
</body>
</html>
${message}:表示显示由HelloWorldController处理器传过来的模型数据。
第十步:部署在tomcat测试
通过请求:http://localhost:8080/springmvc_01/hello.action,如果页面输出“Hello World! ”就表明我们成功了!
总结:
主要进行如下操作:
1、前端控制器DispatcherServlet配置
2、HandlerMapping配置
3、HandlerAdapter配置
4、ViewResolver配置
5、后端控制器编写
6、后端控制器配置
7、视图编写
从上边的步骤可以看出,通常情况下我们只需要编写后端控制器和视图。
6. HandlerMapping处理器映射器
HandlerMapping 给前端控制器返回一个HandlerExecutionChain对象(包含一个Handler (后端控制器)对象、多个HandlerInterceptor 拦截器)对象。
BeanNameUrlHandlerMapping
beanName Url映射器
<!—beanName Url映射器 -->
<beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
将后端控制器的bean name作为请求的url。
SimpleUrlHandlerMapping
<!—简单url映射 -->
<beanclass="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<propertyname="mappings">
<props>
<propkey="/hello1.action">hello_controller</prop>
<propkey="/hello2.action">hello_controller</prop>
</props>
</property>
</bean>
可定义多个url映射至一个后端控制器。
7. HandlerAdapter处理器适配器
HandlerAdapter会把后端控制器包装为一个适配器,支持多种类型的控制器开发,这里使用了适配器设计模式。
SimpleControllerHandlerAdapter
简单控制器处理器适配器
所有实现了org.springframework.web.servlet.mvc.Controller接口的Bean作为
Springmvc的后端控制器。
适配器配置如下:
<beanclass="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
HttpRequestHandlerAdapter
HTTP请求处理器适配器
HTTP请求处理器适配器将http请求封装成HttpServletResquest 和HttpServletResponse对象,和servlet接口类似。
适配器配置如下:
<beanclass="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
Controller实现如下:
public class HelloWorldController2 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException,IOException {
request.setAttribute("message","HelloWorld!");
request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(request, response);
}
}
从上边可以看出此适配器器的controller方法没有返回ModelAndView,可通过response修改定义响应内容。
8. Controller控制器
ParameterizableViewController(参数控制器)
参数化视图控制器,不进行功能处理(即静态视图),根据参数的逻辑视图名直接选择需要展示的视图。
<beanname="/success.action"
class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<propertyname="viewName"value="success"/>
</bean>
AbstractCommandController(命令控制器)
该控制器能把请求参数封装到一个命令对象(模型对象)中。
public class MyCommandController extendsAbstractCommandController{
/**
* 通过构造函数设置命令对象
*/
public MyCommandController(){
this.setCommandClass(Student.class);
this.setCommandName("student");//不是必须设置
}
@Override
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response, Object command,BindException errors)
throws Exception {
Student student = (Student)command;
System.out.println(student);
return null;
}
/**
* 字符串转换为日期属性编辑器
*/
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinderbinder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
}
public class Student {
public Student() {
}
public Student(String name) {
this.name = name;
}
private Stringname;//姓名
private Integerage;//年龄
private Datebirthday;//生日
private Stringaddress;//地址
….get/set方法省略
Controller配置;
<beanid="command_controller" name="/command.action"
class="springmvc.action.MyCommandController"/>
SimpleFormController(表单控制器)
表单控制器可以实现通用的表单显示及表单提交操作。
public class MyFormController extendsSimpleFormController{
public MyFormController(){
this.setCommandClass(Student.class);
this.setCommandName("student");
}
/**
* 注册属性编辑器(字符串转日期)
*/
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
/**
* 表单显示
*/
@Override
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors, MapcontrolModel)
throws Exception {
// TODO Auto-generatedmethod stub
return super.showForm(request, response, errors, controlModel);
}
/**
* 表单提交
*/
@Override
protected void doSubmitAction(Object command) throws Exception {
System.out.println(command);
super.doSubmitAction(command);
}
}
Controller配置:
<beanid="from_controller"name="/form.action"class="springmvc.action.MyFormController">
<!-- 表单视图 -->
<propertyname="formView"value="student"/><!--逻辑视图名 -->
<!-- 成功视图 -->
<propertyname="successView"value="success"/><!--逻辑视图名 -->
</bean>
问题解决
日期格式化
在controller注册属性编辑器:
/**
* 注册属性编辑器(字符串转换为日期)
*/
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
Post时中文乱码
在web.xml中加入:
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
9. 注解开发
第一个例子
创建工程的步骤同第一个springmvc工程,注解开发需要修改handlermapper和handlMapperAdapter,如下:
在springmvc-servlet.xml中配置:
<!-- 注解映射器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 注解适配器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
注意:
Spring3.1 之前版本,开启注解式处理器为:DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter。
Spring3.1 之后的版本,开启注解式处理器为:RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
HelloWorldController编写:
@Controller
public class HelloWorldController {
@RequestMapping(value="/hello")
public String hello(Model model)throws Exception{
model.addAttribute("message","HelloWorld!");
return"hello";
}
}
注解描述:
@Controller:用于标识是处理器类
@RequestMapping:请求到处理器功能方法的映射规则
Controller配置
在springmvc-servlet.xml中配置定义的controller:
<!-- controller -->
<bean class="springmvc.action.HelloWorldController"/>
组件扫描
<context:component-scanbase-package="springmvc.action" />
扫描@component、@controller、@service、@repository的注解
注意:如果使用组件扫描则controller不需要在springmvc-servlet.xml中配置
@Controller
标识该类为控制器类,@controller、@service、@repository分别对应了web应用三层架构的组件即控制器、服务接口、数据访问接口。
@RequestMapping
URL路径映射
@RequestMapping(value="/user")或@RequestMapping("/user")
根路径+子路径
根路径:
@RequestMapping放在类名上边,如下:
@Controller
@RequestMapping("/user")
子路径:
@RequestMapping放在方法名上边,如下:
@RequestMapping("/useradd")
public String useradd(….
URI 模板模式映射
@RequestMapping(value="/useredit/{userId}"):{×××}占位符, 请求的URL可以是“/useredit/001”或“/useredit/abc”,通过在方法中使用@PathVariable获取{×××}中的×××变量。
@RequestMapping("/useredit/{userid}")
public String useredit(@PathVariable String userid,Modelmodel)throws Exception{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute("userid", userid);
return"/user/useredit";
}
多个占位符:
@RequestMapping("/useredit/{groupid}/{userid}")
public String useredit(@PathVariable Stringgroupid,@PathVariable Stringuserid,Model model)throwsException{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute("groupid",groupid);
model.addAttribute("userid", userid);
return"/user/useredit";
}
正则表达式url映射
限制只允许输入数字:
RequestMapping(value="/useredit/{userid:\\d+}")
限制只允许输入数字、英文字符:
RequestMapping(value="/useredit/{userid:[A-Za-z0-9]+}")
请求方法限定
限定GET方法
@RequestMapping(method = RequestMethod.GET)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'POST' notsupported
例如:
@RequestMapping(value="/useredit/{userid}",method=RequestMethod.GET)
限定POST方法
@RequestMapping(method = RequestMethod.POST)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'GET' notsupported
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
请求数据绑定
默认支持的参数类型
HttpServletRequest
通过request对象获取请求信息
HttpServletResponse
通过response处理响应信息
HttpSession
通过session对象得到session中存放的对象
Model、Map、ModelMap
通过model、map及modelMap向页面传递数据,如下:
modelMap.put("user1", new User("张三"));
model.addAttribute("user2", new User("李四"));
map.put("user3",new User("王五"));
命令/表单对象
自动将请求参数绑定到功能处理方法的命令/表单对象上。
Java基本数据类型
布尔型:
页面如下:
<tr>
<td>是否好学生:</td>
<td>
<inputtype="radio"name="isgood"value="true"/>
<inputtype="radio"name="isgood"value="false"/></td>
</tr>
<tr>
日期型需要添加属性编辑器:
@InitBinder
public void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,newCustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
Pojo对象
页面上以pojo对象中属性名称命名:
将pojo对象中的属性名于传递进来的属性名对应,对应上的将值设置在pojo对象中
页面定义如下;
<inputtype="text" name="age"/>
<inputtype="text" name="birthday"/>
页面上以pojo对象名点 属性名命名:
需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
包装对象定义如下:
public class UserVo {
private Useruser;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
页面定义:
<inputtype="text" name="user.height" />
字符串数组
页面传递逗号分隔的字符串,springmvc中以String[]接收。
List
List中存放对象,并将定义的List放在包装类中,action使用包装对象接收。
List中对象:
成绩对象
public classStudentScore {
private Stringcoursename;//课程名称
private Floatscore;//成绩
public String getCoursename(){
return coursename;
}
public void setCoursename(Stringcoursename) {
this.coursename = coursename;
}
public Float getScore() {
return score;
}
public void setScore(Float score) {
this.score = score;
}
}
包装类中定义List对象,并添加get/set方法如下:
private List<StudentScore> scores;//成绩
页面:
<tr>
<td>兴趣课程:</td>
<td>
课程名:<inputtype="text"name="scores[0].coursename"/>成绩:<inputtype="text"name="scores[0].score"/><br/>
课程名:<inputtype="text"name="scores[1].coursename"/>成绩:<inputtype="text"name="scores[1].score"/><br/>
课程名:<inputtype="text"name="scores[2].coursename"/>成绩:<inputtype="text"name="scores[2].score"/><br/>
</td>
</tr>
Map
在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:
private Map<String, Object>userinfo = new HashMap<String, Object>();
页面定义如下:
<tr>
<td>学生详细信息:</td>
<td>
地址:<inputtype="text"name="userinfo['address']"/>
朋友:<inputtype="text"name="userinfo['firend']"/>
</td>
</tr>
@RequestParam绑定单个请求参数
value:参数名字,即入参的请求参数名字,如value=“studentid”表示请求的参数区中的名字为studentid的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
@PathVariable 绑定URI 模板变量值
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上
@RequestMapping(value="/useredit/{groupid}/{userid}",method={RequestMethod.GET,RequestMethod.POST})
public String useredit(@PathVariable String groupid,@PathVariable Stringuserid,Model model)throwsException{
//方法中使用@PathVariable获取useried的值,使用model传回页面
model.addAttribute("groupid", groupid);
model.addAttribute("userid", userid);
return"/user/useredit";
}
如请求的 URL 为“控制器URL/useredit/1/admin.action”,则自动将URL 中模板变量{groupid}和{userid}绑定到@PathVariable注解的同名参数上,即入参后groupid=“1”、userid=“admin”
@RequestBody @ResponseBody实现json数据交互
@RequestBody
作用:
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。
本例子应用:
@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象
@ResponseBody
作用:
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
本例子应用:
@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端
请求json,响应json实现:
环境准备
Springmvc默认用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson的包,如下:
配置:
在注解适配器中加入messageConverters
<!-- 注解适配器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<propertyname="messageConverters">
<list>
<beanclass="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
controller编写
/**
* 请求json单个对象,返回json单个对象
* @param user
* @return
* @throws Exception
*/
@RequestMapping("/requestjson")
//@RequestBody接收json串自动转为user对象,@ResponseBody将user转为json数据响应给客户端
public @ResponseBody User requestjson(@RequestBody User user)throws Exception{
System.out.println(user);
return user;
}
页面js方法编写:
function request_json(){
var user =JSON.stringify({name:"张三", age: 3});
alert(user);
$.ajax(
{
type:'post',
url:'${pageContext.request.contextPath}/requestjson.action',
contentType:'application/json;charset=utf-8', //请求内容为json
data:user,
success:function(data){
alert(data.name);
}
}
)
}
测试结果:
从上图可以看出请求的数据是json格式
从上图可以看出响应的数据也是json格式,json数据的内容是从User对象转换得来。
Form提交,响应json实现:
采用form提交是最常用的作法,通常有post和get两种方法,响应json数据是为了方便客户端处理,实现如下:
环境准备
同第一个例子
controller编写
/**
* 客户端提交表单,服务端返回json
* @param user
* @return
* @throws Exception
*/
@RequestMapping("/formsubmit")
public @ResponseBody Userformsubmit(User user)throws Exception{
System.out.println(user);
return user;
}
页面js方法编写:
function formsubmit(){
var user ="name=张三&age=3";
alert(user);
$.ajax(
{
type:'post',//这里改为get也可以正常执行
url:'${pageContext.request.contextPath}/formsubmit.action',
//ContentType没指定将默认为:application/x-www-form-urlencoded
data:user,
success:function(data){
alert(data.name);
}
}
)
}
从上边的js代码看出,已去年ContentType的定义,ContentType默认为:application/x-www-form-urlencoded格式。
测试结果:
从上图可以看出请求的数据是标准的key/value格式。
从上图可以看出响应的数据也是json格式,json数据的内容是从User对象转换得来。
简化配置:
注解映射器和注解适配器可以使用<mvc:annotation-driven />代替。
<mvc:annotation-driven />默认注册了注解映射器和注解适配器等bean。
如下:
以下配置可用<mvc:annotation-driven />代替:
<!-- 注解映射器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 注解适配器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<propertyname="messageConverters">
<list>
<beanclass="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
10. 拦截器
定义
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
拦截器定义
实现HandlerInterceptor接口,如下:
public class HandlerInterceptor1 implements HandlerInterceptor{
/**
*controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generatedmethod stub
return false;
}
/**
*controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generatedmethod stub
}
/**
* controller执行后且视图返回后调用此方法
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exceptionex)
throws Exception {
// TODO Auto-generatedmethod stub
}
}
拦截器配置
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<propertyname="interceptors">
<list>
<refbean="handlerInterceptor1"/>
<refbean="handlerInterceptor2"/>
</list>
</property>
</bean>
<beanid="handlerInterceptor1"class="springmvc.intercapter.HandlerInterceptor1"/>
<beanid="handlerInterceptor2"class="springmvc.intercapter.HandlerInterceptor2"/>
正常流程测试
代码:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2,每个拦截器的preHandler方法都返回true。
运行流程
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
中断流程测试
代码:
定义两个拦截器分别为:HandlerInterceptor1和HandlerInteptor2。
运行流程
HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,运行流程如下:
HandlerInterceptor1..preHandle..
从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且controller也不执行了。
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,运行流程如下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了。
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
拦截器应用
用户身份认证
public class LoginInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//如果是登录页面则放行
if(request.getRequestURI().indexOf("login.action")>=0){
return true;
}
HttpSession session = request.getSession();
//如果用户已登录也放行
if(session.getAttribute("user")!=null){
return true;
}
//用户没有登录挑战到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
转自:http://blog.csdn.net/u010575112/article/details/41369431?ref=myread