Struts2入门教程(全新完整版)

一、发展历史及简介

发展历史

Struts最早是作为Apache Jakarta项目的组成部分,项目的创立者希望通过对该项目的研究,改进和提高JavaServer Pages、Servlet、标签库以及面向对象的技术水准。Struts这个名字来源于在建

筑和旧式飞机中使用的支持金属架。这个框架之所以叫"Struts",是为了提醒我们记住那些支撑我们房屋,建筑,桥梁,甚至我们踩高跷时候的基础支撑。这也是一个解释Struts在开发Web应用程序中所扮演的角色的精彩描述。当建立一个物理建筑时,建筑工程师使用支柱为建筑的每一层提供支持。同样,软件工程师使用Struts为业务应用的每一层提供支持。它的目的是为了帮助我们减少在运用MVC设计模型来开发Web应用的时间。我们仍然需要学习和应用该架构,不过它将可以完成其中一些繁重的工作。如果想混合使用Servlets和JSP的优点来建立可扩展的应用,Struts是一个不错的选择。

早期Smalltalk程序语言便采用了MVC(Model-View -Controller) 模式( Patterns ) 以增加程序代码弹性,MVC模式将程序代码整理切割为三部分,Model 部分是业务与应用领域(Business domain) 相

关逻辑、管理状态之对象,Controller 部分接收来自View 所输入的资料并与Model 部分互动,

struts 业务流程控制(Flow Control) 之处,View 部分则负责展现资料、接收使用者输入资料。在Java 应用中,JFC/Swing、AWT、JSP皆是可用作View 的技术规格,而JavaBean与Enterprise JavaBean 规格则可用于Model程序代码,一旦应用程序以MVC 模式加以适当的分割,Model 部分程序代码可在不同使用者接口外观的应用程序中重复使用。

随着JSP 与Servlet 技术大量应用于以Web 为基础的应用程序,Java 开发人员群体认为应以较佳的模式以提升Web 应用程序的可维护性与重复使用性。早期JSP 规格书中曾列举两种可行之JSP 应用架构,分别为Model1 与Model 2。

在Model 1 架构中,JSP 直接处理Web浏览器送来的请求(Request ),并辅以JavaBean 处理应用相关逻辑。Model 1 架构单纯编写比较容易,但在Model 1 中JSP 可能同时肩负View 与Controller 角色,两类程序代码有可能混杂而不易维护。而Model 2 中将Servlet 纳入架构中扮演前端Controller 角色,将Web浏览器送出的请求集中送至Servlet ,Servlet 可集中管理使用者登入、权限控制、多国语言转换等前置处理,再视需求转向给对应的JSP 处理。Model 2 中采用了较佳的MVC 模式,但增加了编写复杂度。

Struts是Apache软件基金下Jakarta项目的一部分。除Struts之外,还有其他成功的开源产品,包括Tomcat,Ant 和Velocity。2000 年Craig R. McClanahan 先生贡献了他编写struts

的JSP Model 2 架构的Application Framework 原始程序代码给Apache 基金会,成为Apache Jakarta 计划Struts Framework 前身。

开始的代码基础从2000年5月开始开发,直到2001年6月,1.0版本发布。有30 多个开发者参与进来,并有数千人参与到讨论组中。Struts代码基础由一个志愿的Commnitter团队来管理。到2002年,Struts 小组共有9个志愿Commnitter。

Struts框架的主要架构设计和开发者是Craig R.McClanahan。Craig 也是Tomcat 4的主要架构师,以及Java Web Services Developer Pack的主要架构师和实现者。他是Sun(于2010年1月被oracle 收购)的JavaServer Faces (JSR-127) 以及J2EE平台的Web层架构的规范领导。Craig R. McClanahan 先生是JCP ExpertGroup 成员之一,曾参与JSP 规格制定与Tomcat 4 之编写,因此Struts Framework 广受Java 开发人员群体所重视。Borland 自2002 年底开始于开发工具JBuilder

中支持Struts Framework。

Struts是Apache 基金会Jakarta 项目组的一个Open Source 项目,它采用MVC模式,能够很好地帮助java 开发者利用J2EE开发Web应用。和其他的java架构一样,Struts 也是面向对象设计,将MVC模式"分离显示逻辑和业务逻辑"的能力发挥得淋漓尽致。Struts 框架的核心是一个弹性struts

的控制层,基于如Java Servlets,JavaBeans,ResourceBundles与XML等标准技术,以及Jakarta Commons 的一些类库。Struts由一组相互协作的类(组件)、Servlet以及jsp tag lib组成。基于struts 构架的web应用程序基本上符合JSP Model2的设计标准,可以说是一个传统MVC设计模式的一种变化类型。

流程

服务器启动后,根据web.xml加载ActionServlet读取struts-config.xml文件内容到内存

