WebService详解

webservice 基本介绍

什么是web服务

这里列举一些常见的web服务:

1.  手机淘宝、京东….

2.  天气预报

3.  手机号归属地

4.  股票查询

5.  发手机短消息

6.  手机充值功能

7.  中英文翻译

8.  银行转账业务

9.  公司的“进销存系统”在某商品缺货时自动给供应商下订单

webservice 即web服务,它是一种跨编程语言和跨操作系统平台的远程调用技术。

Web Service所使用的是Internet上统一、开放的标准,如HTTP、XML、SOAP(简单对象访问协议)、WSDL等,所以Web Service可以在任何支持这些标准的环境(Windows,Linux)中使用。

这有助于大量异构程序和平台之间的互操作性,从而使存在的应用程序能够被广泛的用户访问。

JAVA 中共有三种WebService 规范,分别是JAX-WS(JAX-RPC)、JAXM&SAAJ、JAX-RS。

webService三要素:soap、wsdl、uddi

SOAP 协议

SOAP即简单对象访问协议(Simple Object Access Protocol),它是用于交换XML(标准通用标记语言下的一个子集)编码信息的轻量级协议。它有三个主要方面:XML-envelope为描述信息内容和如何处理内容定义了框架,将程序对象编码成为XML对象的规则,执行远程过程调用(RPC)的约定。SOAP可以运行在任何其他传输协议上。

SOAP作为一个基于XML语言的协议用于有网上传输数据。

SOAP = 在HTTP的基础上+XML数据。

SOAP是基于HTTP的。

SOAP的组成如下:

  • Envelope – 必须的部分。以XML的根元素出现。
  • Headers – 可选的。
  • Body – 必须的。在body部分,包含要执行的服务器的方法。和发送到服务器的数据。

wsdl说明书

Web Service描述语言WSDL(SebService Definition Language)就是用机器能阅读的方式提供的一个正式描述文档而基于XML(标准通用标记语言下的一个子集)的语言,用于描述Web Service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的。

(1)通过wsdl说明书,就可以描述webservice服务端对外发布的服务;

(2)wsdl说明书是一个基于xml文件,通过xml语言描述整个服务;

(3)在wsdl说明中,描述了:

  • ​对外发布的服务名称(类)
  • 接口方法名称(方法)
  • 接口参数(方法参数)
  • ​服务返回的数据类型(方法返回值)

UDDI

Web 服务提供商又如何将自己开发的 Web 服务公布到因特网上,

这就需要使用到 UDDI 了,UDDI的话,是一个跨产业,跨平台的开放性架构,可以帮助 Web 服务提供商在互联网上发布 Web 服务的信息。

UDDI 是一种目录服务,企业可以通过 UDDI 来注册和搜索 Web 服务。

简单来时候话,UDDI 就是一个目录,只不过在这个目录中存放的是一些关于 Web 服务的信息而已。

并且 UDDI 通过SOAP 进行通讯,构建于 . Net 之上。

UDDI 即 Universal Description,Discovery andIntegration,也就是通用的描述,发现以及整合。

UDDI 的目的是为电子商务建立标准;UDDI是一套基于Web的、分布式的、为WebService提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。

应用场景

Web Service 可以适用于应用程序集成、软件重用、跨防火墙通信等需求。不同的业务要求不同。具体如下:

(1)   跨防火墙通信

(2)   应用系统集成

(3)   软件和数据重用

简单来说,如果一个功能,需要被多个系统使用可以使用webservice开发一个服务端接口,供不同的客户端应用。主要应用在企业内部系统之间的接口调用、面向公网的webservice服务。

优缺点

优点

1、异构平台的互通性

理论上, Web Service 最大的优势是提供了异构平台的无缝街接技术手段。由于不同的用户使用不同的硬件平台,不同的操作平台,不同的操作系统,不同的软件,不同的协议通信,这就产生了互相通信的需求。 Web Service 使任何两个应用程序,只要能读写XML,那么就能互相通信。

2、更广泛的软件复用(例如手机淘宝可以复用已有淘宝的业务逻辑)

