Spring boot+CXF開發WebService Demo
最近工作中需要用到webservice,而且結合spring boot進行開發,參照了一些網上的資料,配置過程中出現的了一些問題,於是寫了這篇博客,記錄一下我這次spring boot+cxf開發的webservice的配置過程,僅供參考。
聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出, 原文地址 如有問題, 可郵件([email protected])諮詢.
一、本次開發除了用到spring boot基礎jar包外,還用到了cxf相關jar包:
1 <!-- cxf支持 --> 2 <dependency> 3 <groupId>org.apache.cxf</groupId> 4 <artifactId>cxf-rt-frontend-jaxws</artifactId> 5 <version>3.1.6</version> 6 </dependency> 7 <dependency> 8 <groupId>org.apache.cxf</groupId> 9 <artifactId>cxf-rt-transports-http</artifactId> 10 <version>3.1.6</version> 11 </dependency>
二、首先我們創建一個實體類,內容是關於用戶信息的查詢和記錄:
1 import java.io.Serializable; 2 import java.util.Date; 3 4 public class User implements Serializable { 5 6 private static final long serialVersionUID = -5939599230753662529L; 7 private String userId; 8 private String username; 9 private String age; 10 private Date updateTime; 11 //getter setter ...... 12 public void setUserId(String userId) { 13 this.userId=userId; 14 } 15 public void setUsername(String username) { 16 this.username=username; 17 } 18 public void setAge(String age) { 19 this.age=age; 20 } 21 public void setUpdateTime(Date updateTime) { 22 this.updateTime=updateTime; 23 } 24 25 26 public String getUserId() { 27 return userId; 28 } 29 public String getUserName() { 30 return username; 31 } 32 public String getAge() { 33 return age; 34 } 35 public Date getUpdateTime() { 36 return updateTime; 37 } 38 }
三、接下來我們創建接口類:
1 import javax.jws.WebMethod; 2 import javax.jws.WebParam; 3 import javax.jws.WebService; 4 5 import cn.paybay.demo.entity.User; 6 7 8 @WebService 9 public interface UserService { 10 11 @WebMethod 12 String getName(@WebParam(name = "userId") String userId); 13 @WebMethod 14 User getUser(String userId); 15 }
四、有了接口類,那麼接下來我們對接口進行實現,也就是接口實現類(也就是業務類)代碼:
1 package cn.paybay.demo.service.impl; 2 3 import java.util.Date; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 8 9 import javax.jws.WebService; 10 11 import cn.paybay.demo.entity.User; 12 import cn.paybay.demo.service.UserService; 13 14 @WebService(targetNamespace="http://service.demo.paybay.cn/",endpointInterface = "cn.paybay.demo.service.UserService") 15 public class UserServiceImpl implements UserService{ 16 17 private Map<String, User> userMap = new HashMap<String, User>(); 18 public UserServiceImpl() { 19 System.out.println("向實體類插入數據"); 20 User user = new User(); 21 user.setUserId("411001"); 22 user.setUsername("zhansan"); 23 user.setAge("20"); 24 user.setUpdateTime(new Date()); 25 userMap.put(user.getUserId(), user); 26 27 user = new User(); 28 user.setUserId("411002"); 29 user.setUsername("lisi"); 30 user.setAge("30"); 31 user.setUpdateTime(new Date()); 32 userMap.put(user.getUserId(), user); 33 34 user = new User(); 35 user.setUserId("411003"); 36 user.setUsername("wangwu"); 37 user.setAge("40"); 38 user.setUpdateTime(new Date()); 39 userMap.put(user.getUserId(), user); 40 } 41 @Override 42 public String getName(String userId) { 43 return "liyd-" + userId; 44 } 45 @Override 46 public User getUser(String userId) { 47 System.out.println("userMap是:"+userMap); 48 return userMap.get(userId); 49 } 50 51 } 註釋(PS):在發佈服務之前,我們要在這裏對業務實現類進行一下說明,請大家看下圖箭頭指向的方框部分 (圖一) 下面我來解釋一下加上圖方框箭頭所指代碼的目的: http://impl.service.demo.paybay.cn/:這是我的業務類所在路徑; http://service.demo.paybay.cn/:這是我的接口類所在路徑; 在不加上圖方框箭頭所指代碼的情況下,你最後發服務的結果是這樣的(如下圖): (圖二)
並且會在你進行客戶端調用的時候回報錯:No operation was found with the name {http://impl.service.demo.paybay.cn/}getUser. 那麼原因就是:在CXF發佈服務的時候,發佈的是業務類(UserServiceImpl.java),那麼默認的命名空間就會是業務類所在包(路徑),而對外界暴露的則是接口類(UserService.java),那麼對於客戶端調用的時侯,需要按照接口類所在路徑進行命名空間的定義。 所以在發佈之前我們要在業務類(UserServiceImpl.java)上增加註解,指定命名空間,然後再進行發佈, 那麼我們最終在加上(圖一)方框箭頭所指代碼情況下,發佈服務的結果爲下圖(請看圖三): (圖三)
五、(發佈服務)接口類,業務類代碼都已經準備好,那麼我接下來我就要對webservice服務進行發佈: 代碼如下:
1 2 3 import javax.xml.ws.Endpoint; 4 5 import org.apache.cxf.Bus; 6 import org.apache.cxf.bus.spring.SpringBus; 7 import org.apache.cxf.jaxws.EndpointImpl; 8 import org.apache.cxf.transport.servlet.CXFServlet; 9 import org.springframework.boot.web.servlet.ServletRegistrationBean; 10 import org.springframework.context.annotation.Bean; 11 import org.springframework.context.annotation.Configuration; 12 13 import cn.paybay.demo.service.UserService; 14 import cn.paybay.demo.service.impl.UserServiceImpl; 15 16 17 @Configuration 18 public class TestConfig { 19 20 @Bean 21 public ServletRegistrationBean dispatcherServlet() { 22 return new ServletRegistrationBean(new CXFServlet(), "/test/*"); 23 } 24 @Bean(name = Bus.DEFAULT_BUS_ID) 25 public SpringBus springBus() { 26 return new SpringBus(); 27 } 28 @Bean 29 public UserService userService() { 30 return new UserServiceImpl(); 31 } 32 @Bean 33 public Endpoint endpoint() { 34 EndpointImpl endpoint = new EndpointImpl(springBus(), userService()); 35 endpoint.publish("/user"); 36 return endpoint; 37 } 38 39 } 那麼到這裏呢,我們的所有的步驟基本完成了,啓動spring boot 然後再瀏覽器中輸入url:http://localhost:8080/webservice/test/user?wsdl 可以看到有相關的wsdl描述信息輸出了,說明服務已經發布了。 那麼這裏我又要增加註釋了,請大家注意,我在最初查詢資料,配置demo的時候,啓動以後,發佈時候總是報404,網上有很多關於什麼端口衝突等說法,我試過後,根本不是那一回事,然後我無意中嘗試了一下,在url地址處加入工程名,結果,問題解決了。 因此請大家注意:在測試發佈服務的時候,你在瀏覽器中輸入的url地址應該是:http://localhost:8080/你的工程名/test/user?wsdl; 然後就是發佈結果如下圖(見圖四): (圖四)
到此爲止,我們的服務發佈成功了。 六、調用服務
1 2 3 4 5 6 import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; 7 8 9 public class Client { 10 12 public static void main(String args[]) throws Exception{ 13 14 JaxWsDynamicClientFactory dcf =JaxWsDynamicClientFactory.newInstance(); 15 org.apache.cxf.endpoint.Client client =dcf.createClient("http://localhost:8080/webservice/test/user?wsdl"); 16 //getUser 爲接口中定義的方法名稱 張三爲傳遞的參數 返回一個Object數組 17 Object[] objects=client.invoke("getUser","411001"); 18 //輸出調用結果 19 System.out.println("*****"+objects[0].toString()); 20 } 21 22 }
七、最後附上我的工程結構圖(見圖五):
(圖五)
寫這篇博客,參照了一些大神的貼子,學習到很多知識,總結出來的,僅供參考,如有錯誤,請各位指導!