Web service介绍
- webservice是什么?
- web服务:服务器端整出一些资源可以让客户端应用访问(获取数据)
- 一个跨语言、跨平台的规范(抽象)
- 多个跨平台、跨语言的应用间通信整合的方案(实际)
- 。。。
- 为什么要用Web service?
- 业务场景:
- 应用A: java写的,运行在windows平台下 List<User> getAllUsers();
- 应用B: c语言写的,运行在linux平台下 需要请求应用A的getAllUsers()得到所有的user信息来展示
- qunar与航司接口交互数据
- 同一家公司的新旧应用 不同公司的应用间
- 一些提供数据的内容聚合应用:天气预报、股票行情
- web service能解决: 跨平台调用 跨语言调用 远程调用
- 业务场景:
- 相关术语
- WSDL:web service definition language
- 定义了web service的服务器端与客户端应用交互传递请求和响应数据的格式和方式
- SOAP:simple object access protocol
- http + xml
- SOAP把XML的使用代码化为请求和响应参数编码模式,并用HTTP作传输、依赖于wsdl文档的定义
- SEI:Service EndPoint Interface
- web service的终端接口,就是服务器端用来处理请求的接口(其中的方法就是处理请求的方法)
- UDDI :Universal Description, Discovery, and Integration
- 它是一个基于XML的跨平台的描述规范,可以使世界范围内的企业在互联网上发布自己所提供的服务。该规范包含了许多相关的文档和一个XML Schema。该XML schema定义了一个基于SOAP的编程协议用于注册和发现一个Web Service。web服务UDDI专题
- WSDL:web service definition language
- 比如两家公司的合作,SOAP 就像两个公司之间签的合同,约束双方按一定规矩和标准办事。WSDL 则像说明书,告诉别人你有什么,能给别人提供什么服务。
- Java开发WebService的框架
- JAX-WS、AXIS、AXIS2(多语言)、CXF(与Spring集成)...
- 与http比较
- 1.接口中实现的方法和要求参数一目了然
- 2.不用担心大小写问题
- 3.不用写额外的xml解析代码
- 4.代码中不用多次声明认证(账号,密码)参数
- 5.传递参数可以为数组,对象等...
- 传递结构化的数据,可读性好,效率并不高
- 相比httpservice能处理些更加复杂的数据类型
- 安全
- 传输 SSL/HTTPS 对连接加密,而不是传输数据
- 消息 数据加密(XML Encryption) 数字签名(XML-DSIG)
- 底层架构 利用应用服务安全机制
webservice开发
- 服务端
- 定义SEI
@WebService public interface StudentWS { @WebMethod Student getStudentById(int id); @WebMethod List<Student> getAllStudents(); }
- 定义SEI的实现
@WebService public class StudentWSImpl implements StudentWS { private static Map<Integer, Student> studentMap; static { studentMap = Maps.newHashMap(); Student tom = new Student(1, "Tom", 90); Student jack = new Student(2, "Jack", 93); Student mike = new Student(3, "Mike", 100); studentMap.put(tom.getId(),tom); studentMap.put(jack.getId(), jack); studentMap.put(mike.getId(), mike); } public Student getStudentById(int id) { return studentMap.get(id); } public List<Student> getAllStudents() { return new ArrayList<Student>(studentMap.values()); } }
- 发布
public class Server { public static void main(String[] args) { String address = "http://localhost:8080/studets"; Endpoint publish = Endpoint.publish(address, new StudentWSImpl()); System.out.println("Server : 发布服务 " + publish.isPublished()); } }
通过在浏览器中打开http://localhost:8080/studets?wsdl 来验证服务端是否启动,并能获得wsdl文档
- 定义SEI
- 客户端
- 获取客户端代码
在src目录下执行:wsimport -keep http://localhost:8080/studets?wsdl 即可
-
- 分析wsdl文档
<?xml version="1.0" encoding="UTF-8"?> <!-- wsdl的作用:定义了webservice的服务器端与客户端应用交互传递请求和响应数据的格式和方式、请求的url --> <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws.song.qunar.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws.song.qunar.com/" name="StudentWSImplService"> <!-- 定义当前wsdl文档中所使用的标签,很重要的一部分为soap消息中xml片断所包含的一些标签 <xs:schema xmlns:tns="http://ws.song.qunar.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://ws.song.qunar.com/"> <xs:element name="getAllStudents" type="tns:getAllStudents"></xs:element> <xs:element name="getAllStudentsResponse" type="tns:getAllStudentsResponse"></xs:element> <xs:element name="getStudentById" type="tns:getStudentById"></xs:element> <xs:element name="getStudentByIdResponse" type="tns:getStudentByIdResponse"></xs:element> <xs:complexType name="getStudentById"> <xs:sequence> <xs:element name="arg0" type="xs:int"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="getStudentByIdResponse"> <xs:sequence> <xs:element name="return" type="tns:student" minOccurs="0"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="student"> <xs:sequence> <xs:element name="id" type="xs:int"></xs:element> <xs:element name="name" type="xs:string" minOccurs="0"></xs:element> <xs:element name="score" type="xs:float"></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="getAllStudents"> <xs:sequence></xs:sequence> </xs:complexType> <xs:complexType name="getAllStudentsResponse"> <xs:sequence> <xs:element name="return" type="tns:student" minOccurs="0" maxOccurs="unbounded"></xs:element> </xs:sequence> </xs:complexType> </xs:schema> --> <types> <xsd:schema> <xsd:import namespace="http://ws.song.qunar.com/" schemaLocation="http://localhost:8080/studets?xsd=1"></xsd:import> </xsd:schema> </types> <!-- 定义请求消息,它的个数为SEI方法个数的2倍 message name 指定消息的名称 part element 指定消息的组成,依赖<types>中定义的某个element --> <message name="getStudentById"> <part name="parameters" element="tns:getStudentById"></part> </message> <message name="getStudentByIdResponse"> <part name="parameters" element="tns:getStudentByIdResponse"></part> </message> <message name="getAllStudents"> <part name="parameters" element="tns:getAllStudents"></part> </message> <message name="getAllStudentsResponse"> <part name="parameters" element="tns:getAllStudentsResponse"></part> </message> <!-- 定义SEI接口 portType name 指定SEI接口名 operation 接口的操作,也就是其方法 input message 服务器端接收的消息,依赖指定的<message>,也就是将哪个消息作为请求消息对应方法的参数 output message 指定服务器返回的消息,依赖指定的<message>,也就是将哪个消息作为响应消息对应方法的返回值 --> <portType name="StudentWSImpl"> <operation name="getStudentById"> <input wsam:Action="http://ws.song.qunar.com/StudentWSImpl/getStudentByIdRequest" message="tns:getStudentById"></input> <output wsam:Action="http://ws.song.qunar.com/StudentWSImpl/getStudentByIdResponse" message="tns:getStudentByIdResponse"></output> </operation> <operation name="getAllStudents"> <input wsam:Action="http://ws.song.qunar.com/StudentWSImpl/getAllStudentsRequest" message="tns:getAllStudents"></input> <output wsam:Action="http://ws.song.qunar.com/StudentWSImpl/getAllStudentsResponse" message="tns:getAllStudentsResponse"></output> </operation> </portType> <!-- 定义服务器端处理请求的SEI实现类对象 binding type :参照<portType>所定义的SEI soap:binding : 绑定的方式,也就数据传递的方式 为文档(即xml) input : 指定请求消息(与<portType>中的input对应) output:指定响应消息(与<portType>中的output对应) body use="literal" 消息体为文本 --> <binding name="StudentWSImplPortBinding" type="tns:StudentWSImpl"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding> <operation name="getStudentById"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal"></soap:body> </input> <output> <soap:body use="literal"></soap:body> </output> </operation> <operation name="getAllStudents"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal"></soap:body> </input> <output> <soap:body use="literal"></soap:body> </output> </operation> </binding> <!-- 定义客户端调用web service的入口 service name :生产客户端的SEI接口实现的工厂类 port binding :处理请求的服务器端的SEI接口实现类对象 address location :web service的请求url --> <service name="StudentWSImplService"> <port name="StudentWSImplPort" binding="tns:StudentWSImplPortBinding"> <soap:address location="http://localhost:8080/studets"></soap:address> </port> </service> </definitions>
- 分析wsdl文档
-
- 获取SEI对象,发送webservice请求
public class Client { public static void main(String[] args) { StudentWSImpl studentWS = new StudentWSImplService().getStudentWSImplPort(); Student student = studentWS.getStudentById(1); System.out.println(student); List<Student> students = studentWS.getAllStudents(); System.out.println(students); } }
- 获取SEI对象,发送webservice请求
服务端与客户端交互
- 1. 客户端调用:getStudentById(1),根据wsdl文档生成一个xml片断
-
<?xml version="1.0" standalone="no"?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:getStudentById xmlns:ns2="http://ws.ws.song.qunar.com/"> <arg0>1</arg0> </ns2:getStudentById> </S:Body> </S:Envelope>
- 2. 将上面的xml数据作为请求体,向服务器发送一个http请求(即soap消息, in消息)
- 3. 服务器端接收到这个请求后,取出请求体的内容
- 4. 服务器解析请求体,得到数据,并调用对应的web service对象的方法(依据wsdl文档)
- 5. 将方法执行的返回值,根据wsdl文档生成一个新的xml片断:
-
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:getStudentByIdResponse xmlns:ns2="http://ws.ws.song.qunar.com/"> <return> <id>1</id> <name>Jack</name> <score>90.0</score> </return> </ns2:getStudentByIdResponse> </soap:Body> </soap:Envelope>
- 6. 将新xml片断作为响应体,返回给客户端(soap消息, out消息)
- 7. 客户端接收到响应数据,解析其响应体中的xml片断,封装成student对象
- 8. 将生成的student对象作为getStudentById(1)的返回值,整个请求结束
小结:
Web Service好比一个服务供应商,给其他厂家提供基础服务,其他厂家再将这个服务包装成自己的产品或者服务提供给别人或自己使用。