软件的复用技术通过组合已有模块来搭建应用程序,能大幅度提高软件的生产效率和质量。用户只要获得了描述 Web Service 的 WSDL 文件,就可以方便地生成客户端代理,并通过代理访问 Web Service 。

3、成本低、可读性强、应用范围广

Web Service 可用基于 XML 的 SOAP 来表示数据和调用请求。并且通过 HTTP 协议传输 XML 格式的数据

缺点

由于soap是基于xml传输,本身使用xml传输会传输一些无关内容从而影响效率,随着soap协议的完善,soap协议增加了许多内容,这样就导致了使用soap去完成简单的数据传输而携带的信息更多效率再受影响;

Web Service作为web跨平台访问的标准技术,很多公司都限定要求使用Web Service,但如果是简单的接口可以直接使用http传输自定义数据格式,开发更快捷。

面向服务架构SOA

SOA(Service-OrientedArchitecture)面向服务架构是一种思想,它将应用程序的不同功能单元通过中立的契约(独立于硬件平台、操作系统和编程语言)联系起来,使得各种形式的功能单元更好的集成。目前来说,WebService 是SOA 的一种较好的实现方式,WebService 采用HTTP 作为传输协议,SOAP(Simple Object Access Protocol)作为传输消息的格式。但WebService 并不是完全符合SOA 的概念,因为SOAP 协议是WebService 的特有协议,并未符合SOA 的传输协议透明化的要求。SOAP 是一种应用协议,早期应用于RPC 的实现,传输协议可以依赖于HTTP、SMTP 等。

SOA 的产生共经历了如下过程:

通常采用SOA 的系统叫做服务总线(BUS),结构如下图所示:

ApacheCXF 框架介绍

关于 Apache CXF

Apache CXF = Celtix + XFire,ApacheCXF 的前身叫 Apache CeltiXfire,现在已经正式更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了 Celtix 和XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding 、DataBinding、Transport 以及各种 Format 的支持,并且可以根据实际项目的需要,采用代码优先(Code First)或者 WSDL 优先(WSDL First)来轻松地实现 Web Services 的发布和使用。目前它仍只是 Apache 的一个孵化项目。

Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTfulHTTP 或者 CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。

功能特性

CXF 包含了大量的功能特性,但是主要集中在以下几个方面:

(1)支持 Web Services 标准:CXF 支持多种 Web Services 标准,包含 SOAP、Basic Profile、WS-Addressing、WS-Policy、WS-ReliableMessaging 和 WS-Security。

(2) Frontends:CXF 支持多种“Frontend”编程模型,CXF 实现了 JAX-WS API (遵循 JAX-WS 2.0 TCK 版本),它也包含一个“simple frontend”允许客户端和 EndPoint 的创建,而不需要 Annotation 注解。CXF 既支持 WSDL 优先开发,也支持从 Java 的代码优先开发模式。

(3)容易使用: CXF 设计得更加直观与容易使用。有大量简单的 API 用来快速地构建代码优先的 Services,各种 Maven 的插件也使集成更加容易,支持 JAX-WS API ,支持 Spring 2.0 更加简化的 XML 配置方式,等等。

(4)支持二进制和遗留协议:CXF 的设计是一种可插拨的架构,既可以支持 XML ,也可以支持非 XML 的类型绑定,比如:JSON 和 CORBA。

实现WebService(Jax-ws)

服务接口模块

注:因为客户端和服务端都需要引用该接口,所以一般会把公共的服务接口和实体类都是抽取出来,作为一个单独的模块,然后在各自的pom文件中引入。

首先需要添加依赖:

<!-- 要进行jaxws 服务开发 -->
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-frontend-jaxws</artifactId>
	<version>3.1.15</version>
</dependency>
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-transports-http</artifactId>
	<version>3.1.15</version>
</dependency>
<!-- 内置jetty web服务器 -->
<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-transports-http-jetty</artifactId>
	<version>3.1.15</version>
</dependency>

定义相关接口:

import javax.jws.WebService;

/**
 * 对外发布服务的接口
 */
@WebService
public interface HelloService {
    /**
     * 对外发布服务的接口的方法
     *
     * @param name
     * @return
     */
    String sayHello(String name);
}

服务端

创建项目

添加cxf依赖

