02-Soap

image-20240826084417405

1. Server

  • http://localhost:8081/webService
image-20240826084628556
  • http://localhost:8081/webService/ooxx?wsdl
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:tns="soapNamespace" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="soapService" targetNamespace="soapNamespace">
    <wsdl:types>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="soapNamespace"
                   elementFormDefault="unqualified" targetNamespace="soapNamespace" version="1.0">
            <xs:element name="m1_obj" type="tns:m1_obj"/>
            <xs:element name="m1_objResponse" type="tns:m1_objResponse"/>
            <xs:element name="m2_param" type="tns:m2_param"/>
            <xs:element name="m2_paramResponse" type="tns:m2_paramResponse"/>
            <xs:element name="myRequest" type="tns:my_request"/>
            <xs:element name="myResponse" type="tns:my_response"/>
            <!--
            入参、出参为obj接口
            -->
            <xs:complexType name="m1_obj">
                <xs:sequence>
                    <xs:element minOccurs="0" name="m1_req" type="tns:my_request"/>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="my_request">
                <xs:sequence>
                    <xs:element minOccurs="0" name="name" type="xs:string"/>
                    <xs:element minOccurs="0" name="pwd" type="xs:int"/>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="m1_objResponse">
                <xs:sequence>
                    <xs:element minOccurs="0" name="m1_result" type="tns:my_response"/>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="my_response">
                <xs:sequence>
                    <xs:element minOccurs="0" name="status" type="xs:int"/>
                    <xs:element minOccurs="0" name="msg" type="xs:string"/>
                    <xs:element minOccurs="0" name="list">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element maxOccurs="unbounded" minOccurs="0" name="list" type="xs:int"/>
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:complexType>
            <!--
            入参、出参为基本数据类型接口
            -->
            <xs:complexType name="m2_param">
                <xs:sequence>
                    <xs:element minOccurs="0" name="m2_name" type="xs:string"/>
                    <xs:element minOccurs="0" name="m2_pwd" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="m2_paramResponse">
                <xs:sequence>
                    <xs:element minOccurs="0" name="m2_result" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>
        </xs:schema>
    </wsdl:types>
    <wsdl:message name="m1_objResponse">
        <wsdl:part element="tns:m1_objResponse" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="m1_obj">
        <wsdl:part element="tns:m1_obj" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="m2_paramResponse">
        <wsdl:part element="tns:m2_paramResponse" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="m2_param">
        <wsdl:part element="tns:m2_param" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:portType name="ISoapSvi">
        <wsdl:operation name="m1_obj">
            <wsdl:input message="tns:m1_obj" name="m1_obj"></wsdl:input>
            <wsdl:output message="tns:m1_objResponse" name="m1_objResponse"></wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="m2_param">
            <wsdl:input message="tns:m2_param" name="m2_param"></wsdl:input>
            <wsdl:output message="tns:m2_paramResponse" name="m2_paramResponse"></wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="soapServiceSoapBinding" type="tns:ISoapSvi">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="m1_obj">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input name="m1_obj">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="m1_objResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="m2_param">
            <soap:operation soapAction="" style="document"/>
            <wsdl:input name="m2_param">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="m2_paramResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <!--
        重点:
            1. 服务名:SoapService
            2. port:SoapServiceImplPort
            3. location:http://localhost:8081/webService/ooxx
    -->
    <wsdl:service name="soapService">
        <wsdl:port binding="tns:soapServiceSoapBinding" name="SoapSviImplPort">
            <soap:address location="http://localhost:8081/webService/ooxx"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

1. pom.xml

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>3.1.6</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>3.1.6</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.22</version>
</dependency>
 
 
 
 
 
 
 
 
 
 
 
 
 
 










2. @Configuration

import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.xml.ws.Endpoint;

@Configuration
public class CxfConfig {

    @Bean
    public ServletRegistrationBean<CXFServlet> servletRegistrationBean() {
        return new ServletRegistrationBean<>(new CXFServlet(), "/webService/*");
    }

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(springBus(), new SoapSviImpl());
        endpoint.publish("/ooxx");
        return endpoint;
    }
}















 










 



