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