Struts2的默认配置文件是struts.xml,它的最大作用就是配置Action和请求之间的对应关系,并配置逻辑视图名和物理视图资源之间的对应关系,除此之外,struts.xml文件还可以配置Bean、常量以及导入其他配置文件。

struts.xml是联系整个Struts2框架的纽带,通过配置文件将Struts2的核心控制器StrutsPrepareAndExecuteFilter、业务控制器Action以及视图等组件关联在一起,实现相应的功能。所以struts.xml对于Struts2的重要性不言而喻,这篇文章我就讲讲struts.xml。


1.常量

Struts2规定了一些特殊的对整个Struts2应用起作用的常量,通过配置这些常量,可以改变Struts2框架的一些默认行为。

Struts2可以在三种配置文件中对常量进行配置,分别为struts.xml,struts.properties,web.xml如果在不同的配置文件中配置了相同的常量,则会进行覆盖,常量加载顺序和覆盖顺序相反
(二)Struts2进阶之Struts2的常规配置_包

比如在struts.xml中配置了常量A,在web.xml中也配置了A,则web.xml中的A的值会覆盖struts.xml的值。

在struts.xml中使用<constant>标签配置常量。定义常量需要指定两个属性:name和value。

(1)在struts.xml中配置常量

<struts>
    <!-- 设置编码,默认为utf-8 -->
    <constant name="struts.i18n.encoding" value="utf-8"></constant>
</struts>

(2)在struts.properties中配置常量

struts.i18n.encoding = utf-8

(3)在web.xml中配置常量

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    <init-param>
        <param-name>struts.i18n.encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
  </filter>

关于struts2的常用常量,可以看这篇文章

ps:推荐在struts.xml中配置常量。在web.xml中配置会让web.xml显得很臃肿,降低可读性。如果配置的常量比较少,则可以在struts.xml中进行配置,便于集中管理,如果配置的常量比较多,则在struts.properties中进行配置,此时可以在web项目中结合使用struts.xml和struts.properties。


2.包

Struts2使用包来组织Action,包使用<package>标签进行定义,每个<package>标签定义了一个包配置。该标签常用属性如下

属性 功能
name 指定包的名字,该属性是必须的。
extends 指定包继承的其他包,即继承了其他包中的Action。拦截器等定义,该属性是可选的。
namespace 指定包的命名空间,该属性是可选的。
abstract 指定包是否的一个抽象包,抽象包中不能包含Action定义,该属性是可选的。

在struts.xml中配置包的示例代码如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <!-- 设置编码,默认为utf-8 -->
    <constant name="struts.i18n.encoding" value="utf-8"></constant>
    <!-- 指定Struts2处于开发阶段,可以进调试 -->
    <constant name="struts.devMode" value="true"></constant>

    <!-- Struts2的Action都必须配置在package里,此处使用默认package -->
    <package name="default" namespace="/" extends="struts-default">
        <!-- 定义一个名为user的action,实现类为 com.codeliu.action.UserAction-->
        <action name="user" class="com.codeliu.action.UserAction">
            <!-- result的name和Action类的execute方法的返回值一一对应,区分大小写 -->
            <!-- result标签指明execute方法的返回值和资源视图的映射关系,转向的资源可以是jsp或者另一个action或者其他 -->
            <result name="success">/success.jsp</result>
            <result name="error">/error.jsp</result>
        </action>
    </package>
</struts>

上述代码配置了一个名为default的包,该包继承struts-default包。struts-default是Struts2的默认抽象包,该包下包含大量的结果类型定义、拦截器及引用定义等,这些定义时配置Action的基础,因此定义包时通常继承struts-default包。

注意:
1.一个包下可以配置多个Action。
2.还有一种包叫抽象包,抽象包里不能有Action定义,当一个包设置属性abstract = true的时候,就成了抽象包。
3.struts.xml配置文件是从上往下解析的,所以父包应该定义在子包的前面,即被继承的包要放在继承包的前面,且任意两个包的name不能相同,不然会抛出异常。
4.如果在同一个包中配置了两个name相同的Action,那么后一个Action会覆盖前一个Action。


3.命名空间

<package>标签还有一个属性叫namespace,用于指定该包所对应的命名空间。这是为了更好的管理重名的问题。同一个命名空间下不能有同名的Action,不同的命名空间里可以有相同的Action。

<action>标签是没有namesapce属性的,同一个package下的Action属于同一个命名空间。如果package没有指定namespace,则该包下的所有Action属于默认的命名空间。

比如上面代码中的<package>标签我改成如下

<!-- Struts2的Action都必须配置在package里,此处使用默认package -->
<package name="default" namespace="/codeliu" extends="struts-default">
    <!-- 定义一个名为user的action,实现类为 com.codeliu.action.UserAction-->
    <action name="user" class="com.codeliu.action.UserAction">
        <!-- result的name和Action类的execute方法的返回值一一对应,区分大小写 -->
        <!-- result标签指明execute方法的返回值和资源视图的映射关系,转向的资源可以是jsp或者另一个action或者其他 -->
        <result name="success">/success.jsp</result>
        <result name="error">/error.jsp</result>
    </action>
</package>

则访问请求的URL就由

localhost:8080/项目名/user.action

变成

localhost:8080/项目名/codeliu/user.action

请求的路径应该符合namespace+Action的形式。

除此之外,还可以设置成根命名空间

namespace = "/"

这样的形式访问的URL和默认的形式一样。

配置命名空间后,Struts2会按照如下顺序搜索Action:
(1)指定命名空间:先查找指定命名空间下是否有对应的Action,如果找到则用此Action处理用户请求。
(2)默认命名空间:如果在指定命名空间下没有找到,则去默认命名空间下查找,找到则用此Action处理用户的请求。
(3)报错:如果指定命名空间和默认命名空间都找不到,则报错。

例如上面的/codeliu/user.action,程序首先去/codeliu命名空间中查找名为user的Action,找到了则用此Action处理用户请求,如果没找到,则去默认命名空间下,如果还没找到,则报错。

默认命名空间和根命名空间的区别:默认命名空间的Action可以处理任何命名空间下的Action请求,而根命名空间里的Action只能处理根命名空间下的请求。比如上面的/codeliu/user.action,如果在指定命名空间下没有此Action,则默认命名空间里的名为user的Action也可以处理这个Action请求。程序如果在指定命名空间里没有找到符合条件的Action,则直接进入默认命名空间,不会去根命名空间。


4.一个struts.xml文件包含其他struts.xml文件

一般在实际开发中,struts.xml都会变得很臃肿,这时候可以通过分解struts.xml,然后在struts.xml中包含其他的struts.xml文件。

在struts.xml中使用<include>标签包含其他struts.xml,比如下面的代码

<struts>
    <include file="struts-part1.xml"></include>
    <include file="struts-part2.xml"></include>
    <include file="struts-part3.xml"></include>
</struts>

注意:包含的每个xml文件也必须是完整的,都必须包含DTD信息、Struts2配置文件的根元素等信息。在<include>引用文件时,是单独解析每个struts.xml文件。