• 使用CXF实现基于Rest方式的WebService


    本文介绍使用CXF实现基于Rest方式的WebService(CXF的版本是3.0.0)

    一. 前言

    Java有三种WebService规范:Jax-WS,Jax-RS,Jaxm

    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支持文件传输,暴露更多底层细节(不推荐)

    二. 引入依赖

    <!-- Jax-RS前端控制模块,处理服务业务的请求 -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
      <version>3.0.0</version>
    </dependency>

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

    <!-- 数据传输模块(与Soap一样) -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http</artifactId>
      <version>3.0.0</version>
    </dependency>

    <!-- 引入内置的Jetty,如在Tomcat中发布服务可以不引入(与Soap一样)  -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http-jetty</artifactId>
      <version>3.0.0</version>
    </dependency>

    三. 编写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获得数据的方式一致,详情略。

     

  • 相关阅读:
    我认为的架构师
    Jenkins github账号密码验证方式失效 解决方式
    android逆向奇技淫巧二十一:ida反反调试&加密算法跟踪(未完待续)(六)
    android逆向奇技淫巧十九:unidbg模拟执行和trace x音so代码(四)
    android逆向奇技淫巧十八:x音so层代码花指令防护分析(三)
    android逆向奇技淫巧十七:android客户端自动x红包(一):代码原理分析
    测试工具安装汇总
    javascript事件节流和防抖
    CompletableFuture-更优雅的使用多线程
    青春
  • 原文地址:https://www.cnblogs.com/zjm701/p/6845813.html
Copyright © 2020-2023  润新知