杰瑞科技汇

Java Webservice文件如何传输与处理?

  1. JAX-WS (Java API for XML Web Services):这是早期和非常成熟的基于 XML 的标准,我们通常说的 "Axis", "CXF" 等框架都是实现 JAX-WS 规范的。
  2. JAX-RS (Java API for RESTful Web Services):这是目前更主流、更轻量级的基于 REST 架构风格的标准,我们通常说的 "Jersey", "RESTEasy", "Spring MVC" 都是实现 JAX-RS 规范的。

下面我将为你详细讲解这两种方式,并提供完整的文件结构和代码示例。

Java Webservice文件如何传输与处理?-图1
(图片来源网络,侵删)

场景设定:一个简单的文件上传服务

我们将创建一个 WebService,它提供一个端点,允许客户端上传一个文件,服务端接收并保存在指定目录中,这个例子能很好地展示 WebService 如何处理二进制文件。


使用 JAX-WS (SOAP 方式)

JAX-WS 通常使用 SOAP 协议,消息格式是 XML,处理文件时,文件内容会被 Base64 编码后嵌入到 SOAP 消息的 <attachment> 中。

项目结构

jax-ws-file-upload/
├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── example
│       │           └── service
│       │               ├── FileUploadWS.java         // WebService 接口
│       │               ├── FileUploadWSImpl.java     // WebService 实现类
│       │               └── Publisher.java           // 发布服务的工具类
│       └── webapp
│           └── WEB-INF
│               └── web.xml

核心代码

a. pom.xml (使用 Maven)

需要引入 cxf-rt-frontend-jaxwscxf-rt-transports-http 依赖。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>jax-ws-file-upload</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cfx.version>3.4.5</cfx.version>
    </properties>
    <dependencies>
        <!-- CXF JAX-WS 核心依赖 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cfx.version}</version>
        </dependency>
        <!-- CXF HTTP 传输依赖 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cfx.version}</version>
        </dependency>
        <!-- Servlet API (如果使用 Tomcat 等容器) -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

b. FileUploadWS.java (WebService 接口)

使用 @WebService 注解来定义一个 WebService。

Java Webservice文件如何传输与处理?-图2
(图片来源网络,侵删)
package com.example.service;
import javax.jws.WebMethod;
import javax.jws.WebParam;
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 消息风格,默认是 DOCUMENT
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
public interface FileUploadWS {
    // @WebMethod 定义这是一个 WebService 方法
    // @WebParam 定义方法的参数名
    // @XmlMimeType 和 DataHandler 结合,用于处理附件(二进制数据)
    @WebMethod
    String uploadFile(
            @WebParam(name = "fileName") String fileName,
            @WebParam(name = "fileContent") @XmlMimeType("application/octet-stream") DataHandler fileContent);
}

c. FileUploadWSImpl.java (WebService 实现类)

实现接口,并处理文件保存逻辑。

