1. 程式人生 > >webService學習(二)CXF框架集合spring boot

webService學習(二)CXF框架集合spring boot

1、CXF框架:

Apache CXF一個開源的Service框架,CXF簡化了構造,整合,面向服務架構(SOA)業務元件與技術的靈活複用。在CXF中,Service使用WSDL標準定義並能夠使用各種不同的訊息格式(或binding)和網路協議(transports)包括SOAP、XML(通過HTTP或JMS)進行訪問。支援多種協議SOAP、POST/HTTP、RESTful、HTTP等。

CXF是一個實現SOA思想框架,依賴spring,核心是org.apache.cxf.Bus(匯流排),類似於Spring的 ApplicationContext

內建了Jetty是一個serlvet容器。

 

2、CXF特點:

(1)可以和spring、servlet無縫對接

(2)可以用註解方式來發布webService(@WebService

(3)能夠新增輸入、輸出攔截器(日誌形式,便於觀察輸入輸出)

 

3、CXF結合springboot釋出服務

(1)新增依賴:

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
	<version>3.2.4</version>
</dependency>

(2)先建立一個實體User:

package com.test.cxfdemo.dao;

import java.io.Serializable;

/**
 * @author yanghao
 * @Description:
 * @date 2018/11/6 9:39
 */
public class User implements Serializable{
    private static final long serialVersionUID = -3628469724795296287L;

    private String userId;
    private String userName;
    private String email;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId='" + userId + '\'' +
                ", userName='" + userName + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

 

(3)寫服務端介面UserService,以及實現程式碼UserServiceImpl:

介面UserService:

package com.test.cxfdemo.Impl;

import com.test.cxfdemo.dao.User;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.soap.Addressing;

/**
 * @author yanghao
 * @Description:
 * @date 2018/11/6 9:44
 */

@WebService(name = "UserService",
        targetNamespace = "http://www.impl.cxfdemo.test.com")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@Addressing(enabled = true)
public interface UserService {

    @WebMethod  ////標註該方法為webservice暴露的方法,用於向外公佈,它修飾的方法是webservice方法,去掉也沒影響的,類似一個註釋資訊
    User getUser(@WebParam(name = "userId") String userId);

    @WebMethod
    @WebResult(name = "String", targetNamespace = "")
    String getUserName(@WebParam(name = "userId") String userId);
}

實現類UserServiceImpl:

package com.test.cxfdemo.Impl;

import com.test.cxfdemo.dao.User;
import org.springframework.stereotype.Component;

import javax.jws.WebService;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author yanghao
 * @Description:
 * @date 2018/11/6 9:49
 */
@WebService(
        serviceName = "UserService", //對外發布的服務名
        targetNamespace = "http://www.impl.cxfdemo.test.com",
        endpointInterface = "com.test.cxfdemo.Impl.UserService")
@Component
public class UserServiceImpl implements UserService {

    private Map<String, User> userMap = new HashMap<>();

    public UserServiceImpl() {
        System.out.println("向實體類插入資料");
        User user = new User();
        user.setUserId(UUID.randomUUID().toString().replace("-", ""));
        user.setUserName("test1");
        user.setEmail("[email protected]");
        userMap.put(user.getUserId(), user);
    }

    @Override
    public String getUserName(String userId) {
        return "userId為:" + userId;
    }

    @Override
    public User getUser(String userId) {
        System.out.println("userMap is " + userMap);
        return userMap.get(userId);
    }
}

CXF釋出方式:

package com.test.cxfdemo.CxfConfig;

import com.test.cxfdemo.Impl.UserService;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.xml.ws.Endpoint;

/**
 * @author yanghao
 * @Description:
 * @date 2018/11/6 9:58
 */
@Configuration
public class CxfConfig {

    @Autowired
    private Bus bus;

    @Autowired
    UserService userService;

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus, userService);
        endpoint.publish("/UserService");
        return endpoint;
    }

}

執行即可:

釋出成功

網頁檢視Wsdl:

 

摘抄別人對wsdl的註解,個人覺得還行:

