首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts2 判斷 AJAX 請求與攔截器效能調優實戰

     編輯:Java 相關知識

前言

在 Struts2 應用中,區分 AJAX 請求與普通表單提交、針對 AJAX 回傳 JSON、以及利用內建攔截器進行效能剖析,是提升開發效率與系統可觀測性的關鍵技能。本文詳細說明基於 Header 的 AJAX 判斷邏輯、基類封裝策略,以及 Profiling 攔截器的啟用與實戰應用。

一、AJAX 請求識別原理

1.1 表單提交 vs AJAX 差異

特性普通表單提交AJAX 請求
發起者瀏覽器原生表單JavaScript (XMLHttpRequest / fetch / jQuery.ajax)
期望回應完整 HTML 頁面資料片段(JSON、XML、HTML 片段)
頁面行為整頁跳轉/重新載入局部更新,無感刷新

1.2 標準識別 Header:X-Requested-With

jQuery 等主流 JS 庫在發送 AJAX 時,會自動加入請求頭:

X-Requested-With: XMLHttpRequest

伺服器端檢測該 Header 即可可靠判斷(前提是前端統一使用 jQuery 或手動加入該 Header)。

1.3 HTTP Header 對比實例

# 普通表單提交
accept: */*
referer: https://localhost:8080/user2/toQueryPage.action
user-agent: Mozilla/4.0 ...
# 無 X-Requested-With

# AJAX 請求 (jQuery)
x-requested-with: XMLHttpRequest
accept: application/json, text/javascript, */*; q=0.01
content-type: application/x-www-form-urlencoded
...

二、Struts2 基類封裝:統一判斷與結果導向

2.1 實作 ServletRequestAware 獲取 Request

public abstract class BaseAction <ParamVo extends BaseParamVo, ResultVo extends BaseResultVo> 
        extends ActionSupport implements ServletRequestAware {

    private static final String AJAX_RESULT = "ajaxResult";
    private static final String XHR_HEADER_VALUE = "XMLHttpRequest";
    private static final String HEADER_NAME = "x-requested-with";

    private HttpServletRequest request;
    protected ParamVo paramVo;
    protected ResultVo resultVo;

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    @Override
    public String execute() {
        String resultPage = SUCCESS;
        try {
            resultVo = doExecute(paramVo); // 子類實作具體業務
        } catch (BaseException e) {
            resultPage = ERROR;
        }

        // 關鍵判斷:若為 AJAX 請求,導向 JSON 結果
        if (XHR_HEADER_VALUE.equals(request.getHeader(HEADER_NAME))) {
            resultPage = AJAX_RESULT;
        }
        return resultPage;
    }

    protected abstract ResultVo doExecute(ParamVo paramVo) throws BaseException;
}

2.2 struts.xml 定義全域 JSON 結果類型

<package name="ajax-default" extends="json-default">
    <global-results>
        <result name="ajaxResult" type="json">
            <param name="excludeNullProperties">true</param>
            <param name="root">resultVo</param> <!-- 只序列化 resultVo -->
            <param name="ignoreHierarchy">false</param>
        </result>
    </global-results>
</package>

子 Action 繼承 BaseAction 並指定 extends="ajax-default" 即可自動擁有 AJAX/普通雙模式支援。

三、效能調優:Profiling 攔截器實戰

3.1 發現內建寶藏

Struts2 核心功能多由攔截器實現。檢視 struts-default.xml 可發現 profiling 攔截器:

<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />

3.2 原始碼分析

public class ProfilingActivationInterceptor extends AbstractInterceptor {
    private String profilingKey = "profiling";
    private boolean devMode;

    @Inject(StrutsConstants.STRUTS_DEVMODE)
    public void setDevMode(String mode) { this.devMode = "true".equals(mode); }

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        if (devMode) {
            Object val = invocation.getInvocationContext().getParameters().get(profilingKey);
            if (val != null) {
                String sval = (val instanceof String) ? (String)val : ((String[])val)[0];
                boolean enable = "yes".equalsIgnoreCase(sval) || "true".equalsIgnoreCase(sval);
                UtilTimerStack.setActive(enable); // 啟動/關閉計時器
                invocation.getInvocationContext().getParameters().remove(profilingKey);
            }
        }
        return invocation.invoke();
    }
}

觸發條件:struts.devMode=true 且請求參數含 profiling=true 或 yes。

3.3 整合至自定義攔截器棧

<package name="ajax-default" extends="json-default">
    <interceptors>
        <interceptor-stack name="ajaxInterceptorStack">
            <interceptor-ref name="defaultStack" />
            <interceptor-ref name="profiling" /> <!-- 新增 profiling -->
        </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="ajaxInterceptorStack" />
    <global-results> ... </global-results>
</package>

3.4 前端啟用剖析

function searchAllUser() {
    jQuery.ajax({
        type: "post",
        url: "searchAllUser.action",
        dataType: 'json',
        data: jQuery("#userQueryForm").serialize() + "&profiling=yes", // 關鍵參數
        success: function(data) { /* ... */ }
    });
}

3.5 輸出範例

[Profiling] Action [searchAllUser] took 125ms
[Profiling]   Method execute took 110ms
[Profiling]   Result json took 15ms

輸出包含 Action 總耗時、業務方法耗時、Result 渲染耗時,精準定位效能瓶頸。

四、最佳實務總結

  1. AJAX 判斷:依賴 X-Requested-With Header,前端統一使用 jQuery 或攔截器統一添加。
  2. 基類抽象:將判斷邏輯、異常處理、結果導向封裝至 BaseAction,子類專注業務。
  3. JSON 序列化控制:配置 root 參數限制序列化範圍,避免循環引用與敏感資料洩露。
  4. 效能剖析:開發/測試環境開啟 devMode 與 profiling,生產環境關閉 devMode 避免開銷。
  5. 攔截器棧組合:按需組合 defaultStack + 業務攔截器(權限、日誌、事務、剖析),避免疊加不必要攔截器。

結語

善用 Struts2 內建機制(Header 判斷、結果類型、Profiling 攔截器),能以最小代價實現 AJAX 雙模式支援與效能可視化,是框架深度使用者的必修課。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved