Struts2的缺點是在ajax結合開發時,無論後臺是否報錯(非ServletException),頁面中異步請求$.ajax都執行的是success對應的函數,即在$.ajax中定義的error:function(){ ... }失效了。這個缺點是由struts的錯誤處理機制導致的,下面進行詳細的說明。
先貼出Struts2中DefaultActionInvation的serviceAction方法,也是Struts2運行機制的核心方法
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
ActionMapping mapping) throws
ServletException {
Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
boolean nullStack = stack == null;
if (nullStack) {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
}
String timerKey = "Handling request from Dispatcher";
try {
UtilTimerStack.push(timerKey);
String namespace = mapping.getNamespace();
String name = mapping.getName();
String method = mapping.getMethod();
Configuration config = configurationManager.getConfiguration();
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
// if the ActionMapping says to go straight to a result, do it!
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();
}
// If there was a previous value stack then set it back onto the request
if (!nullStack) {
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
}
} catch (ConfigurationException e) {
// WW-2874 Only log error if in devMode
if(devMode) {
String reqStr = request.getRequestURI();
if (request.getQueryString() != null) {
reqStr = reqStr + "?" + request.getQueryString();
}
LOG.error("Could not find action or result\n" + reqStr, e);
}
else {
if (LOG.isWarnEnabled()) {
LOG.warn("Could not find action or result", e);
}
}
sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);//產生錯誤的模板頁面,並返回到客戶端
} catch (Exception e) {
sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);//產生錯誤的模板頁面,並返回到客戶端
} finally {
UtilTimerStack.pop(timerKey);
}
}
由以上源代碼可知,由DefaultActionInvocation做的事情依次如下:
1、創建ActionContext
2、創建值棧
3、創建ActionProxy
4、執行ActionProxy中的攔截器的攔截方法
5、執行Action的方法
6、執行結果集(響應頁面或跳轉到另一個action)
上述4、 5、 6步中如果拋出配置信息錯誤(ConfigurationException)和非ServletException異常,則會在方法內部以try、
catch的方式自行處理,即以框架自定義的錯誤模板(response.getWriter.print)的方式響應頁面。
雖然Servlet也是通過response響應錯誤頁面,struts並沒有沿用Servlet在相應錯誤頁面時設置響應狀態碼(成功200,錯誤則404
、405等),貼出Servlet的service方法源碼一部分如下:
if(method.equals("GET"))
{
long lastModified = getLastModified(req);
if(lastModified == -1L)
{
doGet(req, resp);
} else
{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < lastModified)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else
{
resp.setStatus(304);
}
}
} else
if(method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else
if(method.equals("POST"))
doPost(req, resp);
protected
void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if(protocol.endsWith("1.1"))
resp.sendError(405, msg);
else
resp.sendError(400, msg);
}
protected
void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if(protocol.endsWith("1.1"))
resp.sendError(405, msg);
else
resp.sendError(400, msg);
}
也就是說Servlet在響應頁面時,還設置了響應狀態碼,以供前臺ajax判斷服務器響應是否異常,從而調用$.ajax({})中
success和error(根據服務器的響應碼)指定的函數。這樣能夠給開發者發送有利的信號。而Struts2由於沒設置響應碼
這一步,因此即使後臺有(非ServletException)異常,$.ajax也會調用success對應的回調函數,data就是錯誤模板頁面。。
如此,相較於Servlet而言,在與ajax結合開發時,若後臺代碼出現異常,Struts2並不會在服務器控制檯報錯,前臺js也不能
根據服務器響應碼執行對應的回調函數。