在JAVA EE應用程序中實現Web Service服務(二)代碼實戰

使用jdk方式發佈web service服務

利用jdk工具包中爲我們開發者提供的工具,來創建Web Service服務端,同時,使用jdk工具包中的工具來實現訪問Web Service的客戶端。

服務端

步驟:

  1. 創建一個服務接口 - interface
  2. 創建服務實現類
  3. 發佈服務
客戶端

步驟:

  1. 生成客戶端代碼
    wsdl2java -d e:/jdk-client http://localhost:8080/hello?wsdl
  2. 調用遠程服務

- 服務器端的代碼實現

  1. 創建服務接口
package com.golden3young.service;

import javax.jws.WebService;

// 在服務接口和實現類上都要加上@WebService註解    
// serviceName對應到 WSDL文件中的<wsdl:service name="HelloServiceWS">
// portName對應到WSDL文件中的<wsdl:port name="HelloServiceWSSoap">

@WebService(serviceName="HelloServiceWS", portName="HelloServiceWSSoap")
public interface HelloService {
	//服務方法
	String sayHello(String name);
}

  1. 創建服務實現類
package com.golden3young.service;

import javax.jws.WebService;

@WebService(serviceName="HelloServiceWS", portName="HelloServiceWSSoap")
public class HelloServiceImpl implements HelloService {

	@Override
	public String sayHello(String name) {
		System.out.println("sayHello invoke!");
		return "Hello " + name;
	}
	
}

  1. 發佈服務
package com.golden3young;

import javax.xml.ws.Endpoint;

import com.golden3young.service.HelloServiceImpl;

public class JdkWSServer {

	public static void main(String[] args) {
		Endpoint.publish("http://localhost:8080/hello?wsdl", new HelloServiceImpl());
	}

}

運行此方法即可發佈服務,我們只需在瀏覽器中輸入規定的路徑,即可訪問到響應的xml文件。xml文件中的具體標籤含義,已在本系列(一)的文章中做過介紹。

- 客戶器端的代碼實現

  1. 生成客戶端代碼

我們藉助的是apache-cxf的第三方工具,這裏面爲我們提供了下載服務器端Web Service的工具,我們只需要在安裝後,bin路徑下,打開cmd命令行面板。輸入“ wsdl2java -d e:/jdk-client http://localhost:8080/hello?wsdl ”命令,即可自動爲我們將指定路徑中的項目代碼進行下載。

wsdl2java -d e:/jdk-client http://localhost:8080/hello?wsdl
解釋一下:

wsdl2java 是一個命令

-d 表示解壓到指定目錄下

e:/jdk-client 是我們指定的文件輸出路徑,第三方工具回將服務器端的代碼下載到我們指定的目錄下,如果文件夾不存在,也會自動創建。

http://localhost:8080/hello?wsdl 這是我們訪問的Web Service服務器端的路徑。只有通過正確的路徑,才能訪問到我們想要的資源代碼。

注意,這個下載過程需要聯網,沒有網絡支持是無法完成的。下載完畢後,將目錄下的代碼文件全部拷貝到我們的工程中,以便我們使用。
其實,下載的所有代碼,其實就是服務器端所部署的代碼,但是,所有獲取數據的代碼都被底層加工成了發送請求獲取的方式,也就是說,我們下載在客戶端的代碼,基本與服務器端的代碼相同,但是所有獲取返回數據的代碼,都會被修改成發送請求到指定路徑的方式來獲取。也就是說,我們客戶端的代碼,在運行起來以後,其實底層就是繼續發送請求到事先指定的路徑拿取數據,然後將數據進行處理,處理所需要的類方法或者類屬性都已經下載在客戶端了。當我們使用的時候,無需關注底層的代碼實現,我們只需要通過調用服務對象即可拿到我們想要的值,中間的所有處理,都是剛纔下載到本地的代碼去執行的。

  1. 調用遠程服務
import com.golden3young.service.HelloServiceImpl;
import com.golden3young.service.HelloServiceWS;

public class JdkWSClient {

	public static void main(String[] args) {
		// <wsdl:service name="HelloServiceWS">
		
		HelloServiceWS ws = new HelloServiceWS();
		//通過service服務名字獲取port
		// 這就相當於是xml文件中的那個<wsdl:port name="HelloServiceWSSoap">標籤
		// getHelloServiceWSSoap(); => 會返回一個遠程代理對象
		HelloServiceImpl helloServiceWSSoap = ws.getHelloServiceWSSoap();
		
		//簡單打印一下,看看這個對象是個啥
		System.out.println(helloServiceWSSoap);
		
		//調用這個對象的sayHello()方法,獲取結果並打印
		String result = helloServiceWSSoap.sayHello("Web Service");
		System.out.println(result);
	}

}

