使用CXF實現基於Rest方式的WebService

本文介紹使用CXF實現基於Rest方式的WebService(CXF的版本是3.0.0)前端

一. 前言java

Java有三種WebService規範:Jax-WS,Jax-RS,Jaxmweb

1. Jax-WS(Java Api for XML-Based WebService):實現Soap協議(Simple Object Access Protocol)(用的也很少了)
2. Jax-RS(Java Api for Resource-Based WebService):實現Rest方式(Representational State Transfer)(推薦)
3. Jaxm支持文件傳輸,暴露更多底層細節(不推薦)spring

二. 引入依賴apache

<!-- Jax-RS前端控制模塊,處理服務業務的請求 -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-frontend-jaxrs</artifactId>
  <version>3.0.0</version>
</dependency>json

<!-- Jax-RS客戶端,用到WebClient等客戶端代碼調用類時需引入 -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-client</artifactId>
  <version>3.0.0</version>
</dependency> 併發

<!-- Json格式自動轉換Provider,Jackson好用一些 -->
<!-- 也能夠引入CXF自帶的cxf-rt-rs-extension-providers(以及它默認使用jettison)-->
<!-- 也能夠不使用Provider,直接使用CXF默認的Response.ResponseBuilder生成Response並返回,格式須要本身轉換,例如使用Gson -->
<dependency>
  <groupId>com.fasterxml.jackson.jaxrs</groupId>
  <artifactId>jackson-jaxrs-json-provider</artifactId>
  <version>2.4.1</version>
</dependency> app

<!-- 數據傳輸模塊(與Soap同樣) -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http</artifactId>
  <version>3.0.0</version>
</dependency>frontend

<!-- 引入內置的Jetty,如在Tomcat中發佈服務能夠不引入(與Soap同樣)  -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http-jetty</artifactId>
  <version>3.0.0</version>
</dependency>ide

三. 編寫SEI(Service Endpoint Interface)

1. 接口

import javax.ws.rs.core.Response;

//Produces & Consumes既能夠加在Class上,也能夠加在Method上,Method上的優先
@Path("/hello")

@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
public interface HelloWorld {

  //Response是CXF默認的返回對象,實際數據能夠封裝在裏面,若是使用WebClient等客戶端測試類時,推薦返回Response 
  @GET
  @Path(value = "/resp")

  public Response sayHelloResponse(); 

  @GET
  @Path(value = "/string/{name}")
  public Result sayHelloString(@PathParam("name") String name); 

  //Result、User都是POJO,代碼略,須要使用某種第三方*JsonProvider,這樣普通對象和Json格式能夠自動互相轉換  
  @POST

  @Path(value = "/user")
  public Result sayHelloUser(User user);

2. 實現類

public class HelloWorldImpl implements HelloWorld {

  // 使用Response.ResponseBuilder生成Response,格式須要本身轉換,例如使用Gson
  @Override

  public Response sayHelloResponse() {
    Response.ResponseBuilder rb = Response.status(Status.OK);
    return rb.entity("Hello").build();
  } 

  @Override
  public Result sayHelloString(String name) {
    return new Result("Hello, (String) " + name);
  } 

