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
大文件:流式讀寫 + 內存緩衝控制
@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 不攜帶文件元數據的缺陷@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<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 | 按需設置 |
# 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:生成客戶端代碼(含啟動類)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);
}
}
使用 SOAP UI 或 TCP Monitor 攔截請求:
<file> 為 Base64 字符串,體積膨脹 33%<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 實現高效文件傳輸的核心三要素:
DataHandler + @XmlMimeTypemtom_enabled=true + 大文件限制參數此方案已在生產環境支撐 500MB+ 文件穩定傳輸,是替代 FTP、HTTP 直傳的企業級標準選擇。