使用CXF方式發佈web service服務

官方地址:cxf.apache.org

	簡單介紹:
	
	   Apache CXF = Celtix + XFire,開始叫 Apache CeltiXfire,後來更名爲 Apache CXF 了,
	以下簡稱爲 CXF。CXF 繼承了 Celtix 和 XFire 兩大開源項目的精華,提供了對 JAX-WS 
	全面的支持,並且提供了多種 Binding 、DataBinding、Transport 以及各種 Format 的支
	持,並且可以根據實際項目的需要,採用代碼優先(Code First)或者 WSDL 優先(WSDL 
	First)來輕鬆地實現 Web Services 的發佈和使用。Apache CXF已經是一個正式的
	Apache頂級項目。

	    支持 Web Services 標準:CXF 支持多種 Web Services 標準,包含 SOAP、Basic 
    Profile、WS-Addressing、WS-Policy、WS-ReliableMessaging 和 WS-Security。
    Frontends:CXF 支持多種“Frontend”編程模型,CXF 實現了JAX-WS API (遵循 JAX-WS
 	2.0 TCK 版本),它也包含一個“simple frontend”允許客戶端和 EndPoint 的創建,而不需
	要 Annotation 註解。CXF 既支持 WSDL優先開發,也支持從 Java 的代碼優先開發模式。
	容易使用: CXF 設計得更加直觀與容易使用。有大量簡單的 API 用來快速地構建代碼優先
	的 Services,各種 Maven 的插件也使集成更加容易,支持 JAX-WS API ,支持 Spring 2.0 
	更加簡化的 XML 配置方式,等等。支持二進制和遺留協議:CXF 的設計是一種可插撥的
	架構,既可以支持 XML ,也可以支持非 XML 的類型綁定,比如:JSON 和 CORBA。
引入maven依賴
<dependency>  
	<groupId>org.apache.cxf</groupId>  
	<artifactId>cxf-rt-frontend-jaxws</artifactId>
	<version>3.1.11</version> 
</dependency> 

<dependency>  
	<groupId>org.apache.cxf</groupId>  
	<artifactId>cxf-rt-transports-http</artifactId> 
	<version>3.1.11</version> 
</dependency> 

<!--  Jetty is needed if you're are not using the CXFServlet --> 
<dependency>  
	<groupId>org.apache.cxf</groupId>  
	<artifactId>cxf-rt-transports-http-jetty</artifactId>
	<version>3.1.11</version> 
</dependency>

服務端

步驟:

  1. 開發服務接口
  2. 開發服務實現
  3. 暴露服務
    3-1 創建服務工廠
    3-2 設置工廠地址
    3-3 設置要發佈的服務接口
    3-4 設置服務實現
    3-5 創建服務
    3-6 啓動服務

客戶端

步驟:

  1. 生成客戶端代碼
    wsdl2java -d e:/jdk-client http://localhost:9090/user?wsdl
  2. 調用遠程服務
    2-1 創建代理工場
    2-2 設置服務地址
    2-3 設置服務接口
    2-4 創建遠程服務代理對象
    2-5 調用遠程服務

- 服務器端的代碼實現

1.開發服務接口

package com.golden3young.server;

import javax.jws.WebService;

import com.etoak.bean.User;

@WebService	//要記得添加這個註解!以此來表示自己是WebService
public interface UserService {

	User queryUserById(int id);
	
}

2.開發服務實現

package com.golden3young.server.impl;

import javax.jws.WebService;

import com.golden3young.bean.User;
import com.golden3young.server.UserService;

@WebService	//必須添加這個註解!以此來表示自己是WebService
public class UserServiceImpl implements UserService {

	@Override
	public User queryUserById(int id) {
		System.out.println("queryById invoke");
		return new User(id,"Tom",19);
	}

}

  1. 暴露服務
    3-1 創建服務工廠
    3-2 設置工廠地址
    3-3 設置要發佈的服務接口
    3-4 設置服務實現
    3-5 創建服務
    3-6 啓動服務
package com.golden3young;

import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import com.golden3young.server.UserService;
import com.golden3young.server.impl.UserServiceImpl;

public class CxfServer {

