一文搞懂WebService基於CXF框架實現[JAX-RS]

前言

上一篇文章我們瞭解JAX-WS基於SOAP(面向簡單對象訪問協議)可以轉化爲XML數據格式進行遠程調用,WSDL文檔可以幫助我們清楚的瞭解到數據解析格式和要求,有興趣的同學可以點擊
一文搞懂WebService基於CXF框架實現[JAX-WS]

什麼是Restful架構風格

REST 全稱是 Representational State Transfer(表述性狀態轉移),是一種軟件架構風格,提供了一組設計原則和約束條件。它主要用於客戶端和服務器交互類的軟件,基於這個風格設置的軟件可以簡潔,更有層次,更易於實現。

什麼是Restful風格的服務

REST 本質上是使用 URL 來訪問資源的一種方式。總所周知,URL 就是我們平常使用的請求地址了,其中包括兩部分:請求方式 與 請求路徑,比較常見的請求方式是 GET 與 POST,但在 REST 中又提出了其它幾種其它類型的請求方式,彙總起來有六種:GET、POST、PUT、DELETE、HEAD、OPTIONS。尤其是前四種,正好與 CRUD(增刪改查)四種操作相對應:GET(查)、POST(增)、PUT(改)、DELETE(刪),這正是 REST 的奧妙所在!

實際上,Web 應用程序最重要的 REST 原則是,客戶端和服務器之間的交互在請求之間是無狀態的,因爲在任何時候都可以由客戶端發出請求到服務端,最終返回自己想要的數據。也就是說,服務端將內部資源發佈 REST 服務,客戶端通過 URL 來訪問這些資源,這不就是 SOA 所提倡的“面向服務”的思想嗎?所以,REST 也被人們看做是一種輕量級的 SOA 實現技術,因此在企業級應用與互聯網應用中都得到了廣泛使用。

總結:

  • Rest是一種編碼規範而不是強制性要求
  • Rest對數據的約束是標準的xml和json

Spring實現JAX-RS【複製即用】

搭建服務端

公用配置pom.xml依賴

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.zjf</groupId>
  <artifactId>jaxrs-parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>jaxrs-parent</name>
  <modules>
  	<module>rs-server</module>
  	<module>rs-client</module>
  </modules>
  
 <properties>
		<junit.version>4.12</junit.version>
		<spring.version>4.2.4.RELEASE</spring.version>
	</properties>
	
<dependencyManagement>
	<!--cxf jax-rs start -->
	<dependencies>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>3.1.7</version>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxrs</artifactId>
			<version>3.1.7</version>
		</dependency>
<!-- 		<dependency> -->
<!-- 			<groupId>org.apache.cxf</groupId> -->
<!-- 			<artifactId>cxf-rt-transports-http-jetty</artifactId> -->
<!-- 			<version>3.1.1</version> -->
<!-- 		</dependency> -->

		<dependency>
			<groupId>org.codehaus.jettison</groupId>
			<artifactId>jettison</artifactId>
			<version>1.3.7</version>
		</dependency>

		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-rs-client</artifactId>
			<version>3.1.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-rs-extension-providers</artifactId>
			<version>3.1.7</version>
		</dependency>
<!-- 		<dependency> -->
<!-- 			<groupId>org.apache.axis2</groupId> -->
<!-- 			<artifactId>axis2-jaxws</artifactId> -->
<!-- 			<version>1.6.2</version> -->
<!-- 			<scope>runtime</scope> -->
<!-- 			<exclusions> -->
<!-- 				Causes java.lang.NoSuchMethodError: javax.ws.rs.core.Response$Status$Family.familyOf(I)Ljavax/ws/rs/core/Response$Status$Family; -->
<!-- 				<exclusion> -->
<!-- 					<groupId>javax.ws.rs</groupId> -->
<!-- 					<artifactId>jsr311-api</artifactId> -->
<!-- 				</exclusion> -->
<!-- 			</exclusions> -->
<!-- 		</dependency> -->
		
		<!-- cxf jax-rs end -->


		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- <dependency> -->
		<!-- <groupId>org.springframework</groupId> -->
		<!-- <artifactId>spring-webmvc</artifactId> -->
		<!-- <version>${spring.version}</version> -->
		<!-- </dependency> -->
		<!-- <dependency> -->
		<!-- <groupId>org.springframework</groupId> -->
		<!-- <artifactId>spring-jdbc</artifactId> -->
		<!-- <version>3.2.13.RELEASE</version> -->
		<!-- </dependency> -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- <dependency> -->
		<!-- <groupId>org.springframework</groupId> -->
		<!-- <artifactId>spring-aspects</artifactId> -->
		<!-- <version>${spring.version}</version> -->
		<!-- </dependency> -->
		<!-- <dependency> -->
		<!-- <groupId>org.springframework</groupId> -->
		<!-- <artifactId>spring-jms</artifactId> -->
		<!-- <version>${spring.version}</version> -->
		<!-- </dependency> -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>



		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.9</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.28</version>
		</dependency>
		<dependency>
			<groupId>javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.11.0.GA</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.10</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>


		<!--日誌 -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.25</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.25</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
			<version>1.7.25</version>
			<scope>test</scope>
		</dependency>
	



		<!-- <dependency> <groupId>javax.ws.rs</groupId> <artifactId>jsr311-api</artifactId> 
			<version>1.1.1</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> 
			<artifactId>cxf-rt-transports-http</artifactId> <version>3.1.7</version> 
			</dependency> -->


		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpclient</artifactId>
			<version>4.3.6</version>
		</dependency>
		<dependency>
			<groupId>org.apache.httpcomponents</groupId>
			<artifactId>httpcore</artifactId>
			<version>4.3.3</version>
		</dependency>
	</dependencies>
