一,WebService的簡介
Web service是一個平臺獨立的,低耦合的,自包含的、基於可編程的web的應用程序,可使用開放的XML(標準通用標記語言下的一個子集)標準來描述、發佈、發現、協調和配置這些應用程序,用於開發分佈式
的互操作的應用程序。
簡單來說,很多個系統,進行分佈的部署,分佈的系統數據通信
解決技術就是WebService
目前比較主流的WebService開發框架主要有:Apache Axis1、Apache Axis2、Codehaus XFire、Apache CXF、Apache Wink、Jboss RESTEasy、sun JAX-WS(最簡單、方便)、阿里巴巴 Dubbo(除外)等。
目前三種主流的web服務實現方法:
REST(新型):表象化狀態轉變 (軟件架構風格)RESTEasy、Wink、CXF、Axis2…….(個人推薦使用)
SOAP(比較成熟):簡單對象訪問協議 Xfire、Axis2、CXF、Axis1
XML-RPC(淘汰):遠程過程調用協議(慢慢被soap 所取代)
二,CXF的下載和使用
CXF WebService 開發,主要分爲兩種服務提供方式 JAX-WS,JAX-RS
JAX-WS 傳輸數據,就是 XML 格式,基於 SOAP 協議
JAX-RS 傳輸數據,傳輸 XML 格式或者 JSON 格式,基於 HTTP 協議(推薦使用)
1.JAX-WS(基於SOAP協議) 獨立服務使用
創建一個maven項目,在項目中導入 CXF jar 包支持
要提供 jaxws 服務,引入 jaxws 的 jar 包 , 要提供 jaxrs 服務,引入 jaxrs 的 jar 包(根據需要選擇導入)
在編寫服務層接口
出現上面的錯誤,是由於編譯插件jre的版本過低造成的
在pom.xml中添加編譯插件,並設置編譯版本,更新項目即可
package cn.xiaogui.cxf.service;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import cn.xiaogui.cxf.domain.Car;
import cn.xiaogui.cxf.domain.User;
@WebService //標記類是WebService服務的提供對象
public interface IUserService {
@WebMethod //標記方法是WebService服務的提供方法
public String sayHello(String name);
@WebMethod
public List<Car> findCarsByUser(User user);
}
@WebService 使用類上面,標記類是 WebService 服務提供對象
@WebMethod 使用方法上面,標記方法 是 WebService 服務提供方法
編寫實現類
package cn.xiaogui.cxf.service.impl;
import java.util.List;
import javax.jws.WebService;
import cn.xiaogui.cxf.domain.Car;
import cn.xiaogui.cxf.domain.User;
import cn.xiaogui.cxf.service.IUserService;
//@WebService 註解設置 endPointInterface 接口服務完整類名, servicename 服務名稱
@WebService(endpointInterface="cn.xiaogui.cxf.service.IUserService",serviceName="IUserService")
public class UserServiceImpl implements IUserService {
//簡單參數傳遞
@Override
public String sayHello(String name) {
// TODO Auto-generated method stub
return null;
}
//複雜參數傳遞
@Override
public List<Car> findCarsByUser(User user) {
// TODO Auto-generated method stub
return null;
}
}
編寫CXF服務端,將 UserService 的服務方法,發佈到網絡上,給其它系統調用
package cn.xiaogui.cxf.ws.server;
import javax.xml.ws.Endpoint;
import cn.xiaogui.cxf.service.IUserService;
import cn.xiaogui.cxf.service.impl.UserServiceImpl;
public class WS_Server {
public static void main(String[] args) {
//使用CXF將userService服務註冊到網絡
//1.創建服務實現類對象
IUserService UserService = new UserServiceImpl();
//2.發佈服務地址
String address = "http://localhost:9999/userService";
//3.發佈服務
Endpoint.publish(address, UserService);
System.out.println("服務發佈....");
}
}
在瀏覽器輸入網址: http://localhost:9999/userService?wsdl 查看發佈的服務
編寫客戶端
package cn.xiaogui.cxf.ws.client;
import java.util.List;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import cn.xiaogui.cxf.domain.Car;
import cn.xiaogui.cxf.domain.User;
import cn.xiaogui.cxf.service.IUserService;
//客戶端應該編寫在另一個項目中,爲了方便測試,服務端和客戶端編寫在了同一個項目中
public class WS_Client {
public static void main(String[] args) {
//編寫客戶端,調用WebService服務
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
//設置服務接口
jaxWsProxyFactoryBean.setServiceClass(IUserService.class);
//訪問服務發佈的地址
jaxWsProxyFactoryBean.setAddress("http://localhost:9999/userService");
//創建調用遠程服務代理對象
IUserService proxy = (IUserService) jaxWsProxyFactoryBean.create();
//調用代理對象的任意方法,都將通過網絡調用服務
// System.out.println(proxy.sayHello("張三"));
User user = new User();
user.setUsername("xiaoming");
List<Car> list = proxy.findCarsByUser(user);
System.out.println(list);
}
}
注意:服務端在開啓後,不要關閉,否則客戶端無法訪問。
2. JAX-WS 原理分析
客戶端創建一個服務接口IUserService的代理對象proxy,當調用服務接口中的方法時,會通過服務發佈的地址,來找到服務接口的實現類對象userService,然後去執行對應的方法。
3.JAX-WS 和 和 Spring 整合開發
注意:實體類和服務接口,實現類與上面的項目相同,不再演示。
創建一個maven web項目,基於 tomcat 發佈服務,導入相關的依賴
<!-- CXF開發 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.1</version>
</dependency>
<!-- spring開發-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!-- spring Web集成 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!-- spring測試開發 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!-- 日誌實現 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
配置web.xml
Spring 配置文件加載、環境初始化
<!-- spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- spring核心監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
CXF 基於 web 訪問 ****
<!--配置CXF基於web訪問 -->
<servlet>
<servlet-name>CXFService</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFService</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
配置applicationContext.xml
引入名稱空間
xmlns:jaxws=“http://cxf.apache.org/jaxws”
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
配置服務
<!--
address:服務發佈的地址
serviceClass:服務接口的全類名
jaxws:serviceBean:服務接口的實現類
-->
<jaxws:server id="userService" address="/userService" serviceClass="cn.xiaogui.cxf.service.IUserService">
<jaxws:serviceBean>
<bean class="cn.xiaogui.cxf.service.impl.UserServiceImpl" />
</jaxws:serviceBean>
</jaxws:server>
配置啓動服務端口
訪問 :http://localhost:9998/services/userService?wsdl 查看發佈的服務
整合spring測試,編寫客戶端
注意: 標準做法是新建一個項目來編寫客戶端,調用服務
客戶端applicationContext.xml的配置
<jaxws:client id="userServiceClient"
serviceClass="cn.xiaogui.cxf.service.IUserService"
address="http://localhost:9998/services/userService">
<!--可選配置 -->
<!-- 來源消息攔截器 主要用於在控制檯查看請求的一些信息 -->
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
</jaxws:inInterceptors>
<!--可選配置 -->
<!-- 輸出消息攔截器 主要用戶在控制檯查看響應客戶端的一些信息-->
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
</jaxws:outInterceptors>
</jaxws:client>
客戶端測試代碼:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext-test.xml")
public class IUserServiceTest {
@Autowired
private IUserService proxy;
@Test
public void testSayHello() {
System.out.println(proxy.sayHello("李四"));
}
@Test
public void testFindCarsByUser() {
User user = new User();
user.setUsername("xiaoming");
List<Car> users = proxy.findCarsByUser(user );
System.out.println(users);
}
}
測試結果:
注意:需要在項目中添加log4j.properties屬性文件,才能查看到控制檯上輸出的上面的信息。
4. JAX-RS(基於REST設計風格) 獨立服務使用
Restful風格:
Restful風格編程的好處:
基於這種風格架構,軟件編寫可以更簡潔
基於 HTTP 協議, 支持多種消息格式,比如 XML 、JSON
基於 HTTP 協議,更易於實現緩存機制 (第一次訪問資源 緩存,第二次訪問資源,返回 304 客戶端調用本地)
編寫 JAX-RS 獨立服務應用
創建maven java項目,導入依賴
<dependencies>
<!-- CXF的RS開發 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 內置jetty web服務器 和tomcat差不多 由於這不是一個web項目,所以需要這個內置的服務器來發布服務 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 日誌實現 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
導入實體
@XmlRootElement 指定序列化(轉換 XML、JSON) 對象名字
編寫業務類接口
@Path("/userService")
public interface IUserService {
@POST
@Path("/user")
@Consumes({ "application/xml", "application/json" })
public void saveUser(User user);
@PUT
@Path("/user")
@Consumes({ "application/xml", "application/json" })
public void updateUser(User user);
@GET
@Path("/user")
@Produces({ "application/xml", "application/json" })
public List<User> findAllUsers();
@GET
@Path("/user/{id}")
@Consumes("application/xml")
public User finUserById(@PathParam("id") Integer id);
@DELETE
@Path("/user/{id}")
@Consumes("application/xml")
public void deleteUser(@PathParam("id") Integer id);
}
第一種 @Path 服務訪問資源路徑
如果訪問 saveUser 方法 /userService/user
第二種 @Produces 生成(方法返回值) @Consumes 消費 (方法參數)
@Consumes 指定能夠處理客戶端傳遞過來數據格式
@Produces 指定能否生成哪種格式數據返回給客戶端
第三種 @GET 查詢 @PUT 修改 @POST 保存(增加或修改) @DELETE 刪除
編寫業務接口實現類
編寫服務端
//使用CXF將userService服務發佈到網絡
//1.創建服務接口的實現類對象
IUserService userService = new UserServiceImpl();
//服務器JAXRSServerFactoryBean 創建服務
JAXRSServerFactoryBean restServer = new JAXRSServerFactoryBean();
//將哪些實體數據轉換成xml,json格式發送
restServer.setResourceClasses(User.class, Car.class);
//設置服務接口的實現類對象
restServer.setServiceBean(userService);
//服務發佈地址
restServer.setAddress("http://localhost:8888");
// 打印日誌
restServer.getInInterceptors().add(new LoggingInInterceptor());
restServer.getOutInterceptors().add(new LoggingOutInterceptor());
//發佈服務
restServer.create();
編寫客戶端
有兩種做法
1) 使用 http client 工具 ,需要自己對 HTTP 協議內容進行定製和解析
2) WebClient 工具類使用 (CXF 自帶)
/**
* create:建立與調用服務資源路徑的連接
* type:發送給服務器的數據格式 -----@Consumes
* accept:接收服務器響應的數據格式 ---@produces
*
* 採用Http協議哪種方式訪問服務器
*/
Collection<? extends User> collection = WebClient.create("http://localhost:8888/userService/user")
.accept(MediaType.APPLICATION_XML)
.getCollection(User.class);
System.out.println(collection);
User user = WebClient.create("http://localhost:8888/userService/user/1")
.accept(MediaType.APPLICATION_XML)
.get(User.class);
System.out.println(user);
輸出結果
JAX-RS 如何傳輸 JSON 格式的數據
在pom.xml中添加依賴
客戶端編寫代碼
User user = WebClient.create("http://localhost:8888/userService/user/1")
.type(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.get(User.class);
System.out.println(user);
輸出結果
5.JAX-RS 和 和 Spring 整合開發(開發中推薦使用)
創建maven web項目,導入依賴
CXF的RS開發
<!-- CXF的RS開發 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.1</version>
</dependency>
<!-- rs客戶端 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>3.0.1</version>
</dependency>
<!-- CXF的擴展提供者,提供轉換json接口 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.1</version>
</dependency>
<!--CXF的擴展提供者轉換json 默認需求的工具包 -->
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.7</version>
</dependency>
spring開發
<!-- spring開發 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- spring集成web開發 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<!-- spring測試開發 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
日誌實現
<!-- 日誌實現 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
tomcat插件
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<path>/</path>
<port>6666</port>
</configuration>
</plugin>
配置服務
在applicationContext.xml中有引入名稱空間:
xmlns:jaxrs=“http://cxf.apache.org/jaxrs”
xsi:schemaLocation="
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd"
<!--
address:服務發佈的地址
jaxrs:serviceBeans:服務接口的實現類
-->
<jaxrs:server id="userService" address="/userService" >
<jaxrs:serviceBeans>
<bean class="cn.xiaogui.cxf.service.impl.UserServiceImpl" />
</jaxrs:serviceBeans>
<!-- 下面兩個可選配置 -->
<!-- 請求來源消息攔截器 -->
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</jaxrs:inInterceptors>
<!-- 輸出消息攔截器 -->
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</jaxrs:outInterceptors>
</jaxrs:server>
編寫客戶端,進行服務調用
public class RS_client {
@Test
public void test1() {
/**
* create:建立與調用服務資源路徑的連接
* type:發送給服務器的數據格式 -----@Consumes
* accept:接收服務器響應的數據格式 ---@produces
*
* 採用Http協議哪種方式訪問服務器
*/
Collection<? extends User> collection = WebClient.create("http://localhost:6666/services/userService/user")
.accept(MediaType.APPLICATION_JSON)
.getCollection(User.class);
System.out.println(collection);
}
}
結果輸出
分享示例項目在碼雲上的地址:https://gitee.com/xiaoguixiaogege/CXF