	public static void main(String[] args) {
		//創建服務工廠
		JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
		
		//設置Wsdl服務地址 -> 也就是客戶只要訪問這個url,就可以拿到我們這個項目對外公開的代碼
		factory.setAddress("http://localhost:9090/user?wsdl");

		//暴露服務接口
		factory.setServiceClass(UserService.class);

		//設置服務實現類
		factory.setServiceBean(new UserServiceImpl());

		//創建服務,並啓動
		Server server = factory.create();
		server.start();
		
		System.out.println("~~~~服務已啓動~~~~");
	}

}

- 客戶器端的代碼實現

  1. 生成客戶端代碼
wsdl2java -d e:/jdk-client http://localhost:9090/user?wsdl

與jdk中提到的方式一樣,都是需要下載服務器端代碼到本地。
然後將所有代碼拷貝到自己的工程中。

  1. 調用遠程服務
    2-1 創建代理工廠
    2-2 設置服務地址
    2-3 設置服務接口
    2-4 創建遠程服務代理對象
    2-5 調用遠程服務
package com.golden3young.cxf;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import com.golden3young.server.User;
import com.golden3young.server.UserService;

public class CxfClient {
	public static void main(String[] args) {
		//創建代理工廠
		JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		//設置服務地址
		factory.setAddress("http://localhost:9090/user?wsdl");
		//設置服務接口
		factory.setServiceClass(UserService.class);
		//創建代理
		UserService service = (UserService) factory.create();
		System.out.println(service);
		//調用服務
		User user = service.queryUserById(10);
		System.out.println(user.getId());
		System.out.println(user.getName());
		System.out.println(user.getAge());
		System.out.println(user);
	}
}

這裏有個地方需要注意,我們在服務器端生成的代碼,一旦被用戶下載到本地,進行使用的時候,客戶端的程序是依賴於客戶端的代碼執行的。舉一個很直接的例子:如果我們在服務器端自定義的User類中,並沒有重寫toString()方法,那麼一但打印User對象,結果其實是 類名@地址映射值,而如果此時,我們在客戶端下載下來的代碼中,給uUser類重寫toString()方法,那麼在客戶端中其他代碼中再打印User對象的時候,就不會像服務器端那樣打印類名@地址映射值 了,而是會依賴於我們拷貝到工程中的代碼來執行,由於我們重寫了toString,那麼打印的結果就會變成我們指定的內容。
同時,一旦服務器端對代碼進行了修改,是不會自動同步到客戶端代碼上的,而是需要客戶自己重新訪問url,重新下載新的代碼,並拷貝到自己的工程中,才能使用更新後的代碼。

複習一下:如果用 jdk的方式來獲取上面的這個Web Service的服務,也是可以的。
package com.golden3young.jdk;

import com.golden3young.server.User;
import com.golden3young.server.UserService;
import com.golden3young.server.UserServiceService;

public class JdkClient {

	public static void main(String[] args) {
		//這裏使用是xml中的serviceName,但此時由於服務器端是利用cxf部署的,
	    //所以不再像剛纔jdk工具生成發xml那種格式了。
	    //通過UserServiceSerivce就不難看出它們兩個的差別
		//獲取Service對象
		UserServiceService us = new UserServiceService();
		
		//通過Service服務名字獲取port
		UserService service = us.getUserServicePort();
		
		//調用這個對象的方法並獲得返回值
		User user = service.queryUserById(10);
		
		//打印驗證
		System.out.println(user.getId());
		System.out.println(user.getName());
		System.out.println(user.getAge());
		System.out.println(user);
	}

}

CXF整合Spring,開發Web Service

- 整合spring web,開發服務端

步驟:

  1. 創建spring-web.xml
  2. 創建spring-context.xml
  3. 配置CXFServlet
  4. 開發服務接口
  5. 開發服務實現
  6. 配置spring容器
  7. 部署到tomcat、測試
引入maven依賴
<dependencies>
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-frontend-jaxws</artifactId>
	</dependency>
	
	<dependency>
		<groupId>org.apache.cxf</groupId>
		<artifactId>cxf-rt-transports-http</artifactId>
	</dependency>
	
	<!-- spring web -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
	</dependency>
	
	<!-- spring-context -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
	</dependency>
	