  @Override
  public Result sayHelloUser(User user) {
    return new Result(new User("Rest_" + user.getName()));
  } 

}

四. 發佈服務

1. 發佈方式一:使用默認的Jetty時,使用CXF提供的JAXRSServerFactoryBean(與Soap相似)

// 1). 服務端工廠類
JAXRSServerFactoryBean server = new JAXRSServerFactoryBean();

// 2). 設置了二個屬性
server.setAddress("http://localhost:8088/testcxf/cxf/rest");

server.setServiceBean(new HelloWorldImpl()); 

// 3). 添加 Provider,用於支持自動解析各類數據格式、如Json
List<Object> providerList = new ArrayList<Object>();
providerList.add(new JacksonJsonProvider());
server.setProviders(providerList); 

// 添加輸入&輸出日誌(可選)
server.getInInterceptors().add(new LoggingInInterceptor());

server.getOutInterceptors().add(new LoggingOutInterceptor());

// 4). 建立併發布服務,會發起一個http服務,默認使用Jetty
server.create();

(http://localhost:8088/testcxf/cxf/rest/hello/string/Jimmy)

2. 發佈方式二:在Web應用中,使用CXFNonSpringServlet發佈(實際是顯式調用了發佈方式一

a. 在web.xml中添加CXFNonSpringServlet的實現類(與Soap同樣)

<servlet>
  <servlet-name>CXFNonSpring</servlet-name>
  <servlet-class>net.jmystudio.servlet.WebServiceNonSpringServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>CXFNonSpring</servlet-name>
  <url-pattern>/cxfns/*</url-pattern>
</servlet-mapping>

b. 實現WebServiceNonSpringServlet類(與Soap相似)

import org.apache.cxf.transport.servlet.CXFNonSpringServlet;

public class WebServiceNonSpringServlet extends CXFNonSpringServlet {

  @Override
  protected void loadBus(ServletConfig servletConfig) {
    super.loadBus(servletConfig);

    //使用JAXRSServerFactoryBean,代碼相似發佈方式一,此處簡略

    // 1). 服務端工廠類
    JAXRSServerFactoryBean server = new JAXRSServerFactoryBean();

    // 2). 設置了兩個屬性 
    ......

    // 3). 建立併發布服務
    server.create();
  }

}

(http://localhost:8090/testcxf/cxfns/rest/hello/string/Jimmy)(應用包名是testcxf)

3. 發佈方式三:在Web應用中,整合Spring+CXFServlet發佈(實際是隱式調用了發佈方式一(最經常使用)

a. 須要引入Spring相關的Jar包(與Soap同樣)

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.1.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>4.1.6.RELEASE</version>
</dependency>

b. 在web.xml中添加Spring配置和CXFServlet(與Soap同樣)

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:spring*.xml</param-value>
</context-param>
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
  <servlet-name>CXF</servlet-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>CXF</servlet-name>
  <url-pattern>/cxf/*</url-pattern>
</servlet-mapping>

c. 添加關於cxf的spring配置文件(例spring-cfx-rest.xml)(與Soap相似)

<!-- 初始化cxf servlet -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<!-- 日誌攔截器bean -->
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>

<!-- 發佈方式1:使用JAXRSServerFactoryBean-->
<jaxrs:server address="/rest">
  <jaxrs:serviceBeans>
    <ref bean="helloWorldService" />
  </jaxrs:serviceBeans>
  <!-- Provider -->

  <jaxrs:providers>
    <bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
  </jaxrs:providers>
  <!-- 輸入日誌攔截器 -->
  <jaxrs:inInterceptors>
    <ref bean="loggingInInterceptor"/>
  </jaxrs:inInterceptors>
  <!-- 輸出日誌攔截器 -->
  <jaxrs:outInterceptors>
    <ref bean="loggingOutInterceptor" />
  </jaxrs:outInterceptors>
</jaxrs:server>

<bean id="helloWorldService" class="net.jmystudio.cxf.rest.HelloWorldImpl" />

(http://localhost:8090/testcxf/cxf/rest/hello/string/Jimmy) (應用包名是testcxf)

五. 調用方式

不管使用哪一種發佈方式,發佈成功後,均可以在火狐RestCilent的調試插件裏調試,都可看到該WebService的接口定義的返回內容

例如 http://localhost:8088/testcxf/cxf/rest/hello/string/Jimmy

代碼調用主要有3種方式

1. 調用方式一:使用JAXRSClientFactory得到靜態的代理Client顯式依賴WebService接口,須要引入服務提供方提供的jar包)(JAX-RS 1.0,已過期,不推薦)(與Soap相似)

HelloWorld staticClient = JAXRSClientFactory.create("http://localhost:8088/testcxf/cxf/rest", HelloWorld.class);
Response resp1 = staticClient.sayHelloResponse();
System.out.println(resp1.getMetadata());
System.out.println(resp1.readEntity(String.class));

2. 調用方式二:使用ClientBuilder、WebTarget

WebTarget webTarget = ClientBuilder.newClient().target("http://localhost:8088/testcxf/cxf/rest").path("/hello/string").path("/Tony");
Response resp2 = webTarget.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).get();
System.out.println(resp2.getMetadata());
System.out.println(resp2.readEntity(String.class));

3. 調用方式三:使用WebClient(推薦)

WebClient webClient = WebClient.create("http://localhost:8088/testcxf/cxf/rest").path("/hello/string").path("/Kevin");
Response resp3 = webClient.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).get();
System.out.println(resp3.getMetadata());
System.out.println(resp3.readEntity(String.class));

4. 其它調用方式:使用HttpClient或HttpURLConnection等鏈接,與常規的URL得到數據的方式一致,詳情略。

相關文章
相關標籤/搜索