這個是官方文檔的上面對result類型的描述
我自己又找了一箇中文的:
本文重點分享一下幾個常用的result類型之後的原理:
一:dispatcher
從源碼分析:
public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("Forwarding to location " + finalLocation);
}
PageContext pageContext = ServletActionContext.getPageContext();
if (pageContext != null) {
pageContext.include(finalLocation);
} else {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
//add parameters passed on the location to #parameters
// see WW-2120
if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {
String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
Map<String, Object> parameters = getParameters(invocation);
Map<String, Object> queryParams = urlHelper.parseQueryString(queryString, true);
if (queryParams != null && !queryParams.isEmpty())
parameters.putAll(queryParams);
}
// if the view doesn't exist, let's do a 404
if (dispatcher == null) {
response.sendError(404, "result '" + finalLocation + "' not found");
return;
}
//if we are inside an action tag, we always need to do an include
Boolean insideActionTag = (Boolean) ObjectUtils.defaultIfNull(request.getAttribute(StrutsStatics.STRUTS_ACTION_TAG_INVOCATION), Boolean.FALSE);
// If we're included, then include the view
// Otherwise do forward
// This allow the page to, for example, set content type
if (!insideActionTag && !response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
request.setAttribute("struts.view_uri", finalLocation);
request.setAttribute("struts.request_uri", request.getRequestURI());
dispatcher.forward(request, response);
} else {
dispatcher.include(request, response);
}
}
}
結果又三個方向:
pageContext.include(finalLocation);
dispatcher.forward(request, response);
dispatcher.include(request, response);
而forward和include是差不多的。
二:chain
主要用於把相關的幾個action連接起來,共同完成一個功能
public void execute(ActionInvocation invocation) throws Exception {
// if the finalNamespace wasn't explicitly defined, assume the current one
if (this.namespace == null) {
this.namespace = invocation.getProxy().getNamespace();
}
ValueStack stack = ActionContext.getContext().getValueStack();
String finalNamespace = TextParseUtil.translateVariables(namespace, stack);
String finalActionName = TextParseUtil.translateVariables(actionName, stack);
String finalMethodName = this.methodName != null
? TextParseUtil.translateVariables(this.methodName, stack)
: null;
if (isInChainHistory(finalNamespace, finalActionName, finalMethodName)) {
addToHistory(finalNamespace, finalActionName, finalMethodName);
throw new XWorkException("Infinite recursion detected: "
+ ActionChainResult.getChainHistory().toString());
}
if (ActionChainResult.getChainHistory().isEmpty() && invocation != null && invocation.getProxy() != null) {
addToHistory(finalNamespace, invocation.getProxy().getActionName(), invocation.getProxy().getMethod());
}
addToHistory(finalNamespace, finalActionName, finalMethodName);
HashMap<String, Object> extraContext = new HashMap<String, Object>();
extraContext.put(ActionContext.VALUE_STACK, ActionContext.getContext().getValueStack());
extraContext.put(ActionContext.PARAMETERS, ActionContext.getContext().getParameters());
extraContext.put(CHAIN_HISTORY, ActionChainResult.getChainHistory());
if (LOG.isDebugEnabled()) {
LOG.debug("Chaining to action " + finalActionName);
}
proxy = actionProxyFactory.createActionProxy(finalNamespace, finalActionName, finalMethodName, extraContext);
proxy.execute();
}
原理是根據action所在的namespace,action,method創建一個proxy代理,並且執行代理的過程。由於是在多個Action之間在同一個http請求中傳遞,所以可以共享其中的資源,這就是上面history的意思。根據以前context中的內容,共享給下面action.
三:redirect和redirection
由於都是一個類ServletRedirectResult中的方法,所以可以當做一個來考慮。
protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
ActionContext ctx = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);
if (isPathUrl(finalLocation)) {
if (!finalLocation.startsWith("/")) {
ActionMapping mapping = actionMapper.getMapping(request, Dispatcher.getInstance().getConfigurationManager());
String namespace = null;
if (mapping != null) {
namespace = mapping.getNamespace();
}
if ((namespace != null) && (namespace.length() > 0) && (!"/".equals(namespace))) {
finalLocation = namespace + "/" + finalLocation;
} else {
finalLocation = "/" + finalLocation;
}
}
// if the URL's are relative to the servlet context, append the servlet context path
if (prependServletContext && (request.getContextPath() != null) && (request.getContextPath().length() > 0)) {
finalLocation = request.getContextPath() + finalLocation;
}
ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(invocation.getResultCode());
if (resultConfig != null) {
Map<String, String> resultConfigParams = resultConfig.getParams();
for (Map.Entry<String, String> e : resultConfigParams.entrySet()) {
if (!getProhibitedResultParams().contains(e.getKey())) {
String potentialValue = e.getValue() == null ? "" : conditionalParse(e.getValue(), invocation);
if (!suppressEmptyParameters || ((potentialValue != null) && (potentialValue.length() > 0))) {
requestParameters.put(e.getKey(), potentialValue);
}
}
}
}
StringBuilder tmpLocation = new StringBuilder(finalLocation);
urlHelper.buildParametersString(requestParameters, tmpLocation, "&");
// add the anchor
if (anchor != null) {
tmpLocation.append('#').append(anchor);
}
finalLocation = response.encodeRedirectURL(tmpLocation.toString());
}
if (LOG.isDebugEnabled()) {
LOG.debug("Redirecting to finalLocation " + finalLocation);
}
sendRedirect(response, finalLocation);
}
方法的結果都是使用這個方法作爲跳轉:sendRedirect(response, finalLocation);重定向。
其他的velocity,freemarker,是整合了模板引擎,這個以前我竟然不知道,google了一下,發現還是很簡單的。大家可以試着加到struts裏面。