</dependencyManagement>

</project>

配置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_2_5.xsd" version="2.5">
  <display-name>Archetype Created Web Application</display-name>
  
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.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>
  </servlet>
  <servlet-mapping>
    <servlet-name>cxfservlet</servlet-name>
    <url-pattern>/rs/*</url-pattern>
  </servlet-mapping>

</web-app>

攔截/rs的URL請求

服務端配置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:context="http://www.springframework.org/schema/context"
	xmlns:cxf="http://cxf.apache.org/core"
	xmlns:jaxrs="http://cxf.apache.org/jaxrs"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		 http://cxf.apache.org/core
        http://cxf.apache.org/schemas/core.xsd
		http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd ">

	<!--
		address 發佈服務地址 
		servicesBeans 服務實現類 
 	 -->
	<jaxrs:server id="userService" address="/userService" >
		<jaxrs:serviceBeans>
			<bean class="com.zjf.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>

	
</beans>

Rest風格服務接口

package com.zjf.service;

import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.zjf.pojo.User;

@Path("/userService")
@Produces("*/*")
public interface UserService {

	@Path("/add")
	@POST
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public void saveUser(User user);

	@Path("/update")
	@PUT
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public void upUser(User user);

	@Path("/get")
	@GET
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public void getUser();

	@Path("/find/{id}")
	@GET
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public User findUser(@PathParam("id") Integer id);

	@Path("/list")
	@GET
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public List<User> listUser();

}

接口註解說明:

  • @path:代表訪問當前接口的URL地址,地址後面可以有隨傳參數
  • @GET | @POST 表示請求方式(GET用於查詢,POST用於新增)
  • @PUT 表示請求方式(主要用於做數據修改的請求URL)
  • @DELETE 主要用於做數據刪除操作
  • @Consumes 定義輸入(調用方傳入)的參數類型(此註解即表示同時支持XML和JSON的格式)
  • Produces 定義輸出(返回調用方)的數據類型
  • 其他參數:@PathParam(接口參數綁定)、@FormParam(表單參數),此外還有 @QueryParam(請求參數)

Rest風格服務接口實現類

package com.zjf.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.zjf.pojo.User;
import com.zjf.service.UserService;

@Service
public class UserServiceImpl implements UserService {

	public void getUser() {
		// TODO Auto-generated method stub
		System.out.println("獲取User成功");

	}

	@Override
	public void saveUser(User user) {
		// TODO Auto-generated method stub
		System.out.println("添加User成功:" + user.getName());

	}

	@Override
	public void upUser(User user) {
		// TODO Auto-generated method stub
		System.out.println("修改User成功:" + user.getName());
	}

	@Override
	public User findUser(Integer id) {
		// TODO Auto-generated method stub
		System.out.println("查詢User成功:" + id);
		User user = new User();
		user.setName("王五");
		user.setAge(19);
		return user;
	}

	@Override
	public List<User> listUser() {
		// TODO Auto-generated method stub
		List<User> list = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			User user = new User();
			user.setName("趙六" + i);
			user.setAge(20);
			list.add(user);

		}
		return list;
	}

}

實體對象參數處理

@XmlRootElement(name = "User")
public class User implements Serializable {

@XmlRootElement 指定序列化(轉化成xml;json)對象名字

搭建客戶端

基於spring配置

<?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:jaxrs="http://cxf.apache.org/jaxrs"
	xmlns:jaxrs-client="http://cxf.apache.org/jaxrs-client" 
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
	http://cxf.apache.org/jaxrs-client http://cxf.apache.org/schemas/jaxrs-client.xsd"> 
        

