上一篇文章《Spring6:基于表明的Spring MVC(上篇)》,讲了Spring MVC环境搭建、@RequestMapping以及参数绑定,这是Spring MVC中最根本也是最主要的内容,本篇文章连续讲讲Spring MVC中别的的知识点,先从Model开始。
前一篇文章比较详细地解读了数据从页面要求到做事器后台的一些细节,那么下一个要办理的问题便是数据如何从后台再次传回前台,答案便是这里要说的Model,关于Model在写例子之前我特殊先解释三点:
1、Model本身是一个接口,实在现类为ExtendedModelMap,除了利用Model之外还可以利用ModelAndView、ModelMap这些,不过假如没有分外需求,利用Model比较大略,我个人也比较喜好利用Model
2、Model的生命周期是Request,也便是说要通过Model传值只能利用转发而不能利用重定向
3、为什么要利用Model而不是用Request,最紧张的缘故原由便是减少代码的侵入性或者说代码的耦合度也行。由于Model是Spring的组件,Request是J2EE的组件,利用Model而不去利用Request可以减少对J2EE的依赖,也便于调试
OK,接下来看例子,总体的代码还是按照上一篇文章的来,先看后台的代码:
@Controller@RequestMapping(value = \"大众/test\"大众)public class TestController{ @RequestMapping public String dispatchTest(Test test, Model model) { model.addAttribute(\"大众modelKey\"大众, \"大众modelValue\公众); return \"大众test\公众; }}
就往Model里面塞一个Key-Value,然后转发到test.jsp下,test.jsp页面要取Model的值,可以通过JSTL(EL表达式也可以)获取,反正直接在jsp页面上通过\公众<% ... %>\公众写Java脚本是行不通的。test.jsp页面这么写:
<%@ page language=\公众java\公众 import=\公众java.util.\"大众 pageEncoding=\公众ISO-8859-1\"大众%><%@ taglib uri=\"大众http://java.sun.com/jsp/jstl/core\"大众 prefix=\"大众c\公众 %><%@ taglib uri=\"大众http://java.sun.com/jsp/jstl/fmt\"大众 prefix=\公众fmt\"大众 %><%String path = request.getContextPath();String basePath = request.getScheme()+\公众://\"大众+request.getServerName()+\"大众:\"大众+request.getServerPort()+path+\公众/\"大众;%><!DOCTYPE HTML PUBLIC \公众-//W3C//DTD HTML 4.01 Transitional//EN\"大众><html> <head> <base href=\"大众<%=basePath%>\公众> <title>test页面</title> <meta http-equiv=\"大众pragma\公众 content=\"大众no-cache\"大众> <meta http-equiv=\"大众cache-control\公众 content=\"大众no-cache\"大众> <meta http-equiv=\公众expires\公众 content=\公众0\"大众> <meta http-equiv=\"大众keywords\公众 content=\公众keyword1,keyword2,keyword3\"大众> <meta http-equiv=\公众description\"大众 content=\"大众This is my page\"大众> <!-- <link rel=\"大众stylesheet\"大众 type=\公众text/css\公众 href=\"大众styles.css\"大众> --> </head> <body> <c:out value=\"大众${modelKey}\"大众 /> </body></html>
OK,然后访问一下\公众http://localhost:8080/SpringMVC/test\"大众这个地址,页面上\公众modelValue\"大众这几个字符就出来了。
之前说过了,Model的生命周期是Request,那么如果页面是重定向到test.jsp上面去,肯定是取不到\"大众modelValue\"大众的,可以自己试一下,因此重定向过去的话,要在后台把数据设置到session中。
test.jsp页面不变,Controller可以这么改:
@Controller@RequestMapping(value = \"大众/test\"大众)public class TestController{ @RequestMapping public String dispatchTest(Test test, HttpSession session) { session.setAttribute(\"大众modelKey\"大众, \"大众modelValue\"大众); return \公众redirect:/test.jsp\"大众; //return \"大众test\公众; }}
可以试一下,再访问一下\"大众http://localhost:8080/SpringMVC/test\公众这个地址,\"大众modelValue\"大众这几个字符在页面上就出来了。
在Spring MVC中,Request、Response、Session、InputStream、OutputStream这些工具是自动注入的,但是就像之前说的,为了减少代码的侵入性与耦合度,能不该用只管即便还是不该用这些J2EE的工具的好。
拦截器(Interceptor)
SpringMVC中的拦截器相称于J2EE中的过滤器,是非常主要和相称有用的,它的紧张浸染便是拦截用户的要求并进行相应的处理的,比如通过它来进行权限验证,或者是来判断用户是否上岸。
在SpringMVC中利用拦截器的方法比较大略,首先实现HandlerInterceptor接口,实现afterCompletion、postHandle、preHandle三个抽象方法,这里定义两个Interceptor:
public class TestInterceptor1 implements HandlerInterceptor{ public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println(\"大众TestInterceptor1.afterCompletion()\"大众); } public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println(\公众TestInterceptor1.postHandle()\"大众); } public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println(\"大众TestInterceptor1.preHandle()\公众); return true; }}
public class TestInterceptor2 implements HandlerInterceptor{ public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println(\"大众TestInterceptor2.afterCompletion()\公众); } public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println(\"大众TestInterceptor2.postHandle()\公众); } public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println(\公众TestInterceptor2.preHandle()\"大众); return true; }}
解释一下三个方法的浸染:
1、afterCompletion:在全体视图渲染完毕之后实行方法里面的内容,紧张用于开释一些资源
2、postHandle:在Controller实行之后,视图渲染之前实行方法里面的内容,也便是说postHandle方法可以对Model进行操作
3、preHandle:在Controller实行之前,实行方法里面的内容,把稳该方法是有返回值的,当方法返回false时全体要求就结束了
然后在springmvc-servlet.xml里面增加拦截器的配置:
<!-- 配置拦截器 --><mvc:interceptors> <mvc:interceptor> <mvc:mapping path=\"大众/test\"大众 /> <bean class=\"大众com.xrq.interceptor.TestInterceptor2\"大众 /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path=\公众/test\"大众 /> <bean class=\"大众com.xrq.interceptor.TestInterceptor1\"大众 /> </mvc:interceptor></mvc:interceptors>
假如有多个拦截器的话,\"大众<mvc:interceptor>...</mvc:interceptor>\"大众定义的顺序便是拦截器实行的顺序。
下面连续访问\公众http://localhost:8080/SpringMVC/test\"大众,代码实行的结果是:
TestInterceptor2.preHandle()TestInterceptor1.preHandle()TestInterceptor1.postHandle()TestInterceptor2.postHandle()TestInterceptor1.afterCompletion()TestInterceptor2.afterCompletion()
大概有些朋友对这个实行结果不是很理解,我实在是懂的,但确实一下子也说不清楚。
如果不是很理解的朋友,可以去看一下Java设计模式里面的任务链模式,拦截器的这种调用方法实际上是一种链式的调用法,TestInterceptor2调用TestInterceptor1,TestInterceptor1方法走了才会回到TestInterceptor2的方法里面。