-
提问:举例什么是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.测试
——————————————————————————