Spring Boot WebService服务搭建

XJC

xjc 是 Java Architecture for XML Binding (JAXB) 的一部分,它是一个命令行工具,用于将 XML 架构(XML Schema)转换为 Java 类。以下是 xjc 工具的基本用法:

基本命令格式

1
xjc [options] <schema file/URL/dir>

常用选项

  • -d <directory>: 指定生成 Java 类的目标目录。
  • -p <package>: 指定生成的 Java 类应该放在哪个包中。
  • -encoding <encoding>: 指定源文件编码。
  • -extension: 使用 JAXB XML 绑定扩展。
  • -verbose: 输出详细的日志信息。

示例

假设你有一个名为 schema.xsd 的 XML Schema 文件,且当前目录下有 src 文件夹,你想将它转换为 Java 类,并将这些类放在 com.example 包中,你可以使用以下命令:

1
xjc -d ./src -p com.example schema.xsd

这将在 ./src 目录下创建 com/example 目录,并将生成的 Java 类放在该目录中。

注意事项

  • 在 JDK 8 中,xjc 工具位于 jaxb-xjc 包中。如果你使用的是 JDK 9 或更高版本,xjc 工具可能不再包含在默认的 JDK 中,你需要单独下载 JAXB 实现。
  • 确保你的环境变量 JAVA_HOME 正确设置,并且 bin 目录在 PATH 环境变量中。
  • 如果你在 Windows 上运行 xjc,可能需要运行 xjc.exe 而不是 xjc

验证安装

在命令行中运行以下命令可以验证 xjc 是否可用:

1
xjc -version

如果 xjc 已正确安装,这个命令将显示版本信息。
使用 xjc 时可能遇到的问题通常与 XML Schema 本身有关,例如不正确的格式或者 xjc 无法处理的某些复杂结构。在这种情况下,你可能需要检查 XML Schema 文件或者查阅更详细的 xjc 文档来解决问题。

Maven插件:jaxb2-maven-plugin:2.5.0

插件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 源 XSD/WSDL 文件目录 -->
<sources>
<source>src/main/resources/xsd</source>
</sources>
<!-- 生成的 Java 文件输出目录 -->
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<!-- 生成的包名 -->
<packageName>com.example.model</packageName>
<!-- 是否清空输出目录, 慎用,会删除 ${outputDirectory} 下的所有文件 -->
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>

主要配置参数说明:

  • sources: XSD 文件所在目录
  • outputDirectory: 生成的 Java 类输出目录
  • packageName: 生成的 Java 类的包名
  • clearOutputDir: 是否在生成前清空输出目录
  • encoding: 文件编码,默认 UTF-8
  • extension: 是否启用 JAXB 扩展
  • args: 传递给 XJC 的额外参数

常用的 goal:

  • xjc: 从 XSD 生成 Java 类
  • schemagen: 从 Java 类生成 XSD
  • testXjc: 用于测试的 XJC goal
  • testSchemagen: 用于测试的 schemagen goal

示例

XSD 文件 book.xsd:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

执行 mvn clean compile 后会生成对应的 Java 类。也可以使用 mvn jaxb:xjc 生成 Java 类

生成的绑定类使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Book book = new Book();
book.setTitle("Java 编程思想");
book.setAuthor("Bruce Eckel");
book.setPrice(new BigDecimal("99.00"));

// 序列化为 XML
JAXBContext context = JAXBContext.newInstance(Book.class);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(book, System.out);

// 从 XML 反序列化
Unmarshaller unmarshaller = context.createUnmarshaller();
Book unmarshalledBook = (Book) unmarshaller.unmarshal(new File("book.xml"));

高级配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<configuration>
<!-- 生成 Fluent API -->
<arguments>
<argument>-Xfluent-api</argument>
</arguments>

<!-- 添加自定义绑定文件 -->
<bindingDirectory>src/main/resources/bindings</bindingDirectory>

<!-- 生成 Episode 文件用于增量编译 -->
<episode>true</episode>

<!-- 自定义类型映射 -->
<bindings>
<binding>
<includeSchema>**/*.xsd</includeSchema>
<bindings>**/*.xjb</bindings>
</binding>
</bindings>
</configuration>

常见问题处理:

  • 如果生成的类有编码问题,检查 encoding 配置
  • 如果需要自定义类型映射,使用 bindings 文件
  • 如果要生成更简洁的 API,可以使用 -Xfluent-api 参数
  • 如果有多个 XSD 之间有依赖关系,使用 episode 功能

最佳实践:

  • 将 XSD 文件放在 src/main/resources/xsd 目录下
  • 使用 clearOutputDir=false 避免覆盖手动修改的文件
  • 对于大型项目建议使用 episode 功能提高编译效率
  • 合理规划包名,避免与其他类冲突
  • 添加必要的注释说明生成的代码用途