	<jaxrs-client:client id="webClient"
         address="http://localhost:8080/rs-server/rs/userService/userService/add"
         serviceClass="org.apache.cxf.jaxrs.client.WebClient">
    </jaxrs-client:client>

</beans>

基於CXF框架客戶端webClient

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class clientTest {

    //引入spring配置的CXF客戶端
	@Autowired
	private WebClient webClient;

	@Test
	public void addUser() {
		User user = new User();
		user.setName("張三");
		user.setAge(18);

		Response post = WebClient.create("http://localhost:8080/rs-server/rs/userService/userService/add")
				.type(MediaType.APPLICATION_JSON).post(user);
		System.out.println("調用返回狀態:" + post.getStatus());

	}

	@Test
	public void addUser1() {
		User user = new User();
		user.setName("張三");
		user.setAge(18);
		Response post = webClient.type(MediaType.APPLICATION_JSON).post(user);
		System.out.println("調用返回狀態:" + post.getStatus());
	}

	@Test
	public void findUser() {

		User user = WebClient.create("http://localhost:8080/rs-server/rs/userService/userService/find/1")
				.accept(MediaType.APPLICATION_JSON).get(User.class);
		System.out.println(user);

	}

	@Test
	public void listUser() {
		Collection<? extends User> collection = WebClient
				.create("http://localhost:8080/rs-server/rs/userService/userService/list")
				.accept(MediaType.APPLICATION_JSON).getCollection(User.class);

		System.out.println(collection);

	}

}

WebClient可以通過Spring配置來創建,也可以通過create(“訪問路徑”)靜態方法來創建,如果通過靜態方法實際仍然是通過JAXRSClientFactoryBean對象進行創建。

訪問URL具體層級路徑

  • 訪問服務端工程地址:http://localhost:prot/項目名/
  • 服務端web.xml配置CxfServlet攔截
 <servlet>
    <servlet-name>cxfservlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>cxfservlet</servlet-name>
    <url-pattern>/rs/*</url-pattern>
  </servlet-mapping>
  • 服務端spring配置暴露address服務地址
<jaxrs:server id="userService" address="/userService" >
  • 服務接口類名路徑@Path("/路徑")
@Path("/userService")
@Produces("*/*")
public interface UserService {
  • 具體服務接口方法路徑@Path("/路徑")
    @Path("/add")
	@POST
	@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public void saveUser(User user);

客戶端Junit測試

package com.zjf.test;

import java.util.Collection;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.cxf.jaxrs.client.WebClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.zjf.pojo.User;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class clientTest {

	@Autowired
	private WebClient webClient;

	@Test
	public void addUser() {
		User user = new User();
		user.setName("張三");
		user.setAge(18);

		Response post = WebClient.create("http://localhost:8080/rs-server/rs/userService/userService/add")
				.type(MediaType.APPLICATION_JSON).post(user);
		System.out.println("調用返回狀態:" + post.getStatus());

	}

	@Test
	public void addUser1() {
		User user = new User();
		user.setName("張三");
		user.setAge(18);
		Response post = webClient.type(MediaType.APPLICATION_JSON).post(user);
		System.out.println("調用返回狀態:" + post.getStatus());
	}

	@Test
	public void findUser() {

		User user = WebClient.create("http://localhost:8080/rs-server/rs/userService/userService/find/1")
				.accept(MediaType.APPLICATION_JSON).get(User.class);
		System.out.println(user);

	}

	@Test
	public void listUser() {
		Collection<? extends User> collection = WebClient
				.create("http://localhost:8080/rs-server/rs/userService/userService/list")
				.accept(MediaType.APPLICATION_JSON).getCollection(User.class);

		System.out.println(collection);

	}

}

WebClient常用方法說明:

  • create():WebClient靜態方法傳入調用服務路徑,創建JAXRSClientFactoryBean對象
  • type():定義傳遞給服務端數據類型格式
  • accept(): 定義服務端返回數據類型格式
  • post(參數): 新增操作,傳遞參數
  • get:查詢操作,返回數據
  • put:修改操作,傳遞參數
  • delete:刪除操作(配合RestFul風格,在服務路徑傳遞參數)
  • getCollection(參數): 查詢操作,返回集合數據

調用服務接口測試:

----------------------------
ID: 3
Address: http://localhost:8080/rs-server/rs/userService/userService/add
Encoding: ISO-8859-1
Http-Method: POST
Content-Type: application/json
Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], Content-Length=[35], content-type=[application/json], host=[localhost:8080], pragma=[no-cache], user-agent=[Apache-CXF/3.1.7]}
Payload: {"User":{"age":18,"name":"å¼ ä¸‰"}}
--------------------------------------
添加User成功:張三
四月 05, 2020 4:24:14 下午 org.apache.cxf.interceptor.LoggingOutInterceptor
信息: Outbound Message
---------------------------
ID: 3
Response-Code: 204
Content-Type: */*
Headers: {Date=[Sun, 05 Apr 2020 08:24:14 GMT], Content-Length=[0]}
--------------------------------------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章