CXF搭建WebService服務端
引入依賴
<!--cxf依賴-->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.4</version>
</dependency>
編寫服務接口
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* webservice服務端接口類
*/
@WebService
public interface CXFTestService {
/**
* 提供調用的方法,使用@WebMethod註釋
* @param id
* @return StudentScore
*/
@WebMethod(operationName = "getStudentScoreById")
StudentScore getStudentScore(@WebParam(name = "id") long id);
}
編寫服務接口實現類
import com.javatest.po.StudentScore;
import com.javatest.service.StudentScoreService;
import com.javatest.webservice.server.CXFTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.jws.WebService;
/**
* webservice服務端實現類。注意,如果使用面向接口,那麼在此實現類中必須通過endpointInterface指定服務端接口類
*/
@WebService(targetNamespace = "http://impl.server.webservice.javatest.com/", // 命名空間一般爲包名的倒置
endpointInterface = "com.javatest.webservice.server.CXFTestService"
)
@Service
public class CXFTestServiceImpl implements CXFTestService {
@Autowired
private StudentScoreService service;
@Override
public StudentScore getStudentScore(long id) {
return service.selectByPrimaryKey(id);
}
}
編寫cxf配置類
import com.javatest.webservice.server.impl.CXFTestServiceImpl;
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 org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.xml.ws.Endpoint;
/**
* 使用cxf發佈webservice服務,實現同一端口同時提供API和webservice
*/
@Configuration
public class WebServiceConfig implements WebMvcConfigurer {
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
// 發佈cxf的webservice接口
@Bean
public CXFTestServiceImpl CXFTestService() {
return new CXFTestServiceImpl();
}
@Bean
public Endpoint endpointForResources() {
EndpointImpl endpoint = new EndpointImpl(springBus(), CXFTestService());
endpoint.publish("/getCXF");
return endpoint;
}
// 修改攔截的路徑,效果與在application.yml中配置cxf.path是一樣的。
// 如果兩者都沒配置,默認路徑爲/services/*。如果兩者都配置了,以本配置類配置的爲準。非必需項
@Bean
public ServletRegistrationBean newServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/cxf/*");
}
}
啓動項目後訪問:http://localhost:9010/javatest/cxf/getCXF?wsdl ,同樣進入了wsdl文檔,說明服務端已經正常啓動。
CXF搭建WebService客戶端
使用cxf搭建client有兩種方式:代理工廠和動態調用。爲了方便調用,客戶端的代碼同樣寫在另一個項目上。
準備工作
當用cxf發佈服務後,在idea通過Tools–>WebServices—>Generate Java Code From Wsdl…—>輸入配置時,可能會有如下提示:
無法按ok了。原因是,這裏需要安裝cxf並指定有效的cxf路徑,具體做法爲:
1)進入cxf的官網http://cxf.apache.org/download.html,下載對應的zip包(windows);
2)解壓壓縮包;
3)配置cxf路徑:在Idea中Ctrl+Alt+s進入Settings–>Tools–>Web Services,在cxf那欄中,將解壓後的文件夾路徑填上去。注意,這裏建議複製文件夾路徑粘貼上去,而不是按右邊的按鈕選擇,否則無法指定文件夾路徑。文件夾路徑不能出現中文。
之後再次Generate Java Code From Wsdl就能用cxf來下載服務。這樣就能將文件下載到本地了。
這裏再次提醒一句,在下載服務前要確保服務端是啓動的。
使用代理工廠調用webservice服務
創建一個controller,利用JaxWsProxyFactoryBean來創建webservice服務。
@PostMapping("/getStudentScoreById")
public StudentScore getStudentScoreById(long id) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(CXFTestService.class);
factory.setAddress("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 需要服務接口文件
CXFTestService client = (CXFTestService) factory.create();
return client.getStudentScoreById(id);
}
使用動態工廠調用webservice服務
如果不想用代理工廠,也可以用JaxWsDynamicClientFactory創建服務。這裏用到了QName來指定標籤。
@PostMapping("/getStudentScoreByIdDynamic")
public Object getStudentScoreByIdDynamic(long id) throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 用QName指定調用的服務端方法
// 注意:第一個參數不是targetNamespace,而是wsdl文檔中,<wsdl:import>標籤裏的namespace
QName qName = new QName("http://server.webservice.javatest.com/","getStudentScoreById");
// client.invoke返回的是一個Object[],因爲getStudentScoreById只返回一個對象,所以取索引爲0的對象
return client.invoke(qName, id)[0];
}
兩個調用方法的完整代碼如下:
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.xml.namespace.QName;
@RestController
@RequestMapping("/cxf")
public class CxfController {
@PostMapping("/getStudentScoreById")
public StudentScore getStudentScoreById(long id) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(CXFTestService.class);
factory.setAddress("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 需要服務接口文件
CXFTestService client = (CXFTestService) factory.create();
return client.getStudentScoreById(id);
}
@PostMapping("/getStudentScoreByIdDynamic")
public Object getStudentScoreByIdDynamic(long id) throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9010/javatest/cxf/getCXF?wsdl");
// 用QName指定調用的服務端方法
// 注意:第一個參數不是targetNamespace,而是wsdl文檔中,<wsdl:import>標籤裏的namespace
QName qName = new QName("http://server.webservice.javatest.com/","getStudentScoreById");
// client.invoke返回的是一個Object[],因爲getStudentScoreById只返回一個對象,所以取索引爲0的對象
return client.invoke(qName, id)[0];
}
}
總結
webservice服務端和客戶端的開發是分離的,意思是服務端使用哪種技術搭建並不會影響客戶端選用的技術,如果服務端使用cxf技術搭建,那麼客戶端既可以用cxf,也可以用axis2、JWS、wsimport等等的技術調用。