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>
Мой вопрос / головоломка:
- В TestAction1, если я получаю ответ от ServletActionContext, я получаю разные ответы до и после включения; перед включением - ответ по умолчанию, но после включения я получил экземпляр моего настроенного ResponseImpl; Я ожидаю получить такой же: т.е. ответ по умолчанию;
- В TestAction2 я получаю ответ от ServletActionContext, который я получаю, это экземпляр моего настроенного ResponseIml. Это моя самая важная вещь, я думаю, что я должен получить экземпляр ответа по умолчанию здесь, то есть: org.apache.catalina.connector.Response, я работаю на JBoss;
- Я получаю другой 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";
}
}
}