- 基于 JAX-WS (SOAP) 的文件上传:传统的、基于 XML 的 WebService 方式。
- 基于 RESTful (JAX-RS) 的文件上传:现代、轻量级、基于 HTTP 的方式,是目前更推荐的做法。
基于 JAX-WS (SOAP) 的文件上传
SOAP WebService 上传文件通常有两种方式:

- MTOM (Message Transmission Optimization Mechanism):强烈推荐,它是一种 SOAP 扩展,允许在 SOAP 消息中以原始二进制形式(而非 Base64 编码)传输大型附件,这极大地提高了效率和性能。
- Base64 编码:将文件内容直接编码到 SOAP 消息的 XML 标签中,这种方式简单,但对于大文件,XML 会变得非常臃肿,性能极差,不推荐用于生产环境。
下面我们重点介绍 MTOM 方式。
服务端 (Server Side)
我们将使用 JAX-WS 的参考实现 JAX-WS RI (通常包含在 JDK 中)。
步骤:
- 创建一个数据类 (POJO),用于接收文件信息。
- 创建一个 WebService 接口,并定义一个用于上传文件的方法。
- 实现接口,编写具体的上传逻辑。
- 发布 WebService。
代码示例:

数据类 FileUploadRequest.java
这个类将作为 SOAP 消息的附件容器。
import javax.activation.DataHandler;
import javax.xml.bind.annotation.XmlMimeType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.InputStream;
// 使用 @XmlMimeType 注解指定附件的 MIME 类型
public class FileUploadRequest {
private String fileName;
private String fileType;
// DataHandler 是 JAX-WS 处理附件的核心类
private DataHandler fileData;
// 构造函数、getters 和 setters
public FileUploadRequest() {}
public FileUploadRequest(String fileName, String fileType, DataHandler fileData) {
this.fileName = fileName;
this.fileType = fileType;
this.fileData = fileData;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public DataHandler getFileData() {
return fileData;
}
public void setFileData(DataHandler fileData) {
this.fileData = fileData;
}
// 一个方便的方法,可以从 DataHandler 获取输入流
public InputStream getFileInputStream() throws Exception {
return fileData.getInputStream();
}
}
WebService 接口 FileUploadService.java
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
// @WebService 定义这是一个 WebService
@WebService
// @SOAPBinding 定义 SOAP 消息风格,使用 DOCUMENT 表示标准的 SOAP 消息格式。
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public interface FileUploadService {
// @WebMethod 定义这是一个可以远程调用的方法
// method = "MTOM" 启用 MTOM 支持,这是关键!
@SOAPBinding(use = SOAPBinding.Use.LITERAL, mode = SOAPBinding.Mode.PARTIAL)
@WebMethod
String uploadFile(FileUploadRequest request);
}
WebService 实现类 FileUploadServiceImpl.java

import javax.jws.WebService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@WebService(endpointInterface = "com.example.webservice.FileUploadService") // 指向接口
public class FileUploadServiceImpl implements FileUploadService {
@Override
public String uploadFile(FileUploadRequest request) {
if (request == null || request.getFileData() == null) {
return "上传失败:请求为空或未包含文件数据。";
}
String fileName = request.getFileName();
String uploadDir = "C:\\uploads\\"; // 定义服务器上存储文件的目录
// 确保目录存在
new File(uploadDir).mkdirs();
String filePath = uploadDir + fileName;
try (InputStream is = request.getFileInputStream();
OutputStream os = new FileOutputStream(filePath)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
System.out.println("文件 '" + fileName + "' 上传成功,保存在: " + filePath);
return "文件 '" + fileName + "' 上传成功!";
} catch (IOException e) {
e.printStackTrace();
return "上传失败: " + e.getMessage();
} catch (Exception e) {
e.printStackTrace();
return "上传失败: " + e.getMessage();
}
}
}
发布 WebService 的主类 Publisher.java
import javax.xml.ws.Endpoint;
public class Publisher {
public static void main(String[] args) {
// 定义 WebService 的发布地址
String address = "http://localhost:8080/FileUploadService";
// 创建并发布 WebService
Endpoint.publish(address, new FileUploadServiceImpl());
System.out.println("WebService 已发布在: " + address);
System.out.println("请使用 MTOM 客户端进行调用。");
}
}
如何运行:
- 将以上 Java 文件放在同一个包下(
com.example.webservice)。 - 编译并运行
Publisher.java。 - 你的 WebService 已经在
http://localhost:8080/FileUploadService上运行了。
客户端 (Client Side)
客户端也需要启用 MTOM 支持。
使用 wsimport 生成客户端代码:
在命令行中运行(确保你的服务端正在运行):
wsimport -keep -p com.example.client http://localhost:8080/FileUploadService?wsdl
这会生成一堆客户端所需的 Java 文件(接口、实现类等)。
客户端调用代码 FileUploadClient.java
import com.example.client.FileUploadRequest;
import com.example.client.FileUploadService;
import com.example.client.FileUploadService_Service;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.soap.SOAPBinding;
import java.io.File;
public class FileUploadClient {
public static void main(String[] args) {
// 1. 创建服务
FileUploadService_Service service = new FileUploadService_Service();
FileUploadService port = service.getFileUploadServicePort();
// 2. 关键步骤:启用 MTOM
// 获取 BindingProvider 并设置 MTOM
BindingProvider bp = (BindingProvider) port;
SOAPBinding binding = (SOAPBinding) bp.getBinding();
binding.setMTOMEnabled(true); // 必须设置!
// 3. 准备要上传的文件
File fileToUpload = new File("C:\\path\\to\\your\\localfile.txt");
if (!fileToUpload.exists()) {
System.out.println("本地文件不存在!");
return;
}
// 4. 创建 DataHandler
// FileDataSource 将文件绑定到 DataHandler
DataHandler dataHandler = new DataHandler(new FileDataSource(fileToUpload));
// 5. 创建请求对象
FileUploadRequest request = new FileUploadRequest();
request.setFileName(fileToUpload.getName());
request.setFileType("text/plain"); // 设置 MIME 类型
request.setFileData(dataHandler);
// 6. 调用远程方法
System.out.println("正在上传文件: " + fileToUpload.getName());
String response = port.uploadFile(request);
System.out.println("服务器响应: " + response);
}
}
基于 RESTful (JAX-RS) 的文件上传
这是目前更流行、更简单的方式,它不依赖 SOAP 协议,直接使用 HTTP POST 请求。
服务端 (Server Side)
我们将使用 Jersey(JAX-RS 的参考实现)作为框架,如果你使用 Spring Boot,集成会更加简单。
依赖 (Maven pom.xml)
<dependencies>
<!-- Jersey 核心依赖 -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.39</version>
</dependency>
<!-- 支持 multipart/form-data -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.39</version>
</dependency>
<!-- 如果需要 JSON 