3. interface

import javax.jws.*;

@WebService(
        serviceName = "soapService",                                // 服务名
        targetNamespace = "soapNamespace",                          // 命名空间
        endpointInterface = "com.listao.soap.service.ISoapSvi"      // 接口地址包名倒写
)
public interface ISoapSvi {

    @WebMethod(operationName = "m1_obj")
    @WebResult(name = "m1_result")
    MyResponse m1(@WebParam(name = "m1_req") MyRequest req);

    @WebMethod(operationName = "m2_param")
    @WebResult(name = "m2_result")
    String m2(@WebParam(name = "m2_name") String name, @WebParam(name = "m2_pwd") String pwd);
}




 












4. Impl

import javax.jws.WebService;

@WebService(
        serviceName = "soapService",        // 与接口中serviceName一致
        targetNamespace = "soapNamespace"   // 与接口中的targetNamespace一致
)
@Component
public class SoapSviImpl implements ISoapSvi {

    @Override
    public MyResponse m1(MyRequest req) {
        return new MyResponse(0, req.getName());
    }

    @Override
    public String m2(String name, String pwd) {
        return "name: " + name + ",pwd: " + pwd;
    }
}




 














5. request & response

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "my_request")
@Data
public class MyRequest {

    @XmlElement(name = "name")
    private String name;

    @XmlElement(name = "pwd")
    private Integer pwd;
}
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "my_response")
@Data
public class MyResponse {

    @XmlElement(name = "status")
    private Integer status;

    @XmlElement(name = "msg")
    private String msg;

    // @XmlElementWrapper
    @XmlElement(name = "list")
    private List<Integer> list;

    public MyResponse() {
    }

    public MyResponse(Integer status, String msg) {
        this.status = status;
        this.msg = msg;
        this.list = CollUtil.newArrayList(0, 1, 2);
    }
}














 












2. Client

1. WebServiceClient

import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;

@WebServiceClient
public class SoapClient extends Service {
    private final static URL SOUP_WSDL;
    private final static Logger logger = Logger.getLogger(SoapClient.class.getName());

    static {
        URL url = null;
        try {
            // 浏览器请求的wsdl
            // 1. <soap:address location="http://127.0.0.1:8081/webService/ooxx"/>
            url = new URL("http://127.0.0.1:8081/webService/ooxx?wsdl");
        } catch (MalformedURLException e) {
            logger.warning("Failed to create URL for the wsdl Location: '', retrying as a local file");
            logger.warning(e.getMessage());
        }
        SOUP_WSDL = url;
    }

    public SoapClient() {
        // 2. name="soapService" targetNamespace="soapNamespace">
        super(SOUP_WSDL, new QName("soapNamespace", "soapService"));
    }

    @WebEndpoint(name = "SoapSviImplPort")
    // 3. <wsdl:port binding="tns:soapServiceSoapBinding" name="SoapServiceImplPort">
    public SoapApi getSoapApi() {
        return super.getPort(new QName(
                "soapNamespace",
                "SoapSviImplPort"), SoapApi.class);
    }
}

/*
<wsdl:service name="soapService">
    <wsdl:port binding="tns:soapServiceSoapBinding" name="SoapSviImplPort">
        <soap:address location="http://127.0.0.1:8081/webService/ooxx"/>
    </wsdl:port>
</wsdl:service>
 */


















 









 






 











2. api

  • 定义调用接口
import javax.jws.WebMethod;


public interface SoapApi {

    // <xs:complexType name="m1_obj">
    @WebMethod(operationName = "m1_obj")
    MyResp m1(MyReq req);

    // <xs:complexType name="m2_param">
    @WebMethod(operationName = "m2_param")
    String m2(String name, String pwd);
}

3. m1_obj

  • 入参、出参为对象的定义
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;

@XmlAccessorType(XmlAccessType.FIELD)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyReq {

    // @XmlElement生效,必须有@XmlAccessorType
    @XmlElement(name = "name")
    private String name_error;

    private Integer pwd;
}
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@NoArgsConstructor
@AllArgsConstructor
@Data
public class MyResp {

    private Integer status;

    private String msg;

    // @XmlElementWrapper // 必须要有
    private List<String> list;
}













 


3. @Test

@Slf4j
public class SoapCtl {

    @Test
    public void m1_obj() {
        SoapClient soapClient = new SoapClient();
        SoapApi soapApi = soapClient.getSoapApi();
        MyResp myResp = soapApi.m1(new MyReq("listao", 111));
        log.error("myResp: {}", myResp);
    }

    @Test
    public void m2_param() {
        SoapClient soapClient = new SoapClient();
        SoapApi soapApi = soapClient.getSoapApi();
        String s = soapApi.m2("listao", "111");
        log.error(s);
    }
}

4. Hutool

1. Request

image-20240826093508634
image-20240826105109320
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="soapNamespace">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:m2_param>
         <!--Optional:-->
         <m2_name>?</m2_name>
         <!--Optional:-->
         <m2_pwd>?</m2_pwd>
      </soap:m2_param>
   </soapenv:Body>
</soapenv:Envelope>
 


 







@Test
public void m1_obj() {
    SoapClient client = SoapClient.create("http://localhost:8081/webService/ooxx")   // SoapUI 地址栏
            .setMethod("soap:m2_param", "soapNamespace")                             // 方法名 + 命名空间
            .setParam("m2_name", "listao", false)                                    // true:参数前添加`soap:`
            .setParam("m2_pwd", 123, false);

    // 打印请求数据
    Console.log(client.getMsgStr(true));
    // 打印响应数据
    Console.log(client.send(true));
}


 
 








<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <soap:m2_param xmlns:soap="soapNamespace">
      <m2_name>listao</m2_name>
      <m2_pwd>123</m2_pwd>
    </soap:m2_param>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns2:m2_paramResponse xmlns:ns2="soapNamespace">
      <m2_result>name: listao,pwd: 123</m2_result>
    </ns2:m2_paramResponse>
  </soap:Body>
</soap:Envelope>
image-20240826093651976
image-20240826112127765
@Test
public void m2_param() throws SOAPException {
    SoapClient client = SoapClient.create("http://localhost:8081/webService/ooxx")
            .setMethod("soap:m1_obj", "soapNamespace");

    SOAPElement arg0 = client.getMethodEle().addChildElement("m1_req");
    arg0.addChildElement("name").setValue("listao");
    arg0.addChildElement("pwd").setValue("123");

    Console.log(client.getMsgStr(true));
    Console.log(client.send(true));
}





 
 
 




<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <soap:m1_obj xmlns:soap="soapNamespace">
      <m1_req>
        <name>listao</name>
        <pwd>123</pwd>
      </m1_req>
    </soap:m1_obj>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>





 
 
 
 



<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:m1_objResponse xmlns:ns2="soapNamespace">
         <m1_result>
            <status>0</status>
            <msg>listao</msg>
            <list>0</list>
            <list>1</list>
            <list>2</list>
         </m1_result>
      </ns2:m1_objResponse>
   </soap:Body>
</soap:Envelope>

2. Response

@Test
public void xmlToBean() throws SOAPException {
    String s = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
            "   <soap:Body>\n" +
            "      <ns2:m1_objResponse xmlns:ns2=\"soapNamespace\">\n" +
            "         <m1_result>\n" +
            "            <status>0</status>\n" +
            "            <msg>listao</msg>\n" +
            "            <list>0</list>\n" +
            "            <list>1</list>\n" +
            "            <list>2</list>\n" +
            "         </m1_result>\n" +
            "      </ns2:m1_objResponse>\n" +
            "   </soap:Body>\n" +
            "</soap:Envelope>";

    Document doc = XmlUtil.parseXml(s);
    // 得到数据节点
    NodeList m1Result = doc.getElementsByTagName("m1_result");
    Node item = m1Result.item(0);
    System.out.println("item = " + item);

    MyResp myResp = XmlUtil.xmlToBean(item, MyResp.class);
    System.out.println("myResp = " + myResp);
}