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

CXF 實戰:WebService 文件上傳下載與大文件 MTOM 優化全流程

     編輯:Java 綜合教學

前言:為什麼選 CXF 做文件傳輸?

Apache CXF 是成熟的 JAX-WS 實現,原生支援 MTOM (Message Transmission Optimization Mechanism),能將二進制附件以 xop:Include 形式外掛傳輸,避免 Base64 編碼 33% 體積膨脹,是企業級文件上傳下載的首選方案。本文完整演示:實體封裝、服務定義、Spring 整合、MTOM 啟用、大文件流式處理、客戶端生成與測試。

架構設計

框架:Spring 3.1 + CXF 2.7.6
協議:SOAP 1.2 + MTOM
傳輸:HTTP/HTTPS
大文件:流式讀寫 + 內存緩衝控制

步驟 1:定義文件傳輸包裝類(支援文件名、類型、二進制流)

@XmlAccessorType(XmlAccessType.FIELD)
public class CxfFileWrapper {
    private String fileName;
    private String fileExtension;

    @XmlMimeType("application/octet-stream") // 關鍵:告訴 CXF 此字段為二進制,啟用 MTOM
    private DataHandler file; // javax.activation.DataHandler 支援流式讀寫

    // Getter/Setter...
}

關鍵點:

  • DataHandler 封裝 DataSource,支援 getInputStream() 流式讀取
  • @XmlMimeType 觸發 CXF MTOM 處理邏輯
  • 額外攜帶 fileName、fileExtension 彌補 SOAP 不攜帶文件元數據的缺陷

步驟 2:定義服務接口與實現

@WebService(name = "FileWS", serviceName = "FileWS")
public interface FileWS {
    @WebMethod
    boolean upload(@WebParam(name = "file") CxfFileWrapper file);

    @WebMethod
    CxfFileWrapper download();
}
@Service("fileWS")
@WebService(endpointInterface = "net.bwda.service.upload.FileWS")
public class FileWSImpl implements FileWS {

    private static final int BUFFER_SIZE = 1024 * 1024; // 1MB 緩衝

    @Override
    public boolean upload(CxfFileWrapper wrapper) {
        try (InputStream is = wrapper.getFile().getInputStream();
             OutputStream os = new FileOutputStream("d:/upload/" + wrapper.getFileName());
             BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE)) {

            byte[] buffer = new byte[BUFFER_SIZE];
            int len;
            while ((len = is.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            bos.flush();
            return true;
        } catch (Exception e) {
            log.error("Upload failed", e);
            return false;
        }
    }

    @Override
    public CxfFileWrapper download() {
        CxfFileWrapper wrapper = new CxfFileWrapper();
        wrapper.setFileName("test.xlsx");
        wrapper.setFileExtension("xlsx");
        DataSource ds = new FileDataSource(new File("D:/test.xlsx"));
        wrapper.setFile(new DataHandler(ds));
        return wrapper;
    }
}

大文件關鍵:

  • 使用 try-with-resources 確保流關閉
  • 固定緩衝區 1MB,避免大文件載入內存 OOM
  • 流式讀寫,不將整個文件載入堆內存

步驟 3:CXF Spring 配置(核心:啟用 MTOM + 設置大文件限制)

<beans xmlns="https://www.springframework.org/schema/beans"
       xmlns:jaxws="https://cxf.apache.org/jaxws"
       xmlns:cxf="https://cxf.apache.org/core"
       xsi:schemaLocation="...">

    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

    <cxf:bus>
        <cxf:properties>
            <!-- 設置最大文本長度 256MB,防止大文件 Base64 回退時 OOM -->
            <entry key="org.apache.cxf.stax.maxTextLength" value="268435456" />
        </cxf:properties>
    </cxf:bus>

    <jaxws:endpoint id="fileWSEndpoint" implementor="#fileWS" address="/file">
        <jaxws:properties>
            <!-- 核心:啟用 MTOM -->
            <entry key="mtom_enabled" value="true" />
        </jaxws:properties>
    </jaxws:endpoint>
</beans>

配置解析:

配置項作用建議值
mtom_enabled啟用 MTOM 優化二進制傳輸true
org.apache.cxf.stax.maxTextLength最大文本長度(字符數),防止非 MTOM 回退時拒絕服務268435456 (256MB)
org.apache.cxf.io.CachedOutputStream.threshold內存緩衝閾值,超過寫臨時文件1048576 (1MB)
org.apache.cxf.io.CachedOutputStream.maxSize最大緩衝大小,防止 OOM按需設置

步驟 4:生成客戶端代碼

# CXF 自帶 wsdl2java 工具
d:\apache-cxf-2.7.6\bin\wsdl2java.bat \
  -frontend jaxws21 \
  -p com.test.webservice.file \
  -client \
  https://localhost:9080/filemark/webservice/file?wsdl
  • -frontend jaxws21:JAX-WS 2.1 規范
  • -p:生成包名
  • -client:生成客戶端代碼(含啟動類)

步驟 5:客戶端上傳測試代碼

public class FileWSClient {
    public static void main(String[] args) throws Exception {
        URL wsdlURL = FileWSImplService.WSDL_LOCATION;
        QName serviceName = new QName("https://upload.serviceimpl.bwda.net/", "FileWSImplService");
        FileWSImplService service = new FileWSImplService(wsdlURL, serviceName);
        FileWS port = service.getFileWSImplPort();

        // 構建上傳對象
        CxfFileWrapper wrapper = new CxfFileWrapper();
        wrapper.setFileName("test.csv");
        wrapper.setFileExtension("csv");
        DataSource ds = new FileDataSource(new File("d:/test.csv"));
        wrapper.setFile(new DataHandler(ds));

        // 調用(內部自動組裝 SOAP + MTOM 發送)
        boolean result = port.upload(wrapper);
        System.out.println("Upload result: " + result);
    }
}

MTOM 抓包驗證(關鍵驗證步驟)

使用 SOAP UI 或 TCP Monitor 攔截請求:

  • 未啟用 MTOM:SOAP Body 中 <file> 為 Base64 字符串,體積膨脹 33%
  • 啟用 MTOM:SOAP Body 中 <file> 為 <xop:Include href="cid:..."/>,二進制內容在 HTTP Multipart 相關部分傳輸
--uuid:xxx
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <root.message@cxf.apache.org>

<soap:Envelope>...<file><xop:Include href="cid:file@cxf.apache.org"/></file>...</soap:Envelope>

--uuid:xxx
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <file@cxf.apache.org>

[二進制文件內容...]

總結

CXF + MTOM 實現高效文件傳輸的核心三要素:

  1. 實體類:DataHandler + @XmlMimeType
  2. 配置:mtom_enabled=true + 大文件限制參數
  3. 實現:流式讀寫 + 固定緩衝區,避免全量載入內存

此方案已在生產環境支撐 500MB+ 文件穩定傳輸,是替代 FTP、HTTP 直傳的企業級標準選擇。

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