Loading...

WebService 基础教程

在我的开发生活中,其实使用到 WebService 的机会很少,毕竟现在流行 RESTful,JSON 替代 XML,RESTful 替代 WebService,这是很正常的现象,毕竟 XML 和 WebService 都太过于笨重,传输和处理效率低,但考虑到在某些复杂或特殊的业务场景中,WebService 仍旧有所应用,因此在这里整理了一下相关的知识内容,以便业务需要时能够快速回顾并应用。

概述

WebService 是什么

WebService 是一种跨编程语言和跨操作系统平台的远程调用技术。

  • WebService 是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的 XML (标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。
  • WebService 技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据 WebService 规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。 WebService 是自描述、 自包含的可用网络模块, 可以执行具体的业务功能。Web Service也很容易部署, 因为它们基于一些常规的产业标准以及已有的一些技术,诸如标准通用标记语言下的子集 XML 、 HTTP 。 WebService 减少了应用接口的花费。 WebService 为整个企业甚至多个组织之间的业务流程的集成提供了一个通用机制。

WebService 能做什么

  • 不同系统、不同平台、不同语言之间的通信访问和远程调用。
  • 应用程序的集成,不同业务的整合。

官方定义

  • Web服务是一种服务导向架构的技术,通过标准的 Web 协议提供服务,目的是保证不同平台的应用服务可以互操作。
  • 表面上看 WebService 就是一个应用程序,它向外界暴露出一个能够通过 Web 进行调用的方法 API ,能用编程的方法通过Web调用来实现某个功能的应用程序。
  • 深层次上看 WebService 是一种新的 Web 应用程序分支,它们是自包含、自描述模块化的应用,可以在网络中被描述、发布、查找以及通过 Web 来调用。

WebService 的两种类型

  • SOAP 协议风格的 Webservice
  • Restful 协议风格的 Webservice

WebService 结构图

WebService 结构图

WebService 核心组件

  • XML 和 HTTP
  • SOAP: 简单对象访问协议
  • WSDL:WebService 描述语言
  • UDDI:统一描述、发现和集成协议

SOAP

WebService 建好以后,你或者其他人就会去调用它。简单对象访问协议(SOAP)提供了标准的RPC方法来调用 WebService 。 SOAP 规范定义了 SOAP 消息的格式,以及怎样通过HTTP协议来使用 SOAP 。 SOAP 也是基于XML(标准通用标记语言下的一个子集)和 XSD 的, XML 是 SOAP 的数据编码方式。

WSDL

WebService 描述语言(WSDL)是一个基于 XML(标准通用标记语言下的一个子集)的语言,用于描述 WebService 及其函数、参数和返回值。WSDL 是机器可阅读的,也是人可阅读的,一些最新的开发工具既能根据你的 WebService 生成 WSDL 文档,又能导入 WSDL 文档,生成调用相应 WebService 的代码。

UDDI

UDDI是统一描述、发现和集成(Universal Description, Discovery, and Integration)的缩写。

UDDI 是一种目录服务,通过它,企业可注册并搜索 WebServices。

它是一个基于 XML 的跨平台的描述规范,可以使世界范围内的企业在互联网上发布自己所提供的服务。

  • UDDI 指通用的描述、发现以及整合。
  • UDDI 是一种用于存储有关 web services 的信息的目录。
  • UDDI 是一种由 WSDL 描述的网络服务接口目录。
  • UDDI 经由 SOAP 进行通迅。
  • UDDI 被构建于 Microsoft .NET 平台之中。

WebService 主流框架

WebService 主流框架

AXIS

参考:axis(阿帕奇可扩展交互系统)_百度百科

  • AXIS(Apache Extensible Interaction System)apache可扩展交互系统
  • AXIS是一款开源的WebService运行引擎,本质上就是一个SOAP引擎,提供创建服务器端、客户端和网关SOAP操作的基本框架。
  • 但AXIS并不完全是一个SOAP引擎,它还是一个独立的SOAP服务器和一个嵌入Servlet引擎(例如Tomcat)的服务器。
  • AXIS分为1.x系列和2系列,两个系列体系结构和使用上有较大的区别,相对而言,Axis1.x更加稳定,文档也比较齐全。
  • 官网:http://axis.apache.org/

XFire

参考:xfire_百度百科

XFire是新一代的Java Web服务引擎,XFire使得在JavaEE应用中发布Web服务变得轻而易举。和其他Web服务引擎相比,XFire的配置非常简单,可以非常容易地和Spring集成,它使得Java开发人员终于可以获得和.Net开发人员一样的开发效率。

支持将Web服务绑定到POJO、XMLBeans、JAXB1.1、JAXB2.0和Castor;

支持基于HTTP、JMS、XMPP等多种协议访问Web服务;

支持多种Web服务业界重要标准如SOAP、WSDL、Web服务寻址(WS-Addressing)、Web服务安全(WS-Security)等;

支持JSR181,可以通过JDK5配置Web服务;

高性能的SOAP实现;

服务器端、客户端代码辅助生成;

对Spring、Pico、Plexus等项目的支持等。

CXF

参考:CXF_百度百科

  • Apache CXF = Celtix + XFire
  • CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。
  • 官网:http://cxf.apache.org/

案例

CXF 案例

  • 创建maven项目。

  • 添加依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-frontend-jaxws -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-transports-http-jetty -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>3.2.7</version>
    </dependency>
  • 创建实体对象

    package com.xfc.cxftest.demo;
    
    public class User {
    
        private String name;
        private String description;
    
        // getter and setter
    }
  • 创建 WebService 接口及实现

    HelloWorld.java

    package com.xfc.cxftest.demo;
    
    import java.util.List;
    import javax.jws.WebParam;
    import javax.jws.WebService;
    
    @WebService
    public interface HelloWorld {
    
        String sayHi(@WebParam(name = "text") String text);
    
        String sayHiToUser(User user);
    
        String[] SayHiToUserList(List<User> userList);
    
    }

    HelloWorldImpl.java

    package com.xfc.cxftest.demo;
    
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import javax.jws.WebService;
    
    @WebService(endpointInterface = "com.xfc.cxftest.demo.HelloWorld", serviceName = "HelloWorld")
    public class HelloWorldImpl implements HelloWorld {
    
        Map<Integer, User> users = new LinkedHashMap<>();
    
        public String sayHi(String text) {
            return "Hello " + text;
        }
    
        public String sayHiToUser(User user) {
            users.put(users.size() + 1, user);
            return "Hello " + user.getName();
        }
    
        public String[] SayHiToUserList(List<User> userList) {
            String[] result = new String[userList.size()];
            int i = 0;
            for (User u : userList) {
                result[i] = "Hello " + u.getName();
                i++;
            }
            return result;
        }
    }
  • 创建服务端启动类

    package com.xfc.cxftest.demo;
    
    import javax.xml.ws.Endpoint;
    
    public class WebServiceApp {
    
        public static void main(String[] args) {
            System.out.println("web service start");
            HelloWorldImpl implementor = new HelloWorldImpl();
            String address = "http://localhost:8080/helloWorld";
            Endpoint.publish(address, implementor);
            System.out.println("web service started");
        }
    
    }
  • 浏览器访问

    启动 WebServiceApp.main() 并在浏览器访问 http://localhost:8080/helloWorld?wsdl 查看是否显示 wsdl 。

  • 创建客户端启动类

    package com.xfc.cxftest.demo;
    
    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
    
    public class HelloWorldClient {
    
        public static void main(String[] args) {
            JaxWsProxyFactoryBean svr = new JaxWsProxyFactoryBean();
            svr.setServiceClass(HelloWorld.class);
            svr.setAddress("http://localhost:8080/helloWorld");
            HelloWorld hw = (HelloWorld) svr.create();
            User user = new User();
            user.setName("Tony");
            user.setDescription("test");
            System.out.println(hw.sayHiToUser(user));
        }
    
    }

    启动 HelloWorldClient.main() 并查看控制台打印信息。

Soap 协议 + TCP/IPMoniter 监控

SOAP 定义

参考:简单对象访问协议_百度百科

简单对象访问协议是交换数据的一种协议规范,是一种轻量的、简单的、基于XML(标准通用标记语言下的一个子集)的协议,它被设计成在WEB上交换结构化的和固化的信息。

SOAP 协议组成

一条 SOAP 消息就是一个普通的 XML 文档,它包含下列元素:

  • Envelope 元素,必有,可把此 XML 文档标识为一条 SOAP 消息。
  • Header 元素,可选,包含头部信息。
  • Body 元素,必有,包含所有的调用和响应信息。
  • Fault 元素,可选,提供有关在处理此消息所发生错误的信息。

语法规则:

  • SOAP 消息必须用 XML 来编码
  • SOAP 消息必须使用 SOAP Envelope 命名空间
  • SOAP 消息必须使用 SOAP Encoding 命名空间
  • SOAP 消息不能包含 DTD 引用
  • SOAP 消息不能包含 XML 处理指令

SOAP消息基本结构:

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
    <soap:Header>
        <!--示例-->
    </soap:Header>
    <soap:Body>
        <!--示例-->
        <soap:Fault>
            <!--示例-->
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

WSDL 文件解析

WSDL 报文结构

<definitions>
	<types>
	  	<!-- 定义 web service 使用的数据类型 -->
	</types>
	<message>
        <!-- 每个消息均由一个或多个部件组成。可以把它当做java中一个函数调用的参数。 -->
	</message>

	<portType>
        <!-- 它类似Java中的一个函数库(或一个模块、或一个类) -->
	</portType>

	<binding>
        <!-- 为每个端口定义消息格式和协议细节。 -->
    </binding>
</definitions>

wsdl:definitions

<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://demo.cxftest.xfc.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloWorld" targetNamespace="http://demo.cxftest.xfc.com/">

</wsdl:definitions>
标签 描述
name 我们java程序中服务接口的实现类,SEI定义是:服务接口类+Service后缀,Service自动追加
targetNamespace 命名空间: 相当于Java里面的package它刚好是和我们Java定义中的包名相反
xmlns:tns 相当于Java里面的import, 包名反转

wsdl:types

用于定义在java服务接口中对应方法的输入参数及返回值类型。

<wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://demo.cxftest.xfc.com/" elementFormDefault="unqualified" targetNamespace="http://demo.cxftest.xfc.com/" version="1.0">
        <xs:element name="SayHiToUserList" type="tns:SayHiToUserList"/>
        <xs:element name="SayHiToUserListResponse" type="tns:SayHiToUserListResponse"/>
        <xs:element name="sayHi" type="tns:sayHi"/>
        <xs:element name="sayHiResponse" type="tns:sayHiResponse"/>
        <xs:element name="sayHiToUser" type="tns:sayHiToUser"/>
        <xs:element name="sayHiToUserResponse" type="tns:sayHiToUserResponse"/>
        <xs:complexType name="sayHiToUser">
            <xs:sequence>
                <xs:element minOccurs="0" name="arg0" type="tns:user"/>
            </xs:sequence>
        </xs:complexType>
        <xs:complexType name="user">
            <xs:sequence>
                <xs:element minOccurs="0" name="description" type="xs:string"/>
                <xs:element minOccurs="0" name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
        <xs:complexType name="sayHiToUserResponse">
    </xs:schema>
</wsdl:types>

wsdl:message

它述了Web服务生产者和消费者之间交换的数据。

<wsdl:message name="sayHiToUser">
    <wsdl:part element="tns:sayHiToUser" name="parameters"> </wsdl:part>
</wsdl:message>
<wsdl:message name="sayHiToUserResponse">
    <wsdl:part element="tns:sayHiToUserResponse" name="parameters"> </wsdl:part>
</wsdl:message>
  • 每个Web服务都有两条消息:输入和输出。

  • 输入描述Web服务的参数,输出描述Web服务的返回数据。

  • 每条消息包含零个或多个 <part> 参数,每个参数对应一个Web服务函数的参数。

  • 每个 <part> 参数与 <types> 容器元素中定义的具体类型相关联。

wsdl:portType

<wsdl:portType name="HelloWorld">
    <wsdl:operation name="sayHiToUser">
        <wsdl:input message="tns:sayHiToUser" name="sayHiToUser"> </wsdl:input>
        <wsdl:output message="tns:sayHiToUserResponse" name="sayHiToUserResponse"> </wsdl:output>
    </wsdl:operation>
</wsdl:portType>

portType相当于在java中定义的接口,operation相当于在java接口中定义的方法。

wsdl:binding

<wsdl:binding name="HelloWorldSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="sayHiToUser">
        <soap:operation soapAction="" style="document"/>
        <wsdl:input name="sayHiToUser">
            <soap:body use="literal"/>
        </wsdl:input>
        <wsdl:output name="sayHiToUserResponse">
            <soap:body use="literal"/>
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>

该元素提供了有关如何通过线路传输 portType 实际操作的具体细节。

  • 绑定可以通过多种传输方式提供,包括HTTP GET,HTTP POST或SOAP。

  • 绑定提供了有关用于传输 portType 操作的协议的具体信息。

  • 绑定提供服务所在的信息。

  • 对于SOAP协议,绑定是使用 <soap:binding> ,表示传输是基于HTTP协议的SOAP消息。

  • 可以为单个 portType 指定多个绑定。

wsdl:service

它负责将网络通信地址赋给一个具体的绑定。

<wsdl:service name="HelloWorld">
    <wsdl:port binding="tns:HelloWorldSoapBinding" name="HelloWorldImplPort">
        <soap:address location="http://localhost:8080/helloWorld"/>
    </wsdl:port>
</wsdl:service>

port 元素的绑定属性将服务的地址与Web服务中定义的绑定元素相关联。

JAX-WS 工具

参考:JAX-WS_百度百科

JAX-WS(Java API for XML Web Services)规范是一组XML web services的JAVA API,JAX-WS允许开发者可以选择RPC-oriented或者message-oriented 来实现自己的web services。

在上述项目中,我们已经用到JAX-WS工具,详见代码内容。

调用天气服务案例

  1. 浏览器访问天气接口

    访问:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

  2. 保存并修改wsdl

    浏览器 CTRL+S 保存该接口的xml格式文件。

    使用编辑器打开该文件并全文替换 <s:element ref="s:schema"/> <s:any /><s:any minOccurs="2" maxOccurs="2" />

    替换完成后,将该文件另存为 .wsdl 格式的文件,例如 WeatherWebService.wsdl ,推荐存放到项目 resources 目录下。

  3. 生成代码

    在项目 src > main > java 目录下执行命令 wsimport -s . E:\idea-workspace\test-weather\src\main\resources\WeatherWebService.wsdl ,如下图:

    ws_weather_cmd

    执行完成后,该项目 src > main > java 目录下即会生成天气接口相关文件。

  4. 创建测试类

    package com.xfc.testweather;
    
    import cn.com.webxml.ArrayOfString;
    import cn.com.webxml.WeatherWebService;
    import cn.com.webxml.WeatherWebServiceSoap;
    
    public class WebserviceTest {
        
        public static void main(String[] args) {
            //也可以使用new WeatherWebService(url)此方法可重新设置请求的地址 URL url=new URL("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl")
            WeatherWebService factory = new WeatherWebService();
            WeatherWebServiceSoap weatherWebServiceSoap = factory.getWeatherWebServiceSoap(); //WeatherWebServiceSoap为调用的实现类
            ArrayOfString strArray = null;
            strArray = weatherWebServiceSoap.getWeatherbyCityName("成都");
            System.out.println(strArray.getString());
        }
        
    }
  5. 启动测试类并查看控制台。

    ws_weather_result

RESTful Web Services(JAX-RS)

定义

参考:什么是RESTful Web Services?

RESTful web services are built to work best on the Web. Representational State Transfer (REST) is an architectural style that specifies constraints, such as the uniform interface, that if applied to a web service induce desirable properties, such as performance, scalability, and modifiability, that enable services to work best on the Web. In the REST architectural style, data and functionality are considered resources and are accessed using Uniform Resource Identifiers (URIs), typically links on the Web. The resources are acted upon by using a set of simple, well-defined operations. The REST architectural style constrains an architecture to a client/server architecture and is designed to use a stateless communication protocol, typically HTTP. In the REST architecture style, clients and servers exchange representations of resources by using a standardized interface and protocol.

Restful web services 为的是在Web上工作的最好而创建的工具。Representational State Transfer (REST)是一种指定约束的设计风格,例如统一接口,它如果应用到webservice上将带来一些合适的特性,例如性能,可扩展性和可修改性,这些属性能够使services在Web上工作的最好。使用Rest设计风格,数据和功能都是被慎重考虑过的资源并且是通过Uniform Resource Identifiers (URIs) 来访问的。就像在Web上的链接。这些资源是按照一些简单并很好定义的的操作来采取行动的。Rest设计风格约束客户端/服务端统一用一种样式并且被设计成用一种无状态的通信协议,例如HTTP。在Rest的风格中,客户和服务端的交换代表资源用都在用标准的接口和协议。

JAX-RS常用注解

  • @Path,标注资源类或者方法的相对路径。
  • @GET,@PUT,@POST,@DELETE,标注方法是HTTP请求的类型。
  • @Produces,标注返回的MIME媒体类型。
  • @Consumes,标注可接受请求的MIME媒体类型。
  • @PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam,分别标注方法的参数来自于HTTP请求的不同位置。

使用案例

创建服务
  • pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-frontend-jaxrs -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxrs</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-transports-http-jetty -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>3.2.7</version>
    </dependency>
    
    <!--没有这两个依赖会:No message body writer has been found for class com.hgx.web.service.restful.bean.Student, ContentType: application/json-->
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-rs-extension-providers -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-extension-providers</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.codehaus.jettison/jettison -->
    <dependency>
        <groupId>org.codehaus.jettison</groupId>
        <artifactId>jettison</artifactId>
        <version>1.4.0</version>
    </dependency>
  • Student.java

    package com.xfc.jaxrs.entity;
    
    import javax.ws.rs.FormParam;
    import javax.xml.bind.annotation.XmlRootElement;
    import java.util.Date;
    
    @XmlRootElement
    public class Student {
    
        @FormParam("number")
        private Integer number;
    
        @FormParam("name")
        private String name;
    
        @FormParam("age")
        private Integer age;
    
        @FormParam("birth")
        private Date birth;
    
        public Student() {
        }
    
        public Student(Integer number, String name, Integer age, Date birth) {
            this.number = number;
            this.name = name;
            this.age = age;
            this.birth = birth;
        }
    
        public Integer getNumber() {
            return number;
        }
    
        public void setNumber(Integer number) {
            this.number = number;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Date getBirth() {
            return birth;
        }
    
        public void setBirth(Date birth) {
            this.birth = birth;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "number=" + number +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", birth=" + birth +
                    '}';
        }
    }
  • StudentServer.java

    package com.xfc.jaxrs.server;
    
    import com.xfc.jaxrs.entity.Student;
    
    import javax.ws.rs.*;
    import javax.ws.rs.core.MediaType;
    import java.sql.Date;
    import java.time.Instant;
    
    @Path("/rest")
    public class StudentServer {
    
        @GET
        @Path("/student/{id}")
        @Produces(MediaType.APPLICATION_JSON)
        public Student getStudentById(@PathParam("id") String id) {
            return new Student(6666, "张三", 20, Date.from(Instant.now()));
        }
    }
  • StudentServerMain.java

    package com.xfc.jaxrs;
    
    import com.xfc.jaxrs.server.StudentServer;
    import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
    
    public class StudentServerMain {
    
        public static void main(String[] args) {
            JAXRSServerFactoryBean jAXRSServerFactoryBean = new JAXRSServerFactoryBean();
            jAXRSServerFactoryBean.setAddress("http://localhost:8080/studentServce");
            jAXRSServerFactoryBean.setResourceClasses(StudentServer.class);
            jAXRSServerFactoryBean.create().start();
            System.out.println("student server 启动");
        }
    
    }
  • 执行 StudentServerMain.main()

    浏览器访问:http://localhost:8080/studentServce/rest/student/12

创建客户端
  • 客户端Get

    package com.xfc.jaxrs.client;
    
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.HttpStatus;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    
    public class RestGetClientMain {
    
        public static void main(String[] args) throws IOException {
            // 1. 创建 HttpClient 的实例
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 2. 创建某种连接方法的实例
            HttpGet httpGet = new HttpGet("http://localhost:8080/studentServce/rest/student/12");
            // 3. 调用第一步中创建好的实例的execute方法来执行第二步中创建好的链接类实例
            HttpResponse httpResponse = httpClient.execute(httpGet);
            // 4. 读response获取HttpEntity
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = httpResponse.getEntity();
                // 5. 对得到后的内容进行处理
                String result = EntityUtils.toString(entity, "utf-8");
                System.out.println("result = " + result);
                EntityUtils.consume(entity);
            } else {
                System.err.println(httpResponse.getStatusLine());
            }
            // 6. 释放连接。无论执行方法是否成功,都必须释放连接
            httpClient.close();
        }
    }

    执行结果:

    result = {"student":{"age":20,"birth":"2020-11-30T15:02:47.325+08:00","name":"张三","number":6666}}
  • 客户端Post

    修改服务端StudentServer.java

    package com.xfc.jaxrs.server;
    
    import com.xfc.jaxrs.entity.Student;
    
    import javax.ws.rs.*;
    
    @Path("/rest")
    public class StudentServer {
    
        @POST
        @Path("/student")
        @Consumes("application/x-www-form-urlencoded")
        public String Student(@BeanParam Student student) {
            return "success:" + student.toString();
        }
        
    }

    创建Post客户端

    package com.xfc.jaxrs.client;
    
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.HttpStatus;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    
    import java.io.IOException;
    import java.time.Instant;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    @SuppressWarnings("all")
    public class RestPostClientMain {
    
        public static void main(String[] args) throws ClientProtocolException, IOException {
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            HttpPost httpPost = new HttpPost("http://localhost:8080/studentServce/rest/student");
            List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
            list.add(new BasicNameValuePair("number", "0222"));
            list.add(new BasicNameValuePair("name", "李四"));
            list.add(new BasicNameValuePair("age", "19"));
            list.add(new BasicNameValuePair("birth", Date.from(Instant.now()).toString()));
    
            HttpEntity httpEntity = new UrlEncodedFormEntity(list, "utf-8");
            httpPost.setEntity(httpEntity);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = httpResponse.getEntity();
                String result = EntityUtils.toString(entity, "utf-8");
                System.out.println("client result = " + result);
                EntityUtils.consume(entity);
            } else {
                System.err.println(httpResponse.getStatusLine());
            }
            httpClient.close();
        }
    
    }

    执行结果:

    client result = success:Student{number=222, name=‘李四’, age=19, birth=Tue Dec 01 05:14:00 CST 2020}