优点

struts跟Tomcat、Turbine等诸多Apache项目一样,是开源软件,这是它的一大优点,使开发者能更深入的了解其内部实现机制。

除此之外,Struts的优点主要集中体现在两个方面:Taglib和页面导航。Taglib是Struts的标记库,灵活运用,能大大提高开发效率。另外,就目前国内的JSP开发者而言,除了使用JSP自带的常用标记外,很少开发自己的标记,或许Struts是一个很好的起点。

关于页面导航,我认为那将是今后的一个发展方向,事实上,这样做,struts 使系统的脉络更加清晰。通过一个配置文件,即可把握整个系统各部分之间的联系,这对于后期的维护有着莫大的好处。尤其是当另一批开发者接手这个项目时,这种优势体现得更加明显。

MVC即Model-View-Controller的缩写,是一种常用的设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合,以及让视图层更富于变化。Struts 是MVC的一种实现,它将Servlet和JSP 标记(属于J2EE 规范)用作实现的一部分。Struts继承了MVC的各项特性,并根据J2EE的特点,做了相应的变化与扩展。

框架

struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发

struts可以清晰地区分控制,事务逻辑和外观,从而简化了开发应用程序的过程。struts提供的类使得开发工作更加简单,这些类包括:

控制程序流程的类

实现和执行程序事务逻辑的类

自定义的标记库使得创建和验证HTML表单更加容易

.

一.MVC的特点:

—多个视图可以对应一个模型。按MVC设计模式,一个模型对应多个视图,可以减少代码的复制及代码的维护量,一旦模型发生改变,也易于维护。

—模型返回的数据与显示逻辑分离。模型数据可以应用任何的显示技术,例如,使用JSP页面、Velocity 模板或者直接产生Excel文档等。

—应用被分隔为三层,降低了各层之间的耦合,提供了应用的可扩展性。

—控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起,完成不同的请求。因此,控制层可以说是包含了用户请求权限的概念。

— MVC更符合软件工程化管理的精神。不同的层各司其职,每一层的组件具有相同的特征,有利于通过工程化和工具化产生管理程序代码。

二.Struts1的特点

Struts 1以ActionServlet作为核心控制器,由ActionServlet负责拦截用户的所有请求。Struts 1框架有3个重要组成部分:Action、ActionForm和ActionForward对象。

ActionForm必须实现ActionForm的基类,设计上并不是真正的POJO

ActionForward就是一个逻辑视图,通过在配置文件中定义ActionFoward的映射,完成逻辑视图名和实际视图资源之间的映射

Struts 1的Action类与Struts 2的Action类有一定的类似性,都通过调用execute方法来处理用户请求。但最大的区别在于Struts 1 Action的execute方法与Servlet API耦合(ActionServlet继承自HttpServlet),但Struts 2 Action类的execute方法无需与Servlet API耦合。

struts1的缺陷:

(1).只支持JSP作为表现层技术,不能与Velocity,FreeMarker等技术整合

(2).与Servlet API严重耦合,难于测试

一个exute有四个参数ActionMapping、ActionForm、HttpServletRequest和HttpServletResponse,初始化困难.

(3).侵入式设计,严重依赖于Struts1API,如如ActionMapping、ActionForm和ActionForward类.一旦系统需要重构时,这些类完全没有利用价值,导致较低的代码复用

三.Struts2的特点

struts2核心控制器:FilterDispatcher

Struts 2用于处理用户请求的Action实例,并不是用户实现的业务控制器,而是Action代理——因为用户实现的业务控制器并没有与Servlet API耦合,显然无法处理用户请求。而Struts 2框架提供了系列拦截器,该系列拦截器负责将HttpServletRequest请求中的请求参数解析出来,传入到Action中,并回调Action 的execute方法来处理用户请求。显然,上面的处理过程是典型的AOP(面向切面编程)处理方式。

?Struts2 Action有以下特点:

— Action类完全是一个POJO,因此具有很好的代码复用性。

— Action类无需与Servlet API耦合,因此进行单元测试非常简单。

— Action类的execute方法仅返回一个字符串作为处理结果,该处理结果可映射到任何的视图,甚至是另一个Action。

Struts 2的配置文件有两份:

—配置Action的struts.xml文件。

—配置Struts 2全局属性的struts.properties文件。

二、准备工作及实例

到指定地址下载https://www.360docs.net/doc/1c19052873.html,/download.cgi#struts252,struts开发包

1.解压struts-

2.1.6-all.zip

apps目录:struts2自带的例子程序

docs目录:官方文档。

lib 目录:存放所有jar文件。

Src 目录:源文%件存放地

2.六个基本包

struts2-core-2.1.6.jar :开发的核心类库

