1. 程式人生 > >【WebService開發】之使用CXF開發WebService

【WebService開發】之使用CXF開發WebService

1.開發服務端

a) 下載CXFapache-cxf-3.1.6

b) cxfjar包加入到專案中,其它不需要改變(同JDK開發webservice一樣),webservice服務端開發完成。

2.開發客戶端

a) 加入環境變數path中,E:\apache-cxf-3.1.6\bin

b) cmd命令下生成客戶程式碼,命令為:wsdl2java url,該命令為cxfbin目錄下的功能。

c) 編寫客戶端測試程式碼

public class ClientTest {
	public static void main(String[] args) {
		HelloWSImplService factory = new HelloWSImplService();
		HelloWs helloWs = factory.getHelloWSImplPort();
		String result = helloWs.sayHello("xdy");
		System.out.println(result);
	}
}

WebService請求的流程

一次web service請求的本質:

1.客戶端向服務端傳送了一個soap訊息(http請求+xml片斷)。

2.伺服器端處理完請求後,向客戶端返回一個soap訊息。

/**********************************華麗分割線******************************************/

CXF框架的使用

1、CXF的攔截器

為什麼設計攔截器?

為了在webservice請求過程中,能動態操作請求和響應資料,CXF設計了攔截器。

攔截器分類:

1.按所處的位置分:伺服器端攔截器,客戶端攔截器。

2.按訊息的方向分:入攔截器,出攔截器。

3.按定義者分:系統攔截器,自定義攔截器。

【示例】演示為客戶端及服務端加入日誌攔截器。

為服務端ServerTest加入日誌攔截器。

public class ServerTest {
	public static void main(String[] args) {
		String address = "http://192.168.0.102:8989/day01_ws/hellows";
		Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl());
		System.out.println(endpoint);
		EndpointImpl endpointImpl = (EndpointImpl)endpoint;	
		//服務端的日誌入攔截器
		List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
		inInterceptors.add(new LoggingInInterceptor());	
		//服務端的日誌出攔截器
		List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
		outInterceptors.add(new LoggingOutInterceptor());	
		System.out.println("釋出webservice成功!");
	}
}

為客戶端ClientTest加入日誌攔截器。

public class ClientTest {
	public static void main(String[] args) {
		HelloWSImplService factory = new HelloWSImplService();
		HelloWs helloWs = factory.getHelloWSImplPort();		
		//傳送請求的客戶端物件
		Client client = ClientProxy.getClient(helloWs);		
		//客戶端的日誌出攔截器
		List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
		outInterceptors.add(new LoggingOutInterceptor());		
		//客戶端的日誌入攔截器
		List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
		inInterceptors.add(new LoggingInInterceptor());		
		String result = helloWs.sayHello("xdy");
		System.out.println(result);
	}
}

2、CXF自定義攔截器

AbstractPhaseInterceptor:抽象過程攔截器,一般自定義的攔截器都會繼承於它

功能:通過自定義攔截器實現使用者名稱和密碼的檢查

1.客戶端攔截器:設定out攔截器,向soap訊息中新增使用者名稱和密碼資料

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	private String name;
	private String password;

	public MyInterceptor(String name,String password) {
		super(Phase.PRE_PROTOCOL);
		this.name = name;
		this.password = password;
	}

	/*
	 <Envelope> 
	 	<head>
	 		<xdy>
	 			<name>xiongdy</name>
	 			<password>123456</password>
	 		</xdy>
	 	</head>
	 	<body>
	 		<sayHello>
	 			<arg0>xdy</arg0>
	 		</sayHello>
	  	</body>
	 </Envelope>
	 */
	public void handleMessage(SoapMessage message) throws Fault {
		 List<Header> headers = message.getHeaders();
		 /*
		  	<xdy>
	 			<name>xiongdy</name>
	 			<password>123456</password>
	 		</xdy>
		  */
		 //Document document = DOMHelper.createDocument();
		 Document document = DOMUtils.createDocument();
		 //<xdy>
		 Element rootEle = document.createElement("xdy");
		 
		 //<name>xiongdy</name>
		 Element nameEle = document.createElement("name");
		 nameEle.setTextContent(name);
		 rootEle.appendChild(nameEle);
		 
		 //<password>123456</password>
		 Element passwordEle = document.createElement("password");
		 passwordEle.setTextContent(password);
		 rootEle.appendChild(passwordEle);
		 
		 //新增為請求訊息的<soap:Header>
		 headers.add(new Header(new QName("xdy"), rootEle));
		 
		 System.out.println("client-----handleMessage");
	}
}