Spring整合CXF

  1. 创建maven项目并添加依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    
    <!-- 添加CXF dependency  -->
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-frontend-jaxws -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-transports-http -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-frontend-jaxrs -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxrs</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-transports-http-jetty -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http-jetty</artifactId>
        <version>3.2.7</version>
    </dependency>
    
    <!--没有这两个依赖会:No message body writer has been found for class com.hgx.web.service.restful.bean.Student, ContentType: application/json-->
    <!--https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-rs-extension-providers-->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-extension-providers</artifactId>
        <version>3.2.7</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.codehaus.jettison/jettison -->
    <dependency>
        <groupId>org.codehaus.jettison</groupId>
        <artifactId>jettison</artifactId>
        <version>1.4.0</version>
    </dependency>
    
    <!--解决rest风格的api没有wadl-->
    <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-rs-service-description -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-service-description</artifactId>
        <version>3.2.7</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
    </dependency>
  2. 创建实体对象

    Customer.java

    package com.xfc.entity;
    
    public class Customer {
    
        private String id;
        private String name;
        private int age;
    
        public Customer(String id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
        
        // getter and setter
    }
  3. 创建HelloWorld接口及其实现

    HelloWorld.java

    package com.xfc.cxf;
    
    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebResult;
    import javax.jws.WebService;
    
    @WebService
    public interface HelloWorld {
    
        @WebMethod
        @WebResult(name = "sayHelloResult")
        String sayHello(@WebParam(name = "userName") String name, @WebParam(name = "userAge") int age);
    }

    HelloWorldImpl.java

    package com.xfc.cxf.impl;
    
    import com.xfc.cxf.HelloWorld;
    
    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebResult;
    
    public class HelloWorldImpl implements HelloWorld {
        @Override
        @WebMethod
        @WebResult(name = "sayHelloResult")
        public String sayHello(@WebParam(name = "userName") String name, @WebParam(name = "userAge") int age) {
            return "spring say hello to: " + name + "\t" + "age: " + age;
        }
    }
  4. 创建服务处理类

    CustomerService.java

    package com.xfc.service;
    
    import com.google.gson.Gson;
    import com.xfc.entity.Customer;
    
    import javax.ws.rs.*;
    
    @Path("/crm")
    public class CustomerService {
    
        @GET
        @Path("/customer/{customer_id}")
        @Produces("application/json")
        public Customer getCustomerById(@PathParam("customer_id") String customer_id) {
            Customer customer = new Customer(customer_id, "z3", 18);
            return customer;
        }
    
        @POST
        @Path("/addcustomer")
        @Consumes("application/json")
        @Produces("application/json")
        public String addCustomer(String customer_json) {
            Gson gson = new Gson();
            Customer customer = (Customer) gson.fromJson(customer_json, Customer.class);
            System.out.println(customer);
            return "success:  " + customer.toString();
        }
    
    }
  5. 配置 application-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:jaxws="http://cxf.apache.org/jaxws"
           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/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
    
        <import resource="classpath:META-INF/cxf/cxf.xml"/>
    
        <jaxws:endpoint id="helloworld" implementor="com.xfc.cxf.impl.HelloWorldImpl" address="/HelloWorld"></jaxws:endpoint>
    
        <jaxrs:server id="customerService" address="/CustService">
            <jaxrs:serviceBeans>
                <bean class="com.xfc.service.CustomerService"/>
            </jaxrs:serviceBeans>
        </jaxrs:server>
    </beans>
  6. 配置 web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <!-- 配置 Spring 配置文件的名称和位置 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application-cxf.xml</param-value>
        </context-param>
    
        <!-- 启动 IOC 容器的 ServletContextListener -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <!--webservice -->
        <servlet>
            <display-name>spring-cxf</display-name>
            <servlet-name>spring-cxf</servlet-name>
            <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>spring-cxf</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
        <!--webservice-->
    
    </web-app>
  7. 配置完成后通过tomcat容器启动项目。

  8. 浏览器访问:http://localhost:8080/spring_cxf

    spring_cxf_view

参考

版权声明

本文链接:https://www.chinmoku.cc/java/framework/webservice-tutorial/

本博客中的所有内容,包括但不限于文字、图片、音频、视频、图表和其他可视化材料,均受版权法保护。未经本博客所有者书面授权许可,禁止在任何媒体、网站、社交平台或其他渠道上复制、传播、修改、发布、展示或以任何其他方式使用此博客中的任何内容。

Press ESC to close