这样配置和使用 jaxb2-maven-plugin 可以方便地实现 XML 架构和 Java 类之间的映射。记得根据实际项目需求调整相关配置参数。

spring-boot-starter-web-services 通过xsd创建服务

依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>

schema文件

./src/main/java/resources/schema/users.xsd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://ws.jeremytsai.com/users"
targetNamespace="http://ws.jeremytsai.com/users"
elementFormDefault="qualified">

<xs:element name="getUserRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:long"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name="getUserResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="user" type="tns:user"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:complexType name="user">
<xs:sequence>
<xs:element name="id" type="xs:long"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="email" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

/**
* @author Jeremy Tsai
* @version 1.0
* @since 2024-10-19 14:20
*/
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}

@Bean(name = "users")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema usersSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("UsersPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://ws.jeremytsai.com/users");
wsdl11Definition.setSchema(usersSchema);
return wsdl11Definition;
}

@Bean
public XsdSchema usersSchema() {
return new SimpleXsdSchema(new ClassPathResource("schema/users.xsd"));
}
}

enpoint类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import com.jeremytsai.ws.wsdl.users.GetUserRequest;
import com.jeremytsai.ws.wsdl.users.GetUserResponse;
import com.jeremytsai.ws.wsdl.users.User;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
/**
* @author Jeremy Tsai
* @version 1.0
* @since 2024-10-19 14:21
*/
@Endpoint
public class UserEndpoint {

private static final String NAMESPACE_URI = "http://ws.jeremytsai.com/users";

@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getUserRequest")
@ResponsePayload
public GetUserResponse getUser(@RequestPayload GetUserRequest request) {
GetUserResponse response = new GetUserResponse();
User user = new User();
user.setId(request.getId());
user.setName("张三");
user.setEmail("zhangsan@example.com");
response.setUser(user);
return response;
}
}

使用插件从xsd生成java对象

插件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/resources/schema/users.xsd</source>
</sources>
<generateEpisode>false</generateEpisode>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<packageName>com.jeremytsai.ws.wsdl.users</packageName>
<clearOutputDir>false</clearOutputDir>
<extension>false</extension>
</configuration>
</plugin>

执行命令 mvn jaxb2:xjc

运行项目即可。

使用插件从pojo生成java对象

先创建各个pojo对象,使用对应的XML注解。这些对象同xsd生成的pojo。然后使用插件指定source为pojo的文件路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.5.0</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>${project.basedir}/src/main/java/com/example/users</source>
</sources>

<generateEpisode>false</generateEpisode>
<outputDirectory>${project.basedir}/src/main/resources/xsd</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>

最后使用 mvn jaxb2:schemagen 生成即可。默认文件名为 schema1.xsd ,需要自己手动修改为对应的文件名。

JAX-WS (Java API for XML Web Services)

定义

JAX-WS 是一个 Java 编程语言 API,用于创建 Web 服务。它是 Java EE 平台的一部分,提供了一种标准化的方法来开发和部署 Web 服务。

目的

JAX-WS 旨在简化 Web 服务的开发,允许开发者专注于业务逻辑而不是底层的通信细节。

主要特性

  • 支持 SOAP (Simple Object Access Protocol) 1.1 和 1.2
  • 支持 WSDL (Web Services Description Language) 1.1
  • 支持通过 HTTP 进行传输
  • 提供了一套注解,简化了 Web 服务的开发
  • 支持同步和异步的 Web 服务调用

关键注解

  • @WebService:用于定义一个 Web 服务
  • @WebMethod:用于暴露一个方法作为 Web 服务操作
  • @WebParam:用于定制化方法参数的属性
  • @WebResult:用于定制化方法返回值的属性

工作原理

JAX-WS 使用 JAXB (Java Architecture for XML Binding) 来处理 XML 和 Java 对象之间的映射。它可以自动生成 WSDL 文件,也可以从 WSDL 文件生成 Java 代码。

优势

  • 标准化:作为 Java EE 的一部分,它提供了一个标准的 Web 服务开发方法
  • 易用性:通过注解简化了 Web 服务的开发
  • 灵活性:支持多种协议和编码
  • 可移植性:JAX-WS 应用可以轻松地在不同的 Java EE 兼容的应用服务器之间移植

与 Spring 的关系

虽然 JAX-WS 不是 Spring 提供的功能,但 Spring 框架提供了对 JAX-WS 的集成支持。Spring 可以管理 JAX-WS 服务的生命周期,并可以将 Spring 的其他特性(如依赖注入)应用到 Web 服务中。