package com.example.service;
import javax.activation.DataHandler;
import javax.jws.WebService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
@WebService(endpointInterface = "com.example.service.FileUploadWS") // 指向接口
public class FileUploadWSImpl implements FileUploadWS {
    @Override
    public String uploadFile(String fileName, DataHandler fileContent) {
        // 1. 创建保存文件的目录
        String uploadDir = "C:/temp/uploads/"; // 请确保此目录存在且有写入权限
        File dir = new File(uploadDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 2. 生成唯一文件名,防止覆盖
        String uniqueFileName = UUID.randomUUID().toString() + "_" + fileName;
        File uploadedFile = new File(uploadDir, uniqueFileName);
        // 3. 保存文件
        try (InputStream is = fileContent.getInputStream();
             FileOutputStream fos = new FileOutputStream(uploadedFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
            return "文件上传成功!保存在: " + uploadedFile.getAbsolutePath();
        } catch (IOException e) {
            e.printStackTrace();
            return "文件上传失败: " + e.getMessage();
        }
    }
}

d. Publisher.java (发布服务)

这是一个独立的 Java 应用,可以直接运行来发布 WebService。

package com.example.service;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
public class Publisher {
    public static void main(String[] args) {
        // 1. 创建 JaxWsServerFactoryBean
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        // 2. 设置服务实现类
        factory.setServiceBean(new FileUploadWSImpl());
        // 3. 设置服务地址
        factory.setAddress("http://localhost:8080/ws/fileupload");
        // 4. 创建并启动服务
        factory.create();
        System.out.println("WebService 已成功发布,访问地址为: http://localhost:8080/ws/fileupload?wsdl");
    }
}

e. web.xml (部署到 Web 容器)

如果你想将服务部署到 Tomcat 等 Web 容器中,需要配置 web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/ws/*</url-pattern>
    </servlet-mapping>
</web-app>

如何使用

  1. 发布服务:运行 Publisher.javamain 方法。
  2. 验证 WSDL:在浏览器中访问 http://localhost:8080/ws/fileupload?wsdl,如果能看到 XML 内容,说明发布成功。
  3. 客户端调用:你需要一个 SOAP 客户端(如 SoapUI,或使用 wsimport 生成的 Java 客户端)来调用这个服务,客户端需要构造一个包含文件附件的 SOAP 请求。

使用 JAX-RS (REST 方式)

JAX-RS 是目前更流行的方式,它使用 HTTP 协议,通常以 JSON 或 XML 交换数据,文件上传通常使用 multipart/form-data 格式。

Java Webservice文件如何传输与处理?-图3
(图片来源网络,侵删)

项目结构

jax-rs-file-upload/
├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── example
│       │           └── resource
│       │               └── FileResource.java        // RESTful 资源类
│       └── webapp
│           └── WEB-INF
│               └── web.xml

核心代码

a. pom.xml (使用 Maven)

需要引入 jersey-server, jersey-container-servlet, 和处理文件上传的 jersey-media-multipart

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>jax-rs-file-upload</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jersey.version>2.37</jersey.version>
    </properties>
    <dependencies>
        <!-- Jersey 核心依赖 -->
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- Jersey 文件上传支持 -->
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-multipart</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <!-- Servlet API (如果使用 Tomcat 等容器) -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

b. FileResource.java (RESTful 资源类)

使用 @Path, @POST, @FormDataParam 等注解来定义资源。

package com.example.resource;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
@Path("/files")
public class FileResource {
    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadFile(
            // @FormDataParam 用于接收 multipart/form-data 中的字段
            @FormDataParam("file") InputStream uploadedInputStream,
            @FormDataParam("file") FormDataContentDisposition fileDetail) {
        // 1. 检查文件是否存在
        if (uploadedInputStream == null || fileDetail == null) {
            return Response.status(Response.Status.BAD_REQUEST).entity("请上传一个文件").build();
        }
        // 2. 创建保存文件的目录
        String uploadDir = "C:/temp/uploads/"; // 请确保此目录存在且有写入权限
        File dir = new File(uploadDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 3. 生成唯一文件名
        String uniqueFileName = UUID.randomUUID().toString() + "_" + fileDetail.getFileName();
        File uploadedFile = new File(uploadDir, uniqueFileName);
        // 4. 保存文件
        try (FileOutputStream out = new FileOutputStream(uploadedFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = uploadedInputStream.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            String output = "文件 '" + uniqueFileName + "' 上传成功!保存在: " + uploadedFile.getAbsolutePath();
            return Response.status(Response.Status.OK).entity(output).build();
        } catch (IOException e) {
            e.printStackTrace();
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("文件上传失败: " + e.getMessage()).build();
        }
    }
}

c. web.xml (部署到 Web 容器)

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.example.resource</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>

如何使用

  1. 部署服务:将项目打包成 WAR 文件,部署到 Tomcat 或其他支持 Servlet 的容器中。
  2. 验证服务:在浏览器中访问 http://localhost:8080/your-app-name/api/files/upload,会返回 405 Method Not Allowed,因为这是一个 POST 接口,这是正常的。
  3. 客户端调用
    • 使用 curl 命令行工具
      curl -X POST -F "file=@/path/to/your/local/file.txt" http://localhost:8080/your-app-name/api/files/upload
    • 使用 Postman
      • 选择 POST 方法。
      • 输入 URL: http://localhost:8080/your-app-name/api/files/upload
      • 在 "Body" 选项卡中,选择 "form-data"。
      • 在 "Key" 列中输入 file,在 "Type" 列中选择 "File",然后点击 "Select Files" 选择你的本地文件。
      • 点击 "Send" 按钮。

总结与对比

特性 JAX-WS (SOAP) JAX-RS (REST)
协议 SOAP (基于 XML) HTTP (GET, POST, PUT, DELETE)
数据格式 XML (严格定义的 Schema) JSON, XML, Text 等 (更灵活)
风格 面向服务,有明确的接口契约 面向资源,风格更轻量、无状态
文件处理 通过 SOAP Attachment (如 MTOM 优化) 通过 multipart/form-data
标准 Java EE 标准的一部分 Java EE 标准的一部分
适用场景 企业级应用,需要高安全性、事务、ACID 特性,与旧系统集成 Web 和移动应用 API,前后端分离,需要高性能和易用性
框架示例 Apache CXF, Metro Jersey, RESTEasy, Spring MVC (也支持 REST)

如何选择?

  • 如果你的项目是传统的企业级应用,需要与现有的 SOAP 服务集成,或者对事务和安全有非常严格的要求,可以选择 JAX-WS
  • 如果你在构建新的 Web 应用或移动 App 的后端 API,追求开发效率、性能和灵活性,JAX-RS (REST) 是绝对的首选,目前绝大多数新的 Java WebService 项目都采用 REST 风格。
分享:
扫描分享到社交APP
上一篇
下一篇