本文摘自 李刚 《Java EE 企业应用实战》
实现了Action处理类之后,就可以在struts.xml文件中配置该Action了。所谓配置Action就是指定让struts2的哪个Action处理哪个请求,也就是完成用户请求和Action之间的关系。我们可以认为struts2的基本“程序单位”。
一. 包
Struts2使用包来组织Action,因此,将Action定义在包定义下完成,定义Action通过使用package下的action子元素来完成,而每个package元素配置一个包。
Struts2框架中的核心组件就是Action和拦截器,Struts2框架使用包来管理Action和拦截器等,每个包就是多个Action、多个拦截器、多个拦截器引用的集合。
配置package元素是必须指定name属性,这个属性是引用该包的唯一标识,除此之外,还可以指定一个可选的extends属性,extends属性必须是另一个包的name属性。指定extends属性表示让该包继承另一个包,子包可以从一个或者多个父包中继承到拦截器、拦截器栈、action等配置。
除此之外,Action2还提供了一种所谓的抽象包,抽象包的意义是该报不能包含Action的定义。为了显示指定一个包是抽象包,可以为该package元素增加一个abstract = "true"属性。
在struts.xml文件中,package 元素用于定义包配置,每个package元素定义一个包配置,定义package时可以指定如下几个属性:
(1) name: 这是一个必须的属性,该属性指定该包的名字,该名字是该包被其他包引用的key。
(2) extends: 该属性是一个可选属性,该属性指定该报继承其他包。继承其他包,就可以继承其他包中的Action定义、拦截器定义等。
(3) namespace: 该属性是一个可选属性,该属性定义该包的命名空间。
(4) abstract: 该属性是一个可选属性,他指定该包是否是一个抽象包,在抽象包中不能有package属性。
因为Struts2的配置文件时从上到下进行处理,所以父包应该在子包的前面定义。
下面是一个简单的struts.xml文件配置文件范例。在下面的struts.xml文件中配置两个包,其中名为default的包,继承了Struts2框架的默认包:struts-default。
<?xml version = "1.0" encoding = "UTF-8"?>
<!--下面是Struts2配置文件的DTD信息 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!--struts是struts2配置文件的跟元素 -->
<struts>
<!--配置第一个包,该包名为default,继承了struts-default-->
<!--package元素是struts配置文件的核心,该元素可以出现0次,或者是无限多次 -->
<package name="default" extends="struts-default">
<!--下面定义了拦截器部分-->
<!--以下的该元素可以出现,也可以不出现,但最多出现1次 -->
<interceptors>
<!--定义拦截器栈-->
<!--下面的元素可以出现0次,也可以出现无限多次 -->
<interceptor-stack name="crudeStack">
<!-- 下面的元素必须出现,可以出现无数多次 -->
<interceptor-ref name="params" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<!-- 下面的元素可以出现0次,也可以出现无限多次 -->
<default-action-ref name="showcase" />
<!--定义一个Action,该Action直接映射到showcase.jsp页面-->
<action name="showcase" class="" method="" convertor="">
<!-- 下面的元素可以出现0次,也可以出现无限多次 -->
<param name="参数名">参数值</param>
<!-- 下面的元素可以出现0次,也可以出现无限多次 -->
<result>showcase.jsp</result>
</action>
<!--定义一个Action,该Action类为lee.DateAction-->
<action name="Date" class="lee.DateAction">
<result name="success">/date.jsp</result>
</action>
</package>
<!--定义一个名为skill的包,该包直接继承default的包-->
<package name="skill" extends="default" namespace="/skill">
<!--定义默认的拦截器引用-->
<default-interceptor-ref name="crudeStack" />
<!--定义一个名为Edit的Action,该Action对应的处理类是lee.SkillAction-->
<action name="edit" class="lee.SkillAction">
<result>/empmanager/editskill.jsp</result>
<interceptor-ref name="params" />
<interceptor-ref name="basicStack" />
</action>
<!--定义一个名为Save的Action ,该Action对应的处理类lee.SkillAction,使用skill方法作为处理方法-->
<action name="Save" class="lee.SkillAction">
<result name="input">/empmanager/editSkill.jsp</result>
<result name="redirect">edit.action?skillName=${currentSkill.name}
</result>
</action>
</package>
</struts>
上面的struts.xm文件中第一个package中定义继承了一个struts-default父包,那这个父包位于何处呢?其实它位于struts核心jar包struts2-core-2.x.x.jar文件中,只要解压该文件就能看到一个struts-default.xml文件。
从上面的配置片段就可以看出,struts2-core-2.x.x.jar里已经定义了struts-default抽象包,该包下包含了大量的结果类型定义、拦截器定义、拦截器引用定义等,这些定义是配置普通Action的基础,所以开发者的package通常应该继承于struts-default包。
注意:实际上所有struts2插件文件都会提供一个struts-plugin.xml文件,而不同的struts-plugin.xml文件会定义另一个抽象包,用于被需要使用该插件的开发者继承,所以如果我们使用struts2中的某个插件时,可能需要用到struts插件文件中的包。
二. 命名空间
从前面的内容可知,每定义一个package元素时,都可以指定一个namespace属性,用于指定该包对应的命名空间。
Struts2只所以提供命名空间的功能,主要是为了处理同一个web应用中包含同名的Action的情形,Struts2以命名空间方式来管理Action,同一个命名空间中不能有相同的Action,不同的命名空间中可以有不同的Action。
Struts2不支持为单独的Action设置命名空间,而是通过包指定namespace属性来为包下面的所有Action指定共同的命名空间。如果配置package时没有指定namespace属性,那么包下的所有Action处于默认的包空间下。
下面用一个应用示例来说明Struts2的命名空间的用法。看下面的struts.xml文件中的代码这份配置文件中配置两个package,并为后一个package指定了命名空间为/book。
<?xml version = "1.0" encoding = "UTF-8"?>
<!--下面是Struts2配置文件的DTD信息 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!--struts是struts2配置文件的跟元素 -->
<struts>
<!--配置国际化资源常量,指定国际化资源文件的baseName为messageResource-->
<!--下面的元素可以出现0次,也可以出现无限多次 -->
<constant name="struts.custom.i18n.resource" value="messageResource"/>
<!--配置名为lee的包,该包继承了struts2的默认包,没有指定命名空间,将使用默认命名空间-->
<!--package元素是struts配置文件的核心,该元素可以出现0次,或者是无限多次 -->
<package name="lee" extends="struts-default">
<!--配置一个名为Login的Action-->
<action name="login" class="lee.LoginAction">
<result name ="input">/login.jsp</result>
<result name ="error">/error.jsp</result>
<result name = "success">/success.jsp</result>
</action>
</package>
<!--配置名为get的包,该包继承了struts2的默认包,指定该包的命名空间为/book-->
<!--package元素是struts配置文件的核心,该元素可以出现0次,或者是无限多次 -->
<package name="get" extends="struts-default" namespace = "/book">
<!--配置一个名为getBooks的Action-->
<action name="getBooks" class="lee.GetBooksAction">
<result name ="input">/login.jsp</result>
<result name = "success">/success.jsp</result>
</action>
</package>
</struts>
在上面的struts.xml配置文件,配置两个包:lee和get,配置get包时namespace属性配置包的命名空间属性为/books。
对于名为lee的包而言,该包没有指定namespace属性。如果该包没有指定namespace属性那么该包使用默认的命名空间,默认空间名总是" "。
当某个包指定了命名空间后,该包下所有的Action处理的URL应该是命名空间+Action名。以上面的代码中get包为例,该包下包含了名为getBooks的Action,该Action处理的URL为:
http://localhost:8080/namespace/book/GetBooks.action
注意:Struts2中的命名空间的作用等同于Struts1中的模块的作用,它允许以模块化的方式来组织Action。
除此之外,Struts2还可以显示指定根命名空间,通过设置某个包的namespace = "/"来指定根命名空间。
(1) 具体路径命名空间和默认命名空间
如果请求为/barspace/bar.action,系统首先查找/barspace命名空间里名为bar的Action,如果在该命名找到对应的Action,则使用该Action处理用户的请求;否则,系统将到默认的命名空间中查找名为bar的Action,如果找到对应的Action,则使用该Action处理用户的请求;如果两个命名空间里都找不到名为bar的Action,则系统将出现错误。
注意:默认的命名空间里的Action可以处理任何命名空间下的Action请求。意思就是说,如果存在URL为/barspace/bar.action的请求,并且/barspace的命名空间下没有名为bar的Action,则默认命名空间下名为bar的Action也会处理用户的请求。但是根命名空间下的Action只处理根命名空间下的请求,这就是根命名空间和默认命名空间的区别。
(2) 根命名空间和系统默认命名空间
如果请求为/login.action,系统会根据根命名空间("/")中查找名为login的Action,如果在根命名空间中找到了名为login的Action,则该Action处理用户的请求;否则系统将转为在默认命名空间中寻找名为login的Action,如果默认的命名空间中有名为login的Action,则由该Action处理用户的请求。如果两个命名空间中都找不到名为login的Action,那么系统将出现错误。
注意:命名空间只有一个级别。如果请求的URL是/bookservice/search/get.action系统将先在/bookservice/search的命名空间下查找名为get的Action,如果在该系统命名空间内找到名为get的Action,则由该Action处理该用户的请求;如果在该命名空间中没有找到名为get的Action,系统将直接进入默认的命名空间中查找名为get的Action,而不会在bookservice的命名空间下查找名为get的Action。