在java中使用spring整合cxf實現webservice
在java中實現webservice有兩種常用的方式,一種是cxf,另一種是axis。這兩種方式的區別大家可以自己在網上找找參考一下。cxf可以與spring進行整合,是一款不錯的webservice產品。今天給大家講解一下使用spring整合cxf實現webservice的方法。
1 建立伺服器端程式
1.1 新建一個web工程
1.1.1 工程環境所依賴的各軟體的版本
首先需要新建一個web工程,工程執行環境為:
java:1.7.0_65
tomcat:apache-tomcat-6.0.47
eclipse:Luna Service Release 2 (4.4.2)
cxf:3.1.8
作業系統:win7
先給大家看一下eclipse中生成的伺服器端程式:
注意將下載之後的cxf的3.1.8版本lib裡的所有jar包都拷貝到專案中,並建立引用關係,筆者這裡就是上圖“Libraries”中的“WebServiceServer”庫。
1.1.2 建立pojo
先寫一個pojo,即檔案Person.java:
package com.yhd.webservice.cxf.server.poto;
/**
* 類名稱:Persion.java<br>
* 類描述:<br>
* 建立時間:2016年11月11日, 下午2:48:45
*
* @version 1.0
* @since JDK1.7.0_65
* @author yhd
*/
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1.1.3 建立介面
定義一個介面,即檔案PersonService.java:
package com.yhd.webservice.cxf.server.service;
import java.util.List;
import javax.jws.WebParam;
import javax.jws.WebService;
import com.yhd.webservice.cxf.server.poto.Person;
/**
* 類名稱:PersonService.java<br>
* 類描述:<br>
* 建立時間:2016年11月11日, 下午2:43:36
*
* @version 1.0
* @since JDK1.7.0_65
* @author yhd
*/
@WebService
public interface PersonService {
public List<Person> findAll(@WebParam(name = "arg0") String name);
}
1.1.4 介面實現類
介面類的實現,即檔案PersonServiceImp.java:
package com.yhd.webservice.cxf.server.service.impl;
import java.util.ArrayList;
import java.util.List;
import javax.jws.WebService;
import com.yhd.webservice.cxf.server.poto.Person;
import com.yhd.webservice.cxf.server.service.PersonService;
/**
* 類名稱:PersonServiceImp.java<br>
* 類描述:<br>
* 建立時間:2016年11月11日, 下午2:47:53
*
* @version 1.0
* @since JDK1.7.0_65
* @author yhd
*/
@WebService(endpointInterface="com.yhd.webservice.cxf.server.service.PersonService",serviceName="person")
public class PersonServiceImp implements PersonService {
@Override
public List<Person> findAll(String name){
ArrayList<Person> persons = new ArrayList<Person>();
Person p1 = new Person();
p1.setName(name + "3");
p1.setAge(18);
Person p2 = new Person();
p2.setName(name + "4");
p2.setAge(20);
persons.add(p1);
persons.add(p2);
return persons;
}
}
1.1.5 spring配置檔案application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<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-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
xmlns="http://www.springframework.org/schema/beans">
<bean id="jaxWsServiceFactoryBean" class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
<property name="wrapped" value="true" />
</bean>
<jaxws:endpoint id="serviceimp" address="/person"
implementor="com.yhd.webservice.cxf.server.service.impl.PersonServiceImp">
<jaxws:serviceFactory>
<ref bean="jaxWsServiceFactoryBean" />
</jaxws:serviceFactory>
</jaxws:endpoint>
</beans>
這裡要注意,網上很多配置cxf的參考文章都提到要將三個配置資訊放到spring的配置檔案中:
<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" />
但是對於這裡使用到的cxf最新版3.1.8,如果加上:
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
反而會報錯:
嚴重: Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:META-INF/cxf/cxf-extension-soap.xml]
網上說cxf3.0之後可能已經不需要這個檔案了,將這個檔案去掉就可以了。或者將這三個配置都去掉也可以。筆者將這三者都去掉了,可以使用。
1.1.6 配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>WebServiceServer</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<display-name>cxfTest</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<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>/hello/*</url-pattern>
</servlet-mapping>
</web-app>
這裡面配置了spring的監聽器,又配置了一個cxf的servlet。
1.2 啟動web工程
筆者這裡在tomcat中配置了web工程的埠號為8081,並且將8081直接指向eclipse中工程的地址,所以訪問該工程時就不用再輸入工程名了。
啟動tomcat。在瀏覽器裡輸入:
如上所示,沒有再輸入工程名“WebServiceServer”。
這時瀏覽器頁面會出現:
能看到“person”前有一個倒過來的類包的名稱。
這說明伺服器端已經建立成功!
2 生成伺服器端介面類
2.1 安裝cxf
在cxf官網下載cxf的3.1.8版本,筆者下載的zip版。將檔案解壓縮並放到一個合適的目錄下。在環境變數中加入變數“CXF_HOME”,值就是安裝路徑;再在“PATH”變數中加入:
%CXF_HOME%\bin
這樣cxf的命令就可以使用了。
2.2 使用“wsdl2java”命令生成介面類
wsdl2java的用法如下:
wsdl2java –p 包名 –d 目錄名 wsdl路徑
具體的意義如下:
-p:指定其wsdl的名稱空間,也就是要生成程式碼的包名
-d:指定要產生程式碼所在目錄
-client 生成客戶端測試web service的程式碼
-server:生成伺服器啟動web service的程式碼
-impl:生成web service的實現程式碼
-ant:生成build.xml檔案
-compile:生成程式碼後編譯
-quient:靜默模式,不輸出警告與錯誤資訊
-all:生成所有開始端點程式碼:types,service proxy,service interface, server mainline, client mainline, implementation object, and an Ant build.xml file.
筆者這裡的命令為:
wsdl2java -p com.yhd.webservice.cxf.client.info -d D:\test http://localhost:8081/hello/person?wsdl
執行之後就會在-d後面的路徑下生成相應的類。
2.3 將介面類拷貝到客戶端專案中
將這些類拷貝到後面新建立的客戶端專案中。
有的時候生成了類之後,將這些類拷貝到客戶端專案,類中的某些super()會報錯。這就需要再加上“-frontend jaxws21”命令,也就是將命令寫為:
wsdl2java -frontend jaxws21 -p com.yhd.webservice.cxf.client.info -d D:\test http://localhost:8081/hello/person?wsdl
再生成的類就不會報錯了。
3 建立客戶端程式
客戶端我們就做一個簡單的程式。
依然建立一個web專案(其實建立一個java專案就可以了),依賴的類與伺服器端一樣,將cxf的jar包都拷貝進去,程式如下:
將伺服器端生成的介面類拷貝過來,然後再建立一個“ClientTest.jar”檔案,內容如下:
package com.yhd.webservice.cxf.client.main;
import java.util.List;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.yhd.webservice.cxf.client.info.Person;
import com.yhd.webservice.cxf.client.info.PersonService;
/**
* 類名稱:ClientTest.java<br>
* 類描述:<br>
* 建立時間:2016年11月15日, 上午10:04:16
*
* @version 1.0
* @since JDK1.7.0_65
* @author yhd
*/
public class ClientTest {
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(PersonService.class);
factory.setAddress("http://localhost:8081/hello/person");
PersonService service = (PersonService)factory.create();
List<Person> list = (List<Person>)service.findAll("張");
for(Person person : list) {
System.out.println("name=" + person.getName());
System.out.println("age=" + person.getAge());
System.out.println("-------------------");
}
}
}
4 執行客戶端程式
在伺服器端保持執行的狀態下,執行客戶端程式。正常的話,會打印出:
name=張3
age=18
-------------------
name=張4
age=20
-------------------
有一點要注意,一方面,一定要保持客戶端和伺服器端使用的jdk版本是一致的,另一方面,cxf從3.1開始已經不支援jdk的1.6版本了,而至少是jdk的1.7或者是以上的版本。所以我們的專案裡的jdk至少需要使用jdk的1.7版本,否則比如使用1.6,有可能會報錯:
Caused by: java.lang.UnsupportedClassVersionError: org/apache/cxf/jaxws/spring/NamespaceHandler : Unsupported major.minor version 51.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access000(UnknownSource)atjava.net.URLClassLoader 1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1191)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1669)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1547)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:266)
at org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve(DefaultNamespaceHandlerResolver.java:124)
這一點大家要注意。
5 關於附件原始碼
文章中伺服器端程式和客戶端程式的原始碼都放在了筆者github的網站裡面,其中:
伺服器端程式位於:
客戶端程式位於: