3

我有一个关于 struts2 链接操作的非常复杂的问题,提前感谢您耐心阅读我的问题。我会尽力把它描述清楚。

下面是我的struts.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

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


    <package name="default" extends="struts-default" namespace="/">
        <action name="test" class="com.bv.test.TestAction1" >
            <result name="success" type="chain">y</result>
        </action>

        <action name="x">
            <result name="success">/index.jsp</result>
        </action>

        <action name="y" class="com.bv.test.TestAction2">
            <result name="success">/index.jsp</result>
        </action>
    </package>
</struts>

我的逻辑是这样的:访问/myapp/test时,TestAction1会处理请求;在 TestAction1 中,我像这样“包含”动作 x(我的配置中的第二个动作):

ResponseImpl myResponse = new ResponseImpl(response);
RequestDispatcher rd = request.getRequestDispatcher("/x.action");
rd.include(request, myResponse); 

重要的是我在包含“x.action”时使用了自定义的 ResponseIml。

包含后,我返回“成功”,因此结果链接到操作 y(我的配置中的第三个操作);
最后,TestAction2继续处理请求,它会去成功的结果,jsp应该被渲染,但我看到的是一个空白页

jsp文件很简单:index.jsp

<h1>Test!</h1>

我的问题/难题是:

  1. 在 TestAction1 中,如果我从 ServletActionContext 获得响应,我会在包含前后得到不同的响应;在包含之前是默认响应,但在包含之后我得到了我自定义的 ResponseImpl 的一个实例;我希望得到相同的结果:即:默认响应;
  2. 在 TestAction2 中,我从 ServletActionContext 获得响应,我得到的是我自定义的 ResponseIml 的实例。这是我最重要的事情,我想我应该在这里得到一个默认的响应实例,即:org.apache.catalina.connector.Response,我在JBoss上运行;
  3. 我在 TestAction2 中获得了不同的 ActionContext(与在 TestAction1 中获得的 ActionContext 相比)。

这个问题真的让我发疯了,我花了好几天的时间。
任何建议将被认真考虑!
太感谢了!!

我的代码:

测试动作1:

public class TestAction1 {
  public String execute() {
    ActionContext ac = ActionContext.getContext();
    System.out.println("Before including: the action context is : " + ac);
    HttpServletRequest request = ServletActionContext.getRequest();
    HttpServletResponse response = ServletActionContext.getResponse();
    System.out.println("Before including: the response is : " + response);

    ResponseImpl myResponse = new ResponseImpl(response);
    RequestDispatcher rd = request.getRequestDispatcher("/x.action");
    try {
      rd.include(request, myResponse); 
      String s = myResponse.getOutput();  
      System.out.println("get from response: " + s);
    }
    catch (Exception e) {
      e.printStackTrace();
    }

    ac = ActionContext.getContext();
    System.out.println("After including : the action context is : " + ac);
    response = ServletActionContext.getResponse();
    System.out.println("After including : the response is : " + response);
    return "success";
  }
}

响应实施:

import java.util.Locale;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.Cookie;
import javax.servlet.jsp.JspWriter;

/**
 * 
 * 
 */
public class ResponseImpl extends HttpServletResponseWrapper  {

  //=========================================================
  // Private fields.
  //=========================================================

  private ServletOutputStream outputStream = null;

  private ByteArrayOutputStream byteArrayOutputStream = null;

  private StringWriter stringWriter = null;

  private PrintWriter printWriter = null;

  private HttpServletResponse _response = null;

  private String contentType= "text/html";

  private String encoding = "UTF-8";

  /**
   *
   */
  class ServletOutputStream extends javax.servlet.ServletOutputStream {

    private OutputStream outputStream = null;

    /**
     *
     */
    ServletOutputStream(ByteArrayOutputStream outputStream) {
      super();
      this.outputStream = outputStream;
    }

    /**
     *
     */
    public void write(int b) throws IOException {
      this.outputStream.write(b);
    }
  }

  //=========================================================
  // Public constructors and methods.
  //=========================================================

  /**
   *
   */
  public ResponseImpl(HttpServletResponse response) {
    super(response);
    this._response = response;
  }

  /**
   *
   */
  public String getOutput() {
    if (this.stringWriter != null) {
      return this.stringWriter.toString();
    }

    if (this.byteArrayOutputStream != null) {
      try {
        return this.byteArrayOutputStream.toString(this.encoding);
      }
      catch (UnsupportedEncodingException e) {
      }
      return this.byteArrayOutputStream.toString();
    }

    return null;
  }

  //=========================================================
  // Implements HttpServletResponse interface.
  //=========================================================

  public void addCookie(Cookie cookie) {
  }

  public void addDateHeader(String name, long date) {
  }

  public void addHeader(String name, String value) {
  }

  public void addIntHeader(String name, int value) {
  }

  public boolean containsHeader(String name) {
    return false;
  }

  public String encodeRedirectURL(String url) {
    if (null != this._response) {
      url = this._response.encodeRedirectURL(url);
    }
    return url;
  }

  public String encodeURL(String url) {
    if (null != this._response) {
      url = this._response.encodeURL(url);
    }
    return url;
  }

  public void sendError(int sc) {
  }

  public void sendError(int sc, String msg) {
  }

  public void sendRedirect(String location) {
  }

  public void setDateHeader(String name, long date) {
  }