</dependencies>
修改web.xml
	<servlet>
		<servlet-name>cxf</servlet-name>
		<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
		<init-param>
			<param-name>config-location</param-name>
			<param-value>classpath:spring-cxf.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>cxf</servlet-name>
		<url-pattern>/ws/*</url-pattern>
	</servlet-mapping>

開發服務接口

package com.golden3young.service;

import java.util.List;

import javax.jws.WebService;

import com.etoak.bean.User;

@WebService		//必須添加這個標籤,用於表明身份
public interface UserService {
	
	int addUser(User user);
	
	List<User> queryAllUsers();
}

開發服務實現

package com.golden3young.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.jws.WebService;

import org.springframework.stereotype.Service;

import com.golden3young.bean.User;
import com.golden3young.service.UserService;

@Service		//爲了告訴spring容器,掃描成一個bean對象。 單例
@WebService		//爲了告訴cxf組件,這是一個jaxws服務,表明身份
public class UserServiceImpl implements UserService {

	//不建議在真實開發中如此書寫(創建全局集合),僅爲測試使用
	List<User> users = new ArrayList<>();
	
	@Override
	public int addUser(User user) {
		users.add(user);
		return users.size();
	}

	@Override
	public List<User> queryAllUsers() {
		System.out.println("查詢所有用戶");
		return users;
	}

}

創建spring-cxf.xml,並移動到指定位置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jaxws="http://cxf.apache.org/jaxws" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation=
	"http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://cxf.apache.org/jaxws
	http://cxf.apache.org/schemas/jaxws.xsd">
	
	<context:component-scan base-package="com.etoak" />
	
	 <!-- http://localhost:8080/contextPath/ws/user?wsdl -->
	 <jaxws:server address="/user" serviceClass="com.etoak.service.UserService">
	 	<jaxws:serviceBean>
	 		<ref bean="userServiceImpl" />
	 	</jaxws:serviceBean>
	 </jaxws:server>
</beans>

上面配置的< jaxws:server >標籤其實就是替代了之前我們手動創建工廠的過程,接下來對於工廠的配置,由一開始的setter方法,變成了現在的標籤或者屬性:

	JaxWSServiceFactroyBean [標籤<jaxws:server>]
	factory.setAddress  [屬性address="/user" ]
	factory.setServiceClass [屬性serviceClass="com.etoak.service.UserService"]
	factory.setServiceBean [標籤<jaxws:serviceBean> + <ref bean="userServiceImpl" />]
	factory.create()	//spring自動爲我們創建

- 整合spring web,開發客戶端

引入maven依賴
<dependencies>
   	<dependency>
	  <groupId>org.apache.cxf</groupId>
	  <artifactId>cxf-rt-frontend-jaxws</artifactId>
	</dependency>
	
	<dependency>
	  <groupId>org.apache.cxf</groupId>
	  <artifactId>cxf-rt-transports-http</artifactId>
	</dependency>
	
	<!-- spring-context -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
	</dependency>
	
	<!-- 
	 Jetty is needed if you're are not using the CXFServlet
	-->
	<dependency>
	  <groupId>org.apache.cxf</groupId>
	  <artifactId>cxf-rt-transports-http-jetty</artifactId>
	  <version>3.1.11</version>
	</dependency>
	
  </dependencies>
使用指令,下載web服務端代碼到本地
wsdl2java -d e:/jdk-client http://localhost:9090/user?wsdl

將下載下來的文件,拷貝到自己的工程中,以備使用。

創建測試類,調用使用
package com.golden3young;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.golden3young.service.User;
import com.golden3young.service.UserService;

public class SpringClient {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-cxf.xml");
		UserService service = (UserService)context.getBean("userService");
		User user = new User();
		user.setId(1);
		user.setName("Tom");
		user.setAge(22);
		int result = service.addUser(user);
		//System.out.println(result);
		List<User> userList = service.queryAllUsers();
		userList.forEach(System.out::println);
	}
}
配置spring-cxf.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jaxws="http://cxf.apache.org/jaxws" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://cxf.apache.org/jaxws
	http://cxf.apache.org/schemas/jaxws.xsd">

	 <!-- jaxws:client 相當於一個遠程代理  是一個spring的Bean -->
	 <jaxws:client id="userService" address="http://localhost:8080/cxf-spring-web/ws/user?wsdl"
	 	serviceClass="com.etoak.service.UserService">
	 </jaxws:client>
</beans>

以上< jaxws:client >標籤,其實相當於我們自己利用cxf組件創建WebService客戶端時書寫的代碼,只不過現在由spring自動爲我們構建。

		JaxWSProxyFactoryBean	[<jaxws:client>]
		factory.setAddress()	[address屬性]
		factory.setServiceClass()	[serviceClass屬性]
		factory.create() 	//返回一個遠程服務的代理對象
發佈了14 篇原創文章 · 獲贊 3 · 訪問量 2086
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章