客户端调用CXF与spring集成发布的Rest服务

近期,因工作需要,接触到CXF与spring集成发布Rest服务,并实现客户端与服务器端的交互,上网查阅相关资料发现CXF与spring集成发布Rest服务的相关文章较多,但涉及到客户端访问服务器的相关资料确很少,几经周折,整合前人的经验,搭建好此框架之后,觉得有必要记录一下,一方面可以巩固一下流程,另一方面,希望能帮助更多有需要的人!

服务器端的搭建

第一步 Spring 框架环境搭建

1.maven 创建普通 java 工程并调整整体工程环境 

 

2.项目目录:

 

第二步 配置相关文件

1.添加maven依赖(以下没有用到的可以不添加)

<dependencies>
  <!-- 单元测试 -->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <!--spring-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!-- 数据库相关 -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
  </dependency>
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.15</version>
  </dependency>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.8</version>
  </dependency>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.5</version>
  </dependency>
  <!-- 日志相关 -->
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.26</version>
  </dependency>
  <!--CXF-->
  <dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-service-description</artifactId>
    <version>${cxf.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-extension-providers</artifactId>
    <version>${cxf.version}</version>
  </dependency>
  <!--Jackdon-->
  <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.13</version>
  </dependency>
  <!-- aspectJ AOP 织入器 -->
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
  </dependency>
  <!-- apache lang3工具包 -->
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
  </dependency>
</dependencies>

2.配置web.xml文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

  <!-- Spring -->
  <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>

  <!-- CXF -->
  <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>/ws/*</url-pattern>
  </servlet-mapping>

</web-app>

第三步、REST服务接口以及实现类

1.在项目目录下新建bean包,在bean文件夹下创建Product类

package com.spring.rest.bean;

public class Product {
    private long id;
    private String name;
    private int price;

    public Product() {
    }

    public Product(long id, String name, int price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}

2.在项目目录下新建service包,在service包下新建impl包和inter包,在impl下新建ProductServiceImpl类,在inter包下新建ProductService接口(项目目录如上)

ProductServiceImpl类中内容:

package com.spring.rest.service.impl;

import com.lenovo.rest.bean.Product;
import com.lenovo.rest.service.inter.ProductService;

import java.lang.reflect.Field;
import java.util.*;

public class ProductServiceImpl implements ProductService {
    private static final List<Product> productList = new ArrayList<Product>();
    static {
        productList.add(new Product(1, "iphone63", 5000));
        productList.add(new Product(2, "ipad mini", 2500));
    }

    @Override
    public List<Product> retrieveAllProducts() {

        Collections.sort(productList, new Comparator<Product>() {

            @Override
            public int compare(Product p1, Product p2) {
                return (p1.getId() > p2.getId()) ? -1 : 1;
            }
        });
        return productList;
    }

    @Override
    public Product retrieveProductById(long id) {
        Product targetProduct = null;
        for (Product product : productList) {
            if (product.getId() == id) {
                targetProduct = product;
                break;
            }
        }
        return targetProduct;
    }

    @Override
    public List<Product> retrieveProductsByName_param(String name){
        List<Product> targetList = new ArrayList<Product>();
        for (Product product : productList) {
            if (product.getName().equals(name)) {
                targetList.add(product);
            }
        }
        return targetList;
    }
    @Override
    public List<Product> retrieveProductsByName_form(String name) {
        List<Product> targetList = new ArrayList<Product>();
        for (Product product : productList) {
            if (product.getName().equals(name)) {
                targetList.add(product);
            }
        }
        return targetList;
    }

    @Override
    public Product createProduct(Product product) {
        product.setId(new Date().getTime());
        productList.add(product);
        return product;
    }

    @Override
    public Product createProduct(String name,int price){
        Product product = new Product();
        product.setId(new Date().getTime());
        product.setName(name);
        product.setPrice(price);

        productList.add(product);
        return product;
    }

    @Override
    public Product updateProductById(long id, Map<String, Object> fieldMap) {
        Product product = retrieveProductById(id);
        if (product != null) {
            try {
                for (Map.Entry<String, Object> fieldEntry : fieldMap.entrySet()) {
                    Field field = Product.class.getDeclaredField(fieldEntry
                            .getKey());
                    field.setAccessible(true);
                    field.set(product, fieldEntry.getValue());

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return product;
    }

    @Override
    public Product updateProduct(Product product){
        if(product != null){
            Product targetProduct = retrieveProductById(product.getId());
            if(targetProduct != null){
                targetProduct.setName(product.getName());
                targetProduct.setPrice(product.getPrice());
            }

            return targetProduct;
        }

        return null;
    }

    @Override
    public Product updateProduct(long id,String name,int price){
        Product product = retrieveProductById(id);
        if(product != null){
            product.setName(name);
            product.setPrice(price);
        }

        return product;
    }

    @Override
    public Product deleteProductById(long id) {
        Product targetProduct = null;
        Iterator<Product> it = productList.iterator();
        while (it.hasNext()) {
            Product product = it.next();
            if (product.getId() == id) {
                targetProduct = product;
                it.remove();
                break;
            }
        }
        return targetProduct;
    }

    @Override
    public Product deleteProductById_param(long id){
        Product targetProduct = null;
        Iterator<Product> it = productList.iterator();
        while (it.hasNext()) {
            Product product = it.next();
            if (product.getId() == id) {
                targetProduct = product;
                it.remove();
                break;
            }
        }
        return targetProduct;
    }
}

ProductService接口中的内容:

package com.spring.rest.service.inter;

import com.spring.rest.bean.Product;

import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
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.QueryParam;
import javax.ws.rs.core.MediaType;


public interface ProductService {
    @GET
    @Path("/products")
    @Produces(MediaType.APPLICATION_JSON)
    List<Product> retrieveAllProducts();

    @GET
    @Path("/product/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    Product retrieveProductById(@PathParam("id")long id);

    /**
     * 参数查询
     * @param name
     * @return
     */
    @GET
    @Path("/products/name")
    @Produces(MediaType.APPLICATION_JSON)
    List<Product> retrieveProductsByName_param(@QueryParam("name")String name);

    /**
     * 提交表单查询
     * @param name
     * @return
     */
    @POST
    @Path("/products/form/name")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    List<Product> retrieveProductsByName_form(@FormParam("name")String name);


    @POST
    @Path("/product")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    Product createProduct(Product product);

    @POST
    @Path("/product/create")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    Product createProduct(@FormParam("name")String name,@FormParam("price")int price);

    @PUT
    @Path("/product/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    Product updateProductById(@PathParam("id")long id,Map<String,Object> fieldMap);

    @PUT
    @Path("/product")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    Product updateProduct(Product product);

    @PUT
    @Path("/product/update")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    Product updateProduct(@FormParam("id")long id,@FormParam("name")String name,@FormParam("price")int price);

    @DELETE
    @Path("/product/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    Product deleteProductById(@PathParam("id")long id);

    @DELETE
    @Path("/product")
    @Produces(MediaType.APPLICATION_JSON)
    Product deleteProductById_param(@QueryParam("id")long id);

}

3.配置xml文件

在main文件下新建resources文件,如下图,点击右上角,将resources文件设置成源文件

在resources文件下新建spring.xml和spring-cxf.xml

 

spring.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="productServiceImpl" class="com.lenovo.rest.service.impl.ProductServiceImpl"></bean>
    <import resource="spring-cxf.xml"/>

</beans>



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


    <jaxrs:server address="/rest">
        <jaxrs:serviceBeans>
            <ref bean="productServiceImpl"/>
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
        </jaxrs:providers>
    </jaxrs:server>



</beans>

 

第四步,调用REST服务

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Demo</title>
    <link href="http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
    <link href="http://cdn.bootcss.com/bootstrap/3.2.0/css/colorbox.css" rel="stylesheet" type="text/css" />
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
    <script type="text/javascript" src="http://apps.bdimg.com/libs/bootstrap/3.3.4/js/bootstrap.min.js"></script>
    <script type="text/javascript" src="https://cdn.bootcss.com/handlebars.js/4.1.0/handlebars.js"></script>
</head>
<body>
<br>
<br>
<div class="container">
   <form role="form" id="form_name">
   <div class="form-group">
      <label for="input_name">根据名称检索</label>
      <input type="text" class="form-control" id="input_name" placeholder="名称" name="name"/>
   </div>
   <button id="submit_name" type="button" class="btn btn-default">检索</button>
   </form>
   <form role="form" id="form_create">
   <div class="form-group">
      <label for="input_create_name">名称</label>
      <input type="text" class="form-control" id="input_create_name" placeholder="名称" name="name"/>
   </div>
   <div class="form-group">
      <label for="input_create_price">价格</label>
      <input type="text" class="form-control" id="input_create_price" placeholder="价格" name="price"/>
   </div>
   <button id="submit_create" type="button" class="btn btn-default">添加</button>
   </form>
   <div class="panel panel-default">
      <button id="all" type="button" class="btn btn-default">RetrieveAll</button>
      <button id="byID" type="button" class="btn btn-default">RetrieveByID</button>
      <button id="name" type="button" class="btn btn-default">RetrieveByName</button>
   </div>
    <div class="page-header">
        <h1>Product</h1>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">Product List</div>
        <div class="panel-body">
            <div id="product"></div>
        </div>
    </div>
</div>

<script type="text/x-handlebars-template" id="product_table_template">
    {{#if data}}
        <table class="table table-hover" id="product_table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Product Name</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody>
                {{#data}}
                    <tr data-id="{{id}}" data-name="{{name}}">
                        <td>{{id}}</td>
                        <td>{{name}}</td>
                        <td>{{price}}</td>
                    </tr>
                {{/data}}
            </tbody>
        </table>
    {{else}}
        <div class="alert alert-warning">Can not find any data!</div>
    {{/if}}
</script>

<script>
    $(function() {
       //检索所有
       $("#all").click(function(){
          $("#product").html("");
          $.ajax({
                type: 'get',
                url: 'http://localhost:8080/springCxfREST/ws/rest/products',
                dataType: 'json',
                success: function(data) {
                    var template = $("#product_table_template").html();
                    var render = Handlebars.compile(template);
                    var html = render({
                        data: data
                    });
                    $('#product').html(html);
                }
            });
       });

       //根据ID检索
       $("#byID").click(function(){
          $("#product").html("");
          $.ajax({
                type: 'get',
                url: 'http://localhost:8080/springCxfREST/ws/rest/product/1',
                dataType: 'json',
                success: function(data) {
                    var template = $("#product_table_template").html();
                    var render = Handlebars.compile(template);
                    var html = render({
                        data: data
                    });
                    $('#product').html(html);
                }
            });
       });

       //根据名称检索
       $("#name").click(function(){
          $("#product").html("");
          $.ajax({
                type: 'get',
                url: 'http://localhost:8080/springCxfREST/ws/rest/products/name?name=ipad mini',
                dataType: 'json',
                success: function(data) {
                    var template = $("#product_table_template").html();
                    var render = Handlebars.compile(template);
                    var html = render({
                        data: data
                    });
                    $('#product').html(html);
                }
            });
       });

       //提交表单,根据名称检索
       $("#submit_name").click(function(){
          $("#product").html("");
          $.ajax({
                type: 'post',
                url: 'http://localhost:8080/springCxfREST/ws/rest/products/form/name?'+$("#form_name").serialize(),
                dataType: 'json',
                success: function(data) {
                    var template = $("#product_table_template").html();
                    var render = Handlebars.compile(template);
                    var html = render({
                        data: data
                    });
                    $('#product').html(html);
                }
            });
       });

       /* 提交表单,添加数据 */
       $("#submit_create").click(function(){
          $("#product").html("");
          $.ajax({
                type: 'post',
                url: 'http://localhost:8080/springCxfREST/ws/rest/product/create?'+$("#form_create").serialize(),
                dataType: 'json',
                success: function(data) {
                    var template = $("#product_table_template").html();
                    var render = Handlebars.compile(template);
                    var html = render({
                        data: data
                    });
                    $('#product').html(html);
                }
            });
       });
       /*使用jQuery发送基于JSONP的AJAX请求*/
       $.ajax({
            type: 'get',
            url: 'http://localhost:8080/springCxfREST/ws/rest/products',
            dataType: 'jsonp',
            jsonp: '_jsonp',
            jsonpCallback: 'callback',
            success: function(data) {
                var template = $("#product_table_template").html();
                var render = Handlebars.compile(template);
                var html = render({
                    data: data
                });
                $('#product').html(html);
            }
        });


    });

    function goColorBox(){
        $("#goOne").colorbox({ opacity:0.65,width: 500, height:500, close: "关闭", overlayClose: true});
  }
</script>
</body>
</html>

第五步,发布并访问

1.配置tomcat及端口(pom.xml)

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.tomcat.maven</groupId>
      <artifactId>tomcat7-maven-plugin</artifactId>
      <version>2.2</version>
      <configuration>
        <port>8080</port>
        <path>/springCxfREST</path>
        <uriEncoding>UTF-8</uriEncoding>
        <server>tomcat7</server>
      </configuration>
    </plugin>
  </plugins>
</build>

2.将打包的压缩文件设置为.war文件

在pom.xml文件中加入<packaging>war</packaging>

如下:

<groupId>com.spring.REST</groupId>
<artifactId>REST</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

3.点击右上角,Maven下的install开始打包

 打包成功后开始运行

 

客户端搭建

重新搭建一个spring框架,环境搭建和服务器端一样

1.项目目录:

 

2.配置pom.xml

<!--CXF-->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-service-description</artifactId>
  <version>${cxf.version}</version>
</dependency>
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-rs-client</artifactId>
  <version>${cxf.version}</version>
</dependency>
<!--Jackdon-->
<dependency>
  <groupId>org.codehaus.jackson</groupId>
  <artifactId>jackson-jaxrs</artifactId>
  <version>1.9.13</version>
</dependency>

3.将服务器端Product类和ProductService接口复制过来

新建WebClientTest类

package com.spring.rest.client;

import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;

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

public class JAXRSClient {

    public static void main(String[] args) {
        JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
        List<Object> providerList = new ArrayList<Object>();
        providerList.add(jsonProvider);
        ProductService us = JAXRSClientFactory.create("http://localhost:8080/springCxfREST/ws/rest",ProductService.class,providerList);
        List<Product> products = us.retrieveAllProducts();
        System.out.println(products.size());
        Product product = us.retrieveProductById(1);
        System.out.println(product.toString());

    }

}

启动服务器端,运行客户端main方法

运行结果