<?xml version="1.0" ?>
<wsdl:definitions name="CodeLanguageService"
    targetNamespace="http://cxf.service.com/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://cxf.service.com/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <!-- tns 型別的描述 -->
    <wsdl:types>
        <xs:schema elementFormDefault="unqualified" targetNamespace="http://cxf.service.com/"
            version="1.0" xmlns:tns="http://cxf.service.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <xs:element name="getCodeRank" type="tns:getCodeRank"></xs:element>
            <xs:element name="getCodeRankResponse" type="tns:getCodeRankResponse"></xs:element>
            <xs:complexType name="getCodeRank">
                <xs:sequence>
                    <xs:element name="codeRank" type="xs:int"></xs:element>
                </xs:sequence>
            </xs:complexType>
            <xs:complexType name="getCodeRankResponse">
                <xs:sequence>
                    <xs:element minOccurs="0" name="codeName" type="xs:string"></xs:element>
                </xs:sequence>
            </xs:complexType>
        </xs:schema>
    </wsdl:types>


    <!-- 描述引數及其型別 -->
    <wsdl:message name="getCodeRankResponse">
        <wsdl:part element="tns:getCodeRankResponse" name="parameters">
        </wsdl:part>
    </wsdl:message>

    <wsdl:message name="getCodeRank">
        <wsdl:part element="tns:getCodeRank" name="parameters">
        </wsdl:part>
    </wsdl:message>

    <!-- 暴露出去的方法的描述,以及對應的描述型別 tns-->
    <wsdl:portType name="CodeLanguage">
        <wsdl:operation name="getCodeRank">
            <wsdl:input message="tns:getCodeRank" name="getCodeRank">
            </wsdl:input>
            <wsdl:output message="tns:getCodeRankResponse" name="getCodeRankResponse">
            </wsdl:output>
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="CodeLanguageServiceSoapBinding" type="tns:CodeLanguage">
        <soap:binding style="document"
            transport="http://schemas.xmlsoap.org/soap/http"></soap:binding>

        <!-- 暴露出去的方法soap格式的描述 -->
        <wsdl:operation name="getCodeRank">
            <soap:operation soapAction="" style="document"></soap:operation>

            <!-- 方法的WSDL引數描述 -->            
            <wsdl:input name="getCodeRank">
                <soap:body use="literal"></soap:body>
            </wsdl:input>

            <!-- 方法的WSDL返回值描述 -->           
            <wsdl:output name="getCodeRankResponse">
                <soap:body use="literal"></soap:body>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <!-- 暴露出去的服務類的描述 -->
    <wsdl:service name="CodeLanguageService">
        <wsdl:port binding="tns:CodeLanguageServiceSoapBinding"
            name="CodeLanguagePort">
            <soap:address location="http://127.0.0.1:6969/ws/CodeLanguageService"></soap:address>
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

內容類似。

4、客戶端呼叫程式碼:

package com.test.cxfdemo.Test;

import com.test.cxfdemo.Impl.UserService;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;

/**
 * @author yanghao
 * @Description:
 * @date 2018/11/6 11:33
 */
public class CxfClient {
    public static void main(String[] args) {
        CxfClient.main1();
    }

    /**
     * 1.代理類工廠的方式,需要拿到對方的介面地址
     */
    public static void main1() {
        try {
            // 介面地址
            String address = "http://127.0.0.1:8182/services/UserService?wsdl";
            // 代理工廠
            JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
            // 設定代理地址
            jaxWsProxyFactoryBean.setAddress(address);
            // 設定介面型別
            jaxWsProxyFactoryBean.setServiceClass(UserService.class);
            // 建立一個代理介面實現
            UserService us = (UserService) jaxWsProxyFactoryBean.create();
            // 資料準備
            String userId = "123456";
            // 呼叫代理介面的方法呼叫並返回結果
            String result = us.getUserName(userId);
            System.out.println("返回結果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 2:動態呼叫
     */
    public static void main2() {
        // 建立動態客戶端
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient("http://127.0.0.1:8182/services/UserService?wsdl");
        // 需要密碼的情況需要加上使用者名稱和密碼
        // client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME, PASS_WORD));
        Object[] objects = new Object[0];
        try {
            // invoke("方法名",引數1,引數2,引數3....);
            objects = client.invoke("getUserName", "123456");
            System.out.println("返回資料:" + objects[0]);
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        }
    }

}

提供了兩種方式,一個是代理模式,還有一個是動態呼叫。但是在公司專案使用中,這兩個方法並不實用!

最好通過生成程式碼方式:

 

5、CXF自動生成客戶端呼叫程式碼:

CXF 專案的主頁地址是:

http://cxf.apache.org/

下載地址是:

http://cxf.apache.org/download.html

可以下載 解壓版也可以下載安裝版的。 具體的下載頁面如下:

這裡下載解壓版就可以了。

下載映象地址:  http://mirror.bit.edu.cn/apache/cxf/3.0.1/apache-cxf-3.0.1.zip

將下載的檔案拷貝到響應的檔案目錄下或者將CXF配置到classPath中:

 

到對應bin目錄下或者在對應工程src下,輸入:

 

這樣在工程目錄下就會自動生成客戶端呼叫程式碼:

 

6、最後給一個客戶端生成程式碼的小例子(非一個工程,但是呼叫方式一樣)


public class CPClientTest {

    public static void main(String[] args) throws MalformedURLException {
        ChargePointService_Service fartory = new ChargePointService_Service(new URL("file:/C:/Users/DELL/Desktop/***********.wsdl"));
        ChargePointService chargePointService = fartory.getChargePointServiceSoap12();

        Client client = ClientProxy.getClient(chargePointService);
        List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
        List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();

        // 客戶端的日誌出攔截器
        outInterceptors.add(new LoggingOutInterceptor());
        inInterceptors.add(new LoggingInInterceptor());

        String chargeBoxIdentity = "chargedot_0";
        RemoteStopTransactionRequest remoteStopTransactionRequest = new RemoteStopTransactionRequest();
        remoteStopTransactionRequest.setTransactionId(12345678);
        RemoteStopTransactionResponse remoteStopTransactionResponse = chargePointService.remoteStopTransaction(remoteStopTransactionRequest, chargeBoxIdentity);
        System.out.println(remoteStopTransactionResponse.getStatus().value());

    }

}

今天的學習記錄就到這兒。

最後記錄一個CXF的apche官網解釋:http://cxf.apache.org/docs/springboot.html#SpringBoot-AutoConfiguration