Struts 2的访问路径问题

struts.xml 定义了浏览器请求的访问路径与 Action 之间的映射关系,本文描述访问路径相关问题。

如:

<package name="default" namespace="/test" extends="struts-default">
        <action name="hello" class="org.iridium.actions.HelloAction1">
            <result name="success">
                /loveyou.jsp
            </result>
            <result name="hello">
                /hello.html
            </result>
        </action>
</package>

对 HelloAction1 的访问路径就是 http://host:port/webroot/test/hello

访问路径由协议名,主机地址或 IP,端口号,应用名,名字空间,Action 名称组成。

通用的说法即:http://{host}:{port}/{webroot}/{namespace}/{action name}

package 可以用来区分同名的 action。它本身是标识一簇 Action

namespace 的属性可以省略,如果省略就相当于 namespace="",另外 namespace 还可以做通配符匹配。

action 可以不配置 class 属性,如果不配置,将默认使用 ActionSupport 类。

对上面描述的 Action, 一般在 Web 端的 JSP 页面中按如下方式访问即可,以提交一个 form 为例:

<% String context = request.getContextPath(); %>
<form action="<%=context %>/test/hello">

用户通过浏览器访问时,会自动取得 http://{host}:{port} 这部分内容,上面代码定义的 context 变量获取的是 {webroot} 的值。

DMI

DMI, Dynamic Method Invocation, 动态方法调用。可以在 struts.xml 中开启或关闭:

<constant name="struts.enable.DynamicMethodInvocation" value="true" />

它的默认值是 false,即默认关闭。

DMI 并非是必须的,但使用它可以大幅减少配置文件的篇幅,如:

使用 DMI 之前的 struts.xml 中的配置:

    <package name="tada" namespace="/tada" extends="struts-default">
  
        <action name="addTada" class="org.iridium.pis.actions.TadaAction"
            method="addTada">
            <result name="success">/jsp/tada/tadaList.jsp</result>
            <result name="detail">/jsp/tada/tadaDetail.jsp</result>
            <result name="add">/jsp/tada/addNewTada.jsp</result>
            <result name="error">/jsp/sys/error.jsp</result>
        </action>
      
        <action name="deleteTada" class="org.iridium.pis.actions.TadaAction"
            method="deleteTada">
            <result name="success">/jsp/tada/tadaList.jsp</result>
            <result name="detail">/jsp/tada/tadaDetail.jsp</result>
            <result name="add">/jsp/tada/addNewTada.jsp</result>
            <result name="error">/jsp/sys/error.jsp</result>
        </action>
      
        ......
    </package>

调用方式:

<a href="<%=path%>/tada/addTada?id=<%=tada.getId()%>">Delete</a>
<a href="<%=path%>/tada/deleteTada?id=<%=tada.getId()%>">Delete</a>

这个例子可以看出,调用 Action 可以指定方法,并非一定是 execute(). 这里针对每个方法都配置一个 action,随着业务的增多,将变得十分臃肿。

使用 DMI 之後的 struts.xml 中的配置:

不再设置 method 属性

    <package name="tada" namespace="/tada" extends="struts-default">
        <action name="tada" class="org.iridium.pis.actions.TadaAction">
            <result name="success">/jsp/tada/tadaList.jsp</result>
            <result name="detail">/jsp/tada/tadaDetail.jsp</result>
            <result name="add">/jsp/tada/addNewTada.jsp</result>
            <result name="error">/jsp/sys/error.jsp</result>
        </action>
  
    </package>

调用方式:

<a href="<%=path%>/tada/tada!deleteTada?id=<%=tada.getId()%>">Delete</a>

Action Wild card,以上还可以通过 Wild card 匹配的方式继续简化:

    <package name="tada" namespace="/tada" extends="struts-default">
        <action name="tada_*" class="org.iridium.pis.actions.TadaAction" method={1}>
            <result name="success">/jsp/tada/tadaList.jsp</result>
            <result name="detail">/jsp/tada/tadaDetail.jsp</result>
            <result name="add">/jsp/tada/addNewTada.jsp</result>
            <result name="error">/jsp/sys/error.jsp</result>
        </action>
      
        <action name="*_*" class="org.iridium.pis.actions.{1}Action" method={2}>
            ......
        </action>
  
    </package>

Wild card 在实践中,可以认为就是以 action name 中的星号通配符匹配访问路径。可以使用多个星号,第一个星号的对应{1}, 第二个星号对应{2}, 以此类推。

对于一个路径被多个项配到到的情况,如果有不含星号的匹配成功,则使用之。如果所有匹配项都包含星号,无论多少星号,都是同一等级,按顺序匹配,谁先匹配到,就用谁。

使用 wild card 方式,会给程序员很大的灵活性,用好了会极大地减少配置工作,但需要对约定规则做比较周全的考虑,而且在项目中要认真执行,否则不如不用。