Struts2 命名空间开头的变量(或等效项)

Struts2 命名空间开头的变量(或等效项),struts2,Struts2,我正在尝试创建类似http://localhost:8080/app/client/shared-名称空间和操作: “/app”将是上下文根 “client”实际上是一个变量,由应用程序的实际客户端版本/接口替换,例如 “约翰”(即: http://localhost:8080/app/john/namespaces-和操作) “/shared namespace and actions”将是包/操作 可在一个或多个客户端下访问(例如“/关于/联系”),或 “/products/73/edit

我正在尝试创建类似
http://localhost:8080/app/client/shared-名称空间和操作

  • /app
    ”将是上下文根
  • client
    ”实际上是一个变量,由应用程序的实际客户端版本/接口替换,例如 “约翰”(即:
    http://localhost:8080/app/john/namespaces-和操作
  • /shared namespace and actions
    ”将是包/操作 可在一个或多个客户端下访问(例如“/关于/联系”),或 “/products/73/edit”)
理想情况下,URL可以完全省略“客户端”组件,因此对于有意义的操作,可以显示某种组合视图。例如,“
/app/
”将显示指向客户端版本的链接,而客户端的“
/app/client/
”将在其主页上显示该客户端想要的内容

这个变量“client”组件就是我要问的

到目前为止,我一直在使用查询字符串参数来处理客户机选择,而不是URL路径的一部分。但是,对于书签之类的东西,这有一些明显的问题,因为我总是必须在查询字符串中传递client参数(不吸引人),否则书签将失败

有没有一个简单的方法来进行这种改变?看起来我想要的是名称空间中的通配符,就像我对操作所做的那样,但是文档似乎不支持这种可能性,实验也不支持。我已经使用包来设置名称空间、拦截器堆栈,并在struts.xml文件中对相关操作进行分组,因此将所有操作更改为在“/”名称空间包下,并为客户端添加一个通配符并不是一件小事

我考虑的一个选项是扩展类
DefaultActionMapper
,覆盖方法
parseNameAndNamespace(String、ActionMapping、ConfigurationManager)
,删除URI的客户端组件(如果存在),然后将修改后的URI传递给父实现。但是,这有很多问题,例如断开所有链接、表单目标和重定向。我希望修复链接/表单会让人恼火,但并非不可能,但我不确定重定向是否也是如此

我使用的是2.3.16.3


struts.xml:

<struts>
    <constant name="struts.enable.SlashesInActionNames" value="true" />
    <constant name="struts.mapper.alwaysSelectFullNamespace" value="false" />
    <constant name="struts.patternMatcher" value="namedVariable"/>

    <constant name="struts.action.extension" value="" />

    <package
        name="poc-default"
        extends="struts-default"
        strict-method-invocation="true">
        <default-interceptor-ref name="defaultStack" />
        <default-action-ref name="http404" />
        <action
            name="http404"
            class="poc.DefaultAction">
            <result name="success">/WEB-INF/http404.jsp</result>
        </action>
    </package>

<package
    name="root"
    namespace="/"
    extends="poc-default"
    strict-method-invocation="true">
    <action
        name=""
        class="poc.DefaultAction">
        <result name="success">/WEB-INF/home.jsp</result>
    </action>
    <action
        name="clients"
        class="poc.DefaultAction">
        <result name="success">/WEB-INF/client-select.jsp</result>
    </action>
</package>
</struts>

现在,URL“
http://localhost:8080/poc/john/
“和”
http://localhost:8080/poc/john/clients

考虑到Dave Newton的评论,我相信他是正确的,我正在着手解决我的问题(URL的可选客户端选择器前缀)这可能不是我应该做的

URL重写似乎是一个更好(也是可能的)选择,而是通过请求的属性将客户端放入上下文中。我创建了一个过滤器,该过滤器显示在web.xml中的Strut2过滤器之前:

@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
        throws ServletException, IOException {
    final HttpServletRequest httpRequest = (HttpServletRequest) request;
    final String requestServletPath = httpRequest.getServletPath();

    // Obtain set of client strings here.
    final List<String> clients = Arrays.asList("john");

    String newServletPath = null;
    for (String client : clients) {
        final String toCheck = "/" + client;
        if (requestServletPath.equals(toCheck) || requestServletPath.startsWith(toCheck + "/")) {
            /*
             * Put client into context here, {@link HttpSession#setAttribute(String, Object)} or
             * {@link ServletRequest#setAttribute(String, Object)}.
             */
            request.setAttribute("uriClientString", toCheck);
            newServletPath = requestServletPath.substring(toCheck.length());
            break;
        }
    }

    if (newServletPath != null)
        request.getRequestDispatcher(newServletPath).forward(request, response);
    else
        chain.doFilter(request, response);
}
@覆盖
公共筛选器(最终ServletRequest请求、最终ServletResponse响应、最终筛选器链)
抛出ServletException、IOException{
最终HttpServletRequest httpRequest=(HttpServletRequest)请求;
最后一个字符串requestServletPath=httpRequest.getServletPath();
//在此处获取一组客户端字符串。
最终列表clients=Arrays.asList(“john”);
字符串newServletPath=null;
用于(字符串客户端:客户端){
最后一个字符串toCheck=“/”+客户端;
if(requestServletPath.equals(toCheck)| | requestServletPath.startsWith(toCheck+“/”){
/*
*将客户端放在此处的上下文中,{@link HttpSession#setAttribute(字符串,对象)}或
*{@link ServletRequest#setAttribute(字符串,对象)}。
*/
setAttribute(“uriClientString”,toCheck);
newServletPath=requestServletPath.substring(toCheck.length());
打破
}
}
if(newServletPath!=null)
getRequestDispatcher(newServletPath).forward(请求,响应);
其他的
链式过滤器(请求、响应);
}
Struts 2的过滤器映射也必须支持转发:

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

支柱2
/*
要求
向前地
不幸的是,如果正在使用客户端前缀,则有必要重写生成的URL以包含客户端前缀,否则Struts2将仅从实际名称空间开始:

<package
    name="root"
    namespace="/{uriClientString}/"
    extends="poc-default"
    strict-method-invocation="true">
    <action
        name=""
        class="poc.DefaultAction">
        <result name="success">/WEB-INF/home.jsp</result>
    </action>
    <action
        name="clients"
        class="poc.DefaultAction">
        <result name="success">/WEB-INF/client-select.jsp</result>
    </action>
</package>
<s:a namespace="%{#request.uriClientString}" action="">Home page</s:a>
<action name="re">
    <result type="redirectAction">
        <param name="namespace">${#request.uriClientString}</param>
        <param name="actionName">clients</param>
    </result>
</action>
主页
最后,如果正在使用客户端前缀,还需要重写重定向以包含该前缀,因为Struts2将再次从实际名称空间开始:

<package
    name="root"
    namespace="/{uriClientString}/"
    extends="poc-default"
    strict-method-invocation="true">
    <action
        name=""
        class="poc.DefaultAction">
        <result name="success">/WEB-INF/home.jsp</result>
    </action>
    <action
        name="clients"
        class="poc.DefaultAction">
        <result name="success">/WEB-INF/client-select.jsp</result>
    </action>
</package>
<s:a namespace="%{#request.uriClientString}" action="">Home page</s:a>
<action name="re">
    <result type="redirectAction">
        <param name="namespace">${#request.uriClientString}</param>
        <param name="actionName">clients</param>
    </result>
</action>

${#request.uriClientString}
客户
这并不像我一开始希望的那样容易实现,但一旦一切都更新了,它确实会满足我的需求


如果没有更好的建议,我将在几天内接受此建议。

如果您熟悉通配符映射,为什么会问这个问题?@RomanC我熟悉操作名称的通配符映射,但不熟悉包名称空间,我没有看到任何文档表明这是可能的,我尝试在名称空间中插入通配符失败。我的希望是不必将我的所有包扁平化为一个包,每个操作名称复制其当前包名称空间中与路径相关的内容,而只是在路径(名称空间)的开头而不是“结束”(操作名称)处获取通配符。因此,我希望确实有某种方法可以在名称空间中/之前使用通配符/变量。您应该发布一段您尝试过的代码,并指出错误。我甚至不确定名称空间路由是否是实现这一点的方法;你真的不需要不同的名称空间,AFAICT。在这种情况下,使用任何合理的XML操作技术来更改XML配置都应该是微不足道的;如果使用注释,则不会太多。我有几个主意