freemarker-2.3.13.jar :struts2的UI标签的模板使用freemarker编写

commons-logging-1.0.4.jar :日志包

ognl-2.6.11.jar :对象图导航语言,通过它来读写对象属性

xwork-2.1.2.jar :xwork类库,struts2在其上进行构建

commons-fileupload-1.2.1.jar:文件上传组件,2.1.6版本后必须加入此jar包

特别需要说明的是目前strust2的最新版本是struts-2.1.6,它作为2.1.X的正式版。特别要注意导入commons-fileupload-1.2.1.jar包,%在此jar包中包含了RequestContext类,如果不导入该jar包将会报异常。

3.初识struts2配置文件

(1).web.xml文件

主要完成对StrutsPrepareAndE%xecuteFilter的配置(在以前的版本中是对FilterDispatcher配置,新版本同样支持用FilterDispatcher配置),它的实质是一个过滤器,它负责初始化整个Struts框架并且处理所有的请求。这个过滤器可以包括一些初始化参数,有的参数指定了要加载哪些额外的xml 配置文件,还有的会影响struts框架的行为。除了StrutsPrepareAndExecuteFilter外,Struts还提供了一个ActionContexCleanUp类,它的主要任务是当有其它一些过滤器要访问一个初始化好了的struts框架的时候,负责处理一些特殊的清除任务。

(2).struts.xml文件

框架的核心配置文件就是这个默认的str%uts.xml文件,在这个默认的配置文件里面我们可以根据需要再包括其它一些配置文件。在通常的应用开发中,我们可能想为每个不同的模块单独配置一个struts.xml文件,这样也利于管理和维护。这也是我们要配置的主要文件。

(3).struts.properties(参default.properties)

在Struts框架使用了很多属性,我们可以通过改变这些属性来满足我们的需求。要改变这些属性,只

需在struts.properties文件中指定属性%的key和value即可。属性文件可以放在任何一个包含在classpath中的路径上,但是通常我们都把它放在/WEB-INF/classes目录下面。我们可以在struts-default.properties文件中找到一个属性的列表。

(4)struts-default.xml

此文件是struts2框架默认加%载的配置文件,它定义了struts2一些核心bean和拦截器,它会自动包含(included)到struts.xml文件中(实质是通过),并为我们提供了一些标准的配置。%%%%%%%%%%%%%我们可以在struts2-core.jar中找到这个文件。

(5)其它配置文件

velocity.properties,struts-default.vm,struts-plugin.xml

4.让MyEclipse提示xml信息

