WebService框架(四)Spring Web Services配置使用

一、Spring Web Services 简介

Spring Web Services 是 Spring 提供的一个用于开发 SOAP Web 服务的框架。它强调契约优先(Contract-First)开发方式,支持 XML Schema、WSDL,适合需要与遗留系统或第三方集成的场景。


二、Spring WS 主要配置方式

Spring WS 支持两种主要配置方式:

  1. 基于 XML 配置(传统方式)
  2. 基于 Java 注解配置(推荐方式,Spring Boot 支持)

下面以 Spring Boot 为例,介绍基于注解的配置方式。


三、Spring WS 使用步骤

1. 添加依赖

如果你使用 Maven,添加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

2. 定义 XML Schema (XSD)

在 src/main/resources 下创建一个 XSD 文件(如 countries.xsd),定义你的数据结构:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://example.com/ws/countries"
           xmlns:tns="http://example.com/ws/countries"
           elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

3. 使用 JAXB 生成 Java 类

可以用工具或 IDE 自动生成,也可以手动编写与 XSD 对应的 Java Bean。

例如:

@XmlRootElement(name = "getCountryRequest", namespace = "http://example.com/ws/countries")
public class GetCountryRequest {
    private String name;
    // getter/setter
}

4. 编写 Endpoint

Endpoint 是处理 SOAP 请求的核心类。

@Endpoint
public class CountryEndpoint {

    private static final String NAMESPACE_URI = "http://example.com/ws/countries";

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
    @ResponsePayload
    public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
        // 业务逻辑
        GetCountryResponse response = new GetCountryResponse();
        // 设置 response 内容
        return response;
    }
}

5. 配置 Web Service

创建一个配置类,注册 XSD Schema。

@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {

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

    @Bean(name = "countries")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("CountriesPort");
        wsdl11Definition.setLocationUri("/ws");
        wsdl11Definition.setTargetNamespace("http://example.com/ws/countries");
        wsdl11Definition.setSchema(countriesSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema countriesSchema() {
        return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
    }
}

6. 启动应用

启动 Spring Boot 应用后,访问 http://localhost:8080/ws/countries.wsdl 可获取 WSDL 文件。


四、常见进阶配置

1. 安全配置(WS-Security)

Spring WS 支持通过拦截器实现 SOAP 消息的安全性,例如用户名密码认证、签名等。

@Bean
public EndpointInterceptor securityInterceptor() {
    Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
    interceptor.setValidationActions("UsernameToken");
    // 配置用户名、密码校验
    return interceptor;
}

@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
    interceptors.add(securityInterceptor());
}

2. 日志与监控

可以通过拦截器或 Spring AOP 实现 SOAP 消息日志记录。


五、客户端调用

Spring WS 也支持客户端调用 SOAP 服务,常用 WebServiceTemplate

@Autowired
private WebServiceTemplate webServiceTemplate;

GetCountryRequest request = new GetCountryRequest();
request.setName("China");
GetCountryResponse response = (GetCountryResponse) webServiceTemplate.marshalSendAndReceive(request);

六、参考资料


七、常见问题

  1. 端点没有被识别?
    检查 @Endpoint 注解和 @PayloadRoot 的命名空间、localPart 是否正确。
  2. WSDL 无法访问?
    检查 ServletMapping 是否正确,Bean 名必须和 WSDL 名一致。
  3. SOAP 消息格式不正确?
    检查 JAXB 类和 XSD 是否匹配。

八、WS-Security 配置详解

Spring WS 支持基于 WS-Security 的 SOAP 消息安全。常见安全需求有:

  • 用户名/密码认证
  • 消息签名和加密
  • 时间戳防重放

1. 添加依赖

除了 spring-boot-starter-web-services,还需要:

<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-ws-security</artifactId>
</dependency>

2. 配置 Wss4jSecurityInterceptor

@Bean
public Wss4jSecurityInterceptor securityInterceptor() {
    Wss4jSecurityInterceptor interceptor = new Wss4jSecurityInterceptor();
    interceptor.setValidationActions("UsernameToken Timestamp");
    interceptor.setValidationCallbackHandler(callbackHandler());
    return interceptor;
}

@Bean
public CallbackHandler callbackHandler() {
    SimplePasswordValidationCallbackHandler handler = new SimplePasswordValidationCallbackHandler();
    Map<String, String> users = new HashMap<>();
    users.put("admin", "password");
    handler.setUsers(users);
    return handler;
}

@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
    interceptors.add(securityInterceptor());
}

这样配置后,客户端必须在 SOAP Header 中携带用户名和密码。


九、拦截器与日志

1. 自定义 EndpointInterceptor

可以实现接口 EndpointInterceptor,在消息处理前后记录日志或做其他处理。

public class LoggingInterceptor implements EndpointInterceptor {
    @Override
    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        // 记录请求日志
        return true;
    }
    // 其他方法略
}

注册到配置类:

@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
    interceptors.add(new LoggingInterceptor());
}

十、异常处理

Spring WS 支持将 Java 异常转换为 SOAP Fault。

1. 使用 @SoapFault 注解

@Endpoint
public class CountryEndpoint {
    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
    @ResponsePayload
    public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) throws CountryNotFoundException {
        // 业务逻辑
        throw new CountryNotFoundException("Country not found");
    }
}
@SoapFault(faultCode = FaultCode.CLIENT)
public class CountryNotFoundException extends Exception {
    public CountryNotFoundException(String message) { super(message); }
}

十一、复杂类型映射

JAXB 支持复杂对象、集合、嵌套对象等,只需在 XSD 中定义复杂类型,生成 Java 类即可。

例如:

<xs:complexType name="city">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="population" type="xs:int"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="country">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="cities" type="tns:city" maxOccurs="unbounded" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

生成 Java Bean:

@XmlType(name = "country")
public class Country {
    private String name;
    private List<City> cities;
    // getter/setter
}

十二、单元测试与集成测试

1. Endpoint 单元测试

可以用 MockWebServiceClient 进行测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class CountryEndpointTest {
    @Autowired
    private ApplicationContext applicationContext;

    private MockWebServiceClient client;

    @Before
    public void setup() {
        client = MockWebServiceClient.createClient(applicationContext);
    }

    @Test
    public void testGetCountry() throws Exception {
        Source requestPayload = new StringSource(
                "<getCountryRequest xmlns='http://example.com/ws/countries'><name>China</name></getCountryRequest>");
        Source responsePayload = new StringSource(
                "<getCountryResponse xmlns='http://example.com/ws/countries'><country><name>China</name></country></getCountryResponse>");
        client.sendRequest(withPayload(requestPayload)).andExpect(payload(responsePayload));
    }
}

十三、与 REST 风格的区别

SOAP Web Service (Spring WS)REST (Spring MVC)
基于 XML、WSDL、XSD基于 HTTP/JSON
强类型契约,易于跨语言集成灵活,易于前后端分离
支持 WS-Security需自定义安全方案
适合企业、金融、遗留系统集成适合轻量级服务

十四、常见问题与解决方案

  1. JAXB 版本冲突
    检查依赖版本,Spring Boot 3.x 以上需要 Jakarta XML Binding。
  2. SOAP Header 处理
    可以用 @SoapHeader 注解接收 Header 信息。
  3. WSDL 动态生成失败
    检查 Bean 名和 /ws/* 映射是否一致。

十五、SOAP 附件处理(MTOM)

1. 什么是 MTOM?

MTOM(Message Transmission Optimization Mechanism)允许在 SOAP 消息中高效地传输二进制数据(如图片、文件),避免 base64 编码带来的性能损耗。

2. 服务端开启 MTOM

在 JAXB Bean 上添加注解:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ImageRequest {
    @XmlMimeType("application/octet-stream")
    protected DataHandler image;
    // getter/setter
}

在端点方法参数和返回值中使用 DataHandler 类型。

3. 启用 MTOM 支持

在配置类中开启 MTOM:

@Bean
public Jaxb2Marshaller marshaller() {
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setPackagesToScan("com.example.ws.images");
    marshaller.setMtomEnabled(true); // 关键
    return marshaller;
}

客户端也需开启 MTOM:

WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.setUnmarshaller(marshaller);
webServiceTemplate.setMtomEnabled(true);

十六、多端点服务管理

如果你有多个 SOAP 服务,可以为每个服务定义不同的 XSD、Endpoint、WSDL Bean:

@Bean(name = "orders")
public DefaultWsdl11Definition ordersWsdl(XsdSchema ordersSchema) { ... }

@Bean(name = "users")
public DefaultWsdl11Definition usersWsdl(XsdSchema usersSchema) { ... }

每个端点类通过不同的命名空间和 localPart 进行区分。


十七、WSDL 定制与版本管理

  1. 定制 WSDL
    可以通过 DefaultWsdl11Definition 的各项属性定制端口名、服务名、命名空间等。

  2. 支持 WSDL 版本管理
    可通过不同的 URL 暴露不同版本的 WSDL,例如 /ws/v1/service.wsdl 和 /ws/v2/service.wsdl,分别对应不同的 XSD 和 Endpoint。


十八、性能优化建议

  1. 开启 Connection Pool
    如果作为客户端调用,建议配置 HTTP 连接池。

  2. 使用 MTOM 处理大文件
    避免 base64 传输,提升效率。

  3. 开启缓存
    对静态 WSDL、XSD 文件开启缓存。

  4. 合理设置线程池
    应用服务器端配置合理的线程池,提升并发处理能力。

  5. 启用 gzip 压缩
    在 Tomcat/Nginx 层开启 gzip 压缩,降低网络带宽消耗。


二九、生产部署建议

  1. 使用 HTTPS
    SOAP 服务通常涉及敏感数据,建议强制启用 HTTPS。

  2. 防止 XML 攻击
    配置 XML 解析器防止 XXE、XML Bomb 等安全漏洞。

  3. 日志与监控
    接入 ELK(Elasticsearch + Logstash + Kibana)、Prometheus 等监控平台,及时发现异常。

  4. 限流与熔断
    在网关层或应用层做限流、熔断处理,防止服务被高并发压垮。


二十、常见集成场景

  1. 与第三方 SOAP 服务对接
    使用 WebServiceTemplate,导入第三方 WSDL,自动生成客户端代码。

  2. 与企业 ESB 总线集成
    Spring WS 支持标准 SOAP,可以与 IBM WebSphere、Oracle SOA Suite 等企业 ESB 平台无缝对接。

  3. 与 REST 服务桥接
    可以在 Endpoint 内部调用 REST 服务,实现 SOAP-REST 转换,兼容新旧系统。


二十一、常见问题排查

问题解决方法
WSDL 无法访问或下载检查 Bean 名与 URL 映射,Servlet 注册路径是否正确
JAXB 类与 XSD 不匹配检查 JAXB 类属性、注解与 XSD 元素是否一致
SOAP Header 处理失败检查 @SoapHeader 注解参数,或用拦截器处理 Header
MTOM 附件无法传输检查 marshaller/unmarshaller 是否开启 MTOM
客户端调用超时配置 WebServiceTemplate 的超时时间参数
安全认证失败检查 Wss4jSecurityInterceptor 配置、用户名密码是否正确
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猩火燎猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值