【Spring】WebService

本文详细介绍了Spring与Apache CXF实现WebService的相关内容,包括SOAP协议、WSDL、UDDI、JAX-WS和JAX-RS。讨论了WebService的优缺点、开发规范,以及RESTful风格与SOAP的区别。还展示了CXF如何实现JAX-WS和JAX-RS服务端和客户端,以及Spring整合CXF的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 提问:举例什么是Web服务?
    比如:
    手机淘宝、京东;
    天气预报;
    手机号归属地;
    股票查询;
    发手机短信;
    手机充值;
    中英文翻译;
    银行转帐;
    。。。

  • 提问:WebService应用场景?

(体现了WebService软件复用的优势)
在这里插入图片描述


WebService

WebService,即Web服务;
是一种【跨编程语言】和【跨操作平台】的【远程调用技术】;
在这里插入图片描述

  • 提问:优点?

  • 1.异构平台的互通性:(最大优势)
    WebService使任何两个应用程序只要能读写XML,就能互相通信;

  • 2.更广泛的软件复用
    比如手机淘宝可以服用淘宝的业务逻辑;用户只要获得了WSDL文件,就可方便生成客户端代理,通过他访问WebService;
    (如 WebService应用场景? 那张插图)

  • 3.成本低、可读性强、应用范围广
    WebService可用基于XML的SOAP协议来表示数据和调用请求,并通过HTTP协议传输XML数据;

  • 4.快速的软件开发方式:
    每个WebService成为一个生产者,不同生产者可以互协助完成整个应用;

  • 5.【最重要】:Client和Server可能由不同语言开发,但WebService提供服务接口后,Client和Server之间可以传递对象!
    —————————————

  • 提问:缺点?

因为SOAP基于XML传输,本身使用XML传输会传输一些无关内容(标签开始、标签结束)而影响效率;
随着SOAP协议的完善(可以传JSON了),SOAP协议增加了很多内容,这样导致使用SOAP完成简单的数据传输而懈怠的信息越来越多,而再次影响效率;

WebService作为Web跨平台访问的标准技术,很多公司规定只使用WebService;
但如果是简单接口,可以直接用HTTP传输自定义数据格式,这样开发更方便;
—————————————

——————————————————————————

WebService 开发规范

  • 提问:Java中的WebService开发规范?

三种;
1.JAX-WS (JAX-RPC) (常用)用SOAP协议;传输XML数据;
2.JAXM&SAAJ
3.JAX-RS (最流行)(REST风格)用HTTP协议;传输XML / JSON数据;

—————————————

  • 1.JAX-WS (Java API For XML-WebService)

—————————————

  • 2.JAXM & SAAJ (Java API For XML-WebService)

他会暴露更多SOAP协议的细节,所以需要手动操作协议内容,可以选择他;
少用;
—————————————

  • 3.JAX-RS (REST)

是Java针对REST风格指定的一套Web服务规范;
推出得较晚;比第一种效率更高;
——————————————————————————

  • 提问:WebService三要素?

1.SOAP
2.WSDL
3.UDDI
——————————————————————————

SOAP协议

简单对象访问协议 Simple Object Access Protocol
适用于交换XML编码信息的轻量级协议;
(用于Client和Server通讯的协议)

特点:
HTTP + XML数据;
意思是,SOAP是基于HTTP的,

  • 提问:SOAP协议是哪一种开发规范下使用的协议?

JAX-WS!!
不要记成 JAX-RS!!

——————————————————————————

WSDL 说明书

WebService Definition Language

他是对SOAP协议的描述!!!
他是一个XML文件,给机器阅读的(因为XML,所以人也可以阅读);
记载了接口、方法、参数、返回值;
得到了他,我们就能调用想调用的接口;
——————————————————————————

UDDI

简单来说,UDDI是一个目录,存放的事Web服务的信息;
Web服务器提供商需要把自己开发的Web服务公布到Internet时,就需要用UDDI;
用它来注册和搜索Web服务;

——————————————————————————

SOA 面向服务架构

SOA ( Service-Oriented Architecture ) 面向服务架构是一种思想;
(如 WebService应用场景? 那张插图)
他把程序不同功能单元通过中立的契约联系起来,使各种形式的功能单元更好地集成;

  • 提问:WebService 和 SOA 的关系?

WebService是SOA一种较好的实现方式;
但WebService没有完全符合SOA的概念,因为SOAP协议是WebService的特有协议,未符合SOA的传输协议透明化的要求;
——————————————————————————

——————————————————————————

——————————————————————————

  • 提问:WebService和RESTful的区别?

RESTful是什么:
首先要了解什么是REST,REST就是(REpresentational State Transfer单词太长记不住就对了)是一种构架风格,REST指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或者设计就是RESTful,核心就是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性,为什么这么说,因为RESTful是无状态的,无状态是指任意一个web请求必须完全与其他请求隔离,是独立的,当请求端提出请求时,请求本身包含了这一请求的全部信息,这个约束提高系统的可伸缩性,可见性,可靠性。无状态优势就是在调用接口,操作资源的时候,可以不考虑上下文,不用考虑当前状态,降低复杂度。

WebService是什么:
WebService就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。也就是说,你可以通过编程的方法通过Web来调用这个应用程序。它可以跨编程语言,跨操作系统平台的这么一个远程调用技术,采用SOAP(面向对象访问协议)协议传输。

RESTful跟WebService的区别:
上面所述,REST是一种架构风格,其核心是面向资源,遵循CRUD原则,这个原则告诉我们对于资源只需要4种行为,分别是:创建,获取,更新和删除,并且这些资源执行的操作时通过HTTP协议规定的,而WebService底层是SOAP协议,核心是面向活动,有严格的规范和标准,包括安全,事务等方面。
那么我们是使用RESTful还是WebService就需要考虑资源本身的 ,看资源本身是那种简单的类似增删改查的业务操作,还是那种比较复杂,如转账,事务处理等。其次是看是否有严格的规范和标准的,而且有多个业务系统集成和开发的时候,我们使用SOAP协议就比较优势,如果是简单的数据操作,无事务处理,开发和调用比较简单的话使用REST架构风格比较有优势,较为复杂的面向活动的服务,我们使用REST意义不大。

总结:
它们之间没有好与坏,只有适合不适合,都各自有自己的优点。

——————————————————————————

Apache CXF

是WebService的实现框架,容易和Spring整合;

除了CXF之外,还有JWS、Axis2、XFire、Dubbo等框架都支持WebService实现;

写CXF框架,从大方向来说,分成【Client】和【Server】两个端;
——————————————————————————

CXF 实现 JAX-WS

先用IDEA创建一个Empty Project,再分别用模块实现各种…
在这里插入图片描述

JAX-WS 服务端

创建01_jaxws_server模块;

    <dependencies>

        <!-- JAX-WS -->

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.3.1</version>
        </dependency>

        <!-- Jetty 内置服务器 若项目发布到Tomcat下就不需要它-->

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                        <showWarnings>true</showWarnings>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

在这里插入图片描述
接口:HelloService

@WebService
public interface HelloService {
    public String sayHello(String name);
}

实现类:HelloService

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

测试类:Server

public class Server {
    public static void main(String[] args) {
        // 发布服务的工厂
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();

        // 设置服务地址(端口只要没有被占用就能用)
        factory.setAddress("http://localhost:8000/ws/hello");

        // 设置服务类
        factory.setServiceBean(new HelloServiceImpl());

        // 发布服务
        factory.create();

        System.out.println("发布服务成功,端口:8000。");
    }
}
输出:
发布服务成功,端口:8000。

OK

如何访问WSDL说明书?
服务地址后加上:?wsdl
即:http://localhost:8000/ws/hello?wsdl

在这里插入图片描述
——————————————————————————

JAX-WS 客户端

创建02_jaxws_client模块;
在这里插入图片描述
依赖一样;
一样的目录结构;
只需要和Server一样的接口文件 + 测试文件;

工作中,我们创建客户端时,一定要知道服务端的服务地址、对外发布服务的接口、方法、参数、返回值;
这些都在【接口说明文档】中有详细描述;
如果工作中没有,应该找人拿到这个资料;

把Server的接口文件复制到Client中来;

测试类:Client

public class Client {
    public static void main(String[] args) {

        // 创建CXF代理工厂
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        // 设置远程访问服务端地址
        factory.setAddress("http://localhost:8000/ws/hello");

        // 设置接口类型
        factory.setServiceClass(HelloService.class);

        // 对接口生成代理对象
        HelloService helloService = factory.create(HelloService.class);

        // 代理对象类型
        System.out.println(helloService.getClass());

        // 远程访问服务端方法
        String content = helloService.sayHello("Kelly");
        System.out.println(content);
    }
}
输出:
class com.sun.proxy.$Proxy35
Kelly Welcome to use WebService!

$Proxy代表JDK动态代理;

说明:客户端已经可以远程访问客户端了!
举例:如果Client和Server在深圳和广州,只需要把地址改成IP地址,就可以远程访问;
——————————————————————————

添加CXF日志拦截器 观察SOAP

之前的测试方法中:参数 "Kelly"、请求数据 "content"在SOAP中是怎么体现出的?

在测试类Server中添加:

        // 附:添加日志输入、输出拦截器、观察SOAP请求、SOAP相应内容
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());
        

但这两个方法已经被deprecated。
https://www.bilibili.com/video/av37531805/?p=13
暂未处理

——————————————————————————

JAX-WS Spring整合CXF实现WebService

——————————————————————————

CXF 实现 JAX-RS

【架构】RESTful API 介绍
https://blog.youkuaiyun.com/weixin_42915286/article/details/84880998

RESTful风格举例:

传统做法:
http://localhost:8080/prj/user/userAction?type=add
http://localhost:8080/prj/user/userAction?type=update
http://localhost:8080/prj/user/userAction?type=delete

RESTful风格做法:一个地址对应后台CRUD四个方法;
@Post
http://localhost:8080/prj/user/userAction
@Put
http://localhost:8080/prj/user/userAction
@Delete
http://localhost:8080/prj/user/userAction

RESTful风格更简洁,更有层次感,更易于浏览器缓存;
(浏览器根据地址缓存)
JAX-RS发布服务就是使用RESTful风格;
——————————————————————————

JAX-RS 服务端

    <!-- JAX-RS -->

    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
      <version>3.3.1</version>
    </dependency>

    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-rs-client</artifactId>
      <version>3.3.1</version>
    </dependency>

    <!-- JAX-RS 需要支持JSON -->

    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-rs-extension-providers</artifactId>
      <version>3.3.1</version>
    </dependency>

    <dependency>
      <groupId>org.codehaus.jettison</groupId>
      <artifactId>jettison</artifactId>
      <version>1.3.7</version>
    </dependency>

    <!-- Jetty 内置服务器 若项目发布到Tomcat下就不需要它-->

    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http-jetty</artifactId>
      <version>3.3.1</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.25</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
。。。
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.2</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>UTF-8</encoding>
            <showWarnings>true</showWarnings>
          </configuration>
        </plugin>
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;

// 基于restful风格的webservice,客户端与服务端之间通讯可以传递xml数据、json数据
// @XmlRootElement 指定对象序列化为xml或json数据时,根节点的名称:比如为"User123"

/*
 * xml:
 * <User123>
 *     <id></id>
 *     <username></username>
 *     <city></city>
 * </User123>
 *
 * json:
 * {"User123":{"id":100,"username":"jack","city":"广州"}}
 */

@XmlRootElement(name = "User")
public class User {
    private Integer Id;
    private String username;
    private String city;

    private List<Car> cars = new ArrayList<>();

    public Integer getId() {
        return Id;
    }

    public void setId(Integer id) {
        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 +
                '}';
    }
}

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Car")
public class Car {
    private Integer id;
    private String carName;
    private Double 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;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carName='" + carName + '\'' +
                ", price=" + price +
                '}';
    }
}

