• WebService基础入门 CXF(WS + RS)


    一、基本介绍

    Web Services是一个软件接口,它描述了一组可以在网络上通过标准化的 XML 消息传递访问的操作。它使用基于 XML 语言的协议来描述要执行的操作或者要与另一个 Web 服务交换的数据。Web Services更多是一种标准,而不是一种具体的技术,不同的平台、语言大都提供Web Services的开发实现。在java领域,Web Services的框架很多,例如:Axis、xfire、CXF等。

    二、CXF基本介绍

    Apache CXF = Celtix + XFire,Apache CXF 的前身叫 Apache CeltiXfire,现在已经正式更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。
    Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。
    CXF WebService 开发,主要分为两种服务提供方式 WS 、RS 。这里分别介绍这两种方式独立发布方法和与Spring整合的发布方法。

    三、CXF-WS开发入门

    1、JAX-WS独立服务使用

    JAX-WS 传输数据,就是 XML 格式,基于 SOAP 协议。
    开发步骤:

    1.建立简单的Maven项目。

    2.引入关键坐标依赖,具体如下配置。

    <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>cn.leon.maven</groupId>
        <artifactId>cxf_ws_first_application</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cxf_ws_first_application</name>
        <description>独立发布的CXF-WS服务java项目</description>
        <dependencies>
    
            <!-- 要进行jax-ws开发,必须引入这个依赖 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxws</artifactId>
                <version>3.0.1</version>
            </dependency>
    
            <!-- 内置的jetty 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>
            
            <!-- ws开发需要的注解配置 -->
            <dependency>
                <groupId>javax.jws</groupId>
                <artifactId>jsr181</artifactId>
                <version>1.0</version>
            </dependency>
        </dependencies>
    </project>
    
    • 第一个坐标是用来开发cxf应用,第二个坐标是搭建一个服务器,可以独立运行cxf应用,这个服务器类似独立的tomca插件服务器。
    • 第三个坐标是日志输出的jar依赖,设置了这个依赖,就可以在项目运行期间打印出详细的数据传递的日志信息。但是不能忘记将log4j.properties配置文件拷贝至项目根目录下。

    3.编写服务端程序,编写实体类。

    User案例实体类:

    package cn.leon.cxf.domain;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class User {
       private Integer id;
       private String username;
       private String city;
       private List<Car> cars = new ArrayList<Car>();
       
       public Integer getId() {
           return id;
       }
       public void setId(Integer id) {
           this.id = id;
       }
       public String getUsername() {
           return username;
       }
       public void setUsername(String username) {
           this.username = username;
       }
       public String getCity() {
           return city;
       }
       public void setCity(String city) {
           this.city = city;
       }
       public List<Car> getCars() {
           return cars;
       }
       public void setCars(List<Car> cars) {
           this.cars = cars;
       }
    }
    

    Car案例实体类:

    package cn.leon.cxf.domain;
    
    public class Car {
        private Integer id;
        private String name;
        private Double price;
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Double getPrice() {
            return price;
        }
        public void setPrice(Double price) {
            this.price = price;
        }
        @Override
        public String toString() {
            return "Car [id=" + id + ", name=" + name + ", price=" + price + "]";
        }
    }
    

    服务端程序:
    服务端口接口程序,这个是对外发布的接口,必须得有,具体的代码业务实现,是它的实现类来完成。接口代码如下:

    package cn.leon.cxf.service;
    
    import java.util.List;
    
    import javax.jws.WebMethod;
    import javax.jws.WebService;
    
    import cn.leoncxf.domain.Car;
    import cn.leon.cxf.domain.User;
    
    /**
     * 该接口是服务端提供对外服务的接口,服务的主要代码由其实现类来完成。
     * @author lemon
     *
     */
    @WebService  // 使用在类上面,标记类是 WebService 服务提供对象
    public interface IUserService {
        @WebMethod  // 使用在方法上面,标记方法 是 WebService 服务提供方法
        String sayHello(String name);
        @WebMethod
        List<Car> findCarByUser(User user);
    }
    

    注解说明:
    @WebService:使用在类上面,标记类是 WebService 服务提供对象;
    @WebMethod:使用在方法上面,标记方法是 WebService 服务提供方法。

    实现类代码实现:

    package cn.leon.cxf.service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.jws.WebService;
    
    import cn.leon.cxf.domain.Car;
    import cn.leon.cxf.domain.User;
    
    @WebService(endpointInterface = "cn.itcast.cxf.service.IUserService", serviceName = "userService")
    // 注解设置 endPointInterface 接口服务完整类名, servicename 服务名称
    public class UserServiceImpl implements IUserService {
    
        // 传递简单的数据
        public String sayHello(String name) {
            return "Hello " + name;
        }
    
        // 传递复杂的数据
        public List<Car> findCarByUser(User user) {
            List<Car> list = null;
            if ("tom".equals(user.getUsername())) {
                list = new ArrayList<Car>();
                Car car = new Car();
                car.setId(1);
                car.setName("QQ汽车");
                car.setPrice(10000D);
                list.add(car);
            }
            return list;
        }
    }
    

    注解参数说明:
    endpointInterface:接口服务的完整类名;
    serviceName:服务名。

    4.服务发布,编写服务发布代码。

    package cn.leon.cxf.ws.server;
    
    import javax.xml.ws.Endpoint;
    import cn.itcast.cxf.service.IUserService;
    import cn.itcast.cxf.service.UserServiceImpl;
    
    /**
     * 使用CXF将将UserService注册到到网络上
     * @author lemon
     *
     */
    public class WS_Server {
        public static void main(String[] args) {
            // 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可以在浏览器上访问这个地址,实现数据的访问,但是由于从浏览器没法传递参数,故无法完成对服务的方法的调用。

    5.编写客户端程序代码,实现通信。

    package cn.leon.cxf.ws.client;
    
    import java.util.List;
    
    import org.apache.cxf.interceptor.LoggingInInterceptor;
    import org.apache.cxf.interceptor.LoggingOutInterceptor;
    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
    
    import cn.leon.cxf.domain.Car;
    import cn.leon.cxf.domain.User;
    import cn.leon.cxf.service.IUserService;
    
    public class WS_Client {
        public static void main(String[] args) {
            // 编写客户端,调用WebService服务
            JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
            jaxWsProxyFactoryBean.setAddress("http://localhost:9999/userService");
            jaxWsProxyFactoryBean.setServiceClass(IUserService.class);
            // 日志打印设置,是可选设置
            jaxWsProxyFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
            jaxWsProxyFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
            // 创建调用远程服务的代理对象
            IUserService proxy = (IUserService) jaxWsProxyFactoryBean.create();
            // 直接调用远程服务的方法
            System.out.println(proxy.sayHello("ITCAST"));
            User user = new User();
            user.setUsername("tom");
            List<Car> cars = proxy.findCarByUser(user);
            for (Car car : cars) {
                System.out.println(car);
            }
        }
    }
    

    这就是一个独立发布的JAX-WS的一个完整流程,现总结如下:

    • 配置相关依赖,也就是配置依赖的jar包;
    • 编写传递数据的载体——实体类;
    • 编写服务端的接口;
    • 编写服务端接口的实现类;
    • 编写服务发布的应用;
    • 提供访问路径给第三方,由第三方编写客户端实现数据的通信。

    JAX-WS原理分析:
    客户端创建jaxWsProxyFactoryBean对象,它是一个服务端实现类的代理对象的创建工厂,通过create()方法可以创建服务端实现类的代理对象,这个对象可以调用一切在接口上添加了@WebMethod的方法,它的类型就是接口的类型,相当于服务端实现类对象的兄弟对象,这就完成了一个完整的Web Service应用。

    2、JAX-WS与Spring整合开发Web Service

    第一步:建立 maven web 项目 ,基于 tomcat 发布服务。

    第二步:导入Maven坐标,建立依赖关系。

    <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>cn.leon.maven</groupId>
        <artifactId>cxf_ws_spring</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>war</packaging>
        <name>cxf_ws_spring</name>
        <description>CXF的WS和Spring整合服务发布</description>
        <dependencies>
    
            <!-- CXF的WS开发的依赖 -->
            <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.1.7.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.1.7.RELEASE</version>
            </dependency>
    
            <!-- 测试 -->
            <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>
    
            <!-- 配置依赖的servlet api,仅仅测试的时候才配置 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.0.1</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <!-- 配置服务启动端口 -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>tomcat-maven-plugin</artifactId>
                    <version>1.1</version>
                    <configuration>
                        <port>9998</port>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    3.配置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"
        id="WebApp_ID" version="2.5">
    
        <!-- 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配置,基于web访问相应的servlet -->
        <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>/service/*</url-pattern>
        </servlet-mapping>
    
        <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>
    </web-app>
    

    4.导入前面已有的实体类、接口和服务实现类。

    5.在applicationContext.xml中配置服务,这个服务交给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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:jaxws="http://cxf.apache.org/jaxws"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/data/jpa 
            http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
            http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
        
        <!-- 配置服务 -->
        <!-- 
            address是访问路径;
            serviceClass是配置接口;
            serviceBean是配置实现类。
         -->
        <jaxws:server id="userService" address="/userService"
            serviceClass="cn.leon.cxf.service.IUserService">
            <jaxws:serviceBean>
                <bean class="cn.leon.cxf.service.UserServiceImpl" />
            </jaxws:serviceBean>
        </jaxws:server>
    </beans>
    

    需要注意的是:需要引入jaxws命名空间和约束。xmlns:jaxws="http://cxf.apache.org/jaxws"

    6.使用tomcat插件启动maven项目,提供给第三方访问路径:http://localhost:9998/cxf_ws_spring/service/userService?wsdl。

    注意:尤其要注意访问路径的拼接问题。tomcat访问路径+项目名+web.xml配置的访问路径+服务名,后面连接上参数wsdl。

    7.整合spring,配置客户端,客户端交给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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:jaxws="http://cxf.apache.org/jaxws"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/data/jpa 
            http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
            http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    
        <!-- 配置服务 -->
        <!-- address是访问路径; serviceClass是配置接口; serviceBean是配置实现类。 -->
        <jaxws:server id="userService" address="/userService"
            serviceClass="cn.leon.cxf.service.IUserService">
            <jaxws:serviceBean>
                <bean class="cn.leon.cxf.service.UserServiceImpl" />
            </jaxws:serviceBean>
        </jaxws:server>
    
        <!-- 配置客户端 -->
        <jaxws:client id="userServiceClient" serviceClass="cn.leon.cxf.service.IUserService"
            address="http://localhost:9998/cxf_ws_spring/service/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>
    </beans>
    

    其中消息拦截器是可选设置。

    8.编写测试案例。

    package cn.leon.cxf.server.test;
    
    import java.util.List;
    
    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 cn.leon.cxf.domain.Car;
    import cn.leon.cxf.domain.User;
    import cn.leon.cxf.service.IUserService;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml")
    public class CXFTest {
    
        // 注入一个代理对象
        @Autowired
        private IUserService proxy;
        
        @Test
        public void testServer() {
            System.out.println(proxy.sayHello("黑马程序员"));
        }
        
        @Test
        public void testServer2() {
            User user = new User();
            user.setUsername("tom");
            List<Car> cars = proxy.findCarByUser(user);
            for (Car car : cars) {
                System.out.println(car);
            }
        }
    }
    

    四、CXF-RS开发入门(重点)

    1、JAX-RS独立服务使用

    1.建立简单的Maven java项目。

    2.导入Maven坐标。

    <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>cn.leon.maven</groupId>
        <artifactId>cxf_rs_first_application</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>cxf_rs_first_application</name>
        <description>独立的jax-rs应用</description>
        <dependencies>
            <!-- 要进行jax-rs开发,必须引入这个依赖 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxrs</artifactId>
                <version>3.0.1</version>
            </dependency>
            <!-- 内置的jetty 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>
            
            <!-- 客户端需要配置的依赖 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-client</artifactId>
                <version>3.0.1</version>
            </dependency>
            
            <!-- 要使用JSON数据格式交互的转换接口 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-extension-providers</artifactId>
                <version>3.0.1</version>
            </dependency>
            
            <!-- 转换JSON必备的一个工具包 -->
            <dependency>
                <groupId>org.codehaus.jettison</groupId>
                <artifactId>jettison</artifactId>
                <version>1.3.7</version>
            </dependency>
        </dependencies> 
    </project>
    

    3.编写实体类。

    User类:

    package cn.leon.cxf.domain;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement(name = "User")
    public class User {
        private Integer id;
        private String username;
        private String city;
        private List<Car> cars = new ArrayList<Car>();
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getCity() {
            return city;
        }
    
        public void setCity(String city) {
            this.city = city;
        }
    
        public List<Car> getCars() {
            return cars;
        }
    
        public void setCars(List<Car> cars) {
            this.cars = cars;
        }
    
        @Override
        public String toString() {
            return "User [id=" + id + ", username=" + username + ", city=" + city + ", cars=" + cars + "]";
        }
        
    }
    

    Car类:

    package cn.itcast.cxf.domain;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement(name = "Car")
    public class Car {
        private Integer id;
        private String name;
        private Double price;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Double getPrice() {
            return price;
        }
    
        public void setPrice(Double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Car [id=" + id + ", name=" + name + ", price=" + price + "]";
        }
    }
    

    注意:@XmlRootElement(name = "Car")指定了转换成xml和json的时候对象的名称。

    4.编写业务接口和业务实现类。

    业务接口:

    package cn.leon.cxf.service;
    
    import java.util.List;
    
    import javax.ws.rs.Consumes;
    import javax.ws.rs.DELETE;
    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 cn.leon.cxf.domain.User;
    
    @Path("/userService")
    @Produces("*/*")
    public interface IUserService {
    
        @POST
        @Path("/user") // 设置二级访问路径
        @Consumes({ "application/xml", "application/json" }) // 设置接收参数的格式
        void saveUser(User user);
    
        @PUT
        @Path("/user")
        @Consumes({ "application/xml", "application/json" })
        void updateUser(User user);
    
        @GET
        @Path("/user")
        @Consumes({ "application/xml", "application/json" })
        @Produces({ "application/xml", "application/json" })   // 指定返回数据格式
        List<User> findAll();
    
        @GET
        @Path("/user/{id}")
        @Consumes({ "application/xml", "application/json" })
        @Produces({ "application/xml", "application/json" })
        User findUserById(@PathParam("id") Integer id);  // 参数指定了接收数据的名字
    
        @DELETE
        @Path("/user/{id}")
        @Consumes({ "application/xml", "application/json" })
        void deleteUserById(@PathParam("id") Integer id);
    }
    

    说明:

    • @Path 指定了服务访问资源路径,访问路径是类上的path+方法上的path;
    • @Consumes 指定能够处理客户端传递过来数据格式,也就是说指定了客户端传递过来的数据格式;
    • @Produces 指定能否生成哪种格式数据返回给客户端;
    • @GET 查询 @PUT 修改 @POST 增加 @DELETE 删除;
    • @PathParam("id")指定了拼接在访问路径上参数。
      业务实现类:
    package cn.leon.cxf.service;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import cn.leon.cxf.domain.Car;
    import cn.leon.cxf.domain.User;
    
    public class UserServiceImpl implements IUserService {
    
        public void saveUser(User user) {
            System.out.println("save user:" + user);
        }
    
        public void updateUser(User user) {
            System.out.println("update user:" + user);
        }
    
        public List<User> findAll() {
            List<User> users = new ArrayList<User>();
            User user1 = new User();
            user1.setId(1);
            user1.setUsername("小明");
            user1.setCity("北京");
    
            List<Car> carList1 = new ArrayList<Car>();
            Car car1 = new Car();
            car1.setId(101);
            car1.setName("保时捷");
            car1.setPrice(1000000d);
            carList1.add(car1);
            Car car2 = new Car();
            car2.setId(102);
            car2.setName("宝马");
            car2.setPrice(400000d);
            carList1.add(car2);
            user1.setCars(carList1);
    
            users.add(user1);
    
            User user2 = new User();
            user2.setId(2);
            user2.setUsername("小丽");
            user2.setCity("上海");
            users.add(user2);
    
            return users;
        }
    
        public User findUserById(Integer id) {
            if (id == 1) {
                System.out.println(22222);
                User user1 = new User();
                user1.setId(1);
                user1.setUsername("小明");
                user1.setCity("北京");
                return user1;
            }
            return null;
        }
    
        public void deleteUserById(Integer id) {
            System.out.println("delete user id :" + id);
        }
    
    }
    

    5.发布服务

    package cn.leon.cxf.server;
    
    import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
    
    import cn.leon.cxf.domain.Car;
    import cn.leon..cxf.domain.User;
    import cn.leon.cxf.service.IUserService;
    import cn.leon.cxf.service.UserServiceImpl;
    
    public class RSServer {
        public static void main(String[] args) {
            // 创建服务端业务接口实现类对象
            IUserService userService = new UserServiceImpl();
            
            // 创建服务
            JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean();
            jaxrsServerFactoryBean.setResourceClasses(User.class, Car.class); // 指定将哪些实体类转换成xml、json进行发送
            jaxrsServerFactoryBean.setAddress("http://localhost:9997");
            jaxrsServerFactoryBean.setServiceBean(userService);
            
            // 发布服务
            jaxrsServerFactoryBean.create();
            System.out.println("服务开启了....");
        }
    }
    

    现在可以通过浏览器来进行对服务端的数据访问了。

    6.编写客户端。

    对于客户端程序的编写 有两种做法

    • 使用 http client 工具 ,需要自己对 HTTP 协议内容进行定制和解析
    • WebClient 工具类使用(CXF 自带)
      使用第二种,需要导入一个依赖,cxf-rt-rs-client。
      依赖:
    <!-- 客户端需要配置的依赖 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-client</artifactId>
                <version>3.0.1</version>
            </dependency>
    

    客户端编写:

    package cn.leon.cxf.client;
    
    import java.util.Collection;
    
    import javax.ws.rs.core.MediaType;
    
    import org.apache.cxf.jaxrs.client.WebClient;
    
    import cn.leon.cxf.domain.User;
    
    public class RSClient {
        public static void main(String[] args) {
            // 参数说明:
            // create是创建一个连接,给定一个访问地址
            // accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
            // getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
            // type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
            Collection<? extends User> collection = WebClient.create("http://localhost:9997/userService/user")
                    .accept(MediaType.APPLICATION_XML).getCollection(User.class);
            System.out.println(collection);
    
            // 保存一个对象
            User user = new User();
            user.setUsername("Lemon");
            WebClient.create("http://localhost:9997/userService/user")
            .type(MediaType.APPLICATION_XML).post(user);
        }
    }
    

    方法说明:

    • create是创建一个连接,给定一个访问地址
    • accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
    • getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
    • type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型

    思考:

    如何是要JSON数据格式进行交互?
    要是要JSON数据进行交互,那就必须导入两个依赖。否则会报错:
    Caused by: javax.ws.rs.ProcessingException: No message body writer has been found for class cn.itcast.cxf.domain.User, ContentType: application/json
    需要导入的依赖是:

    <!-- 要使用JSON数据格式交互的转换接口 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-extension-providers</artifactId>
                <version>3.0.1</version>
            </dependency>
            
            <!-- 转换JSON必备的一个工具包 -->
            <dependency>
                <groupId>org.codehaus.jettison</groupId>
                <artifactId>jettison</artifactId>
                <version>1.3.7</version>
            </dependency>
    

    使用JSON数据进行交互的客户端:

    package cn.leon.cxf.client;
    
    import java.util.Collection;
    
    import javax.ws.rs.core.MediaType;
    
    import org.apache.cxf.jaxrs.client.WebClient;
    
    import cn.leon.cxf.domain.User;
    
    public class RSClient2 {
        public static void main(String[] args) {
            // 参数说明:
            // create是创建一个连接,给定一个访问地址
            // accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
            // getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
            // type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
            Collection<? extends User> collection = WebClient.create("http://localhost:9997/userService/user")
                    .accept(MediaType.APPLICATION_JSON).getCollection(User.class);
            System.out.println(collection);
    
            // 保存一个对象
            User user = new User();
            user.setUsername("Lemon");
            WebClient.create("http://localhost:9997/userService/user")
            .type(MediaType.APPLICATION_JSON).post(user);
        }
    }
    

    2、JAX-RS与Spring整合开发Web Service

    1.建立Maven Web项目。

    2.导入相关依赖。

    <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>cn.leon.maven</groupId>
        <artifactId>cxf_rs_spring</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>war</packaging>
        <name>cxf_rs_spring</name>
        <description>CXF的rs服务发布与spring整合</description>
    
        <dependencies>
            <!-- cxf 进行rs开发 必须导入 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxrs</artifactId>
                <version>3.0.1</version>
            </dependency>
    
            <!-- 日志引入 -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.12</version>
            </dependency>
    
            <!-- 客户端 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-client</artifactId>
                <version>3.0.1</version>
            </dependency>
    
            <!-- 扩展json提供者 -->
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-extension-providers</artifactId>
                <version>3.0.1</version>
            </dependency>
    
            <!-- 转换json工具包,被extension providers 依赖 -->
            <dependency>
                <groupId>org.codehaus.jettison</groupId>
                <artifactId>jettison</artifactId>
                <version>1.3.7</version>
            </dependency>
    
            <!-- 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 整合junit -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>4.1.7.RELEASE</version>
            </dependency>
    
            <!-- junit 开发包 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>tomcat-maven-plugin</artifactId>
                    <version>1.1</version>
                    <configuration>
                        <port>9996</port>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    第三步:3.导入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"
        id="WebApp_ID" version="2.5">
    
        <!-- 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配置,基于web访问相应的servlet -->
        <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>/service/*</url-pattern>
        </servlet-mapping>
    
        <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>
    </web-app>
    

    4.导入上述的实体类和服务接口、服务实现类。需要注意的是:服务接口上的@Path需要删除,或者将applicationContext.xml中发访问地址设置为空。@Path与applicationContext.xml 配置重复,所以一般注释掉,但是还是建议将xml中的配置设置为空,这里的path设置不为空,因为xml中可以配置接口的多个实现类,如果在xml设置配置统一的访问路径,那么就难以区分到底是哪个实现类在工作,而在类上设置@path,那么就可以区分不同的实现类,很明了。

    5.配置applicationContext.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.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="cn.itcast.cxf.service.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>
    

    需要注意的是:需要引入名称空间:

    xmlns:jaxrs="http://cxf.apache.org/jaxrs" http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd

    6.启动服务,访问路径。

    访问路径:服务器根目录地址(项目地址) + web.xml 配置 + applicationContext.xml address 配置 (或类 @Path )+ 方法 @Path

    7.编写客户端。

    package cn.leon.cxf.client;
    
    import java.util.Collection;
    
    import javax.ws.rs.core.MediaType;
    
    import org.apache.cxf.jaxrs.client.WebClient;
    
    import cn.leon.cxf.domain.User;
    
    public class RSClient {
        public static void main(String[] args) {
            // 参数说明:
            // create是创建一个连接,给定一个访问地址
            // accept是接收一个指定类型的数据,但是这个类型必须是服务接口中指定的返回数据类型
            // getCollection是获取所有的对象的方法,如果是一个对象,就是要get,这个根据实际来定
            // type是发送数据的格式,这个必须是服务端接口定义的接收的数据类型
            Collection<? extends User> collection = WebClient.create("http://localhost:9996/cxf_rs_spring/service/userService/user")
                    .accept(MediaType.APPLICATION_XML).getCollection(User.class);
            System.out.println(collection);
    
            // 保存一个对象
            User user = new User();
            user.setUsername("Lemon");
            WebClient.create("http://localhost:9996/cxf_rs_spring/service/userService/user")
            .type(MediaType.APPLICATION_XML).post(user);
        }
    }
    



    作者:Leon丶l
    链接:https://www.jianshu.com/p/478ab367e294
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 相关阅读:
    jFinal基于maven简单的demo
    quartz定时任务
    cors解决跨越问题
    poi导出excel
    layui富文本编译器后台获取图片路径
    HttpClient短信接口
    js分页
    El表达式日期处理
    【传智播客】Libevent学习笔记(二):创建event_base
    【传智播客】Libevent学习笔记(一):简介和安装
  • 原文地址:https://www.cnblogs.com/Jeely/p/10761920.html
Copyright © 2020-2023  润新知