pom.xml文件引入服务接口模块(引入后一些cxf依赖也引入了)

服务接口实现

public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return name + "Welcome to yu";
    }
}

发布服务

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

public class Server {

    public static void main(String[] args) {
        //发布服务的工厂
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        //设置服务地址
        factory.setAddress("http://localhost:8010/ws/hello");
        //设置服务类
        factory.setServiceBean(new HelloServiceImpl());
        //添加日志输入、输出拦截器,观察soap请求,soap响应内容
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutFaultInterceptors().add(new LoggingOutInterceptor());
        //发布服务
        factory.create();
        System.out.println("发布服务成功,端口8010!!!!");
    }
}

访问wsdl说明书

访问:http://localhost:8010/ws/hello?wsdl

客户端

写客户端之前要先明确:

  1. 服务端地址
  2. 服务端接口、接口方法(方法参数、返回值)

创建项目

pom.xml文件引入服务接口模块(引入后一些cxf依赖也引入了)

远程访问服务端

public class Client {
    public static void main(String[] args) {
        //服务接口访问地址 http://localhost:8010/ws/hello
        //创建cxf代理工厂
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        //设置远程访问服务端地址
        factory.setAddress("http://localhost:8010/ws/hello");
        //设置接口类型
        factory.setServiceClass(HelloService.class);
        //对接口生成代理对象
        HelloService helloService = factory.create(HelloService.class);
        // 代理对象 class com.sun.proxy.$Proxy34 Java代理:1静态代理 2动态代理(Jdk接口代理,cglib子类代理) ¥CGLIB
        System.out.println(helloService.getClass());
        //远程访问服务端方法
        String content = helloService.sayHello("Jet");
        System.out.println(content);
    }
}

添加日志拦截器,观察soap协议内容

服务端添加:

//添加日志输入、输出拦截器,观察soap请求,soap响应内容
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutFaultInterceptors().add(new LoggingOutInterceptor());

实现webservice (Jax-rs)

基于restful风格的webservice,请求使用的是http协议,可以传递xml/json数据

服务端

添加依赖

<!-- 要进行jaxws 服务开发 -->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>3.1.15</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>3.1.15</version>
</dependency>
<!-- 内置jetty web服务器 -->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http-jetty</artifactId>
    <version>3.1.15</version>
</dependency>

<!-- 客户端调用时候使用的包(WebClient工具类调用服务端) -->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-client</artifactId>
    <version>3.1.15</version>
</dependency>

<!-- 基于restful风格的webservice,客户端与服务端之间可以传递json,这个就是json支持相关包 -->
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-extension-providers</artifactId>
    <version>3.1.15</version>
</dependency>

<!--
            没有引入jettison的jar包会出现这个错误:
            javax.ws.rs.ProcessingException: No message body writer has been found for class
            com.harvey.changyong.cxfrest.entity.User, ContentType: application/json
        -->
<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.7</version>
</dependency>

服务接口、实现、实体类

1、实体类

/**
 * @XmlRootElement 指定根元素,作用:客户端与服务端传递对象数据时候,序列化为xml或json的根元素的名称
 * 客户端与服务端传递XML:
 * <Car1></Car> 这里的根元素Car是由name="Car"指定的
 * <p>
 * 客户端与服务端传递JSON:
 * {"Car": {"id":100,"name":"","price":100}}
 */
@XmlRootElement(name = "Car")
public class Car {
    private Integer id;
    private String carName;
    private Double price;

    public Car() {
    }

    public Car(Integer id, String carName, Double price) {
        this.id = id;
        this.carName = carName;
        this.price = price;
    }

    public Integer getId() {
        return id;
    }

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

    public String getCarName() {
        return carName;
    }

    public void setCarName(String carName) {
        this.carName = carName;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}
@XmlRootElement(name = "User")
public class User{
    private Integer id;
    private String username;
    private String city;
    private List<Car> cars = new ArrayList<Car>();

    public User() {
    }

    public User(Integer id, String username, String city, List<Car> cars) {
        this.id = id;
        this.username = username;
        this.city = city;
        this.cars = cars;
    }

    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;
    }
}