当我们在编写struts.xml时,%%%%%%%%%%%%发现eclipse并不会给出帮助提示,那是因为MyEclipse 默认并不支持struts2,所以我们需要手工导入dtd以支持提示。步骤:[window][preferences][MyEclipse][Files and Editors][XML][xml Catelog]然后在右边点add添加:location为dtd文件所在的位置(struts-2.0.dtd文件struts2-core-2.1.6.jar中可以得到),KeyType 选择URI,Key为struts-2.0.dtd文件中文档声明的内容(https://www.360docs.net/doc/1c19052873.html,/dtds/struts-2.0.dtd),在struts.xml文件中也有此key值。

5.如何使用alt+/提示

在MyEclipse6.5中,默认的提示%%%%%%%%%%%为Ctrl+Space,而它会与我们的输入法切换冲突,使提示失效。找到key,先取消Content Assist命令的绑定,再用“alt+/”来绑定。

6.实例

步骤一,新建myStruts2项目,并导入struts2的六个基本jar包。

步骤二,建立LoginAction文件,主要代码如下:

package com.asm;

import com.opensymphony.xwork2.Action;

public class LoginAction implements Action {

private String username;

private String password;

...省略get/set方法

public String execute() throws Exception {

if (username.equals("struts2")) {

return"loginSuccess";

} else {

return"loginFailure";

}

}

}

说明:实现了Action接口,主要是为了保证execute的正确定义,其实我们也可以不实现此接口,只要能保证execute方法书写的正确书写(方法名,返回值)。

步骤三,在struts.xml文件中注册LoginAction。此配置文件要放在src目录下,实质就是成为classpath 环境变量下的文件。主要代码如下:

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

"https://www.360docs.net/doc/1c19052873.html,/dtds/struts-2.0.dtd">

/success.jsp

/failure.jsp

说明:package后面会有详细说明。action元素中的name属性值指定了此action所指定的请求路径为“login.action”。后面login.jsp中的

属性值就会参照此name属性。

步骤四、提供jsp页面

login.jsp主要代码:

户名:

密码:

failure.jsp主要代码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@ taglib uri="/struts-tags" prefix="s" %>

登录失败,错误的用户名:

返回

说明:使用了标签库,在struts2中使用标签库非常简单,只需要像上面那样导入标签库便可以使用所有的struts2的所有标签

success.jsp主要代码

登录成功!

步骤五、配置web.xml。完成核心监听器注册。内容如下:

xmlns="https://www.360docs.net/doc/1c19052873.html,/xml/ns/j2ee"

xmlns:xsi="https://www.360docs.net/doc/1c19052873.html,/2001/XMLSchema-instance"

xsi:schemaLocation="https://www.360docs.net/doc/1c19052873.html,/xml/ns/j2ee

https://www.360docs.net/doc/1c19052873.html,/xml/ns/j2ee/web-app_2_4.xsd">

struts2

org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

struts2

/*

说明:注释掉的部分为以前2.1.4版本中用的核心filter类。StrutsPrepareAndExecuteFilter类的init方法将会读取类路径下默认的配置文件struts.xml,并以javabean形式存放在内存中,以后struts2对用户的每次请求将使用内存中数据,而不是重读struts.xml文件。

步骤六、发布测试。

简要分析执行流程:

当输入login.jsp访问jsp页面填写完相关信息并提交给login.action时,它会首先被在web.xml中配置的过滤器监听到,过滤器会去查找strust.xml文件,并结合namespace查找名为login的action,查找到此action便交给其处理,LoginAction内部会执行execute方法,并返回结果result(result 也是参照的struts.xml中action下的result配置)。关于表单传参,主要是参照的action中的方法名,而非属性名。

7.开启struts2自带的开发模式常量

在以前的开发中,当修改一些配置时总是不能及时地更新到服务器,我们总会重新部署或重启来更新改变的内容,在struts2中可以通过一个常量来达到此目的。即在struts.xml中的元素下增加如下内容: 这样配置后,当配置文件修改保存时就会及时更新到服务器中。其它一些常量:

注意:在struts2.1.6版本中存在一个bug:即配置了struts.i18n.encoding常量也不能解决中文乱码问题,原因是此版本在获取请求参数后才调用了setCharacterEncoding()方法进行编码设置。解决此bug的方法是配置一个filter,并在doFilter方法中增加如下代码:request.setCharacterEncoa2.1.8版本中解决了此问题及2.1.6中存在的其它bug,建议新项目使用2.1.8版本。

8.vo传参模式

Copy上面的myStruts2项目,改名为myStruts2Vo项目。作如下修改:在LoginAction中有两个字段:username,password。把此两个属性重构到https://www.360docs.net/doc/1c19052873.html,er类中,然后在LoginAction中提供User 对象及相应的get/set方法。现在需要注意的是在login.jsp中会有如下的修改:户名:

密码:

关键就是改掉name属性值。其它基本无变动。后话:假如此此User对象并不能和Model层的相应对象完全对应,我们还应借助此User对象在Action中构建出Model层的相应对象,这样,在exectue 方法中便能通过构建的Model对象作为参数与Model层交互。

9.ModerDriven传参模式(不建议采用)

Copy上面的myStruts2Vo项目,改名为myStruts2Model项目。重点是修改LoginAction,修改后的主要内容如下:

package com.asm;

import https://www.360docs.net/doc/1c19052873.html,er;

import com.opensymphony.xwork2.Action;

import com.opensymphony.xwork2.ModelDriven;

public class LoginAction implements Action, ModelDriven { private User user = new User();

public String execute() throws Exception {

if (user.getUsername().equals("struts2")) {

return"loginSuccess";

} else {

return"loginFailure";

}

}

public User getModel() {

return user;

}

}

说明:它实现了ModelDriven接口,并使用了泛性机制(必须),因此要求jdk1.5以上。

现在需要注意的是在login.jsp中name属性值为User中两个字段,和第一个实例一样。说明:此方式一般不会使用,在此略作了解。

10.为什么要使用struts2代替struts1.x

(1)struts2的execute方法中的参数不会依赖于servletAPI,实现了也servlet解耦,是一种无侵入式的设计。

(2)struts2提供了拦截器,利用拦截器可以进行AOP编程,实现权限拦截等功能。

(3)struts2提供了类型转换器,我们可以很容易地对请求参数转换成需要的类型。

(4)提供了同种表现层技术支持,如JSP、freeMarker、velocity等

(5)可以对指定的方法进行校验,可以轻松地实现表单校验功能

(6)提供了全局范围、包范围和action范围的国际化资源文件管理实现。

二、struts.xml配置及例程

1.配置文件的优先级

在struts2中一些配置(比如常量)可以同时在struts-default.xml(只读性),strtus-plguin.xml (只读性),struts.xml,struts.properties和web.xml文件中配置,它们的优先级逐步升高,即是说后面的配置会覆盖掉前面相同的配置。

2.配置形式

下面以对struts.i18n.encoding=UTF-8的配置为例进行说明:

在struts.xml配置形式如下:

在struts.properties的配置形式如下:

struts.i18n.encoding=UTF-8

在web.xml中配置如下:

struts2

org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

struts.i18n.encoding

UTF-8

说明:官方声称配置了此常量可以解决中文乱码问题,但实事上并不能达到目的,在前面的三个项目中,如果我们在表单中输入中文,其结果是会出现乱码。解决此问题参看[一.7的注意]。这是struts2.1.6中的一bug,它的下一版2.1.8已解决此问题。

3.package配置相关

属性名是否必须说明

Name 是Package的唯一标识,不允许同名

Extends 否指定要继承的包

Namespace 否指定名称空间

Abstract 否声明包为抽象否

下面我们建立struts2package项目来进行package相关测试:

链接地址

test1

struts.xml中的内容:

/forward/test1.jsp

/forward/test2.jsp

链接地址

test2

说明:在上面的配置文件中所用到的Test1Action和Test2Action这两个Action都只是继承了

com.opensymphony.xwork2.ActionSupport类,而ActionSupport默认返回的就是“success”,所以当点击上面的链接分别转到了forward目录下的test1.jsp和test2.jsp。下面重点来看这个package元素的namespace属性及action的name属性,它们共同定义了action所映射到的实质文件。上图展示了链接地址和action的对应关系,所以当我们要想访问一个action所关联到的jsp文件时,应该用

namespace+action的name 关于它的内容测试可以参考struts2package项目。

补充:通常情况下,action元素的name是属性值是不能出现“/”的,所以希望通过action中name属性来实现多级映射,需要在struts.xml中增加如下属性:

这样配置后就

可以再action的name元素中使用“/”了。比如:

/forward/test3.jsp

然后输入test3
链接地址就可以访问了

强调:namespace默认值“”,即不配置namespace属性。它的意思是:如果action不能进行完整路径匹配,则会来此namespace下进行匹配,比如:.../test/test/test.action,如果参照namespace 及action的name不能找到也之完全对应的action,它会再到依次追溯到上级目录中查找,即是说它会以…/test/test.action这样的路径来对应namespace和action的name进行查找。如果返回到最终的目录仍找不到,它就会到namespace="/"对应的包下查找名为test的action,如果仍找不到,它就会去默认的namespace下查找名为test的action,如果找到则执行此action。另外,namespace也可以配置成namespace="/"。它代表配置为项目的根。总结action的名称探索顺序:完全对应、逐步追溯到上级目录查找、"/"下查找、默认namespace下查找。

为什么要提出namespace,主要是避免多人共同开发项目出现名字冲突。如果不使用namespace,多个人所写的action中可能出现重名的现象,这样当项目合并时就会出现冲突。而有了namespace可以在项目开发时由项目经理给每一个人分不同的namespace,这样每个开发人员只需要保证自己所写的action不同名即可。

namespace引发的链接问题:当我们为action配置了namespace时,访问此action的形式总会是如下形式:.../webappname/xxx/yyy/ActionName.action 而当此action成功执行跳转到某个jsp页面时,如想在此jsp页面写链接,一定要写绝对路径,因为相对路径是相对.../webappname/xxx/yyy/,而如果以后我们修改了action的namespace时,相对路径又要变,所以链接不能写成相对路径。以下介绍绝对路径的写法:通常用myeclipse开发时建立一个jsp文件,默认总会有如下内容:

<%

String path = request.getContextPath();

String basePath =

request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort() +path+"/";

%>

我们写绝对路径可以参此内容。还可以参下的 来完成绝对路径的书写。

4.分工合作include:指定多个配置文件

比如让jack来单独开发一个action,在jack.xml中的配置文件为:

/forward/test4.jsp

然后在struts.xml文件中增加如下内容: 它实质就是把jack.xml中的及其内容写进struts.xml中的根元素下。

链接:test4 这样便可以访问到了forward 目录下的test4.jsp了。

5.tomcat认证访问

接上例:namespce的作用除了在前面提到的避免协同开发名字冲突外,还为认证提供一个条件。比如jack

开发的东西所关联到的页面需要权限才能被访问。由于多为tomcat中的内容,下面只列出步骤。

步骤一,tomcat的conf目录下tomcat-users.xml内容如下:

步骤二,在web.xml中增加如下内容:

jack

/jack/*

POST

GET

admin

admin

BASIC

input authentication message

这样配置完成后,当我们访问.../jack中的任何内容都会要求输入密码认证信息,认证时输入tomcat-users.xml配置的admin权限的用户名和密码即可访问(这里就只有jack用户名可以访问)6.初识拦截器

拦截器能在action被调用之前和被调用之后执行一些“代码”。Struts2框架的大部分核心功能都是通过拦截器来实现的,如防止重复提交、类型转换、对象封装、校验、文件上传、页面预装载等等,都是在拦截器的帮助下实现的。每一个拦截器都是独立装载的(pluggable),我们可以根据实际的需要为每一个action配置它所需要的拦截器。

在myStruts2项目下,重新对配置文件作如下修改:

class="com.opensymphony.xwork2.interceptor.TimerInterceptor" />

class="com.opensymphony.xwork2.interceptor.ParametersInterceptor" />

/success.jsp

/failure.jsp

首先在package中定义了两个拦截器,然后在login action中引用了这两个拦截器,需要说明的是这里使用的拦截器都是系统自带的拦截器。其实在extends所继承的struts-default中就包含了很多拦截器,也包括我们这里所用的拦截器,但如果在此action中不使用params拦截器,将会报空指针错,因为params 拦截器的作用是传递表单参数,如果不使用此拦截器就不能在action中得到表单参数,所以引用时会报空指针错。虽然extends继承的strust-default自带有params拦截器,但是当我们自己引用了拦截器时,继承struts-default将不会再为我们分配默认的拦截器(有点类似构造器),但是我们仍然可以通过来继续使用struts-defalut的拦截器。补充:由于上面的package继承于struts-default,而我们这里所用到的timer和params都是在struts-defalut中定义过,所以即使我们在中没有定义过这两个拦截器,也可以直接在action中引用。

使用组合多个拦截器:比如我们想把上面的params和timer这两个拦截器组合:

然后再在action引用”,效果和分别引用两个是一样的。其实我们使用strtus-default中的也是使用interceptor-stack方式。

(6)为什么我用User来做却不行ModerDriver。

7.Action中的method属性

在struts1.x中我们知道通过继承DispatchAction可以实现把多个Action进行统一操作,在struts2中实现action的统一操作也很简单。我们以crud操作为例,把crud集中到一个Action中。

步骤一、建立CRUDAction,内容如下:

package com.asm;

import com.opensymphony.xwork2.ActionSupport;

public class CRUDAction extends ActionSupport {

public String add() {

return"success";

}

public String del() {

return"success";

}

public String update() {

return"success";

}

public String query() {

return"success";

}

}

步骤二、配置此Action,为了清晰明了,专为此Action,建立一个配置文件crud.xml,主要内容如下:

/crud/addSuccess.jsp

/crud/delSuccess.jsp

/crud/updateSuccess.jsp

/crud/querySuccess.jsp

分析:上面的method方法的值来源于CRUDAction中方法的名字,这样当我们访问上面的每一个Action 时,它实质是和method指定的方法关联上。

步骤三、把crud.xml配置文件并入struts.xml中,只需增加如下代码:

步骤四、编写相应的jsp页面,在此略去crud文件夹下的四个跳转jsp页面(addSuccess.jsp等),重点是crud.jsp页面。内容如下:

<%

String path=request.getContextPath();

%>

添加数据

删除数据

查询数据

修改数据

步骤五、发布测试。

补充扩展,动态调用DMI:不使用method实现统一.我们在crud.xml中增加如下内容:

/crud/op.jsp

然后再在crud.jsp中定义如下链接:

添加数据

删除数据

查询数据

修改数据

注意查看上面的链接地址,它们都是针对op action,然后再加地上“!+CRUDAction中相应的方法名”,最后再写上.action即可以访问到统一页面op.jsp。这样做虽然能减少页面,但是由于它们实质用到的是同一个Action,所以这就意味着我们要使用的拦截器相同,相同的跳转result。实际中这种方式很少使用,在此略作了解。如果不想使用动态方法调用,我们可以通过常量来关闭,即在struts.xml中

增加如下配置:

扩展2:在CRUDAction中使用do。举例:我们在CRUDAction中增加一个新的方法,内容如下:public String doMain(){

return"success";

}

然后再在在crud.xml中增加如下内容:

/crud/main.jsp

注意:配置中method属性值是doMain中去掉do后M小写。然后再在crud.jsp中增加如下链接:

main页面

随后便可以访问到.../crud/main.jsp页面了。

8.使用ForwardAction实现页面屏蔽。

我们在jsp页面之间写链接总会是.../xxx.jsp,而如果我们想屏蔽掉具体的jsp,只需要所jsp页面配置成一个ForwardAction即可实现。示例如下:在根目录下有一个index.jsp主页,我们strtus.xml 中作如下配置:

/index.jsp

说明:如果没有未action指定class,默认就是ActionSupport类,如果没有为action指定method 属性,则默认执行execute方法,如果没有指定result的name属性,默认值为success。知道了这些再结合ActionSupport的源码就不难理解实现转发的原理了。

随后再在前面第7点扩展中用到的op.jsp中增加如下代码:

forward

最后再测试访问op.jsp,在op.jsp中页面中直接点链接便可以跳到index.jsp,观察地址栏发现此时跳到index页面是进行的服务器跳转,如果我们在上面的配置中的result增加type属性变成/index.jsp,实现的跳转就是客户端跳转。补充:像这种forward 形式的action实质是执行的ActionSupport 这个Action。因此配置它的result可以参看此类的api 文档,比如它常用的result name有:success、login、input等。

8.使用default-Action配置统一访问

default-action-ref,当访问没有找到对应的action时,默认就会调用default-action-ref指定的action.同样在上面的package中增加如下内容:

/other/error.jsp

上面一段内容就是说当我们访问的action不能被找到时便指向名为error的action中去,接着我们在下面配置了这个error Action。但是要注意,一个package内只配置一个,如果配置多个,就无法预测结果了. 此时我们只要输入.../myStruts2/luanFangWen.action这样的形式,它就会去访问这个默认的,通常我们会为它配置一个错误页面,以提示用户访问的页面不存在。在web开发中,我们还可以把这个默认的action访问配置成主页,这样当用户访问一些不存在的action时,总会跳到主页上去。

通过此配置,只要是访问一个不存在的action便会转向到.../other目录下的error.jsp页面。但是如果访问是其它的不存在资源则仍是报tomcat所标识的404错误,我们可以在web.xml中作如下配置:

404

/other/404error.jsp

这样配置后,访问错误页面将跳到.../other/404error.jsp页面中去。补充说明:如果我们用ie 访问时,如果选中了[工具][IE选项][高级][浏览][显示友好的http错误信息],则配置的错误页面将失效,因为找不到资源时会报HTTP404错误,而ie截取到此错误进行了它自身的友好处理,所以我们设置就失效。

小结Action

在struts2中一个普通的java类只要有public String execute()这样的方法都可以配置成一个Action,另外我们可以实现Action接口来使java类成为一个Action,但通常的做法是继承ActionSupport类,这也是以后的项目中惯用的方法,也是推荐的首选方法。与struts1.x不同的是:在struts2中每一个Action被请求访问时都会new出这个Action对象,所以Action本身不存在线程安全的问题。

9.使用通配符

建立struts2wildcard项目,此实例基本仿照前面前面第7点的实例改写而成。为了使用通配符,只需要改写配置文件即可。此实例未使用通配时的配置文件如下:

/user/addUser.jsp

/user/delUser.jsp

/user/queryUser.jsp

/user/updateUser.jsp

我们注释掉上面的配置,使用通配符只需如下内容即可达到相同的效果:

/user/{1}User.jsp

原理:当有.../addUser.action请求时,如果不能在当前应用中找到完全相同的addUser名字的Action 时,通配符配置这时就起作用了,按通配原则,它便和上面的name="*User"相配成功,这里不难明了*此时代指的内容是add,再来看method恰恰是引用第一个*的内容,所以它的method此时的完整名为addUser,它刚好和com.asmUserAction中的addUser方法相对,所以它会去addUser方法,再来看下面的result配置所指代的页面,它也用到了{1},所以它的完整页面是/addUser.jsp。其实如果我们有良好的编程命名习惯,所有的Action我们都只需要进行一次配置。举例:规定所有的Action类都用XXXAction 来命名,类中所有的CRUD方法都用add/del/update/query。Jsp页面也用add/del/update/query_XXX.jsp 这样的形式。即配置文件可以写成如下形式:

.../{1}_{2}.jsp

Name中第一个*代表CRUD操作的名字,第二个*代表类的名字。所以访问链接地址举例如下:.../del_User.action将访问到User类的del方法,成功后跳到del_User.jsp页面。补充说明{0}是代表name 中所有的*组合。

10.使用0配置:ZERO Annotation

11.Result配置详解

说明:在前面的许多案例中我们所用到的Action基本都继承自ActionSupport这个类,而在这个类中我们定义了五个字段:SUCCESS,NONE,ERROR,INPUT,LOGING。我们可以直接返回这些字段值,这些字段值实质是被定义成:String SUCCESS=”success”这样的形式,所以我们只要在Result元素中用它们的小写即可。

标准完整形式如下:

/default.jsp

如果我们都采用默认的形式,最终可以简写成:/default.jsp

探讨type类型:

Type类型值作用说明对应类

chain 用来处理Action链com.opensymphony.xwork2.ActionChainResult dispatcher用来转向页面,通常处理JSP org.apache.struts2.dispatcher.ServletDispatcherResult redirect重定向到一个URL org.apache.struts2.dispatcher.ServletRedirectResult redirectAction 重定向到一个Action org.apache.struts2.dispatcher.ServletActionRedirectResult plainText显示源文件内容,如文件源码org.apache.struts2.dispatcher.PlainTextResult freemarker处理FreeMarker模板org.apache.struts2.views.freemarker.FreemarkerResult httpheader控制特殊http行为的结果类型org.apache.struts2.dispatcher.HttpHeaderResult

stream

向浏览器发送InputSream对

象,通常用来处理文件下载,

还可用于返回AJAX数据。

org.apache.struts2.dispatcher.StreamResult

velocity处理Velocity模板org.apache.struts2.dispatcher.VelocityResult xslt 处理XML/XLST模板 org.apache.struts2.views.xslt.XSLTResult

以上对type类型作简要的说明,下面来看实例:当一个Action处理后要返回的Result是另一个Action 时,作如何配置,关键就是配置type类型。下面建立struts2result项目说明

步骤一:建立两个Action:TestAction、Test2Action

步骤二:web.xml配置省略。struts.xml主要配置内容如下:

test2

/test2Suc.jsp

说明:在名为“test ”的action 中,我们配置result 元素的type 类型值为chain ,意为将继续把Action 传递到下一个名为test2的Action 中去,在test2.action 中会把页面转向到test2Suc.jsp 中去。在type 类型为chain 时,它的param 有4个值可配,除了这里用到的name=”actionName ”外(必须配置,否则报错),还有name=namespace|method|skipActions 。其中namespace 指定要转向到action 的名字空间,由于此处是转到Action 位于同一个namespace 下,而namesapace 的默认值the current namespace ,所以可以省略不写(需要说明的是如果要跳到别的名称空间的action 中去,除了使用namespace 指定外,还可以用:/要跳去action 所在名称空间的值/要跳去的action 的name 值)。Method 用于指定转向到一个目标action 所调用的方法,默认是调用下一个action 的execute 方法,所以此处仍可以省略。SkipActions 是一个可选的属性,一般不用。具体可以参看chain 所对应类的api 帮助。

在本实例中,我们还在TestAction 中设定一个username 字段,并在execute 方法执行为它赋了值,并在test2Suc.jsp 中引用了此值。其实这种做法在web 开发中还是很有用处,比如可以代替隐藏域。需要注意的是之所以在action 的传递中能把设定的这个值保存下去,主要是因为转向都是服务器跳转。如果我们跳转时采取了客户端跳转,比如在test2 action 的result 中指定type 类型为redirect ,要想传递参数可以在result 指向的jsp 页面中附加参数即可,我们可以在test2 action 的result 中写成:

/test2Suc.jsp?username=${username}

随后在test2Suc.jsp 页面中引用时会出现三个问题:1.EL 表达式引用失效,(EL 表达式

应该使用${https://www.360docs.net/doc/1c19052873.html,ername}形式)。我们也可以使用<%=request.getParameter("username")%>获取参数值。 2.由于在前面的TestAction 中设定的值为中文,而附加到这里的uri 请求的参数后面时会出现乱码问题。(可以使用URI 编码再解码解决此问题)3.值栈取值失效:因为每一次request 共享同一个值栈,所以服务器端的forward 跳转也是能共享同一值栈得。但是着当test action 执行后把请求交由test2 action 时,test2 action 采取的是redirect 重定向到test2Suc.jsp 页面,这时其实就是重发的一次request,所以在test action 保存的值栈内容全部失效。这也就是为什么我们要附加参数的原因。而参数是保存在actionContext 中,所以采用了#的方式来取出值。图示说明:

步骤三,编写链接页面index.jsp 。发布测试:

test.action

test2

/test2Suc.jsp?username=${username}

test2.action

同一个 context map

result tyep: chain

配置 test2Suc.jsp

创建新的 context map

从新的context map 中取值

result tyep: redirect

如果我们所有的action均有可能跳到相同的页面,则不防使用全局result。为了方便引用我们专门建立一个package来存放公共的result。在会用到个全局的跳转时,只需要把继承自这个公共的package即可。建立公共包,代码如下:

/error.jsp

由于它下面没的action配置,所以我们可以像默认的struts-default包一样,声明abstract=true,这样声明表示此packgage下不会有action,它一般是用来让别的package继承。随后再在要用到全局result中引用这个公共的package。代码如下:

这样操作相当于把全局的result加到了此package下的所有action中去。

动态Result:了解

步骤一:建立DynaAction,主要代码如下:

package com.asm;

public class DynaAction extends ActionSupport {

private String username;

private String nextAction;

public String execute() throws Exception {

if (username.equals("admin")) {

nextAction = "admin";

} else if (username.equals("user")) {

nextAction = "user";

} else {

nextAction = ERROR;

}

return SUCCESS;

}

...省略get/set方法

}

步骤二、建立jsp页面dyna.jsp,主要是为了向DynaAction中传递username参数。

步骤三、相关配置如下:

${nextAction}

/admin.jsp

相关文档
最新文档