設計概念如下:
- 利用interceptor判斷Action是否需要Result的內容,如果需要就註冊PreResultListener。
- PreResultListener執行時,判斷Result若是可以記錄的型別則替換mock response物件,並且執行Result execute method。
- 從mock response物件取得content和content type,並且將原始的response物件還原。
- 呼叫callback method將content和content type傳回Action,讓Action自己implement想要處理的動作。
程式如下:
ObtainResultInterceptor
package com.gss.gmo.cao.struts2.interceptor;
import com.gss.gmo.cao.struts2.interceptor.obtainresult.ObtainResultAware;
import com.gss.gmo.cao.struts2.interceptor.obtainresult.ObtainResultListener;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* @author linus_chien
*
*/
public class ObtainResultInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
@Override
public String intercept(ActionInvocation invocation) throws Exception {
if (invocation.getAction() instanceof ObtainResultAware) {
invocation.addPreResultListener(new ObtainResultListener());
}
return invocation.invoke();
}
}
import com.gss.gmo.cao.struts2.interceptor.obtainresult.ObtainResultAware;
import com.gss.gmo.cao.struts2.interceptor.obtainresult.ObtainResultListener;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* @author linus_chien
*
*/
public class ObtainResultInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
@Override
public String intercept(ActionInvocation invocation) throws Exception {
if (invocation.getAction() instanceof ObtainResultAware) {
invocation.addPreResultListener(new ObtainResultListener());
}
return invocation.invoke();
}
}
ObtainResultListener
package com.gss.gmo.cao.struts2.interceptor.obtainresult;
import static org.apache.commons.lang3.ArrayUtils.contains;
import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.StreamResult;
import org.apache.struts2.views.jasperreports.JasperReportsResult;
import org.springframework.mock.web.MockHttpServletResponse;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.DefaultActionInvocation;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.interceptor.PreResultListener;
import com.opensymphony.xwork2.mock.MockActionInvocation;
/**
* @author linus_chien
*
*/
public class ObtainResultListener implements PreResultListener, StrutsStatics {
private static final Class<?>[] RESULT_TYPES = { StreamResult.class, JasperReportsResult.class };
@Override
@SneakyThrows
public void beforeResult(ActionInvocation invocation, String resultCode) {
Object action = invocation.getAction();
if (action instanceof ObtainResultAware) {
ObtainResultAware obtainResultAction = (ObtainResultAware) action;
Result result = getResult(invocation);
if (isNotValidResultType(result)) {
return;
}
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
HttpServletResponse realResponse = (HttpServletResponse) invocation.getInvocationContext().get(HTTP_RESPONSE);
invocation.getInvocationContext().put(HTTP_RESPONSE, mockResponse);
try {
result.execute(invocation);
byte[] content = mockResponse.getContentAsByteArray();
String contentType = mockResponse.getContentType();
obtainResultAction.handleResult(content, contentType);
} finally {
invocation.getInvocationContext().put(HTTP_RESPONSE, realResponse);
}
}
}
private boolean isNotValidResultType(Result result) {
return result == null || !contains(RESULT_TYPES, result.getClass());
}
@SneakyThrows
private Result getResult(ActionInvocation invocation) {
Result result;
if (!isMock(invocation)) {
result = ((DefaultActionInvocation) invocation).createResult();
} else {
result = invocation.getResult();
}
return result;
}
private boolean isMock(ActionInvocation invocation) {
return invocation instanceof MockActionInvocation;
}
}
import static org.apache.commons.lang3.ArrayUtils.contains;
import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.StreamResult;
import org.apache.struts2.views.jasperreports.JasperReportsResult;
import org.springframework.mock.web.MockHttpServletResponse;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.DefaultActionInvocation;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.interceptor.PreResultListener;
import com.opensymphony.xwork2.mock.MockActionInvocation;
/**
* @author linus_chien
*
*/
public class ObtainResultListener implements PreResultListener, StrutsStatics {
private static final Class<?>[] RESULT_TYPES = { StreamResult.class, JasperReportsResult.class };
@Override
@SneakyThrows
public void beforeResult(ActionInvocation invocation, String resultCode) {
Object action = invocation.getAction();
if (action instanceof ObtainResultAware) {
ObtainResultAware obtainResultAction = (ObtainResultAware) action;
Result result = getResult(invocation);
if (isNotValidResultType(result)) {
return;
}
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
HttpServletResponse realResponse = (HttpServletResponse) invocation.getInvocationContext().get(HTTP_RESPONSE);
invocation.getInvocationContext().put(HTTP_RESPONSE, mockResponse);
try {
result.execute(invocation);
byte[] content = mockResponse.getContentAsByteArray();
String contentType = mockResponse.getContentType();
obtainResultAction.handleResult(content, contentType);
} finally {
invocation.getInvocationContext().put(HTTP_RESPONSE, realResponse);
}
}
}
private boolean isNotValidResultType(Result result) {
return result == null || !contains(RESULT_TYPES, result.getClass());
}
@SneakyThrows
private Result getResult(ActionInvocation invocation) {
Result result;
if (!isMock(invocation)) {
result = ((DefaultActionInvocation) invocation).createResult();
} else {
result = invocation.getResult();
}
return result;
}
private boolean isMock(ActionInvocation invocation) {
return invocation instanceof MockActionInvocation;
}
}
ObtainResultAware
package com.gss.gmo.cao.struts2.interceptor.obtainresult;
/**
* @author linus_chien
*
*/
public interface ObtainResultAware {
void handleResult(byte[] content, String contentType);
}
/**
* @author linus_chien
*
*/
public interface ObtainResultAware {
void handleResult(byte[] content, String contentType);
}