)
Spring Boot 3.x 构建 SOAP WebService5步实现国家查询服务附完整代码在当今企业级应用开发中SOAP协议仍然是金融、电信等关键领域的主流选择。Spring Boot 3.x与Spring Web Services的深度整合让开发者能够快速构建符合WS-I标准的Web服务。本文将手把手带你实现一个完整的国家信息查询服务涵盖从XSD定义到端点测试的全流程。1. 环境准备与项目初始化首先创建一个基础的Spring Boot 3.x项目添加以下关键依赖到pom.xmldependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web-services/artifactId /dependency dependency groupIdwsdl4j/groupId artifactIdwsdl4j/artifactId /dependency /dependencies build plugins plugin groupIdorg.codehaus.mojo/groupId artifactIdjaxb2-maven-plugin/artifactId version3.1.0/version executions execution idxjc/id goals goalxjc/goal /goals /execution /executions /plugin /plugins /build关键配置说明spring-boot-starter-web-services提供SOAP支持wsdl4j用于WSDL处理jaxb2-maven-plugin实现XSD到Java类的自动转换2. 定义XSD架构与WSDL在src/main/resources/schemas目录下创建countries.xsdxs:schema xmlns:xshttp://www.w3.org/2001/XMLSchema targetNamespacehttp://example.com/countries xmlns:tnshttp://example.com/countries elementFormDefaultqualified xs:element namegetCountryRequest xs:complexType xs:sequence xs:element namename typexs:string/ /xs:sequence /xs:complexType /xs:element xs:element namegetCountryResponse xs:complexType xs:sequence xs:element namecountry typetns:country/ /xs:sequence /xs:complexType /xs:element xs:complexType namecountry xs:sequence xs:element namename typexs:string/ xs:element namecapital typexs:string/ xs:element namepopulation typexs:int/ xs:element namecurrency typetns:currency/ /xs:sequence /xs:complexType xs:simpleType namecurrency xs:restriction basexs:string xs:enumeration valueUSD/ xs:enumeration valueEUR/ xs:enumeration valueCNY/ /xs:restriction /xs:simpleType /xs:schema执行mvn compile命令后JAXB会在target/generated-sources目录生成对应的Java类包括GetCountryRequestGetCountryResponseCountry等3. 实现数据仓库与端点创建内存型国家数据仓库Component public class CountryRepository { private static final MapString, Country countries new HashMap(); PostConstruct public void initData() { Country china new Country(); china.setName(China); china.setCapital(Beijing); china.setPopulation(1412000000); china.setCurrency(Currency.CNY); countries.put(china.getName(), china); Country usa new Country(); usa.setName(USA); usa.setCapital(Washington); usa.setPopulation(331000000); usa.setCurrency(Currency.USD); countries.put(usa.getName(), usa); } public Country findCountry(String name) { return countries.get(name); } }实现服务端点Endpoint public class CountryEndpoint { private static final String NAMESPACE_URI http://example.com/countries; private final CountryRepository countryRepository; Autowired public CountryEndpoint(CountryRepository countryRepository) { this.countryRepository countryRepository; } PayloadRoot(namespace NAMESPACE_URI, localPart getCountryRequest) ResponsePayload public GetCountryResponse getCountry(RequestPayload GetCountryRequest request) { GetCountryResponse response new GetCountryResponse(); response.setCountry(countryRepository.findCountry(request.getName())); return response; } }关键注解解析Endpoint标记为SOAP端点PayloadRoot定义处理的消息类型ResponsePayload声明返回值为响应体4. 服务配置与WSDL暴露配置WebService基础设置EnableWs Configuration public class WebServiceConfig extends WsConfigurerAdapter { Bean public ServletRegistrationBeanMessageDispatcherServlet 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 wsdl new DefaultWsDL11Definition(); wsdl.setPortTypeName(CountriesPort); wsdl.setLocationUri(/ws); wsdl.setTargetNamespace(http://example.com/countries); wsdl.setSchema(countriesSchema); return wsdl; } Bean public XsdSchema countriesSchema() { return new SimpleXsdSchema(new ClassPathResource(schemas/countries.xsd)); } }启动应用后可通过以下URL访问WSDLhttp://localhost:8080/ws/countries.wsdl5. 服务测试与验证使用cURL测试服务curl --header content-type: text/xml \ --data request.xml \ http://localhost:8080/ws其中request.xml内容为soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ xmlns:gshttp://example.com/countries soapenv:Header/ soapenv:Body gs:getCountryRequest gs:nameChina/gs:name /gs:getCountryRequest /soapenv:Body /soapenv:Envelope预期响应示例SOAP-ENV:Envelope xmlns:SOAP-ENVhttp://schemas.xmlsoap.org/soap/envelope/ SOAP-ENV:Header/ SOAP-ENV:Body ns2:getCountryResponse xmlns:ns2http://example.com/countries ns2:country ns2:nameChina/ns2:name ns2:capitalBeijing/ns2:capital ns2:population1412000000/ns2:population ns2:currencyCNY/ns2:currency /ns2:country /ns2:getCountryResponse /SOAP-ENV:Body /SOAP-ENV:Envelope对于更复杂的场景可以添加SOAP头处理PayloadRoot(namespace NAMESPACE_URI, localPart getCountryRequest) ResponsePayload public GetCountryResponse getCountry( RequestPayload GetCountryRequest request, SoapHeader({ SECURITY_NS }authentication) SoapHeaderElement auth) { // 验证头信息 if (!validateHeader(auth)) { throw new AuthenticationException(Invalid credentials); } // ...原有处理逻辑 }6. 高级配置与优化对于生产环境建议添加以下增强配置WS-Security配置Bean public Wss4jSecurityInterceptor securityInterceptor() { Wss4jSecurityInterceptor interceptor new Wss4jSecurityInterceptor(); interceptor.setSecurementActions(UsernameToken); interceptor.setSecurementUsername(admin); interceptor.setSecurementPassword(secret); return interceptor; } Override public void addInterceptors(ListEndpointInterceptor interceptors) { interceptors.add(securityInterceptor()); }性能优化建议启用JAXB编译缓存plugin groupIdorg.codehaus.mojo/groupId artifactIdjaxb2-maven-plugin/artifactId configuration clearOutputDirfalse/clearOutputDir /configuration /plugin配置HTTP压缩server.compression.enabledtrue server.compression.mime-typestext/xml,application/soapxml7. 异常处理与调试实现自定义SOAP错误处理Endpoint public class CountryEndpoint { // ...其他方法 ExceptionHandler public void handleException(Exception ex, SoapMessage response) { TransformerFactory.newInstance().newTransformer() .transform(new DOMSource(createFault(ex)), new StreamResult(response.getSoapBody().getResult())); } private org.w3c.dom.Document createFault(Exception ex) { // 构建详细的SOAP Fault XML } }调试技巧启用SOAP消息日志logging.level.org.springframework.ws.client.MessageTracing.sentTRACE logging.level.org.springframework.ws.client.MessageTracing.receivedTRACE使用SoapUI工具进行可视化测试通过WireShark抓包分析原始SOAP报文