【问题标题】:Struts action not rendering correct path after change in controller更改控制器后,Struts 动作未呈现正确的路径
【发布时间】:2014-12-11 05:33:08
【问题描述】:

我正在开发一个非常古老的 J2EE/struts 站点,并且由于 PayPal 最近停止支持 SSL 3 协议,我正在尝试实现一个新的托管结帐流程,其中支付网关接受带有订单详细信息的 POST,处理信用卡验证,并通过另一个 POST 返回响应代码(和一百万个其他值)。

我正在尝试利用 struts 中的现有操作,但由于 struts-config.xml (/store/order/confirmation.do) 中指定的路径没有被渲染;相反,在处理来自远程服务器的 POST 请求并调用 ActionMapping.findForward() 之后,应用程序只会呈现在远程服务器返回的 POST 中请求的相同路径 (/store/checkout/submitOrder .do).

如果我尝试将 redirect="true" 添加到 struts-config.xml 中的转发,我会被重定向到正确的路径,但会出现一个我无法调试的 pagecontext 异常,因为它没有被记录。

过去的工作方式是 submitOrder 表单是空的——只是一个提交输入。然后,来自基于会话的购物车和相关的客户帐单的结帐细节将被移交给一个特殊的威瑞信库以生成响应。我现在想使用来自新提供商的 POST 表单,但被这个重定向失败困住了。

struts-config.xml 中的行如下所示:

<action path="/store/checkout/submitOrder" type="com.company.action.CheckoutAction" parameter="submitOrder" scope="request">
  <set-property property="secure" value="true"/>
  <forward name="success" path="/store/order/confirmation.do"/>
</action>

动作是这样的:

public ActionForward submitOrder(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
  String method = request.getMethod();
  if (method != null && method.equals("POST")) {
    ShoppingCart sc = (ShoppingCart) request.getSession(false).getAttribute("shoppingCart");
    if (sc == null) { throw new SessionExpiredException("Submit Order - Shopping Cart is not in session"); }
    ResourceBundle appConfig = ResourceBundle.getBundle("resources.application");

    PFProClient client = new PFProClient();

    /* THIS saveOrder() METHOD WAS RE-WRITTEN TO TAKE the httpservletrequest (form POST) instead of an instance of VerisignResponse, defined in another library. */

    client.saveOrder(sc, request);
    User user = (User)request.getSession(false).getAttribute(Globals.USER);
    if (user != null) { UserModel.saveUser(user, sc.getCustomer(), sc.getOrder()); }
    //Remove items from session
    request.getSession().setAttribute("customerBillingForm", null);
    request.getSession().setAttribute("customerShippingForm", null);
    request.getSession().setAttribute("customerCreditForm", null);
    request.getSession().setAttribute("cartForm", null);
    request.getSession().setAttribute("shoppingCart", null);
    //remove the shopping cart from the cookie & DB
    ShoppingCartUtils.deleteSavedCartFromCookie(response, request);
    //remove the CHECKING_OUT flag
    request.getSession().setAttribute(Globals.CHECKING_OUT, null);
    //remove the PAYING_WITH_PAYPAL flag
    request.getSession().setAttribute(Globals.PAYING_WITH_PAYPAL, null);
    // Set cart in request for order confirmation page
    request.setAttribute("shoppingCart", sc);
    return mapping.findForward("success");
  } else {
    // HTTP method was not POST
  }
  return mapping.findForward("success");
}

编辑

我已验证 submitOrder 操作正在作为 POST 请求进行处理。我想知道,由于之前的 POST 只是一个空表单,额外的 POST 参数是否会弄脏某些东西并阻止正确的路由。

在tiles-defs.xml中,confirmation.do视图的资源是:

<definition name="confirm.order" path="/templates/layouts/order-confirmation.jsp">
  ...
  <put name="content" value="/store/checkout/confirmOrder.jsp"/>
</definition>

应用程序正在为 confirmOrder.jsp 视图提供服务,但没有路由到 /store/order/confirmation.do,因此任何重新加载页面的尝试都会提示用户重新提交表单,即显然不受欢迎。

我还从 struts-config.xml 中的 submitOrder 操作定义中删除了对 name="emptyForm" 的引用(因为来自远程服务器的表单 POST 将没有 emptyForm name 属性),定义为:

<form-bean name="emptyForm" type="org.apache.struts.action.DynaActionForm"/>

我也不确定这会产生什么影响。

【问题讨论】:

  • 我完全错了。一切都正确路由!我以为路由会解析 /store/order/confirmation.do 但它实际上应该路由到 submitOrder.do!

标签: java struts-config struts1 struts-1


【解决方案1】:

使用转发,客户端将始终认为它仍在查看请求的资源 (submitOrder.do),因为它无法更好地了解(即对资源发出单个请求并返回响应)。不过,响应内容应该来自转发资源 (confirmation.do)。

如果响应内容不是来自confirmation.do,那么我们正在寻找不同的问题。在这种情况下,PayPal 回调很可能使用与 POST 不同的请求方法,这将绕过大部分 submitOrder() 代码 (// HTTP method was not POST)。而confirmation.do 后面的 Struts Action,缺少必要的会话或请求属性,可能会显示 submitOrder 页面。

【讨论】:

  • 非常感谢!重申一下,会发生以下情况:1)我们将数据发布到支付服务,2)支付服务处理客户输入(信用卡/礼品卡等),3)支付服务向 /submitOrder.do 发出 POST -- 我已将支付服务中的表单复制到我们网站的源中,以确保它是一个 POST 请求。我知道它没有绕过 submitOrder 操作,因为 client.saveOrder() 方法调用工作得很好......似乎唯一的问题是 Confirm.do 的解析,一旦处理了 POST 请求。
  • 我忘了提到响应内容(在 tiles-defs.xml 中定义为 '/store/checkout/confirmOrder.jsp')正在被提供——它只是没有路由到 /confirmation。 do path,因此任何重新加载页面(或查看源代码,甚至通过传统方法)的尝试都会提示用户重新提交表单。
  • 好的,这是您最简单的解决方法。我通常不建议为您的会话增加权重,但如果您将表单 scope 指定为会话而不是 strutsConfig.xml 中的请求,对于 submitOrder.do 和 Confirmation.do,再加上可能将 "shoppingCart" 属性保留在通过confirmation.do清理会话(不要将其移至请求),然后您可以安全地在成功转发时设置redirect =“true”。
猜你喜欢
  • 2018-07-10
  • 2013-08-19
  • 2014-08-28
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多