一、服务端:
1.1目录结构:
1.2maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>soapdemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-features-logging</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
</dependencies>
</project>
1.3WebServiceConfig配置类
package com.soap.config;
import com.soap.service.StudentService;
import org.apache.cxf.Bus;
import org.apache.cxf.ext.logging.LoggingInInterceptor;
import org.apache.cxf.ext.logging.LoggingOutInterceptor;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.xml.ws.Endpoint;
/**
* @author Administrator
* @date 2019/01/30
*/
@Configuration
public class WebServiceConfig {
@Resource
private Bus bus;
@Resource
private StudentService studentService;
@Bean
public Endpoint endpointStudentService() {
EndpointImpl endpoint=new EndpointImpl(bus,studentService);
endpoint.getInInterceptors()
.add(loggingInInterceptor());
endpoint.getOutInterceptors()
.add(loggingOutInterceptor());
endpoint.publish("/studentService");
return endpoint;
}
@Bean
public LoggingInInterceptor loggingInInterceptor() {
return new LoggingInInterceptor();
}
@Bean
public LoggingOutInterceptor loggingOutInterceptor() {
return new LoggingOutInterceptor();
}
}
1.3Student实体类
package com.soap.entity;
public class Student {
private String stuName;
private Integer stuAge;
public Student() {}
public Student(String stuName, Integer stuAge) {
this.stuName = stuName;
this.stuAge = stuAge;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Integer getStuAge() {
return stuAge;
}
public void setStuAge(Integer stuAge) {
this.stuAge = stuAge;
}
}
1.4提供服务类
package com.soap.service;
import com.soap.entity.Student;
import javax.jws.WebMethod;
import javax.jws.WebService;
import java.util.List;
@WebService(targetNamespace = "http://service.soap.com")// 命名空间,建议包名倒写
public interface StudentService {
@WebMethod
List<Student> getStudentList();
}
1.5服务实现类
package com.soap.service.impl;
import com.soap.entity.Student;
import com.soap.service.StudentService;
import org.springframework.stereotype.Component;
import javax.jws.WebService;
import java.util.Arrays;
import java.util.List;
/**
* @author Administrator
* @date 2019/01/30
*/
@WebService(serviceName = "StudentService",
targetNamespace = "http://service.soap.com",
endpointInterface = "com.soap.service.StudentService")
@Component
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> getStudentList() {
Student stu1 = new Student("学生1",25);
Student stu2 = new Student("学生2",30);
return Arrays.asList(stu1,stu2);
}
}
1.6启动类
package com.soap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SoapBootApplication {
public static void main(String[] args) {
SpringApplication.run(SoapBootApplication.class,args);
}
}
1.7 application.yml文件
server:
port: 8081
servlet:
context-path: /
1.8启动后访问地址:http://localhost:8081/services/studentService?wsdl
1.9====================服务端配置完成================================
二、客户端
2.1目录结构
2.1maven依赖,其他依赖自行添加
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxb</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-soap</artifactId>
<version>10.2.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.10.1</version>
</dependency>
<!-- openfeign远程调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2ConvertConfig配置类(解析xml)
package com.example.consumer.config;
import feign.Logger;
import feign.Util;
import feign.codec.Decoder;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.jaxb.JAXBContextFactory;
import org.springframework.context.annotation.Bean;
import org.w3c.dom.Document;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.*;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.ws.soap.SOAPFaultException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static javax.xml.soap.SOAPConstants.DEFAULT_SOAP_PROTOCOL;
public class ConvertConfig {
private Charset charsetEncoding = StandardCharsets.UTF_8;
private String soapProtocol = DEFAULT_SOAP_PROTOCOL;
private static final JAXBContextFactory jaxbContextFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.build();
@Bean
public Encoder feignEncoder() {
return (object, bodyType, template) -> {
if (!(bodyType instanceof Class)) {
throw new UnsupportedOperationException(
"SOAP only supports encoding raw types. Found " + bodyType);
}
try {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Marshaller marshaller = jaxbContextFactory.createMarshaller((Class<?>) bodyType);
marshaller.marshal(object, document);
SOAPMessage soapMessage = MessageFactory.newInstance(soapProtocol).createMessage();
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
soapEnvelope.addNamespaceDeclaration("ser", "http://service.soap.com");
soapMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, charsetEncoding.displayName());
soapMessage.getSOAPBody().addDocument(document);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
soapMessage.writeTo(bos);
template.body(new String(bos.toByteArray()).replaceAll("getStudentList", "ser:getStudentList"));
} catch (SOAPException | JAXBException | ParserConfigurationException|IOException| TransformerFactoryConfigurationError e) {
throw new EncodeException(e.toString(), e);
}
};
}
@Bean
public Decoder feignDecoder() {
return (response, type) ->{
try {
if (response.status() != 404 && response.status() != 204) {
if (response.body() == null) {
return null;
} else {
SOAPMessage message = MessageFactory.newInstance(soapProtocol).createMessage(null,response.body().asInputStream());
SOAPBody soapBody = message.getSOAPBody();
if (soapBody != null) {
if (message.getSOAPBody().hasFault()) {
throw new SOAPFaultException(message.getSOAPBody().getFault());
}
//重要!!!!
Class<?> tt =(Class<?>)type;
Unmarshaller unmarshaller = jaxbContextFactory.createUnmarshaller(tt);
return unmarshaller.unmarshal(soapBody.extractContentAsDocument(),tt).getValue();
}
}
} else {
return Util.emptyValueOf(type);
}
}catch (Exception e){
e.printStackTrace();
}
return Util.emptyValueOf(type);
};
}
@Bean
feign.Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
2.3GetStudentList实体类
package com.example.consumer.soap.entity;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class GetStudentList {
}
2.4GetStudentListResponse实体类
package com.example.consumer.soap.entity;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
@XmlRootElement(name = "getStudentListResponse")
@XmlAccessorType(XmlAccessType.FIELD)
public class GetStudentListResponse {
@XmlElement(name = "return")
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
2.5 Student实体类
package com.example.consumer.soap.entity;
public class Student {
private int stuAge;
private String stuName;
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getStuAge() {
return stuAge;
}
public void setStuAge(int stuAge) {
this.stuAge = stuAge;
}
}
2.6 feign远程调用类
package com.example.consumer.soap.feign;
import com.example.consumer.config.ConvertConfig;
import com.example.consumer.soap.entity.GetStudentList;
import com.example.consumer.soap.entity.GetStudentListResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
@FeignClient(name = "SoapFeign",url = "http://localhost:8081",configuration = {ConvertConfig.class})
public interface SoapFeign {
@PostMapping(value = "/services/studentService",consumes = {MediaType.TEXT_XML_VALUE})
public GetStudentListResponse getStudentList(GetStudentList getStudentList);
}
2.7 启动类
package com.example.consumer;
import com.alibaba.fastjson.JSON;
import com.example.consumer.soap.entity.GetStudentListResponse;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import java.io.ByteArrayInputStream;
@SpringBootApplication
@EnableFeignClients(basePackages = {"com.example.consumer.soap.feign"})
public class ConsumerApplication {
public static void main(String[] args){
ConsumerApplication consumerApplication=new ConsumerApplication();
// try {
// consumerApplication.method();
// } catch (Exception e) {
// e.printStackTrace();
// }
SpringApplication.run(ConsumerApplication.class, args);
}
//可进行测试
public void method() throws Exception {
String example ="<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
" <soap:Body>\n" +
" <ns2:getStudentListResponse xmlns:ns2=\"http://service.soap.com\">\n" +
" <return>\n" +
" <stuAge>25</stuAge>\n" +
" <stuName>学生1</stuName>\n" +
" </return>\n" +
" <return>\n" +
" <stuAge>30</stuAge>\n" +
" <stuName>学生2</stuName>\n" +
" </return>\n" +
" </ns2:getStudentListResponse>\n" +
" </soap:Body>\n" +
"</soap:Envelope>";
SOAPMessage message = MessageFactory.newInstance().createMessage(null,
new ByteArrayInputStream(example.getBytes()));
Unmarshaller unmarshaller = JAXBContext.newInstance(GetStudentListResponse.class).createUnmarshaller();
JAXBElement<GetStudentListResponse> unmarshal = unmarshaller.unmarshal(message.getSOAPBody().extractContentAsDocument(), GetStudentListResponse.class);
GetStudentListResponse value = unmarshal.getValue();
System.out.println(JSON.toJSONString(value));
}
}
2.8 开启feign日志
logging:
level:
com.example.consumer.soap.feign.SoapFeign: debug
2.9 controller类
@Resource
private SoapFeign soapFeign;
@GetMapping("/soap")
//R类,可以用Map代替
public R testSoap() {
GetStudentListResponse response= soapFeign.getStudentList(new GetStudentList());
return R.success().put("students:",response);
}
3.0 xml或wsdl文件
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://service.soap.com" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="StudentService" targetNamespace="http://service.soap.com">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://service.soap.com" elementFormDefault="unqualified" targetNamespace="http://service.soap.com" version="1.0">
<xs:element name="getStudentList" type="tns:getStudentList"/>
<xs:element name="getStudentListResponse" type="tns:getStudentListResponse"/>
<xs:complexType name="getStudentList">
<xs:sequence/>
</xs:complexType>
<xs:complexType name="getStudentListResponse">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="return" type="tns:student"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="student">
<xs:sequence>
<xs:element minOccurs="0" name="stuAge" type="xs:int"/>
<xs:element minOccurs="0" name="stuName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="getStudentListResponse">
<wsdl:part element="tns:getStudentListResponse" name="parameters"> </wsdl:part>
</wsdl:message>
<wsdl:message name="getStudentList">
<wsdl:part element="tns:getStudentList" name="parameters"> </wsdl:part>
</wsdl:message>
<wsdl:portType name="StudentService">
<wsdl:operation name="getStudentList">
<wsdl:input message="tns:getStudentList" name="getStudentList"> </wsdl:input>
<wsdl:output message="tns:getStudentListResponse" name="getStudentListResponse"> </wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="StudentServiceSoapBinding" type="tns:StudentService">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getStudentList">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="getStudentList">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getStudentListResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="StudentService">
<wsdl:port binding="tns:StudentServiceSoapBinding" name="StudentServiceImplPort">
<soap:address location="http://localhost:8081/services/studentService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
3.1可用soapUI(soap请求,推荐)、postman(post请求)进行测试