  public void setHeader(String name, String value) {
  }

  public void setIntHeader(String name, int value) {
  }

  public void setStatus(int sc) {
  }

  public void resetBuffer() {
  }

  //=========================================================
  // Implements deprecated HttpServletResponse methods.
  //=========================================================

  public void setStatus(int sc, String sm) {
  }

  //=========================================================
  // Implements deprecated HttpServletResponse methods.
  //=========================================================

  public String encodeRedirectUrl(String url) {
    return encodeRedirectURL(url);
  }

  public String encodeUrl(String url) {
    return encodeURL(url);
  }

  //=========================================================
  // Implements ServletResponse interface.
  //=========================================================

  public void flushBuffer() {
  }

  public int getBufferSize() {
    return 0;
  }

  public String getCharacterEncoding() {
    return this.encoding;
  }

  public String getContentType() {
    return this.contentType;
  }

  public Locale getLocale() {
    return null;
  }

  public javax.servlet.ServletOutputStream getOutputStream() {
    if (this.outputStream == null) {
      this.byteArrayOutputStream = new ByteArrayOutputStream();
      this.outputStream =
        new ServletOutputStream(this.byteArrayOutputStream);
    }
    return this.outputStream;
  }

  public PrintWriter getWriter() {
    if (this.printWriter == null) {
      this.stringWriter = new StringWriter();
      this.printWriter = new PrintWriter(this.stringWriter);
    }
    return this.printWriter;
  }

  public boolean isCommitted() {
    return true;
  }

  public void reset() {
  }

  public void setBufferSize(int size) {
  }

  public void setCharacterEncoding(String charset) {
  }

  public void setContentLength(int len) {
  }

  public void setContentType(String type) {
    int needle = type.indexOf(";");
    if (-1 == needle) {
      this.contentType = type;
    }
    else {
      this.contentType = type.substring(0, needle);
      String pattern = "charset=";
      int index = type.indexOf(pattern, needle);
      if (-1 != index) {
        this.encoding = type.substring(index + pattern.length());
      }
    }
  }

  public void setLocale(Locale locale) {
  }
}

测试动作2:

public class TestAction2 {

  public String execute() {
    ActionContext ac = ActionContext.getContext();
    System.out.println("In TestAction 2 : the action context is : " + ac);

    HttpServletResponse response = ServletActionContext.getResponse();
    System.out.println("In TestAction 2 : the response is : " + response);
    return "success";
  }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Struts2 Application</display-name>

     <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
</web-app>

这是我的调试信息。

  • 在包括之前:动作上下文是:com.opensymphony.xwork2。ActionContext@c639ce
  • 包括之前:响应是:org.apache.catalina.connector.ResponseFacade@8b677f
  • 从响应中获取:<h1>Test!</h1>
  • 包括后:动作上下文是:com.opensymphony.xwork2。ActionContext@2445d7
  • 包括后:响应为:com.bv.test.ResponseImpl@165547d
  • 在 TestAction 2 中:动作上下文是 :com.opensymphony.xwork2。ActionContext@19478c7
  • 在 TestAction 2 中:响应是:com.bv.test.ResponseImpl@165547d

所以,在包含之前和之后我有不同的 ActionContext 实例!!

4

2 回答 2

1

当您执行 rd.include 时,Web 服务器内部会触发另一个请求。因此,从 struts 的角度来看,它看到了一个全新的请求,并因此创建了一个新的操作上下文。(这就是为什么你需要在 struts2 过滤器中包含 'INCLUDE' 的东西。这样它也能看到包含的请求)。可能是因为线程局部变量用于跟踪操作上下文,当您执行 ActionContext.getContext() 时,将检索与新请求(与包含相关)相关的上下文。

您是否尝试在 finally 块中将响应重置为初始响应,如下所示

try {
      rd.include(request, myResponse); 
      String s = myResponse.getOutput();  
      System.out.println("get from response: " + s);
    }
    catch (Exception e) {
      e.printStackTrace();
    } finally {
       ServletActionContext.setResponse(response);
    }

如果这解决了响应问题..您可能可以将字符串“s”作为变量存储在操作上下文中并在 Action2 中检索它

于 2013-05-05T06:30:01.330 回答
0

您也可以尝试以下方法。而不是使用链接.. 在您的 TestAction1 中包含带有原始响应的 TestAction2 。从动作中返回“无”作为返回值。

public class TestAction1 {
  public String execute() {
    ActionContext ac = ActionContext.getContext();
    System.out.println("Before including: the action context is : " + ac);
    HttpServletRequest request = ServletActionContext.getRequest();
    HttpServletResponse response = ServletActionContext.getResponse();
    System.out.println("Before including: the response is : " + response);

    ResponseImpl myResponse = new ResponseImpl(response);
    RequestDispatcher rd = request.getRequestDispatcher("/x.action");
    try {
      rd.include(request, myResponse); 
      String s = myResponse.getOutput();  
      System.out.println("get from response: " + s);
    }
    catch (Exception e) {
      e.printStackTrace();
    }



      RequestDispatcher rd = request.getRequestDispatcher("/y.action");
        try {
          rd.include(request, response); 
        }
        catch (Exception e) {
          e.printStackTrace();
        } finally {
          return "none";
        }
      }
    }
于 2013-05-05T06:40:45.933 回答