Struts2 ActionContext и Response для цепочки действий

У меня довольно сложная проблема с цепочечными действиями 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); 

И важно то, что я использую настроенный ResponseIml при включении "x.action".

После включения я возвращаю "success", поэтому результат цепляется за действие y (3-е действие в моей конфигурации);
И, наконец, TestAction2 продолжает обрабатывать запрос, он будет успешно обработан, и jsp должен быть обработан, но я вижу пустую страницу.

Файл JSP очень прост: index.jsp

<h1>Test!</h1>

Мой вопрос / головоломка:

  1. В TestAction1, если я получаю ответ от ServletActionContext, я получаю разные ответы до и после включения; перед включением - ответ по умолчанию, но после включения я получил экземпляр моего настроенного ResponseImpl; Я ожидаю получить такой же: т.е. ответ по умолчанию;
  2. В TestAction2 я получаю ответ от ServletActionContext, который я получаю, это экземпляр моего настроенного ResponseIml. Это моя самая важная вещь, я думаю, что я должен получить экземпляр ответа по умолчанию здесь, то есть: org.apache.catalina.connector.Response, я работаю на JBoss;
  3. Я получаю другой ActionContext в TestAction2 (по сравнению с ActionContext, который я получаю в TestAction1).

Эта проблема действительно сводит меня с ума, я потратил на это дни.
Любой совет будет оценен!
Бесконечно благодарен!!

Мой код:

TestAction1:

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";
  }
}

ResponseImpl:

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) {
  }
}

TestAction2:

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 до и после включения!!

2 ответа

Когда вы делаете rd.include, другой запрос запускается внутри веб-сервера. Таким образом, с точки зрения Struts он видит совершенно новый запрос, и в результате создается новый контекст действия. (именно поэтому вам нужно включить функцию 'INCLUDE' в фильтр struts2... так, чтобы он также видел включенные запросы). Вероятно, поскольку локальные переменные потока используются для отслеживания контекста действия, и все, что, когда вы выполняете 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

Вы также можете попробовать следующее. Вместо использования цепочки.. внутри вашей 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";
        }
      }
    }
Другие вопросы по тегам