(转)CXF学习笔记一:如何创建、发布和访问基于CXF的服务
FROM:http://blog.csdn.net/yuvmen/archive/2009/11/09/4790805.aspx
?
主要參考http://cxf.apache.org的相關內容:
1.使用CXF創建服務的基本方法(使用CXF自帶的jetty容器)
?? 參考:http://cxf.apache.org/docs/a-simple-jax-ws-service.html
分4步:
① 設置build環境
② 寫服務
③ 發布服務
④ 訪問服務
?
1)設置build環境
創建一個新項目,將apache-cxf-2.2.4.zip中lib目錄中的下列文件添加到Build Path:
commons-logging-1.1.1.jar
geronimo-activation_1.1_spec-1.0.2.jar (or Sun's Activation jar)
geronimo-annotation_1.0_spec-1.1.1.jar (JSR 250)
geronimo-javamail_1.4_spec-1.6.jar (or Sun's JavaMail jar)
geronimo-servlet_2.5_spec-1.2.jar (or Sun's Servlet jar)
geronimo-ws-metadata_2.0_spec-1.1.2.jar (JSR 181)
geronimo-jaxws_2.1_spec-1.0.jar (or Sun's jaxws-api-2.1.jar)
geronimo-stax-api_1.0_spec-1.0.1.jar (or other stax-api jar)
jaxb-api-2.1.jar
jaxb-impl-2.1.12.jar
jetty-6.1.21.jar
jetty-util-6.1.21.jar
neethi-2.0.4.jar
saaj-api-1.3.jar
saaj-impl-1.3.2.jar
wsdl4j-1.6.2.jar
wstx-asl-3.2.8.jar
XmlSchema-1.4.5.jar
xml-resolver-1.2.jar
cxf-2.2.4.jar
可選:添加Spring jars,為XML Configuration添加Spring支持。添加的jars如下:
aopalliance-1.0.jar
spring-core-2.5.5.jar
spring-beans-2.5.5.jar
spring-context-2.5.5.jar
spring-web-2.5.5.jar
?
2)寫服務
A)寫接口
@WebService
public interface HelloWorld {
String sayHi(String text);
?
??? // JAX-WS/JAXB 不能直接支持高級用例,處理他們需要寫特殊的XmlAdapter
??? String sayHiToUser(User user);
?
??? /* Map 傳遞
???? * JAXB 不支持 Maps。它能很好的處理Lists,但Maps不能直接支持他們。
???? * 他們也需要使用一個XmlAdapter來將maps映射進JAXB可以使用的beans
???? */
??? @XmlJavaTypeAdapter(IntegerUserMapAdapter.class)
??? Map<Integer, User> getUsers();
}
注意:wsdl會重命名參數的名字,如果不希望這樣,應該這樣寫:
@WebService
public interface HelloWorld {
??? String sayHi(@WebParam(name="text") String text);
}
B)寫實現:
package demo.hw.server;
?
import java.util.LinkedHashMap;
import java.util.Map;
?
import javax.jws.WebService;
?
@WebService(endpointInterface = "demo.hw.server.HelloWorld",
??????????? serviceName = "HelloWorld")??? //告訴CXF用哪一個接口創建WSDL
public class HelloWorldImpl implements HelloWorld {
??? Map<Integer, User> users = new LinkedHashMap<Integer, User>();
?
??? public String sayHi(String text) {
??????? System.out.println("sayHi called");
??????? return "Hello " + text;
??? }
?
??? public String sayHiToUser(User user) {
??????? System.out.println("sayHiToUser called");
??????? users.put(users.size() + 1, user);
??????? return "Hello "? + user.getName();
??? }
?
??? public Map<Integer, User> getUsers() {
??????? System.out.println("getUsers called");
??????? return users;
??? }
}
?
3)發布服務(CXF自帶Jetty服務器,所以無需Tomcat就可發布)
A)使用jws的高層封裝:
System.out.println("Starting Server");
HelloWorldImpl implementor = new HelloWorldImpl();
String address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
B)使用下列代碼比較精確地控制服務的行為:
HelloWorldImpl implementor = new HelloWorldImpl();
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setServiceClass(HelloWorld.class);?? //可省,但不建議,因為可能會有些小問題
svrFactory.setAddress("http://localhost:9000/helloWorld");
svrFactory.setServiceBean(implementor);
svrFactory.getInInterceptors().add(new LoggingInInterceptor());
svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());
svrFactory.create();
自此,可以通過http://localhost:9000/helloWorld?wsdl來顯示該服務的wsdl
LoggingInInterceptor和LoggingOutInterceptor是日志攔截器,用于輸入和輸出時顯示日志,下同。
?
4)訪問服務
A)使用jws的高層封裝:
//第一個參數是接口實現類包名的反綴
private static final QName SERVICE_NAME = new QName("http://server.hw.demo/", "HelloWorld");
private static final QName PORT_NAME= new QName("http://server.hw.demo/", "HelloWorldPort");
……
Service service = Service.create(SERVICE_NAME);
// Endpoint Address
String endpointAddress = "http://localhost:9000/helloWorld";
// Add a port to the Service
service.addPort(PORT_NAME, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
HelloWorld hw = service.getPort(HelloWorld.class);
System.out.println(hw.sayHi("World"));
B)或者使用下面代碼更精確的控制服務:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(HelloWorld.class);
factory.setAddress("http://localhost:9000/helloWorld");
HelloWorld client = (HelloWorld) factory.create();
?
String reply = client.sayHi("HI");
System.out.println("Server said: " + reply);
System.exit(0);
?
2.wsdl2java:從wsdl文檔中生成java類,供client使用
設置環境變量CXF_HOME=D:\Program Files\apache-cxf-2.2.4,PATH后加上“;%CXF_HOME%\bin”(可選),然后執行wsdl2java批處理程序,用法如下:
wsdl2java –p 包名 –d 目錄名 wsdl路徑
如:wsdl2java –p demo.service.client –d e:\src htt://localhost:8080/helloWorld?wsdl
-p? 指定其wsdl的命名空間,也就是要生成代碼的包名
-d? 指定要產生代碼所在目錄
-client 生成客戶端測試web service的代碼
-server 生成服務器啟動web? service的代碼
-impl 生成web service的實現代碼
-ant? 生成build.xml文件
-all 生成所有開始端點代碼:types,service proxy,,service interface, server mainline, client mainline, implementation object, and an Ant build.xml file.
詳細用法見http://cwiki.apache.org/CXF20DOC/wsdl-to-java.html
3.定義復雜類型(基本類型如int,String,無須額外定義),參考資料:http://cxf.apache.org/docs/defining-contract-first-webservices-with-wsdl-generation-from-java.html
例如:
package com.example.customerservice;
?
@XmlAccessorType( XmlAccessType.FIELD )
public class Customer {? //自定義類
??? String name;
??? String\[\] address;
??? int numOrders;
??? double revenue;
??? BigDecimal test;
??? Date birthDate;
??? CustomerType type; //自定義枚舉類型
}
?
public enum CustomerType {
??? PRIVATE, BUSINESS
}
//定義Exception
@WebFault(name="NoSuchCustomer")
@XmlAccessorType( XmlAccessType.FIELD )
public class NoSuchCustomerException extends RuntimeException {
/**
?* We only define the fault details here. Additionally each fault has a message
?* that should not be defined separately
?*/
String customerName;
}???? //定義Exceptions的默認行為是在后面生成Java code時創建Exception_Exception,所以必須用@WebFault標記來為Bean取一個名字,以與Exception名字相區別
?
@WebService??? //標記本接口為一個服務
public interface CustomerService {
public Customer[] getCustomersByName(@WebParam(name="name") String name) throws NoSuchCustomerException;???? //@WebParam標記wsdl中的參數名。如果省略,wsdl將使用arg0代替
}
// @WebService還可用來自定義接口名和服務名,分別對應:endpointInterface和serviceName,如:
@WebService(endpointInterface = "com.example.customerservice", serviceName = "HelloWorld")
?
生成的WSDL:
<xs:complexTypeCOLOR: green">customer">? //復雜類型
??? <xs:sequence>
??????? <xs:element minOccurs="0"COLOR: green">name" type="xs:string"/>
??????? <xs:element maxOccurs="unbounded" minOccurs="0"COLOR: green">address" nillable="true"COLOR: green">xs:string"/>
??????? <xs:elementCOLOR: green">numOrders"COLOR: green">xs:int"/>
??????? <xs:elementCOLOR: green">revenue"COLOR: green">xs:double"/>
??????? <xs:element minOccurs="0"COLOR: green">test"COLOR: green">xs:decimal"/>
??????? <xs:element minOccurs="0"COLOR: green">birthDate"COLOR: green">xs:dateTime"/>
??????? <xs:element minOccurs="0"COLOR: green">type"COLOR: green">tns:customerType"/>
??? </xs:sequence>
</xs:complexType>
minOccurs="0"是可選項,這樣可以隨時加入新元素,保持兼容性。如果不想要這個選項,可以使用標記@XmlElement(required=true)
maxOccurs="unbounded"是為了便于后面的xml重復該元素以形成數組。
?
<xs:simpleTypeCOLOR: green">customerType">??? //枚舉類型
??? <xs:restriction base="xs:string">
??????? <xs:enumeration value="PRIVATE"/>
??????? <xs:enumeration value="BUSINESS"/>
??? </xs:restriction>
</xs:simpleType>
?
<xs:elementCOLOR: green">NoSuchCustomer"COLOR: green">tns:NoSuchCustomer"/> //異常類
??? <xs:complexTypeCOLOR: green">NoSuchCustomer">
??????? <xs:sequence>
??????????? <xs:elementCOLOR: green">customerName" nillable="true"COLOR: green">xs:string"/>
??????? </xs:sequence>
?</xs:complexType>
?<wsdl:messageCOLOR: green">NoSuchCustomerException">
??? <wsdl:partCOLOR: green">NoSuchCustomerException" element="tns:NoSuchCustomer">
??? </wsdl:part>
?</wsdl:message>
// 注意:Element和Message的名字是不同的,這是通過標記@Webfault標記來實現的。也可以讓他們同名,但那樣會話,生成的Exception的名字會比較丑:NoSuchCustomerException_Exception
總結
以上是生活随笔為你收集整理的(转)CXF学习笔记一:如何创建、发布和访问基于CXF的服务的全部內容,希望文章能夠幫你解決所遇到的問題。