23.3.1  模型视图类ModelAndView

从名字上看ModelAndView中的Model代表模型,View代表视图,这个名字就很好地解释了该类的作用。业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该Spring MVC框架。框架通过调用配置文件中定义的视图解析器,对该对象进行解析,最后把结果数据显示在指定的页面上。

【示例23-7】下面看ModelAndView.Java的代码,如下所示。

package org.springframework.web.servlet;

import Java.util.HashMap;

import Java.util.Map;

publicclass ModelAndView {

private Object view;                    //该

属性用来存储返回的视图信息

private Map model;                      //该属

性用来存储处理后的结果数据

//下面是一些参数不同的构造函数,用来创建ModelAndView实例

public ModelAndView() {

}

public ModelAndView(View view) {

this.view = view;

}

public ModelAndView(String viewName) {

this.view = viewName;

}

public ModelAndView(View view, Map model) {

this.view = view;

this.model = model;

}

public ModelAndView(String viewName, Map model) {

this.view = viewName;

this.model = model;

}

public ModelAndView(View view, String modelName,

Object modelObject) {

this.view = view;

addObject(modelName, modelObject);

}

public ModelAndView(String viewName, String modelName,

Object modelObject)  {

this.view = viewName;

addObject(modelName, modelObject);

}

//view属性的getter、setter方法,可以看出view属性可以是一个View类的实例,也可

以是一个String

publicvoid setView(View view) {

this.view = view;

}

public View getView() {

return (this.view instanceof View ? (View) this.view : null);

}

publicvoid setViewName(String viewName) {

this.view = viewName;

}

public String getViewName() {

return (this.view instanceof String ? (String) this.view : null);

}

publicboolean isReference() {

return (this.view instanceof String);

}

//下面的方法用来给model属性赋值、或者获取该属性的值,model是一个Map类型的属性

protected Map getModelInternal() {

returnthis.model;

}

public Map getModel() {

if (this.model == null) {

this.model = new HashMap(1);

}

returnthis.model;

}

public ModelAndView addObject(String modelName, Object modelObject) {

getModel().put(modelName, modelObject);

returnthis;

}

public ModelAndView addAllObjects(Map modelMap) {

getModel().putAll(modelMap);

returnthis;

}

...

}

通过上面的代码可以看出,ModelAndView创建了两个属性view和model,并且创建了获取这两个属性以及给这两个属性赋值的一些方法。view属性可以是View接口的一个实例,也可以是一个String类型的值,所有的视图类都必须实现View接口,在后面的内容中将会讲到;model属性是一个Map类型的值,所以其每一个元素都是一个Key-Value对。

说明:回忆Struts2框架,当该框架的业务处理器处理完用户请求后,将数据存储在ActionContext的实例中,在试图层通过OGNL表达式获取该实例中的结果数据。而Spring MVC框架是将结果数据存在ModelAndView类实例的model属性中。

Spring MVC支持不同的视图技术,如JSP/Servlet、Jstl、Velocity等。每种视图技术对应一个XXXView.Java类,它们都要实现View接口。例如,JSP/Servlet技术对应的类是InternalResourceView.Java;Jstl技术对应的类是JstlView.Java;Velocity技术对应的类是VelocityView.Java。

【示例23-8】要想在一个工程中使用不同的视图技术,需要在配置文件中进行配置,下面是配置代码:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.

org/dtd/spring-beans.dtd">

<beans>

<bean id="viewResolver"class="org.springframework.web.servlet.view.

ResourceBundleViewResolver">

<!--basename 属性指定用views.properties文件统一保存视图信息-->

<property name="basename" value="views"/>

</bean>

<bean id="helloWorldAction"class="com.examp.ch22.HelloWorldAction">

<property name="helloWorld" value="HelloWorld"/>

<!--下面的JspPage 、JstlPage、VelocityPage都定义在views.properties文

件中-->

<property name="viewPage1" value="JspPage"/>

<property name="viewPage2" value="JstlPage">

<property name="viewPage3" value="VelocityPage"/>

</bean>

...

</beans>

可以看出,上面代码在定义viewResolver时,指定<property name="basename" value="views"/>,这表示把关于页面的定义统一编写在一个views.properties文件中,上面代码中的JspPage、JstlPage、VelocityPage都定义在这个文件中,其代码如下:

#定义JspPage

JspPage.class=org.springframework.web.servlet.

view.InternalResourceView

JspPage.url=/WEB-INF/JspPage.jsp

#定义JstlPage

JstlPage.class=org.springframework.web.servlet.view.JstlView

JstlPage.url=/WEB-INF/JstlPage.jsp

#定义VelocityPage

VelocityPage.class=org.springframework.web.servlet.view.VelocityView

VelocityPage.url=/WEB-INF/VelocityPage.jsp

上面的代码对JspPage、JstlPage、VelocityPage 3个页面进行了定义,每个要素都包括class和url两个属性,class指定的就是对应技术的类,url是该页面的位置。这样就可以在一个工程中同时使用不同技术实现的页面。

23.4  使用拦截器

和Struts2一样,Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口。

【示例23-9】HandlerInterceptor接口的代码如下:

package org.springframework.web.servlet;

import Javax.servlet.http.HttpServletRequest;

import Javax.servlet.http.HttpServletResponse;

publicinterface HandlerInterceptor {

// preHandle()方法在业务处理器处理请求之前被调用

boolean preHandle(HttpServletRequest request,

HttpServletResponse response,

Object handler)

throws Exception;

// postHandle()方法在业务处理器处理请求之后被调用

void postHandle(

HttpServletRequest request, HttpServletResponse

response, Object

handler, ModelAndView modelAndView)

throws Exception;

// afterCompletion()方法在DispatcherServlet完全处理完请求后被调用

void afterCompletion(

HttpServletRequest request, HttpServletResponse

response, Object

handler, Exception ex)

throws Exception;

}

下面对代码中的三个方法进行解释。

preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。

postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet向客户端返回请求前被调用,在该方法中对用户请求request进行处理。

afterCompletion():这个方法在DispatcherServlet完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

下面通过一个例子来说明如何使用Spring MVC框架的拦截器。

【示例23-10】要求编写一个拦截器,拦截所有不在工作时间的请求,把这些请求转发到一个特定的静态页面,而不对它们的请求进行处理。

首先编写TimeInterceptor.Java,代码如下:

package com.examp.ch23;

import Java.util.Calendar;

import Javax.servlet.http.HttpServletRequest;

import Javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

publicclass TimeInterceptor extends HandlerInterceptorAdapter {

//继承HandlerInterceptorAdapter类

privateint openingTime;            //openingTime 属性指定上班时间

privateint closingTime;            //closingTime属性指定下班时间

private String outsideOfficeHoursPage;

//outsideOfficeHoursPage属性指定错误

提示页面的URL

publicvoid setOpeningTime(int openingTime) {

this.openingTime = openingTime;

}

publicvoid setClosingTime(int closingTime) {

this.closingTime = closingTime;

}

publicvoid setOutsideOfficeHoursPage(String outsideOfficeHoursPage) {

this.outsideOfficeHoursPage = outsideOfficeHoursPage;

}

//重写 preHandle()方法,在业务处理器处理请求之前对该请求进行拦截处理

publicboolean preHandle(

HttpServletRequest request,

HttpServletResponse response,

Object handler)

throws Exception {

Calendar cal = Calendar.getInstance();

int hour = cal.get(Calendar.HOUR_OF_DAY);       //获取当前时间

if (openingTime<=hour && hour<closingTime) {    //判断当前是否处于工作

时间段内

returntrue;

} else {

response.sendRedirect(outsideOfficeHoursPage);  //返回提示页面

returnfalse;

}

}

}

可以看出,上面的代码重载了preHandle()方法,该方法在业务处理器处理请求之前被调用。在该方法中,首先获得当前的时间,判断其是否在openingTime和closingTime之间,如果在,返回true,这样才会调用业务控制器去处理该请求;否则直接转向一个静态页面,返回false,这样该请求就不会被处理。

下面是在dispatcherServlet-servlet.xml中对拦截器进行的配置,代码如下:

<bean id="urlMapping"class="org.springframework.web.servlet.handler.Simple-

UrlHandlerMapping">

<property name="mappings">

<props>

<prop key="helloWorld.do">helloWorldAction</prop>

<prop key="login.do">loginController</prop>

</props>

</property>

<property name="interceptors">

<!--在interceptors 属性中定义所有的拦截器-->

<list>

<ref bean="officeHoursInterceptor"/>

<!--引用officeHoursInterceptor 拦截器-->

</list>

</property>

</bean>

<!--定义TimeInterceptor拦截器,id为officeHoursInterceptor -->

<bean id="officeHoursInterceptor"

class="com.examp.ch23.TimeInterceptor">

<!--openingTime 属性指定上班时间-->

<property name="openingTime"><value>9</value></property>

<!--closingTime属性指定下班时间-->

<property name="closingTime"><value>18</value></property>

<!--outsideOfficeHoursPage属性指定提示页面的URL-->

<property name="outsideOfficeHoursPage"><value>http://localhost:8080/

ch23/outsideOfficeHours.html</value></property>

</bean>

可以看出,上面代码用bean标签去定义TimeInterceptor,令其id为officeHoursInterceptor,并给它的3个属性赋值。在urlMapping中通过<property name="interceptors">去指定officeHoursInterceptor为一个拦截器,读者可以在<list>和</list>之间定义多个拦截器。

