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