import com.test.Entity.User;
import javax.ws.rs.*;
import java.util.List;

// @Produces 服务器支持的【返回】的数据格式类型:("*/*") 任意类型
// @Produces({"application/xml","application/json"}) 只支持返回xml和json
// @Consumes 服务器支持的【请求】的数据格式类型

@Path("/userService")
@Produces("*/*")
public interface IUserService {

    @POST
    @Path("/user")
    @Consumes({"application/xml","application/json"})
    public void saveUser(User user);

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

    @GET
    @Path("/user")
    @Produces({"application/xml","application/json"})
    public List<User> findAllUsers();

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

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

public class Server {
    public static void main(String[] args) {
        // 创建发布服务的工厂
        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();

        // 设置服务地址
        factory.setAddress("http://localhost:8001/ws/");

        // 设置服务类
        factory.setServiceBean(new UserServiceImpl());

        // 添加日志,输入输出拦截器

        // 发布服务
        factory.create();

        System.out.println("发布服务成功,端口8001");
    }
}

输出:
发布服务成功,端口8001

——————————————————————————

JAX-RS 客户端 ( WebClient )

https://www.bilibili.com/video/av37531805/?p=16

把Server的Entity:Car、User复制到Client中;

public class Client {

    @Test
    public void testSave(){
        User user = new User();
        user.setId(100);
        user.setUsername("Jerry");
        user.setCity("广州");
        // 通过WebClient对象远程调用服务端
        WebClient
                .create("http://localhost:8001/ws/userService/user")
                .type(MediaType.APPLICATION_JSON) // 指定请求的数据格式为JSON
                .post(new User());
    }
    @Test
    public void testGet(){
        User user =
                WebClient
                        .create("http://localhost:8001/ws/userService/user/1")
                        .type(MediaType.APPLICATION_JSON)
                        .get(User.class);
        System.out.println(user);
    }
}

Test中输入的参数只有在Server配置了CXF日志拦截器后,才能在Server的返回中看到;

WebClient:
.create() 指定服务端地址;
.type() 指定请求数据格式(xml、json)MediaType.APPLICATION_JSON MediaType.APPLICATION_XML
.accept() 指定相应数据格式;
.post() / put() / delete() / get() 指定请求类型;
——————————————————————————

JAX-RS Spring整合CXF实现RESTful风格的WebService

—————————————
服务端
1.创建Web项目
2.添加依赖
3.web.xml
4.服务端口、实现、实体类
5.Spring整合CXF
6.发布服务

名称:05_jaxrs_spring_server

去掉了cxf-rt-transports-http-jetty(Jetty内置服务器),加入了两个Spring包,新增一个JUnit包;

    <!-- JAX-RS -->

    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxrs</artifactId>
      <version>3.3.1</version>
    </dependency>

    <!-- CXF 客户端 -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-rs-client</artifactId>
      <version>3.3.1</version>
    </dependency>

    <!-- JAX-RS 需要扩展JSON提供者 -->

    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-rs-extension-providers</artifactId>
      <version>3.3.1</version>
    </dependency>

    <!-- JAX-RS 需要扩展转换JSON工具包 -->
    <dependency>
      <groupId>org.codehaus.jettison</groupId>
      <artifactId>jettison</artifactId>
      <version>1.3.7</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.25</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!-- Spring-->

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <!-- JUnit 这两个可选-->

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.1.4.RELEASE</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
。。。

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.2</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>UTF-8</encoding>
            <showWarnings>true</showWarnings>
          </configuration>
        </plugin>

        <plugin>
          <groupId>org.apache.tomcat.maven</groupId>
          <artifactId>tomcat7-maven-plugin</artifactId>
          <version>2.2</version>
          <configuration>
            <port>8080</port>
            <path>/</path>
          </configuration>
        </plugin>

—————————————
客户端
1.创建项目
2.添加依赖
3.实体类
4.测试

——————————————————————————

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值