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
客户端
写客户端之前要先明确:
- 服务端地址
- 服务端接口、接口方法(方法参数、返回值)
创建项目
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);
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战