2.5 程序文件详解
流程清楚后,Struts 2运行的纵向概念就清楚了,下面详细讲解横向知识。主要包括Struts 2中的Action、结果类型、struts.xml及struts.properties。
2.5.1 Action类应用详解
从2.3 节的例子中的LoginAction类中可以看出,Struts 2 的Action可以是一个简单的POJO(Plain Ordinary Java Object)类,但其实在实际应用中一般的自定义的Action类都会继承Struts 2框架提供的ActionSupport类,下面具体介绍该类。
1.使用ActionSupport
继承ActionSupport类能够帮助程序员更好地完成一些工作,它实现了5 个接口并包含了一组默认的实现。如果编程中想要用到该类提供的某些功能,只要重写它提供的方法就可以了,例如,要实现验证功能,只需在自定义Action类中重写validate()方法即可。
public class ActionSupport implements Action,Validateable,ValidationAware, TextProvider,LocaleProvider,Serializable{ }
从上面的代码中可以看出ActionSupport实现了5个接口。下面简要介绍这5个接口。
(1)Action接口:该接口提供了5个常量及一个execute()方法。代码如下:
public interface Action{ public static final String SUCCESS="success"; public static final String NONE="none"; public static final String ERROR="error"; public static final String INPUT="input"; public static final String LOGIN="login"; public String execute()throws Exception; }
如果Action类继承了ActionSupport类,就可以直接应用这几个常量,比如在2.3 节例子中的Action的代码:
package org.action; public class LoginAction{ ... public String execute(){ return"success"; //不做任何判断直接返回“success” } }
就可以改为:
package org.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport{ ... public String execute(){ return SUCCESS; //不做任何判断直接返回“success” } }
两者具有同样的效果。因为这几个是在程序中经常用到的,所以Struts 2框架提供了这几个常量,如果有需要,完全可以自定义返回值,只要在“struts.xml”的结果中对应就可以了。
(2)Validateable接口:该接口提供了一个validate()方法用于校验表单数据,在实际应用中只要在Action类中重写该方法即可。例如2.3 节例子中,并没有对填入的数据进行任何判断,即使用户未输入任何内容,提交后也会跳转到欢迎界面,在一般情况下是不会允许的。这时就可以在Action类中重写validate()方法,然后在该方法中对取得的数据进行判断,如果为空或其他不允许的情况就可以保存错误信息。该方法是在执行execute()方法之前执行的。
(3)ValidationAware接口:该接口定义了一些方法用来对Action执行过程中产生的信息进行处理。例如,该接口中提供了addFieldError(String fieldname,String errorMessage)方法用来在验证出错时保存错误信息。
(4)TextProvider接口:该接口中提供了一系列getText()方法,用于获得对应的国际化信息资源。在Struts 2中的国际化信息资源都是以key-value对出现的,通过使用该接口中的getText()方法可以用key来获得相应的value值(国际化内容会在国际化部分讲解)。
(5)LocaleProvider接口:该接口提供了一个getLocale()方法,用于国际化时获得语言/地区信息。
2.Action传值
在2.3节例子中的LoginAction代码如下:
package org.action; public class LoginAction{ private String username; private String password; public String getUsername(){ return username; } public void setUsername(String username){ this.username=username; } public String getPassword(){ return password; } public void setPassword(String password){ this.password=password; } public String execute(){ return"success"; } }
其中有两个属性“username”和“password”,并且生成了它们的get和set方法。其实在运行login.jsp的时候,Struts 2框架会根据页面的文本框名在Action类中寻找其set方法来对其进行赋值,例如,页面的文本框为“username”的字段就会直接在Action类中找相应的setUsername(String username)方法为其赋值,而不是找其对应的在Action类中的属性“username”,所以在Action类中的属性名不一定要和页面中的文本框名相对应,但是在Action类中必须是页面的文本框名对应的set和get方法,而不是Action类中属性的get和set方法。也就是说,在Action类中,username属性可以不叫username,可以叫“name”或其他,但是里面必须有页面的文本框名“username”对应的setUsername()方法,而不是setName()方法。但一般情况下,程序员都会把它们统一起来,让Action类中的属性就对应页面中的输入框名,这样会方便很多。
前面这种传值方式称为字段传值方式,如果一个表单中字段比较多,而在Action中就要写很多字段,若在不同的Action中都要用到就要重复写,这样就会很麻烦,也不利于维护,所以Struts 2框架提供了另一种传值方式即模型传值方式。使用该传值方式首先要把字段封装成一个类,并生成其get和set方法,就是通常说的JavaBean了。如上例可把“username”和“password”封装成一个“User”类,代码如下:
package org.model; public class User{ private String username; private String password; public String getUsername(){ return username; } public void setUsername(String username){ this.username=username; } public String getPassword(){ return password; } public void setPassword(String password){ this.password=password; } }
然后在Action中就可以改变写法:
package org.action; public class LoginAction{ private User user; public User getUser(){ return user; } public void setUser(User user){ this.user=user; } public String execute(){ return SUCCESS; } }
可以发现,这样简单了很多。还要注意的是,传值页面也就是JSP页面(这里就是login.jsp页面)的“属性名”也要做小小的修改,要把以前的“属性名”改为“模型对象名.属性名”,例如这里要把以前的“<input type="text" name="username"/>”中的“username”及“<input type="password" name="password"/>”中的name值“password”修改为“user.username”和“user.passoword”,而欢迎界面的取值也要相应地修改为“user.username”。这样修改后,再重新启动Tomcat服务器,运行项目会得到相同的结果。
注意:当项目的“.java文件”或者一些配置文件如“*.xml”经过修改后,一定要重新启动Tomcat服务器,而若修改了JSP页面则只需刷新页面即可。
3.在Action类中访问Servlet API
学过Struts 1.x的都知道,Struts 1.x的Action类中的方法有4 个参数,其中有两个是“request”及“response”,而Struts 2中却没有与任何的Servlet API关联,这样大大降低了程序的耦合性,但是有时候在写程序时需要用到Servlet的一些API,例如“request”、“response”、“application”、“session”等。Struts 2 提供了两种方式来访问Servlet API:一种是通过ActionContext访问Servlet API,另一种是通过实现*Aware()接口来获得。
(1)通过ActionContext访问:ActionContext类提供了一个静态的getContext()方法来获得ActionContext对象,然后根据其对象来获得一些Servlet API的对象。例如:
ActionContext ac=ActionContext.getContext(); //获得ActionContext对象 Map session=ac.getSession(); //获得session对象 Map application=ac.getApplication(); //获得application对象 Map request=ac.get(); //获得request对象
大家可能有些奇怪,这些方法得到的都是Map类型,而不是要求的“HttpSession”或“Application”,其实Struts 2把Map对象模拟成了“HttpSession”等对象,从而将Servlet从Action中分离出来。
由于“request”和“response”比较特殊,也是在开发中经常会用到的,所以Struts 2提供了专门的类来获取,即“ServletActionContext”。
HttpServletRequest request=ServletActionContext.getRequest(); //获得HttpServletRequest对象 HttpServletResponse response=ServletActionContext.getResponse(); //获得HttpServletResponse对象 HttpSession session=request.getSession(); //获得HttpSession对象
除了这种方法外,还可以用如下方法得到:
ActionContext ac=ActionContext.getContext(); //获得HttpServletRequest对象 HttpServletRequest request=(HttpServletRequest)ac.get(ServletActionContext.HTTP_REQUEST); //获得HttpServletResponse对象 HttpServletResponse response=(HttpServletResponse)ac.get(ServletActionContext.HTTP_RESPONSE); //获得HttpSession对象 HttpSession session=request.getSession();
(2)通过实现*Aware接口获得:Struts 2中提过了一系列的*Aware接口,如表2.1所示。
表2.1 *Aware接口及获得对象方法
例如要获得Application对象,Action类就可以如下编写:
import java.util.Map; import org.apache.struts2.interceptor.ApplicationAware; public class TestApplication implements ApplicationAware{ private Map application; public void setApplication(Map application){ this.application=application; } public String execute()throws Exception{ //...其他内容,这里可以直接应用application } }
4.Action类中返回多个结果
在一个Action类中,有时会返回多个结果,例如判断一件事情,如果为真就返回SUCCESS,否则就返回ERROR(或"error")。在2.4 节的例子中,没有对输入的“username”和“password”做任何判断,现在对其进行判断,然后返回不同结果。
public String execute(){ if(user.getUsername().equals("李方方")&&user.getPassword().equals("123456")){ return SUCCESS; }else{ return ERROR; } }
这里判断如果输入的姓名为“李方方”且密码为“123456”就返回成功,然后根据配置文件的返回跳转到欢迎界面,如果两者有一个不符合就返回错误页面,所以还要在“struts.xml”配置文件中配置返回错误时跳转的页面,比如:
<action name="login"class="org.action.LoginAction"> <result name="success">/welcome.jsp</result> <result name="error">/login.jsp</result> </action>
这里设置如果返回错误跳转到登录界面。当然,在方法中可以返回很多的值(可以为任意字符串),但不管返回什么值,都要在配置文件中进行对应,而且不能返回两个或几个结果相同的值。对于继承了ActionSupport的Action类可以返回前面提到的5个常量,该5个常量对应的字符串值前面已经讲过,这里不再赘述。
5.Action类中定义多个方法
大家可以想象这样一种情况:有一个用户登录,定义了一个LoginAction类,如果现在程序还需有一个注册功能,是否还要定义一个RegistAction类呢?显然这样是可以的,但并不是最好的办法。如果程序中功能越来越多,那就要定义越来越多的Action类,所以一般不采取这样的方法,而是利用把相关的功能定义在同一个Action类中,这样Action类就会有多个方法来实现不同的功能。
例如,在TestAction类中定义两个方法:
import com.opensymphony.xwork2.ActionSupport; public class TestAction extends ActionSupport{ private String username; private String password; public String login()throws Exception{ if(username.equals("程明")){ return"login"; } else{ return ERROR; } } public String regist()throws Exception{ return"regist"; } }
这里暂时列举在Action类中定义不同方法,并没有说明请求时如何映射到具体的方法,不同的请求怎么对应相应的处理方法会在下节的action配置中讲解。
2.5.2 <action>配置详解
Struts 2的核心功能是Action。对于开发人员来说,使用Struts 2框架,主要的编码工作就是编写Action类。当开发好Action类后,就需要配置Action映射,以告诉Struts 2框架,针对某个URL的请求应该交由哪一个Action进行处理。这就是struts.xml中action配置要起的作用。在2.3节例子中:
<action name="login"class="org.action.LoginAction"> <result name="success">/welcome.jsp</result> </action>
上例表示请求名为“login”的请求,交由“org.action.LoginAction”这个类来处理,返回结果为“success”时就跳转到“welcome.jsp”页面。
1.<action>属性
<action>有以下属性:
name:该属性是必需的,对应请求的Action的名称。
class:该属性不是必需的,指明处理类的具体路径,例如“org.action.LoginAction”。
method:该属性不是必需的,若Action类中有不同的方法,该属性指定请求对应应用哪个方法。
converter:该属性不是必需的,指定Action使用的类型转换器(类型转换内容会在类型转换部分讲解)。
在一般情况下,都会为<action>设置name和class属性,如果没有设置method属性,系统会默认调用Action类中的execute方法。若在Action中存在多个方法,请求其某个方法的时候就要通过这里的method属性来指定所请求的方法名。例如在2.5.1节中的第5点的Action类中有login和regist两个方法,如果要在请求中应用login方法,就要在相应的action中配置method属性:
<action name="login"class="org.action.LoginAction"method="login">
...
</action>
黑体部分就是要配置的指定的方法,表示应用LoginAction类中的login方法,如果是:
<action name="login"class="org.action.LoginAction"method="regist">
...
</action>
就应用LoginAction类中的regist方法。
2.在<action>中应用通配符
前面讲过,可以在<action>中指定method属性来决定应用Action类中的哪个方法,但这样有些麻烦,应用两个不同的方法就要配置两个<action>,Struts 2中提供了通配符的使用,可以应用通配符只配置一个Action就可以根据通配符来识别应用Action类中的哪个方法。
<action>配置要修改为:
<action name="*"class="org.action.LoginAction"method="{1}"> ... </action>
其中“{1}”就是取前面的“*”的值。例如,如果要应用Action类中的login方法,请求就为:
<form action="login.action"method="post"> ... </form>
这样用请求中“login”与action配置中的“*”匹配,得出“*”为“login”,<action>中method的值就为“login”,也就是应用Action类中的login方法。如果要应用regist方法,请求为:
<form action="regist.action"method="post"> ... </form>
“regist”就会与“*”匹配,得出“*”为“regist”,则<action>中method属性的值就为“regist”,就会应用Action类中的regist方法。
不仅方法可以使用通配符这样匹配,返回的值也可以。例如,如果应用login方法返回“error”时就让其跳转到“login.jsp”界面,而应用regist方法返回“error”时就跳转到“regist.jsp”界面。<action>配置修改为:
<action name="*"class="org.action.LoginAction"method="{1}"> ... <result name="error">/{1}.jsp</result> </action>
使用通配符可以很大程度地减少struts.xml的配置内容,但是可以发现,在编写时也会对Action类中的方法命名有限制,必须和请求名称对应,返回视图的名称也同样要对应。所以在实际开发中,可以根据实际情况来决定是否要使用通配符。
3.访问Action类中方法的其他实现方式
仍以前面的LoginAction为例,该例中有两个方法“login”和“regist”。首先访问login方法,<action>配置可以用正常情况,只需配置name和class:
<action name="login"class="org.action.LoginAction"> ... </action>
在<action>配置中完全不知道要访问LoginAction类中的哪个方法,但是需要在请求中指明,请求的form表单要改为:
<form action="login!login.action"method="post"> ... </form>
其中,“login!login.action”中“!”前面的“login”对应<action>中name属性值,“!”后面的“login”对应要使用的LoginAction类中的方法名。例如,如果要使用该类中的regist方法,只需将请求改为:
<form action="login!regist.action"method="post"> ... </form>
该方法是在请求中指定应用Action类中的哪个方法,还有一种方法是在提交按钮中设置的,<action>不用做任何改变,不过提交按钮需要用Struts 2的标签来实现,并且要指定method:
<form action="login.action"method="post"> ... <s:submit value="登录"method="login"></s:submit> <s:submit value="注册"method="regist"></s:submit> </form>
该form中有两个按钮,一个是登录按钮,另一个是注册按钮,分别都指定了它们各自要用的方法,不会产生冲突。这里大家只要知道这种方法就行了,Struts 2的标签库内容会在后面专门讲解。
4.使用默认类
如果未指明class属性,则系统将会自动引用<default-class-ref>标签中所指定的类,即默认类。在Struts 2中,系统默认类为ActionSupport,当然也可以自己定义默认类,例如:
<package name="default"extends="struts-default">
<default-class-ref class="org.action.LoginAction"></default-class-ref>
<action name="login">
...
</action>
<action name="regist">
...
</action>
</package>
上面代码中定义了默认类,则在两个没有指定class属性的请求中都会应用该默认类,若指定了自己的class属性,则默认类在该action中将不起作用。
2.5.3 <result>配置详解
<result>是为Action类的返回值指定跳转方向的,在Struts 2框架中,一个完整的<result>配置为:
<result name="Action类对应返回值"type="跳转结果类型"> <param name="参数名">参数值</param> </result>
<result>包含两个属性name和type。name属性与Action类中返回的返回值进行匹配,type属性指定了将要跳转的结果类型,在实际应用中不一定都要跳转到一个页面,有可能会从一个action跳转到另一个action,这时就要指定type属性。<param>是为返回结果设置参数的。
Struts 2中支持多种结果类型,在下载的Struts 2的struts-default.xml文件中可以找到所有的支持类型,该文件的位置在“struts-2.0.14\src\core\src\main\resources”下,打开该文件可以发现下面的代码:
<result-types> <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult"default="true"/> <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/> <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/> <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/> <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/> <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/> <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult"/> <result-type name="redirect-action" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <result-type name="plaintext" class="org.apache.struts2.dispatcher.PlainTextResult"/> </result-types>
下面简要介绍这些类型的作用范围。
● chain:用来处理Action链。
● chart:用于整合JFreeChart的结果类型。
● dispatcher:用来转向页面,通常处理JSP,该类型也为默认类型。
● freemaker:处理FreeMarker模板。
● httpheader:控制特殊http行为的结果类型。
● jasper:用于JasperReports整合的结果类型。
● jsf:JSF整合的结果类型。
● redirect:重定向到一个URL。
● redirect-action:重定向到一个Action。
● stream:向浏览器发送InputStream对象,通常用来处理文件下载,还可用于返回AJAX数据。
● tiles:与Tiles整合的结果类型。
● velocity:处理Velocity模板。
● xslt:处理XML/XSLT模板。
● plaintext:显示原始文件内容,例如文件源代码等。
其实,<result>的两个属性都有默认值,如果没有指明就是默认值,name属性的默认值为“success”,type属性的默认值为“dispatcher”,就是跳转到JSP页面。下面详细讲解几个常用的结果类型。
1.dispatcher类型
该结果类型是默认的结果类型,从“struts-default.xml”中也可以看出,其定义为“default="true"”。定义该类型时,物理视图为JSP页面,并且该JSP页面必须和请求信息处于同一个Web应用中。还有一点值得注意的是,请求转发时地址栏不会改变,也就是说,属于同一请求,所以请求参数及请求属性等数据不会丢失,该跳转类似于JSP中的“forward”。从前面的例子中也可以看出,跳转到“welcome.jsp”页面后,仍可以取出“username”的值。在应用该类型时,一般都会省略不写。配置该类型后,<result>可以指定以下两个参数。
● location:指定请求处理完成后跳转的地址,例如“/welcome.jsp”。
● parse:指定是否允许在location参数值中使用表达式,例如“/welcome.jsp?username=${username}”,在实际运行时,这个结果信息会替换为用户输入的“username”值,该参数默认值是true。
2.redirect类型
该结果类型可以重定向到JSP页面,也可以重定向到另一个Action。该类型是与dispatcher类型相对的,当Action处理用户请求结束后,将重新生成一个请求,转入另一个界面。例如在2.3 节的例子中,当用默认值“dispatcher”时,请求完成,转向“welcome.jsp”界面,如图2.12所示。
图2.12 dispatcher类型时的跳转界面
可以发现,请求没变,还是“login.action”,但页面已经跳转到“welcome.jsp”,并且可以取出“username ”的值。如果把< result>中的内容改为:
<result name="success"type="redirect">/welcome.jsp</result>
则请求完成,转向“welcome.jsp”界面,如图2.13所示。
图2.13 redirect类型重定向的界面
可以看出,转向已经变为“welcome.jsp”界面,而且数据已经不能取出,表明请求参数及请求属性等数据已经丢失。
配置redirect类型后,<result>也可指定location和parse两个参数。
3.redirect-action类型
该结果类型与redirect类似,都是重定向而不是转发,该类型一般都为了重定向到一个新的action请求,而非JSP页面。配置该类型时,<result>可以配置如下两个参数。
● actionName:该参数指定重定向的action名。
● namespace:该参数指定需要重定向的action所在的命名空间(命名空间会在后面讲解)。
注意:这些参数是可选配置的,不是必需的,在实际情况中可以根据需要配置。
看下面一段代码:
...
<package name="test1"extends="struts-default">
<action name="regist"class="org.action.LoginAction"method="regist">
<result name="success"type="redirect-action">
<param name="actionName">login</param>
<param name="namespace">/test2</param>
</result>
</action>
</package>
<package name="test2"extends="struts-default"namespace="/test2">
<action name="login"class="org.action.LoginAction"method="login">
<result name="success">/welcome.jsp</result>
</action>
</package>
...
上面代码就是redirect-action类型应用的体现。首先对“test1”包中的“regist”进行请求,通过LoginAction类中的regist方法来处理请求,完成后用redirect-action结果类型来重新定向到“test2”包中的“login”,然后用LoginAction类中的login方法处理,完成后跳转到“welcome.jsp”页面,由于“test2”包指定了命名空间“namespace”,所以必须配置参数指定:
<param name="actionName">login</param> <param name="namespace">/test2</param>
分别指定重定向的action名及该action所在的命名空间。
4.chain类型
前面的redirect及redirect-action虽然都可以重定向到另外的action,但是它们都不能实现数据的传递,在重定向过程中,请求属性等都会丢失,这样有的时候就不利于编程了。所以,Struts 2又提供了另一种结果类型“chain”,用来实现action之间的跳转,而非重定向,意思就是可以跳转到另外的action而且数据不丢失,通过设置chain类型,可以组成一条action链,不用担心数据的丢失,这样就大大方便了编程。action跳转可以共享数据的原理是处于同一个action链的action都共享同一个值栈,每个action执行完毕后都会把数据压入值栈,如果需要就可以直接到值栈中取出。
5.全局结果
从前面的例子中可以看出,<result>都是包含在<action>...</action>中的,这配置的是局部结果,只对当前action请求返回的结果起作用。假如都返回到同一页面,而且在不同的action请求中都会用到,那么配置局部结果就显得唆了。所以,Struts 2提供了全局结果的配置,例如,如果返回“error”,都跳转到错误页面:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="default"extends="struts-default"> <global-results> <result name="error">/error.jsp</result> </global-results> <action name="login"class="org.action.LoginAction"> ... </action> <action name="test2"class="org.action.TestAction"> ... </action> </package> </struts>
上面代码的黑体部分定义了一个全局结果,当用户请求处理完成以后,如果返回“error”,就会到当前action配置的返回中寻找,如果没有找到就会到全局结果中寻找。也就是说,局部结果配置的优先级大于全局结果。
2.5.4 <package>配置详解
从前面的例子也可以看出,Struts 2的action都是放在<package>…</package>中。package元素用于定义struts.xml中的包配置,<package>中可以定义action和拦截器等。用package定义包配置时可以指定下面几个属性。
1.name
该属性必须指定,代表包的名称,由于struts.xml中可以定义不同的<package>,而且它们之间还可以互相引用,所以必须指定名称。
2.extends
该属性是可选的,表示当前定义的包继承其他的包,继承了其他包,就可以继承其他包中的action、拦截器等。由于包信息的获取是按照配置文件中的先后顺序进行的,所以父包必须在子包之前被定义。
在一般情况下,定义包时都会继承一个名为“struts-default”的包,该包是Struts 2内置的,定义在struts-default.xml这个文件中。这个文件的位置在前面讲解<result>结果类型的时候已经说过,打开该文件找到这个包,可以发现该包下定义了一些结果类型、拦截器及拦截器栈,结果类型在前面已经讲解,拦截器会在后面详细讲解。
3.namespace
该属性是可选的,用来指定一个命名空间,例如在前面讲redirect-action类型时已经用到了,定义命名空间非常简单,只要指定“namespace="/*"”就行了,其中“*”是我们自定的,如果直接指定“"/"”,表示设置命名空间为根命名空间。如果不指定任何namespace,则使用默认的命名空间,默认的命名空间为“" "”。
当指定了命名空间后,相应的请求也要改变,例如:
<action name="login"class="org.action.LoginAction"namespace="/user"> ... </action>
请求就不能是“login.action”,而必须改为“user/login.action”。当Struts 2接收到请求后,会将请求信息解析为namespace名和action名两部分,然后根据namespace名在struts.xml中查找指定命名空间的包,并且在该包中寻找与action名相同的配置,如果没有找到,就到默认的命名空间中寻找与action名称相同的配置,如果再没找到,就给出错误信息。看下面的代码:
<package name="default"> <action name="foo"class="org.TestAction"> <result name="success">/foo.jsp</result> </action> <action name="bar"class="org.TestAction"> <result name="success">/bar.jsp</result> </action> </package> <package name="mypackage1"namespace="/"> <action name="moo"class="org.TestAction"> <result name="success">/moo.jsp</result> </action> </package> <package name="mypackage2"namespace="/barspace"> <action name="bar"class="org.TestAction"> <result name="success">/bar.jsp</result> </action> </package>
如果页面中请求为barspace/bar.action,框架将首先在命名空间为/barspace的包中查找bar这个action配置,如果找到了,则执行bar.action;如果没有找到,则到默认的命名空间中继续查找。在本例中,/barspace命名空间中有名为bar的Action,因此它会被执行。
如果页面中请求为barspace/foo.action,框架会在命名空间为/barspace的包中查找foo这个action配置。如果找不到,框架会到默认命名空间中去查找。在本例中,/barspace名称空间中没有foo这个action,因此默认的命名空间中的/foo.action将会被找到并执行。
如果页面中请求为moo.action,框架会在根命名空间“/”中查找moo.action,如果没有找到,再到默认命名空间中查找。
4.abstract
该属性是可选的,如果定义该包是一个抽象包,则该包不能包含<action>配置信息,但可以被继承。
<package>主要包含以上4个属性,<package>下面还可配置以下几个标签。
● <action>:action标签,其作用前面已经详细讲解。
● <default-action-ref>:配置默认action,如果配置了默认action,则若请求的action名在包中找不到与之匹配的名称就会应用默认action。
● <default-class-ref>:配置默认类。
● <default-interceptor-ref>:配置默认拦截器。
● <global-exception-mappings>:配置发生异常时对应的视图信息,为全局信息,与之对应还有局部异常配置,局部异常配置要配置在<action>标签中,局部异常配置用<exception-mapping>进行配置。配置异常信息格式如下:
<package name="default"extends="struts-default"> <global-exception-mappings> <exception-mapping result="逻辑视图"exception="异常类型"/> </global-exception-mappings> <action name="action名称"> <exception-mapping result="逻辑视图"exception="异常类型"></exception-mapping> </action> </package>
<exception-mapping>中可以指定3 个属性,分别为name:可选属性,用来标识该异常配置信息;result:该属性必须指定,指定发生异常时显示的视图信息,必须配置为逻辑视图;exception:该属性必须指定,用来指定异常类型。
● <global-results>:配置全局结果,前面已经讲述。
● <interceptors>:配置拦截器。
● <result-types>:配置结果类型。
拦截器知识会在拦截器部分讲解,读者这里做个了解即可。
2.5.5 struts.xml文件
Struts 2.0.14版本下的struts.xml的大体格式如下:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> ... </struts>
在该版本下,这个格式是不变的,前面是编码格式及一些头文件信息,接着是<struts>…</struts>,该文件中的其他配置都包含在其中。该标签下可以编写下面几个标签。
● include:用于导入其他xml配置文件。
● constant:配置一些常量信息。
● bean:由容器创建并注入的组件。
● package:配置包信息。
这几个标签可以并排编写在<struts>下,而其他一些配置大都配置在<package>中。由于package前面已经详细讲解,这里就不再讲述,而bean标签不常用,所以这节主要讲解其他两个标签。
1.<include>
在实际开发中,可能大多数情况下会把所有的配置信息都放在一个struts.xml文件下,但这仅限于一些小的项目。如果一个项目很大,需要的配置信息就会很多,有可能成千上万行的代码,这么大一个配置文件,无论是管理还是维护都是相当不容易的,所以这时就要“分而治之”,把不同方面的信息分别编写配置文件,例如在学生信息系统中,把学生信息的配置、课程信息的配置、成绩信息的配置分别放入各自的配置文件xs.xml、kc.xml和cj.xml中,然后再用Struts 2提供的<include>标签把它们导入到struts.xml中。
例如xs.xml为:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="xs"extends="struts-default"> <action name="addXs"class="org.action.XsAction"> ... </action> </package> </struts>
在struts.xml中导入应为:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <include file="xs.xml"></include> ... </struts>
这样就成功导入了。
注意:这里xs.xml也是放在classes文件夹下的,即在MyEclipse中直接放在src下即可,如果xs.xml放在其他包中,例如放在“xs”包中,那么struts.xml中引入的时候就要加上包名:
<?xml version="1.0"encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <include file="/xs/xs.xml"></include> ... </struts>
2.<constant>
<constant>是用来在struts.xml中定义属性的,例如设置编码形式、设置开发模式等。该标签里面有两个属性:name和value。例如,可以做下面的设置:
<struts> <!-- 设置开发模式 --> <constant name="struts.devMode"value="true"></constant> <!-- 设置编码格式GB2312--> <constant name="struts.il8n.encoding"value="GB2312"></constant> ... </struts>
其中,name的值均为Struts 2的常量信息,这些常量信息并不多,不仅可以在struts.xml中设置,还可以在Struts 2的另一个配置文件struts.properties中单独设置。下节将介绍该配置文件。
2.5.6 struts.properties文件
struts.properties文件是一个标准的properties文件,该文件中存放一系列的key-value对,每个key就是一个Struts 2属性,而其对应的value值就是一个Struts 2的属性值。struts.properties文件和struts.xml一样,要放在项目的classes文件夹下,Struts 2框架会自动加载该文件。
通常情况下,项目并不需要这个配置文件,因为Struts 2框架已经提供了一个默认的配置文件default.properties,但是在开发中,有时为了方便可以更改默认信息,这时就要应用struts.properties,把要修改的属性的key-value对放入其中,这样新的配置信息就会覆盖系统默认的值。struts.properties文件中所包含的所有属性都可以在web.xml配置文件中使用“init-param”标签进行配置,或者在struts.xml文件中使用“constant”标签进行配置。
下面介绍Struts 2中常量配置信息:
● struts.action.extension:该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts 2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。
● struts.configuration:该属性指定加载Struts 2配置文件的配置文件管理器。该属性的默认值是org.apache.Struts2.config.DefaultConfiguration,这是Struts 2默认的配置文件管理器。如果需要实现自己的配置管理器,可以编写一个实现Configuration接口的类,该类可以自己加载Struts 2配置文件。
● struts.configuration.files:该属性指定Struts 2框架默认加载的配置文件,如果需要指定默认加载多个配置文件,则多个配置文件的文件名之间以英文逗号(,)隔开。该属性的默认值为struts-default.xml,struts-plugin.xml,struts.xml。前面说过,Struts 2会自动加载struts.xml文件,这里就是最好的解释。
● struts.configuration.xml.reload:该属性设置当struts.xml文件改变后,系统是否自动重新加载该文件。该属性的默认值是false。
● struts.custom.i18n.resources:该属性指定Struts 2应用所需要的国际化资源文件,如果有多份国际化资源文件,则多个资源文件的文件名以英文逗号(,)隔开。
● struts.custom.properties:该属性指定Struts 2应用加载用户自定义的属性文件,该自定义属性文件指定的属性不会覆盖struts.properties文件中指定的属性。如果需要加载多个自定义属性文件,多个自定义属性文件的文件名以英文逗号(,)隔开。
● struts.devMode:该属性设置Struts 2应用是否使用开发模式。如果设置该属性为true,则可以在应用出错时显示更多、更友好的出错提示。该属性只接受true和flase两个值,该属性的默认值是false。通常,应用在开发阶段,将该属性设置为true,当进入产品发布阶段后,则该属性设置为false。
● struts.dispatcher.parametersWorkaround:对于某些Java EE服务器,不支持HttpServlet Request调用getParameterMap()方法,此时可以设置该属性值为true来解决该问题。该属性的默认值是false。对于WebLogic、Orion和OC4J服务器,通常应该设置该属性为true。
● struts.enable.DynamicMethodInvocation:该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false。
● struts.enable.SlashesInActionNames:该属性设置Struts 2是否允许在Action名中使用斜线,该属性的默认值是false。如果开发者希望允许在Action名中使用斜线,则可设置该属性为true。
● struts.freemarker.manager.classname:该属性指定Struts 2使用的FreeMarker管理器。该属性的默认值是org.apache.struts2.views.freemarker.FreemarkerManager,这是Struts 2内建的FreeMarker管理器。
● struts.freemarker.wrapper.altMap:该属性只支持true和false两个属性值,默认值是true。通常无须修改该属性值。
● struts.i18n.encoding:指定Web应用的默认编码集。一般当获取中文请求参数值时会将该属性值设置为GBK或者GB 2312。该属性默认值为UTF-8。
● struts.i18n.reload:该属性设置是否每次HTTP请求到达时,系统都重新加载资源文件(允许国际化文件重载)。该属性默认值是false。在开发阶段将该属性设置为true会更有利于开发,但在产品发布阶段应将该属性设置为false。开发阶段将该属性设置了true,将可以在每次请求时都重新加载国际化资源文件,从而可以看到实时开发效果。产品发布阶段将该属性设置为false,是为了提高响应性能,每次请求都重新加载资源文件会大大降低应用的性能。
● struts.locale:指定Web应用的默认Locale。
● struts.multipart.parser:该属性指定处理multipart/form-data的MIME类型(文件上传)请求的框架,该属性支持cos、pell和jakarta等属性值, 即分别对应使用cos的文件上传框架、pell上传及common-fileupload文件上传框架。该属性的默认值为jakarta。
注意:如果需要使用cos或者pell的文件上传方式,则应该将对应的JAR文件复制到Web应用中。例如,使用cos上传方式,则需要自己下载cos框架的JAR文件,并将该文件放在WEB-INF/lib路径下。
● struts.multipart.saveDir:该属性指定上传文件的临时保存路径,该属性的默认值是javax.servlet.context.tempdir。
● struts.multipart.maxSize:该属性指定Struts 2文件上传中整个请求内容允许的最大字节数。
● struts.mapper.class:指定将HTTP请求映射到指定Action的映射器,Struts 2提供了默认的映射器org.apache.struts2.dispatcher.mapper.DefaultActionMapper。默认映射器根据请求的前缀与<action>配置的name属性完成映射。
● struts.objectFactory:指定Struts 2默认的ObjectFactoryBean,该属性默认值是spring。
● struts.objectFactory.spring.autoWire:指定Spring框架的自动装配模式, 该属性的默认值是name,即默认根据Bean的name属性自动装配。
● struts.objectFactory.spring.useClassCache:该属性指定整合Spring框架时,是否缓存Bean实例,该属性只允许使用true和false两个属性值,它的默认值是true。通常不建议修改该属性值。
● struts.objectTypeDeterminer:该属性指定Struts 2的类型检测机制,支持tiger和notiger两个属性值。
● struts.serve.static:该属性设置是否通过JAR文件提供静态内容服务,该属性只支持true和false属性值,该属性的默认属性值是true。
● struts.serve.static.browserCache:该属性设置浏览器是否缓存静态内容。当应用处于开发阶段时,如果希望每次请求都获得服务器的最新响应,则可设置该属性为false。
● struts.tag.altSyntax:该属性指定是否允许在Struts 2标签中使用表达式语法,因为通常都需要在标签中使用表达式语法,故此属性应该设置为true,该属性的默认值是true。
● struts.url.http.port:该属性指定Web应用所在的监听端口。该属性通常没有太大的用户,只是当Struts 2需要生成URL时(例如Url标签),该属性才提供Web应用的默认端口。
● struts.ui.theme:该属性指定视图标签默认的视图主题,该属性的默认值是xhtml。
● struts.ui.templateDir:该属性指定视图主题所需要模板文件的位置,该属性的默认值是template,即默认加载template路径下的模板文件。
● struts.url.https.port:该属性类似于struts.url.http.port属性的作用,区别是该属性指定的是Web应用的加密服务端口。
● struts.url.includeParams:该属性指定Struts 2生成URL时是否包含请求参数。该属性接受none、get和all三个属性值,分别对应于不包含、仅包含GET类型请求参数和包含全部请求参数。
● struts.ui.templateSuffix:该属性指定模板文件的后缀,该属性的默认属性值是ftl。该属性允许使用ftl、vm或jsp,分别对应FreeMarker、Velocity和JSP模板。
● struts.velocity.configfile:该属性指定Velocity框架所需的velocity.properties文件的位置。该属性的默认值为velocity.properties。
● struts.velocity.contexts:该属性指定Velocity框架的Context位置,如果该框架有多个Context,则多个Context之间以英文逗号(,)隔开。
● struts.velocity.toolboxlocation:该属性指定Velocity框架的toolbox的位置。
● struts.xslt.nocache:该属性指定XSLT Result是否使用样式表缓存。当应用处于开发阶段时,该属性通常被设置为true。当应用处于产品使用阶段时,该属性通常被设置为false。
2.5.7 web.xml文件
在前面开发例子的过程中,首先就配置了web.xml,它是一个正规的xml文件,包括版本及编码信息,然后就是<web-app>标签。这里具体讲解在<web-app>里面配置的信息。
… <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> …
这里面配置了一个过滤器,那么就先来介绍过滤器的使用。
Filter过滤器是Java项目开发中的一种常用技术。过滤器是用户请求和处理程序之间的一层处理程序。这层程序可以对用户请求和处理程序响应的内容进行处理。过滤器可以用于权限控制、编码转换等场合。
Servlet过滤器是在Java Servlet规范中定义的,它能够对过滤器关联的URL请求和响应进行检查和修改。Servlet过滤器能够在Servlet被调用之后检查response对象,修改response Header对象和response内容。Servlet过滤器过滤的URL资源可以是Servlet、JSP、HTML文件,或者是整个路径下的任何资源。多个过滤器可以构成一个过滤器链,当请求过滤器关联的URL的时候,过滤器就会逐个发生作用。
所有过滤器必须实现java.Serlvet.Filter接口,这个接口中含有3个过滤器类必须实现的方法:
● init(FilterConfig):这是Servlet过滤器的初始化方法。Servlet容器创建Servlet过滤器实例后将调用这个方法。
● doFilter(ServletRequest,ServletResponse,FilterChain):这个方法完成实际的过滤操作。当用户请求与过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法,返回响应之前也会调用此方法。FilterChain参数用于访问过滤器链上的下一个过滤器。
● destroy():Servlet容器在销毁过滤器实例前调用该方法。这个方法可以释放Servlet过滤器占用的资源。
过滤器类编写完成后,必须要在web.xml中进行配置,格式如下:
<filter> <!-- 自定义的名称 --> <filter-name>过滤器名</filter-name> <!-- 自定义的过滤器类,注意,如果类放在指定包下,要加完整包名 --> <filter-class>过滤器对应类</filter-class> <init-param> <!-- 类中参数名称 --> <param-name>参数名称</param-name> <!-- 对应参数的值 --> <param-value>参数值</param-value> </init-param> </filter>
过滤器必须和特定的URL关联才能发挥作用,过滤器的关联方式有3种:与一个URL关联、与一个URL目录下的所有资源关联、与一个Servlet关联。
与一个URL资源关联:
<filter-mapping> <!-- 这里与上面配置所起的名称要相同 --> <filter-name>过滤器名</filter-name> <!-- 与该url资源关联--> <url-pattern>xxx.jsp</url-pattern> </filter-mapping>
与一个URL目录下的所有资源关联:
<filter-mapping> <filter-name>过滤器名</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
与一个Servlet关联:
<filter-mapping> <filter-name>过滤器名</filter-name> <url-pattern>Servlet名称</url-pattern> </filter-mapping>
通过上面的讲解,相信大家对web.xml文件中配置的内容已经很清楚了。Struts 2框架中的web.xml文件中配置的就是一个过滤器,其对应的类是Struts 2中的“org.apache.struts2. dispatcher.FilterDispatcher”,“url-pattern”指定为“/*”,表示该URL目录下的所有请求都交由Struts 2处理,这就把Web应用与Struts 2框架关联起来了。