outsideOfficeHours.html的代码很简单,只是输出一句提示语。

运行程序,在浏览器中随便访问一个页面,如果请求的时间在9点~18点之间,则该请求可以被处理;否则,返回一句提示语,如图23-5所示。

(点击查看大图)图23-5  请求被拦截效果图

说明:在第22章中介绍过控制反转是Spring框架的核心思想,即用一个接口去定义一些操作,在接口的实现类中去重写这些操作,然后在Spring的配置文件中去把该接口的实现类注入到应有框架中,这样就可以通过调用接口去调用接口的实现类。本节讲的拦截器就体现了这种思想,即实现HandlerInterceptorAdapter接口,重写preHandle()方法并在配置文件中实现TimeInterceptor的注入。这样当框架调用HandlerInterceptorAdapter时,就可以调用到TimeInterceptor类的preHandle()方法。

转载于:https://blog.51cto.com/longx/1286712

Spring 核心控制器DispatcherServlet(二)相关推荐

  1. Spring MVC的核心控制器DispatcherServlet的作用

    关于Spring MVC的核心控制器DispatcherServlet的作用,以下说法错误的是( )? A.它负责处理HTTP请求 B.加载配置文件 C.实现业务操作 D.初始化上下应用对象Appli ...

  2. Spring 核心方法 refresh 刷新流程简要概述及相关源码扩展实现(二)

    前言 registerBeanPostProcessors initMessageSource 如何实际应用国际化处理 initApplicationEventMulticaster onRefres ...

  3. spring mvc 入门DispatcherServlet转发

    目录 一,配置相关 二,java类测试 三,测试 一,配置相关 maven坐标依赖 <dependencies><!-- spring context --><depen ...

  4. java 切面_Java笔试面试精心整理得到89道Spring 核心知识【收藏向】

    点击上方"蓝字",关注了解更多 Spring Framework 简称 Spring,是 Java 开发中最常用的框架,地位仅次于 Java API,就连近几年比较流行的微服务框架 ...

  5. 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  6. 小白初写Spring核心容器功能

    Spring核心容器功能 1.spring优点 方便解耦,简化开发 AOP编程的支持 申明式事务的支持 方便程序的测试等等 一,Spring模块架构图 core container : 核心容器,是s ...

  7. Spring核心容器

    目录 一,什么是Spring 概念 常见的框架 作用 二,什么是IoC&DI Core Container(核心容器) 1.IoC(控制反转) 2.DI(依赖注入) 3.IoC和DI之间的关系 ...

  8. 05. 手写Spring核心框架

    目录 05 手写Spring核心框架 Pt1 手写IoC/DI Pt1.1 流程设计 Pt1.2 基础配置 application.properties pom.xml web.xml Pt1.3 注 ...

  9. Spring MVC-ContextLoaderListener和DispatcherServlet

    2019独角兽企业重金招聘Python工程师标准>>> Spring MVC-ContextLoaderListener和DispatcherServlet 博客分类: spring ...

最新文章

  1. 句号一定要划在句子最美的地方
  2. 人脸检测-- Face R-FCN + Face R-CNN
  3. jupyter notebook上完美运行tensorflow、keras
  4. ubuntu修改gcc版本
  5. 【Java注解】自定义注解、与数据库结合使用
  6. linux下面拷贝gbk编码的网页
  7. 命令执行——系统命令执行(三)
  8. 数组初始化 和 vector初始化
  9. 拯救你的颈椎,笔记本支架如何选择?
  10. 用汇编的眼光看C++(之循环流程)
  11. jQuery调用WebService详解
  12. 32位寄存器用法介绍
  13. 单片机c语言直接寻址 间接寻址,pic单片机教程之数据存储器的直接间接寻址方式...
  14. 我的Java传承名单(不知为何以前的又没有了,幸亏有备份才可以又贴出来)
  15. 超分辨率复原matlab,matlab超分辨率重构
  16. Java中的注解(Annotation)处理器解析
  17. 第三百篇博客:写给自己的总结
  18. java.sql.SQLException: The server time zone value‘xxxxxxxx‘ is unrecognized
  19. 判断一个点是否在圆内
  20. Jenkin权限控制——项目矩阵授权策略

热门文章

  1. mysql导入组织树脚本_mysql存储过程递归调用发作树数据
  2. c语言由n个斐波纳函数,6、C语言 —— 字符串
  3. linux yum下载不安装,【APP】yum只下载软件不安装的两种方法
  4. IDEA 查看本地历史版本
  5. Linux中的head命令
  6. linux+cd英文全称,Linux命令英文全称
  7. chart放入panel_使用JPanel将ChartPanel添加到JTabbedPane
  8. kettle设置变量中变量范围的设置说明
  9. Oracle触发器5-Instead of触发器
  10. tomcat ---- jndi方式配置连接