- 基于 SOAP (JAX-WS + MTOM):这是传统的、标准化的方式,通过 SOAP 协议传输,并利用 MTOM (Message Transmission Optimization Mechanism) 机制来高效地传输二进制文件数据。
- 基于 REST (JAX-RS):这是目前更流行、更简洁的方式,将文件作为
multipart/form-data请求体的一部分进行传输,类似于常见的 HTML 表单文件上传。
下面我将详细介绍这两种方式的完整实现步骤和代码示例。

基于 SOAP (JAX-WS + MTOM)
这种方式的核心是 MTOM (Message Transmission Optimization Mechanism),MTOM 允许在 SOAP 消息中,将较大的二进制数据(如文件)以原始字节的形式(XOP: XML-binary Optimized Packaging)进行传输,而不是用 Base64 编码嵌入到 XML 中,从而大大提高了传输效率。
步骤 1: 服务端实现
我们将使用 JAX-WS API 来创建一个 WebService。
-
创建 Maven 项目,并添加依赖:
<dependencies> <!-- JAX-WS API --> <dependency> <groupId>javax.xml.ws</groupId> <artifactId>jaxws-api</artifactId> <version>2.3.1</version> </dependency> <!-- JAX-WS RI (参考实现) --> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.3.3</version> </dependency> <!-- 为了简化服务器,使用嵌入式 Jetty --> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.4.48.v20250622</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>9.4.48.v20250622</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>apache-jsp</artifactId> <version>9.4.48.v20250622</version> </dependency> </dependencies> -
创建文件传输服务接口:
(图片来源网络,侵删)import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.bind.annotation.XmlMimeType; import javax.activation.DataHandler; import java.io.InputStream; // @WebService 标记这是一个 WebService 接口 @WebService // @SOAPBinding 指定 SOAP 协议版本 @SOAPBinding(style = SOAPBinding.Style.DOCUMENT) public interface FileTransferService { // @WebMethod 标记这是一个 WebService 方法 // @XmlMimeType 指定 DataHandler 处理的数据类型为 "application/octet-stream",即任意二进制流 @WebMethod String uploadFile(@XmlMimeType("application/octet-stream") DataHandler fileData, String fileName); } -
创建服务接口的实现类:
import javax.activation.DataHandler; import javax.jws.WebService; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @WebService(endpointInterface = "com.example.FileTransferService") public class FileTransferServiceImpl implements FileTransferService { @Override public String uploadFile(DataHandler fileData, String fileName) { // 定义服务器上存储文件的目录 String uploadDir = "uploads/"; File uploadDirFile = new File(uploadDir); if (!uploadDirFile.exists()) { uploadDirFile.mkdirs(); } String filePath = uploadDir + fileName; System.out.println("开始接收文件: " + filePath); try (InputStream is = fileData.getInputStream(); FileOutputStream fos = new FileOutputStream(filePath)) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { fos.write(buffer, 0, bytesRead); } System.out.println("文件接收成功: " + filePath); return "文件上传成功: " + fileName; } catch (IOException e) { e.printStackTrace(); return "文件上传失败: " + e.getMessage(); } } } -
发布 WebService:
import com.sun.net.httpserver.HttpServer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import javax.xml.ws.Endpoint; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import javax.xml.ws.spi.http.HttpHandler; import javax.xml.ws.spi.http.HttpExchange; import java.util.Collections; import java.util.Set; public class ServerApp { public static void main(String[] args) throws Exception { // 创建 Jetty 服务器 Server server = new Server(8080); // 创建 Servlet 上下文处理器 ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); server.setHandler(context); // 创建我们的 WebService 实现 FileTransferServiceImpl serviceImpl = new FileTransferServiceImpl(); // 使用 JAX-WS 的 Endpoint 发布服务 // 注意:为了支持 MTOM,需要设置属性 "javax.xml.ws.soap.http.enabled" Endpoint endpoint = Endpoint.create(serviceImpl); endpoint.setProperties(Collections.<String, Object>singletonMap("javax.xml.ws.soap.http.enabled", "true")); // 将服务绑定到 /ws/file 的路径 context.addServlet(new ServletHolder(new SoapServletAdapter(endpoint)), "/ws/file"); System.out.println("SOAP WebService 已启动,地址: http://localhost:8080/ws/file?wsdl"); server.start(); server.join(); } // 这是一个简单的适配器,将 JAX-WS Endpoint 集成到 Jetty 中 // 在实际项目中,你可能需要更复杂的配置或使用 CXF 等框架 public static class SoapServletAdapter extends javax.servlet.http.HttpServlet { private final Endpoint endpoint; public SoapServletAdapter(Endpoint endpoint) { this.endpoint = endpoint; } @Override public void init() { endpoint.publish(this); } } }
步骤 2: 客户端实现
客户端可以使用 wsimport 工具从 WSDL 文件生成客户端代码,或者直接使用 JAX-WS API 调用。
-
使用
wsimport生成客户端代码: 在项目根目录下运行以下命令(确保服务端已启动):
(图片来源网络,侵删)wsimport -keep -p com.example.client http://localhost:8080/ws/file?wsdl
这会生成一堆
.java文件,包括FileTransferService和FileTransferService_Service等。 -
编写客户端调用代码:
import com.example.client.FileTransferService; import com.example.client.FileTransferService_Service; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.xml.ws.BindingProvider; import javax.xml.ws.soap.MTOMFeature; import java.io.File; public class ClientApp { public static void main(String[] args) { // 创建服务实例 FileTransferService_Service service = new FileTransferService_Service(); FileTransferService port = service.getFileTransferServicePort(); // 关键步骤:启用 MTOM // MTOMFeature.DEFAULT_THRESHOLD 是 64KB,小于此大小的文件不会使用 MTOM // 我们可以显式地启用它 ((BindingProvider) port).getBinding().setHandlerChain(null); // 清除可能的处理器 // 准备要上传的文件 File fileToUpload = new File("path/to/your/localfile.txt"); if (!fileToUpload.exists()) { System.out.println("本地文件不存在: " + fileToUpload.getAbsolutePath()); return; } // 创建 DataHandler,它会将文件封装起来 DataHandler dataHandler = new DataHandler(new FileDataSource(fileToUpload)); // 调用服务端的 uploadFile 方法 System.out.println("开始上传文件: " + fileToUpload.getName()); String result = port.uploadFile(dataHandler, fileToUpload.getName()); System.out.println("收到服务端响应: " + result); } }
基于 REST (JAX-RS)
这种方式更现代、更简单,非常适合文件上传这类场景,它将文件作为 multipart/form-data 请求体的一部分发送。
步骤 1: 服务端实现
我们将使用 JAX-RS API (通常与 Jersey 或 RESTEasy 实现一起使用)。
- 创建 Maven 项目,并
