第八单元 Struts 开源MVC框架
Struts课程目标 深入理解MVC模式 掌握Struts体系架构 掌握Struts开发流程 熟练掌握Struts的配置方法
从Servlet说开去 什么是Servlet? 如何编写Servlet? 如何映射Servlet? 相对路径与绝对路径的基本概念 JavaBeans JavaBean是一种java类 JavaBean必须是具体的和公共的,并且具备无参构造器 JavaBean通过提供符合一致性设计模式的公共方法将内部域暴露称为属性 JavaBean提供两种方法来访问Bean的内部状态: 访问器(getters)用来读JavaBean状态 – 以小写get前缀开始,后跟属性名,属性名的第一个字母必须大写,返回值必须匹配相应修改器的方法的参数;如果访问器返回boolean值,则使用is前缀开始,后跟属性名,属性名第一个字母必须大写。 修改器(setters)用来改变JavaBean状态 – 以小写set前缀开始,后跟属性名,属性名的第一个字母必须大写,修改器的返回值通常为void
Struts是什么? Struts的目标是提供一个开发Web应用的开源框架。Struts鼓励基于M2模式(即MVC设计模式)来开发程序。 Model View Controller
Model1与Model2设计模式简介 以JSP为中心的开发模型,称为Model1(JSP+JAVABEAN) 业务逻辑与表示逻辑混和,不利维护与重用 HTML中嵌入了大量的JAVA代码 验证、流程控制、更新程序的状态全部在JSP中完成 基于MVC模式的框架 MVC将问题进行分解 模型包含应用程序的核心功能。模型封装了应用程序的状态。它对视图或控制器一无所知。 视图提供模型的表示。它是应用程序的 外观。视图可以访问模型的读方法,但不能访问写方法。此外,它对控制器一无所知。 控制器对用户的输入作出反应。它创建并设置模型。
Model2
Struts框架概览
Struts框架概览 浏览器 控制器 模型 视图 web容器将对来自HTTP的每个请求创建一个request对象,并用一个response对象作出响应 控制器 控制器接收来自浏览器的请求,在struts中,是由一个servlet来充当控制器的角色,struts-config.xml文件配置控制器 模型 在struts中,由Action类充当业务逻辑的包装器,ActionForm是程序的状态 视图 JSP文件
Struts框架组件 ActionServlet类控制导航流 ActionServlet根据URI来决定哪个Action类 被用于处理请求,Action可以校验输入,并访 问业务层以便从数据库检索信息 Action需要知道页面提交了哪些内容,所以 由ActionServlet根据请求URI来决定将请求 参数绑定到哪个ActionForm中,并传入Action Action在完成业务逻辑后,返回一个ActionForward 对象,ActionServlet根据ActionForward对象中的路径来调用页面完成响应 Struts将这些信息绑定在一个ActionMapping对象中,一个ActionMapping对应一个请求URI,当请求路径到达的时候,ActionServlet就会查询ActionMapping对象,ActionMapping对象将告诉ActionServlet哪个Action类会被调用、哪个ActionForm类被用于传递页面数据以及哪些ActionForward将被用于转向 有关Action、ActionForm、ActionForward等信息,Struts通过一个配置文件:struts-config.xml文件来定义。
Struts1.X 和Struts2.X Struts1.X 与Struts2.X 的差异较大 Struts1.X 应用更加广泛 Struts2.X 实际上是另外一个框架Webwork发展而来的 后续课程将会有对webwork/Struts2.X的介绍以及实例操作
快速开始一个Struts项目 第一个项目,实现用户登录操作 用户将看到一个登录页面,要求用户输入用户名以及密码 如果用户名以及密码都是admin,提示登录成功 否则提示登录失败 1、用Eclipse创建一个J2EE Web应用项目,如右图所示 2、下载并解压Struts项目 *从Apache网站下载struts最新版 *将压缩包解压到一个目录,此目录为STRUTS_HOME目录 3、将STRUTS_HOME/lib目录下的所有.jar文件拷贝到刚创建的 web项目的WebContent/WEB-INF/lib目录下 4、配置ActionServlet: 修改web项目的web.xml文件,添加如下Servlet映射配置 (转下一页)
web.xml 的配置 <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <url-pattern>*.do</url-pattern> </servlet-mapping>
我们将需要创建如下文件 一个ActionForm – LoginActionForm.java 一个Action – LoginAction.java struts-config.xml文件 三个页面 登录页面 – login.jsp 登录成功提示页面 – login_success.jsp 登录失败提示页面 – login_error.jsp
创建LoginActionForm.java ActionForm是一个JavaBean,需继承org.apache.struts.action.ActionForm类,它捕获通过HTTP请求传送的参数 ActionForm针对每个HTML表单中的字段具有一个对应的属性 ActionServlet匹配请求中的参数和ActionForm中的属性,并调用ActionForm中的setter方法,将参数传入ActionForm 我们的login.jsp有username和password两个表单字段(下面将会看到),所以,我们需要定义ActionForm中相应的setter方法:setUsername和setPassword方法 ActionForm中的getter/setter方法,可以通过Eclipse集成环境,自动生成 ActionForm中的内部属性全部定义为私有的(private),并通过公共(public)的getter/setter方法来访问 package com.bjsxt.strutstest; import org.apache.struts.action.ActionForm; public class LoginActionForm extends ActionForm { private String username; private String password; /** * @return Returns the password. */ public String getPassword() { return password; } * @param password The password to set. public void setPassword(String password) { this.password = password; * @return Returns the username. public String getUsername() { return username; * @param username The username to set. public void setUsername(String username) { this.username = username;
创建LoginAction.java Action是一个Java类,需继承org.apache.struts.action.Action类 ActionServlet将会组装ActionForm,并将它传递给Action Action 通常负责: 输入校验 调用业务逻辑类执行业务逻辑操作 决定返回哪个ActionForward 我们的LoginAction做了如下事情,这些是一个Action通常都会做的最典型的事情: 将输入的ActionForm强制转换为LoginActionForm 从LoginActionForm对象中获取用户名以及密码的数据信息 执行用户名及密码的逻辑判断操作(在通常的情况下,要将这些业务逻辑交给专门的类去处理,这里这样做是为了演示的需要) 根据业务逻辑执行的结果,决定返回哪个ActionForward,我们在这里使用success这个标识来表示登录成功页面,用error标识来表示登录失败页面 public class LoginAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { //将ActionForm强制转换为LoginActionForm LoginActionForm loginForm = (LoginActionForm)form; //从LoginActionForm中提取从页面表单传递过来的参数 String username = loginForm.getUsername(); String password = loginForm.getPassword(); //根据这些参数,执行业务逻辑操作 if("admin".equals(username) && "admin".equals(password)){ //如果用户名和密码均为admin,则转向登录成功页面 return mapping.findForward("success"); }else{ //否则转向登录失败页面 return mapping.findForward("error"); }
创建Struts配置文件struts-config.xml 在WebContent/WEB-INF目录下创建struts-config.xml文件 并添加如下内容(空白的struts-config.xml),紧接着,我们将往这个空白的配置文件中添加其它配置信息 <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd"> <struts-config> </struts-config> struts-config.xml文件,是由ActionServlet读取的配置文件,它定义了所有关于Action、ActionForm、ActionForward等的详细信息
添加ActionForm配置,配置LoginActionForm 我们在struts-config.xml文件中,在<struts-config>标签的内部,添加如下配置: <form-beans> <form-bean name="loginForm" type="com.bjsxt.strutstest.LoginActionForm"/> </form-beans> <form-beans>标签内部可以包含多个<form-bean>标签 <form-bean>标签必须指定name和type属性 name属性是给此ActionForm一个标识名称 type属性指定了此ActionForm是哪个类,必须是全路径的类名
添加Action配置,配置LoginAction 我们在struts-config.xml文件中,紧接着<form-beans>标签的下面,添加对LoginAction的配置 <action>标签可以配置的重要属性包括: path-从页面上通过一个什么样的URL路径来访问Action(不包含.do) type – 访问这个URL的时候,调用哪个Action类,这是Action的全路径类名 name – 这个属性用来标识哪个ActionForm将被创建,并将提交的表单组件给它 scope – FormBean的作用域范围,可以取值为session和request,一般取值都是request <action-mappings> <action path="/login“ type="com.bjsxt.strutstest.LoginAction“ name="loginForm“ scope=“request” > <forward name="success" path="/login_success.jsp"/> <forward name="error" path="/login_error.jsp"/> </action> </action-mappings>
创建login.jsp 在WebContent目录下创建login.jsp文件,如右边所示 添加一个表单,action为login.do,这个login.do的意思,将会告诉struts的ActionServlet,它将需要调用哪个Action来处理这个表单的请求 添加输入域username,这个username的表单字段,必须跟LoginActionForm中的属性一致 添加密码输入域password <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>请登录</title> </head> <body> <form action="login.do" method="post"> 请输入用户名:<input type="text" name="username"> <br/> 请输入密码:<input type="password" name="password"> <br/> <input type="submit" name="submit1" value="登录"> </form> </body> </html>
创建login_success.jsp和login_error.jsp login_success.jsp <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>登录成功</title> </head> <body> 欢迎您,您已经成功登录!您创建的第一个Struts应用程序已成功运行!!! </body> </html> login_error.jsp <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>登录失败</title> </head> <body> 您的登录失败了,可能原因是用户名或密码不正确,请返回重新输入 <a href="login.jsp">返回登录页面</a> </body> </html>
启动Tomcat并运行login.jsp 运行login.jsp之后,能看到如下所示的登录表单 输入用户名admin和密码admin,将能看到登录成功的界面 输入其它用户名或密码,将能看到登录失败的界面
在这个简单的应用程序背后发生了什么? 当你从浏览器输入地址:http://localhost:8088/Struts-Test/login.jsp,Tomcat将按通常情况来处理这个JSP并返回浏览器 当你提交表单,实际上是提交到了这样一个URL地址:http://localhost:8088/Struts-Test/login.do,Tomcat将会根据web.xml的配置,将这个请求发送给相应的Servlet,在我们的应用中,Tomcat将会把这个请求发送给org.apache.struts.action.ActionServlet这个类(请参看web.xml的配置) 然后ActionServlet根据struts-config.xml的配置信息,调用LoginAction对象去处理这个请求,在此之前,它会将页面表单的请求数据封装到LoginActionForm对象中,并传递给LoginAction LoginAction返回一个ActionForward对象,包含了将要转向的路径信息 ActionServlet根据这个ActionForward对象所包含的路径信息,调用相应的页面去执行响应 流程图请参考下一页
LoginAction应用程序的流程图
Struts项目架构图
Struts工作流程图
Struts与MVC 视图(View) 控制器(Controller) 模型(Model) 在使用Struts框架的web应用程序中,JSP以及相关的技术(如Taglib)等共同组成视图层,这一层的主要职责是显示用户界面。Struts提供了很多机制让我们能更加轻松地创建视图 控制器(Controller) Struts中,ActionServlet是控制器层组件 模型(Model) 模型包括:系统的内部状态以及改变系统状态的动作 Struts中的Action和ActionForm是模型的一部分 Struts建议把”做什么”(Action)和”如何做”(业务逻辑)相分离
创建业务逻辑处理类(Model) 使用单例模式(Singleton)来创建业务逻辑处理类 创建UserManager业务逻辑处理类 package com.bjsxt.strutstest; public class UserManager { private static UserManager userManager; private UserManager(){ } public static synchronized UserManager getInstance(){ if(userManager == null){ userManager = new UserManager(); return userManager; public void validate(String username,String password) throws UserNotFoundException,PasswordErrorException { if(!"admin".equals(username)){ throw new UserNotFoundException(); if(!"admin".equals(password)){ throw new PasswordErrorException(); 使用单例模式(Singleton)来创建业务逻辑处理类 创建UserManager业务逻辑处理类 创建validate方法 创建UserNotFoundException 创建PasswordErrorException
Action中如何调用业务逻辑处理类? 我们看下面的代码: try { UserManager.getInstance().validate(username,password); return mapping.findForward("success"); } catch (UserNotFoundException e) { e.printStackTrace(); } catch (PasswordErrorException e) { } return mapping.findForward("error"); 通过添加业务逻辑处理类,我们将验证逻辑转移到了业务逻辑处理层
页面之间数据的传递 如何将数据从Action中传递到下一个JSP页面? 在原来LoginAction的基础上编写相应的代码,测试页面数据传递 一般使用request.setAttribute方法: 在Action中,使用request.setAttribute(String name,Object data)方法往request中设置参数 在JSP中,使用request.getAttribute(String name)来获取相应的参数 在原来LoginAction的基础上编写相应的代码,测试页面数据传递 传递登录成功者的帐号信息到成功页面,并显示
进一步理解Struts控制流
细节:所有的页面请求由容器接收 Struts的核心组件是ActionServlet,像其它所有Servlet一样,它是生存在容器中的,比如Tomcat、WebLogic等,当容器启动的时候,它会读取web.xml文件(部署描述符),告诉容器它会装入哪些Servlet 一个标准的Servlet是通过servlet-mapping来设定,哪些请求,将会被提交到哪些servlet中 Struts的servlet-mapping配置一般是: <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> 这样配置的意思是:任何以.do结尾的URL请求,都会被发送到ActionServlet进行处理
小结 MVC基本结构 Struts的主要组成部分 如何编写ActionForm 如何编写Action 如何在配置文件中定义映射URL、Action以及ActionForm 如何获取从页面传递到Action的数据 如何将数据从Action传递到下一个页面 如何将业务逻辑与表示层分离 需牢记原则:不要在Action中进行业务逻辑的处理,业务逻辑应交给专门的Model层去做 在业务逻辑层抛出异常,并在Action中捕捉和处理
Struts Taglib 易于使用,能代替直接在页面上写JAVA脚本 便于重用 用Struts Taglib实现成功页面
尝试简单的tag lib使用 在JSP文件的头部添加如下声明: <%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean" %> <%@ taglib prefix="logic" uri="http://struts.apache.org/tags-logic" %> <%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %> 关于struts tag lib的说明,可以查看相关的参考文档 常用的struts tag lib <bean:write> <logic:empty>和<logic:notEmpty> <logic:present>和<logic:notPresent> <logic:iterator>
JSTL 简介:SUN的标准Taglib库 表达式语言(EL) JSP标准标签库(JSP Standard Tag Library,JSTL ) 迭代和条件判断 数据管理格式化 XML 操作 数据库访问 函数标签库 表达式语言(EL) EL隐式对象 存取器 运算符
在项目中使用JSTL 拷贝jstl.jar和standard.jar到WEB-INF/lib目录下 在JSP中添加伪指令 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> 常用JSTL标记 <c:out> <c:if> <c:choose>、<c:when>和<c:otherwise> <c:forEach> <fmt:formatNumber> <fmt:formatDate>
进一步理解ActionForm ActionForm的要求 DynaActionForm 必须扩展自org.apache.struts.action.ActionForm 如果要获取表单的值,必须定义一个public属性 如果要求在将ActionForm传递到Action之前进行校验,必须实现validate方法 如果想要在组装前初始化属性,必须实现reset方法 DynaActionForm 举例说明DynaActionForm的配置 DynaActionForm的使用
ActionForm作为表单字段收集器 通过HTTP提交表单数据 通过HTTP上传文件 通过HTTP提交空字段 通过例子演示文件上传的简易方法 通过HTTP提交空字段 修改原来的JSP文件,提交空字段
ActionForm作为类型转换器 所有从表单提交到后台的数据均为字符串类型 如何利用ActionForm自动转换int数据类型 举例说明 如何利用ActionForm自动转换boolean数据类型 如何利用ActionForm自动转换Date类型 定义Converter 注册Converter 如何利用ActionForm自动转换Double类型
ActionForm作为传输对象 ActionForm 可以被其它bean或者过程作为数据载体。 Transfer 对象 (也称为值对象(value object) )用来通过发送粗糙—规整的数据视图来交换精细规整的数据。 ActionForm 的各个属性都必须是可变的。 提示: 使用粗糙—规整 ActionForm来减小类维护。 应用中的表单一般共享属性 创建一个基本的 ActionForm,具有表单需要的所有属性
ActionForward ActionForward能做什么? ActionForward的属性 在Action中,经常问的问题是:“OK,操作成功了,然后呢?” ActionForward会回传给ActionServlet ActionForward中的路径,可以是一个带参数的URI ActionForward的属性 name path redirect className 转发(forward)与重定向(redirect) 全局ActionForward与局部ActionForward
动态创建ActionForward 将ActionForward定义在一个Struts 配置文件中是个好的选择 但也可以在Action中动态创建ActionForward,而不需要在配置文件中指定 如下所示: ActionForward forward = new ActionForward("/do/itemEdit?action=edit"); 举例说明
ActionMapping 理解ActionMapping unknow ActionMapping path forward type name scope validate input parameter unknow ActionMapping
Scope属性 在Action映射配置中,Scope属性可以取值为:request或session Scope属性表示:Struts框架在将ActionForm对象(与目标Action匹配的ActionForm)传送到Action之前,会将ActionForm对象保存的位置 如:scope=“request”配置,将指示struts调用request.setAttribute(“ActionForm名称”,ActionForm对象)方法,将ActionForm对象保存到request。 其中,ActionForm名称与struts-config.xml配置中的ActionForm名称一致,如:<form-bean name=“uploadForm” type=“com.bjsxt.struts.actionform.UploadActionForm”/>,其中uploadForm就是其名称。 我们明白scope属性的意义之后,就可以利用struts的这些特性,来解决开发过程中的某些常见问题
常见问题:如何在程序出现异常的时候返回录入界面重新录入 假设现在要在一个页面上输入用户的信息(可能会有十几个属性值需要输入),用户不小心输入了一个重复的帐号,而帐号是不允许重复的,这个时候,系统应该提示用户有关帐号重复的信息,同时让用户重新选择一个帐号。 这种情况下,我们需要返回用户录入界面,让用户修改帐号字段。 现在的问题是:如何在返回这个录入界面的时候,将用户输入的其它信息保持住?
搞定Action对象 如果应用需要保存一个记录到数据库中,典型的过程可能是 ActionForward提供一个链接到输入页面 ActionForm捕获输入 ActionMapping配置Action Action将输入送到数据库中(通常会将这一步操作委托给业务逻辑类去实现) J2EE是一个多线程的环境,服务器针对每个请求启动一个线程来处理。所以有可能会有多个线程同时访问一个Servlet实例的情况 在Struts里面也是一样的,有可能会有多个线程同时访问一个Action实例的情况 所以必须保证Action类中的方法具有“可重入性”,即不能在Action的方法里改变实例变量的值
Action的主要职责 校验输入数据 调用业务逻辑方法 检测处理异常 根据逻辑进行转向操作
I18N问题 什么是I18N问题? 在英文中, 国际化(Internationalization)被缩写为I18N, 即只取首尾两个字母, 中间字母为18个 问题在哪里? 页面字符串硬编码 异常消息的硬编码 提示信息的硬编码
Java如何支持I18N? 一个简单的例子 不支持I18N的例子 – NoI18NSample.java 支持I18N的例子 我们需要将硬编码文本转移到外部的资源文件 编写MessagesBundle.properties 编写MessagesBundle_zh_CN.properties 编写MessagesBundle_en_US.properties 编写I18NSample.java 运行I18NSample.java 乱码? 因为资源文件必须是Latin-1或Unicode编码(如\udddd)的字符 使用native2ascii工具,将中文资源文件进行转换
Java支持I18N的编码过程总结 1、创建属性文件(可能要用native2ascii工具转换) 2、定义Locale对象 3、创建一个ResourceBundle对象 ResourceBundle对象用于分离跟本地相关的数据 如果找不到相应语言或国家代码的属性文件,将使用默认的属性文件(即没有标识语言和国家代码的属性文件:MessagesBundle.properties) 其创建方式如下: message = ResourceBundle.getBundle("MessagesBundle", currentLocale); 第一个参数,表示要从哪些资源属性文件中(MessagesBundle_XX.properties)获取数据 第二个参数,是一个Locale对象,表示要选择哪个资源属性文件 4、从ResourceBundle对象中获取数据
Locale对象 我们通过指定一个语言代码和国家代码来创建一个Locale对象 国家代码是可选的 语言代码是小写字母;国家代码是大写字母 Locale.getDefault()可以获得系统当前的Locale Java都支持哪些语言代码和国家代码? DateFormat.getAvailableLocales() 语言代码标准:http://ftp.ics.uci.edu/pub/ietf/http/related/iso639.txt 国家代码标准:http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html 与Locale相关的数据: 消息文本(带参数?) 日期(时间) 货币(数字) 等等。。。
Struts如何支持I18N 1、需要在struts配置文件中指定资源属性文件的位置和名称,如 2、在相应的位置放置相应的文件 <message-resources parameter="MessageResources" /> 2、在相应的位置放置相应的文件 3、在JSP页面中使用<bean:message key=“key string”/>来输出文本,以避免硬编码 以登录页面的国际化作为例子讲解 创建相应的资源属性文件 用<bean:message/>标签替换登录页面的硬编码文本 测试(更改网页显示语言,以便测试不同的版本)
关于message-resources 配置中parameter的值 举例: <message-resources parameter="MessageResources" /> 表示在类路径根目录(WEB-INF/classes目录)下有MessageResources_XX_XX.properties文件(注意:国家代码可以省略,跟java中对资源属性文件的处理一样) <message-resources parameter="resources.application"/> 表示在类路径根目录下,有一个resources目录,在这个resources目录中存放着所有的application_XX_XX.properties资源属性文件
如何用程序切换网页显示的语言 struts利用在session中存放一个Locale对象来达到设置当前语言的目的 默认的情况下,struts根据网页向后台提交时所包含的语言编码信息来提供缺省的Locale对象,这就是我们为什么可以通过更改网页显示语言设置,就能显示不同的语言文字的原因。 struts在session中存放的这个Locale对象,取名为:Globals.LOCALE_KEY 的值,Globals是struts框架提供的一个对象 利用这个原理,我们可以用编程的方式来手工切换整个应用系统的语言。 举例说明 ChangeLanguageAction
Struts消息处理 为什么需要消息处理? 比如登录成功的提示 比如创建失败的提示 等等……总之,程序总是要通过界面来跟用户交互,所以,在交互的过程中,就产生了众多的消息文本 struts提供了专门的处理机制,来将这些消息文本国际化,避免消息文本的硬编码 消息处理,就是在Action和JSP之间传递的消息文本的处理(区别于JSP页面硬编码文本的消息,JSP页面消息可以使用<bean:message/>标签来处理) Struts交互消息,是通过ActionMessages等对象,以及相应的<html:messages/>标签来处理的
如何创建消息对象? ActionMessages与ActionMessage对象 ActionMessages messages = new ActionMessages(); 如何创建ActionMessage对象? ActionMessage msg = new ActionMessage(“key”); 其构造方法带的参数,就是一个在资源属性文件中的key,所以,它能表示一个国际化消息文本 如何将ActionMessage对象添加到ActionMessages对象中? messages.add(“message_id”,msg); 第一个参数(message_id)表示本ActionMessage对象在ActionMessages对象中区别于其它ActionMessage对象的标识符
如何将消息对象从Action中传递到下一个页面(JSP)? 首先我们要决定的是,我们要传递的消息是普通消息还是错误消息? 普通消息:即普通的消息文本 错误消息:即提示错误的消息文本 本质上,这两种消息没有什么区别,都是消息文本,但是如果一个页面同时需要显示普通的消息文本和错误消息文本的时候,就需要进行区分了,比如不同类型的消息文本可能要用不同的样式来显示 通过一句简单的代码,将ActionMessages对象保存到HttpServletRequest对象中 保存普通消息:this.saveMessages(request,messages); 保存错误消息:this.saveErrors(request,messages); 这就是调用父类(Action)所提供的方法saveMessages()/saveErrors()来保存消息对象 实际上,父类的saveMessages()方法,将消息对象保存在了request中,并命名为Globals.MESSAGE_KEY saveErrors()方法,将消息对象保存在了request中,并命名为Globals.ERROR_KEY
如何在JSP中使用消息对象? 使用<html:messages/>标签来显示消息 name – 消息对象的名称,如果我们调用saveMessages/saveErrors方法来传递消息,那么这个名字不需要标识(struts使用缺省的名称,即Globals.MESSAGE_KEY 或Globals.ERROR_KEY ) id – (这是必需的属性)因为我们传递的是ActionMessages对象,而不是ActionMessage对象,ActionMessages对象相当于一个集合,我们需要在JSP上依次输出它所包含的消息,因此需要一个id标识一个变量来临时存放其每条消息(与<logic:iterate/>标签的id属性的意义是一样的) property – 我们传递的ActionMessages对象,包含了多条消息文本,如果我们只需要显示其中一条,则可以通过property属性来指定显示哪条消息 message – 可以取值为true或false,如果取值为true,将显示普通消息,如果取值为false,将显示错误消息
<html:errors/>标签 <html:errors/>标签与<html:messages/>标签类似,但无id属性 <html:errors/>标签通过提供header/footer属性以及prefix/suffix属性来定制每条消息的显示格式 header/footer – 定义整个错误消息显示之前(之后)要显示的内容,这些内容也是在资源属性文件中定义的一些key值,默认的情况下,它们的取值分别为:errors.header和errors.footer prefix/suffix – 定义每条错误消息显示之前(之后)要显示的内容,这些内容也是在资源属性文件中定义的一些key值,默认的情况下,它们的取值分别为:errors.prefix和errors.suffix 举例如下: errors.header=<UL> errors.prefix=<LI> errors.suffix=</LI> errors.footer=</UL>
Struts的异常自动处理机制 编程式异常处理 即我们在Action中调用业务逻辑层对象的方法时,用try{ }catch的方式来截获异常之后,手工对异常进行处理 我们以前的开发过程中,都是使用编程式的异常处理 在编程式异常处理的时候,我们可以使用struts的消息处理机制(前面所讲的内容)来对这些异常信息进行处理 自动异常处理机制 即在Action中不捕捉异常,而是将异常抛出给struts框架处理 我们需要在配置文件中指示struts如何处理这些被抛出的异常 使用<exception/>元素来定义自动异常处理
<exception/>元素的配置及使用 <exception/>元素的配置,指示了struts如何处理异常的方式 在通常的情况下,我们得到异常以后,需要将页面导航到一个错误提示的页面,提示错误信息 <exception/>元素配置的关键属性是: key – 即这个异常所对应的错误提示消息文本的key,这个key的值,需要在资源属性文件中进行定义 type – 即定义需要处理哪种类型的Exception path – 定义一旦出现异常,需要转向哪个页面来进行提示,如果不定义path属性,默认情况下,将使用Action配置中的input属性的值来作为转向的页面 如何显示错误消息? 在JSP页面中,使用<html:errors/>标签,即可将其异常对应的错误消息文本进行显示(测试login.jsp页面)
标准Action Struts框架缺省提供了一些Action,来完成一些常见的功能 ForwardAction - ForwardAction仅仅简单的转发控制到其他资源 为什么需要ForwardAction? 目的是发出一个RequestDispatcher 转发 ForwardAction 的绝大多数使用是作为Action的占位符 ForwardAction 创建一个请求分派器,并根据ActionMapping提供的上下文相关的URI转发控制 许多 Struts 开发人员避免从一个页面直接连接到其他地方而是通过Action 或者 ActionForward来传递控制。这保证了工作流在Struts 配置的控制之下,在这里可以进行集中管理。 然而,许多页面并不需要特殊的预处理(至少还不需要)。如果为这些页面创建ActionMapping ,你可以使用ForwardAction ,来仅进行路由控制。如果以后,需求改变,又需要进行预处理,你可以改变mapping 来为那个页面引用到一个Action。因为链接是引用到mapping, 而不是Action类, 所以你可以修改Action类而不用改变链接。
标准的Base Action DispatchAction – 避免每个Action创建一个类 DispatchAction的配置方法 添加parameter属性到Action的配置中 unspecified方法 举例说明DispatchAction的使用
struts配置中的路径与模式匹配 struts配置中的action,有一个path属性,它表明请求的URI 一般情况下,我们需要在配置文件中明确指定某个特定的URI,如path=“/user/add” 在一些大型应用中,如果能够制定一套严格的路径及其操作规范的话,我们可以利用path的路径模式匹配功能,来简化struts配置文件繁琐的编写工作量 假设有如下规范:
路径匹配规范示例 对user对象的所有处理Action,均需要以如下的路径进行访问: 所有操作(Action)对应的JSP如下: /user/add.do – 处理用户添加的有关操作 /user/delete.do – 处理用户删除的有关操作 /user/update.do – 处理用户更新的有关操作 … 所有操作(Action)对应的JSP如下: 所有操作成功(失败)之后的转向页面,有如下命名规范: /user/add.do -> /user/add_success.jsp或/user/add_error.jsp /user/delete.do -> /user/delete_success.jsp或/user/delete_error.jsp 所有操作的输入界面有如下命名规范: 添加操作 -> /user/add_input.jsp 更新操作 -> /user/update_input.jsp
Action配置示例 <action > </action> path="/user/*" type="com.bjsxt.struts.web.actions.UserAction" name="userForm" parameter="method" > <forward name="index" path="/user/index.jsp"/> <forward name="success" path="/user/{1}_success.jsp"/> <forward name="error" path="/user/{1}_error.jsp"/> <forward name="input" path="/user/{1}_input.jsp"/> </action>
Action配置解释 所有的/user/*.do请求,都将由UserAction这个类来处理,UserAction类继承DispatchAction,它将根据传入的method参数的值,来分发到不同的方法来进行处理 在UserAction类中的任何一个方法,都可以返回index/success/error/input等名称的ActionForward 根据请求路径的不同,即使调用相同的返回代码,但其转向也将不同,如: /user/add.do?method=add请求,将被转发给UserAction类的add方法处理,假设它用mapping.findForward(“success”);来返回成功页面,这将转向的实际JSP页面是:/user/add_success.jsp 而/user/delete.do?method=delete请求,将被转发给UserAction类的delete方法处理,假设它用mapping.findForward(“success”);来返回到删除成功页面,这将转向的实际JSP页面是:/user/delete_success.jsp,所以,不同URI请求的相同名称的返回页面将是不同的。 而/user/index.do请求(或者任何一个其它请求,如/user/abcd.do或/user/test.do),都因为没有传递method参数,而触发调用UserAction的unspecified方法
Struts回顾 Struts tag lib的配置和使用 JSTL的配置和使用 错误消息的处理 ActionForm的多种用途 DynaActionForm ActionForward的主要作用,如何动态创建ActionForward Action的主要职责和处理过程 如何保证Action的线程安全性 国际化与资源文件的配置、使用 ForwardAction DispatchAction