注解分析:

  • @XmlRootElement 指定根元素。作用:客户端与服务端传递对象数据时候,序列化为xml或json的根元素的名称
  • @Path("/userService") 路径;访问当前服务接口时候的路径、接口方法的路径。
  • @POST   insert操作
  • @PUT    update操作
  • @GET    select 查询操作
  • @DELETE   delete删除操作
  • @Consumes 服务端支持的请求的数据格式(xml、json)
  • @Produces 服务端支持的响应的数据格式

2、服务接口

@Path("/userService") // 路径;访问当前服务接口时候的路径。
@Produces("*/*")
public interface IUserService {
    @POST
    @Path("/user") // 路径; 访问当前服务接口的方法路径
    // @Consumes 服务端支持的请求的数据格式(xml、json)
    @Consumes({"application/xml", "application/json"})
    void saveUser(User user);

    @PUT
    @Path("/user")
    @Consumes({"application/xml", "application/json"})
    void updateUser(User user);

    @GET
    @Path("/user")
    // @Produces 服务端支持的响应的数据格式
    @Produces({"application/xml", "application/json"})
    List<User> findAllUsers();

    @GET
    @Path("/user/{id}")
    @Consumes("application/xml")
    @Produces({"application/xml", "application/json"})
    User finUserById(@PathParam("id") Integer id);

    @DELETE
    @Path("/user/{id}")
    @Consumes({"application/xml", "application/json"})
    void deleteUser(@PathParam("id") Integer id);
}

3、接口实现

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> findAllUsers() {
        List<User> users = new ArrayList<User>();
        // 汽车
        List<Car> carList1 = new ArrayList<Car>();
        Car car1 = new Car(101, "保时捷", 1000000d);
        Car car2 = new Car(102, "林肯", 400000d);
        carList1.add(car1);
        carList1.add(car2);
        // 用户
        User user1 = new User(1, "小明", "广州", carList1);
        User user2 = new User(2, "小丽", "深圳", carList1);
        // 用户集合
        users.add(user1);
        users.add(user2);
        return users;
    }

    public User finUserById(Integer id) {
        if (id == 1) {
            return new User(1, "小明", "广州", null);
        }
        return null;
    }

    public void deleteUser(Integer id) {
        System.out.println("delete user id :" + id);
    }
}

4、发布服务

public class Server {

    /**
     * 发布restful风格的webservice的服务
     */
    public static void main(String[] args) {
        //1.创建服务工厂
        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
        //2.设置服务地址、
        factory.setAddress("http://localhost:8001/rs");
        //3.实例化服务类、
        factory.setServiceBean(new UserServiceImpl());
        // 添加日志拦截器
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());
        //4.创建服务
        factory.create();
        System.out.println("发布服务成功..8001");
    }
}

客户端

添加依赖

与服务端依赖一样

写junit,远程访问服务端

public class Client {

    @Test
    public void save() throws Exception {
        // 基于restful风格的webservice开发的客户端调用,直接通过一个类:WebClient类完成
        WebClient
                .create("http://localhost:8001/rs/userService/user") // 地址
                .type(MediaType.APPLICATION_JSON) // 请求数据格式是json
                .post(new User(100, "Kobe", "gz", null)); // 发送请求的类型
    }

    @Test
    public void update() throws Exception {
        WebClient
                .create("http://localhost:8001/ws/userService/user") // 地址
                .type(MediaType.APPLICATION_JSON) // 请求数据格式是json
                .put(new User(100, "Kobe", "gz", null)); // 发送请求的类型
    }

    @Test
    public void delete() throws Exception {
    }

    @Test
    public void findOne() throws Exception {
        User user =
                WebClient
                        .create("http://localhost:8001/ws/userService/user/1") // 地址
                        .accept(MediaType.APPLICATION_JSON) // 响应的数据格式
                        .get(User.class);
        System.out.println(user);
    }

    @Test
    public void findAll() throws Exception {
        Collection<? extends User> collection =
                WebClient
                        .create("http://localhost:8001/ws/userService/user")
                        .accept(MediaType.APPLICATION_JSON)
                        .getCollection(User.class);
        System.out.println(collection);
    }
}

 

posted @ 2022-09-30 16:21  残城碎梦  阅读(1280)  评论(0编辑  收藏  举报