2.服務端攔截器:設定in攔截器,從soap訊息中獲取使用者名稱和密碼資料,如果不滿足條件就不執行web service的方法

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	public MyInterceptor() {
		super(Phase.PRE_PROTOCOL);
	}

	@Override
	public void handleMessage(SoapMessage msg) throws Fault {
		System.out.println("server-----handleMessage");
		
		Header header = msg.getHeader(new QName("xdy"));
		if(header==null) {
			throw new Fault(new RuntimeException("使用者名稱密碼不存在 "));
		} else {
			Element data = (Element) header.getObject();
			if(data==null) {
				throw new Fault(new RuntimeException("使用者名稱密碼不存在22"));
			} else {
				String name = data.getElementsByTagName("name").item(0).getTextContent();
				String password = data.getElementsByTagName("password").item(0).getTextContent();
				if(!"xiongdy".equals(name) || !"123456".equals(password)) {
					throw new Fault(new RuntimeException("使用者名稱密碼不正確"));
				}
			}
		}
		System.out.println("通過攔截器了!");
	}
}

3.服務端測試程式碼:

public class ServerTest {
	public static void main(String[] args) {
		String address = "http://192.168.0.102:8989/day01_ws/hellows";
		Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl());
		System.out.println(endpoint);
		EndpointImpl endpointImpl = (EndpointImpl)endpoint;
		
		//服務端的自定義入攔截器
		List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
		inInterceptors.add(new MyInterceptor());
		
		System.out.println("釋出webservice成功!");
	}
}

4.客戶端測試程式碼

public class ClientTest2 {
	public static void main(String[] args) {
		HelloWSImplService factory = new HelloWSImplService();
		HelloWs helloWs = factory.getHelloWSImplPort();
		
		//傳送請求的客戶端物件
		Client client = ClientProxy.getClient(helloWs);
		
		//客戶端的自定義出攔截器
		List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
		outInterceptors.add(new MyInterceptor("xiongdy", "123456"));
		
		String result = helloWs.sayHello("xdy");
		System.out.println(result);
	}
}


/**********************************華麗分割線******************************************/

CXF編寫基於SpringWebService

server端:

1. 新建web工程,匯入cxfjar

2. 定義SEI和其實現

@WebService
public interface OrderService {
	@WebMethod
	public Order getOrderByNo(String orderNo);
}
@WebService
public class OrderServiceImpl implements OrderService {
	public OrderServiceImpl() {
		System.out.println("OrderServiceImpl()");
	}

	public Order getOrderByNo(String orderNo) {
		System.out.println("getOrderByNo() orderNO=" + orderNo);
		return new Order(3, orderNo, 10000000);
	}
}
public class Order {
	private int id;
	private String orderNo;
	private double price;
}

3. 釋出web service

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
										http://www.springframework.org/schema/beans/spring-beans.xsd
										http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	<!-- 配置一些cxf的核心bean -->
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<!--
		終端:釋出webservice(將SEI的實現類物件與web service所提供的網路地址關聯)
	-->
	<jaxws:endpoint id="orderService"
		implementor="com.xdy.ws.OrderServiceImpl" address="/orderService" />
</beans>

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<!-- 配置上下文初始化引數:指定cxf的spring的beans.xml -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:beans.xml</param-value>
	</context-param>

	<!-- 載入上面引數的配置檔案的listener -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- 匹配所有請求,將請求先交給cxf框架處理 -->
	<servlet>
		<servlet-name>CXFServlet</servlet-name>
		<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>CXFServlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

client

1. 新建web工程,匯入cxfjar

2. 根據wsdl文件生成客戶端程式碼(src下)

3. client-beans.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
									http://www.springframework.org/schema/beans/spring-beans.xsd
									http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	<!-- 配置傳送請求的客戶端 -->
	<jaxws:client id="orderClient"
		serviceClass="com.xdy.ws.OrderService" address="http://localhost:8080/wsspringserver/orderService" />
</beans>

4. 編寫測試程式碼:

public class ClientTest {
	public static void main(String[] args) {
		// 載入client-beans.xml
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("client-beans.xml");
		// 根據bean的id載入所對應的OrderService
		OrderService orderService = (OrderService) context.getBean("orderClient");
		// 呼叫方法,傳送soap請求
		Order order = orderService.getOrderByNo("hao123");
		System.out.println("client " + order.getId() + "_" + order.getOrderNo()+ "_" + order.getPrice());
	}
}

/**********************************華麗分割線******************************************/

CXF編寫基於SpringWebService新增攔截器


客戶端:

client-beans.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
									http://www.springframework.org/schema/beans/spring-beans.xsd
									http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	<!-- 配置傳送請求的客戶端 -->
	<jaxws:client id="orderClient"
		serviceClass="com.xdy.ws.OrderService" address="http://localhost:8080/wsspringserver/orderService" >
			<jaxws:outInterceptors>
				<bean class="com.xdy.ws.interceptor.MyInterceptor">
					<property name="name" value="xiongdy"></property>
					<property name="password" value="123456"></property>
				</bean>
			</jaxws:outInterceptors>
	</jaxws:client>
</beans>

客戶端攔截器MyInterceptor:

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	private String name;
	private String password;

	public MyInterceptor(String name,String password) {
		super(Phase.PRE_PROTOCOL);
		this.name = name;
		this.password = password;
		System.out.println("MyInterceptor.....");
	}
	
	public MyInterceptor() {
		super(Phase.PRE_PROTOCOL);
		System.out.println("MyInterceptor.....^_^");
	}

	/*
	 <Envelope> 
	 	<head>
	 		<xdy>
	 			<name>xiongdy</name>
	 			<password>123456</password>
	 		</xdy>
	 	</head>
	 	<body>
	 		<sayHello>
	 			<arg0>xdy</arg0>
	 		</sayHello>
	  	</body>
	 </Envelope>
	 */
	public void handleMessage(SoapMessage message) throws Fault {
		 List<Header> headers = message.getHeaders();
		 /*
		  	<xdy>
	 			<name>xiongdy</name>
	 			<password>123456</password>
	 		</xdy>
		  */
		 //Document document = DOMHelper.createDocument();
		 Document document = DOMUtils.createDocument();
		 //<xdy>
		 Element rootEle = document.createElement("xdy");
		 
		 //<name>xiongdy</name>
		 Element nameEle = document.createElement("name");
		 nameEle.setTextContent(name);
		 rootEle.appendChild(nameEle);
		 
		 //<password>123456</password>
		 Element passwordEle = document.createElement("password");
		 passwordEle.setTextContent(password);
		 rootEle.appendChild(passwordEle);
		 
		 //新增為請求訊息的<soap:Header>
		 headers.add(new Header(new QName("xdy"), rootEle));
		 
		 System.out.println("client-----handleMessage");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}

伺服器端:

Beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
										http://www.springframework.org/schema/beans/spring-beans.xsd
										http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	<!-- 配置一些cxf的核心bean -->
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<!--
		終端:釋出webservice(將SEI的實現類物件與web service所提供的網路地址關聯)
	-->
	<jaxws:endpoint id="orderService"
		implementor="com.xdy.ws.OrderServiceImpl" address="/orderService" >
		<jaxws:inInterceptors>
			<bean class="com.xdy.ws.interceptor.MyInterceptor"/>
		</jaxws:inInterceptors>
	</jaxws:endpoint>
</beans>

服務端攔截器MyInterceptor:

public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	
	public MyInterceptor() {
		super(Phase.PRE_PROTOCOL);
	}

	public void handleMessage(SoapMessage msg) throws Fault {
		System.out.println("server-----handleMessage");
		
		Header header = msg.getHeader(new QName("xdy"));
		if(header==null) {
			throw new Fault(new RuntimeException("使用者名稱密碼不存在 "));
		} else {
			Element data = (Element) header.getObject();
			if(data==null) {
				throw new Fault(new RuntimeException("使用者名稱密碼不存在22"));
			} else {
				String name = data.getElementsByTagName("name").item(0).getTextContent();
				String password = data.getElementsByTagName("password").item(0).getTextContent();
				if(!"xiongdy".equals(name) || !"123456".equals(password)) {
					throw new Fault(new RuntimeException("使用者名稱密碼不正確"));
				}
			}
		}
		System.out.println("通過攔截器了!");
	}
}