【WebService開發】之使用CXF開發WebService
1.開發服務端
a) 下載CXF:apache-cxf-3.1.6
b) 把cxf的jar包加入到專案中,其它不需要改變(同JDK開發webservice一樣),webservice服務端開發完成。
2.開發客戶端
a) 加入環境變數path中,E:\apache-cxf-3.1.6\bin
b) 在cmd命令下生成客戶程式碼,命令為:wsdl2java url,該命令為cxf的bin目錄下的功能。
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編寫基於Spring的WebService
server端:
1. 新建web工程,匯入cxf的jar包
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工程,匯入cxf的jar包
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編寫基於Spring的WebService新增攔截器
客戶端:
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("通過攔截器了!");
}
}