杰瑞科技汇

Java webservice上传文件怎么实现?

  1. 基于 SOAP (JAX-WS + MTOM):这是传统的、标准化的方式,通过 SOAP 协议传输,并利用 MTOM (Message Transmission Optimization Mechanism) 机制来高效地传输二进制文件数据。
  2. 基于 REST (JAX-RS):这是目前更流行、更简洁的方式,将文件作为 multipart/form-data 请求体的一部分进行传输,类似于常见的 HTML 表单文件上传。

下面我将详细介绍这两种方式的完整实现步骤和代码示例。

Java webservice上传文件怎么实现?-图1
(图片来源网络,侵删)

基于 SOAP (JAX-WS + MTOM)

这种方式的核心是 MTOM (Message Transmission Optimization Mechanism),MTOM 允许在 SOAP 消息中,将较大的二进制数据(如文件)以原始字节的形式(XOP: XML-binary Optimized Packaging)进行传输,而不是用 Base64 编码嵌入到 XML 中,从而大大提高了传输效率。

步骤 1: 服务端实现

我们将使用 JAX-WS API 来创建一个 WebService。

  1. 创建 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>
  2. 创建文件传输服务接口

    Java webservice上传文件怎么实现?-图2
    (图片来源网络,侵删)
    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);
    }
  3. 创建服务接口的实现类

    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();
            }
        }
    }
  4. 发布 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 调用。

  1. 使用 wsimport 生成客户端代码: 在项目根目录下运行以下命令(确保服务端已启动):

    Java webservice上传文件怎么实现?-图3
    (图片来源网络,侵删)
    wsimport -keep -p com.example.client http://localhost:8080/ws/file?wsdl

    这会生成一堆 .java 文件,包括 FileTransferServiceFileTransferService_Service 等。

  2. 编写客户端调用代码

    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 实现一起使用)。

  1. 创建 Maven 项目,并
分享:
扫描分享到社交APP
上一篇
下一篇