【Java】WebService笔记

本文详细介绍了Java中WebSocket的原理和通信特点,以及Socket在OSI七层模型中的位置。进一步探讨了使用Http协议访问应用层的优缺点,并深入讲解了WebService的技术规则,包括其依赖的SOAP和WSDL。此外,还介绍了CXF框架及其在SOA架构中的作用,以及如何通过CXF整合Spring发布WebService。
摘要由CSDN通过智能技术生成

目录

β.需求

-1.使用Socket(传输层)

*Socket原理

*Socket的通信特点

*再来复习一下OSI的七层模型:

0.使用Http协议访问(应用层)

*特点

1.WebService技术和规则

*前面两种访问第三方项目的方法都存在问题:

*WebService技术和规则

2.访问WebService的方式

* 一般访问方式  HttpClient

*推荐访问方式 wsimport 生成本地代理(本地有文件)(jdk6之后)

3.WSDL语法

3.1 eg:

3.2 @WebService 修改WSDL文件

4.CXF框架

4.1 CXF介绍

4.2 为什么要使用CXF

4.4 CXF整合Spring发布WebService

5. webservice 访问流程:


 

β.需求


需求:

- 不同的移动客户端访问(客户端无法调用服务端内部的方法)

- 需要访问第三方的项目 (比如查个天气、查手机的归属地等)

 

 

-1.使用Socket(传输层)


*Socket原理

Server代码:

package com.tencent.server;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketSer {
	
	public static void main(String[] args) throws Exception {
		// 1.建立服务器端的TCP Socket服务并监听指定端口
		ServerSocket ss = new ServerSocket(7777);
		// 2.创建从客户端通过ServerSocket监听的端口传来的Socket对象
		Socket s = null;
		// 2.1 使用flag是为了写ss.close()不提示不可达语句的错误
		boolean flag = true;
		// 3.获取客户端的数据
		while(flag) {
			s = ss.accept();
			System.out.println("Accept Success!!!");
			//从Socket输入流获取客户端发送过来的输出流
			InputStream in = s.getInputStream();
			byte[] buf = new byte[1024];
			int len = in.read(buf);
			String str = new String(buf, 0, len);
			System.out.println("客户端传来的数据:"+str);
			OutputStream out = s.getOutputStream();
			out.write(str.toUpperCase().getBytes());
			out.close();
			in.close();
			s.close();
		}
		ss.close();
	}
	
}

Client代码:

package com.tencent.client;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class SocketClient {
	public static void main(String[] args) throws Exception{
		Scanner input = new Scanner(System.in);
		
		// 1.创建一个从指定端口传递到服务器端的Socket对象
		Socket s = new Socket("127.0.0.1",7777);
		// 2.用Socket对象来获取Socket中的输出流
		OutputStream out = s.getOutputStream();
		System.out.print("请输入要转换到大写的字母、单词:");
		String word = input.next();
		out.write(word.getBytes());
		// 3.通过建立的Socket对象的输入流,获取来自服务器端的数据
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		// 4.获取输入字节流的数据,注意此方法是堵塞的,如果没有获取数据会一直等待
		int len = in.read(buf);
		String str = new String(buf, 0, len);
		System.out.println("服务器返回的结果是"+ str);
		in.close();
		out.close();
		s.close();
	}
}

*Socket的通信特点

1)开启端口,该通信是 长连接的通信 ,很容易被防火墙拦截,可以通过心跳机制(过几秒传个几字节)来实现 ,开发难度大
2)传输的数据一般是字符串 ,可读性不强
      lj|16|1|60|up  
3)socket端口不便于推广 
      http:17.23.23.2:2345   www.jd.com   www.360buy.com
4)性能相对于其他的通信协议是最优的

 

*再来复习一下OSI的七层模型:

Socket属于传输层,它是对Tcp/ip协议的实现,包含TCP/UDP,它是所有通信协议的基础

Http协议需要Socket支持,以Socket作为基础

 

*如果对于一些复杂一点的需求,比如又要小写转大写、又要大写转小写的需求,可以采用"Socket+规定格式"来创建Web服务

但是这样有缺点:不利于推广(别人不知道你的服务器端需要客户端传怎样的格式)

 

 

0.使用Http协议访问(应用层)


属于应用层的协议,对Socket进行了封装(也就是以Socket为基础,加多了点东西,比Socket更加笨重),短连接通信

 

*特点

1)跨平台(大部分操作系统都支持HTTP)

2)传数据的方式不够友好:get请求: http://127.0.0.1:8888?username=lj&pwd=1234

      最好可以直接传一个对象过来,因为属性一多就会变成一长串

3)对第三方应用提供的服务,希望对外暴露服务接口(因为返回的是一些页面

 

 

1.WebService技术和规则


*前面两种访问第三方项目的方法都存在问题:

- 数据封装不够友好 (XML)

-希望给第三方应用提供web方式的服务  (HTTP + XML = WebService)

 

*通俗的讲,Web Service就是一个部署在Web服务器上的一个,它向外界暴露出一个能够通过Web进行调用的API

 

*WebService技术和规则

--->xml(可拓展标记语言)数据通过XML来进行封装
--->soap(简易对象访问协议simple object access protocal)  soap 依赖-->http+xml-->socket

使用soap来以web的形式来调用外部的service服务(暴露服务),如果在内部的service就只能用java了

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

eg:getDatabaseInfoResponse方法(获得国内手机号码归属地数据库信息)

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getDatabaseInfoResponse xmlns="http://WebXml.com.cn/">
      <getDatabaseInfoResult>
        <string>string</string>
        <string>string</string>
      </getDatabaseInfoResult>
    </getDatabaseInfoResponse>
  </soap:Body>
</soap:Envelope>

--->wsdl(web services 描述语言) 教你怎么调用service,怎么使用里面的方法

  • 通过XML形式说明服务在什么地方-地址。
  • 通过XML形式说明服务提供什么样的方法 – 如何调用。

eg:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL

--->uddi(通用描述、发现及整合) -->>推广不好

有一个全球的WebService目录,收集了大部分的WebService(注册、登记之后)

就可以通过uddi来找到想要的WebService(唯一标识)

 

 

2.访问WebService的方式


  • 使用别人已准备好的服务器端www.webxml.com.cn
  • 自己准备客户端,调用第三方的WebService服务

 

这些访问方式只是抽取出业务层的接口,并没有真正获取到业务层的对象

所以在使用时是这样的

先获取到的是服务

再通过服务获取到到这个业务类的接口(phoneServicePort)

因为WebService本来就是要调用服务器的方法,而不是调用本地有的方法,所以不可能是获得真正的对象

 

 

* 一般访问方式  HttpClient

       1. Http-GET
       2. Http-Post 
       3. Soap (http+xml)

写法参考http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?op=getMobileCodeInfo

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;

/**调用第三方的webservice服务 ,获取电话号码信息
 * 
 */
public class MobileCodeService {
	//1. http-get方式访问webservice
	public void get(String mobileCode ,String userID ) throws Exception{
		URL url=new URL("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode="+mobileCode+
				"&userID="+userID);
		HttpURLConnection conn=(HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
		if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){ //结果码=200
			InputStream is=conn.getInputStream();
			//内存流 ,  
			ByteArrayOutputStream boas=new ByteArrayOutputStream();
			byte[] buffer=new byte[1024];
			int len=-1;
			while((len=is.read(buffer))!=-1){
				boas.write(buffer, 0, len);
			}
		    System.out.println("GET请求获取的数据:"+boas.toString());	
		    boas.close();
		    is.close();
		}
	}
	
	//2.Post请求 :通过Http-Client 框架来模拟实现 Http请求
	public void post(String mobileCode ,String userID) throws Exception{
		/**HttpClient访问网络的实现步骤:
		 *  1. 准备一个请求客户端:浏览器 
		 *  2. 准备请求方式: GET 、POST
		 *  3. 设置要传递的参数
		 *  4.执行请求
		 *  5. 获取结果
		 */
		HttpClient client=new HttpClient();
		PostMethod postMethod=new PostMethod("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo");
		//3.设置请求参数
		postMethod.setParameter("mobileCode", mobileCode);
		postMethod.setParameter("userID", userID);
		//4.执行请求 ,结果码
		int code=client.executeMethod(postMethod);
		//5. 获取结果
		String result=postMethod.getResponseBodyAsString();
		System.out.println("Post请求的结果:"+result);
	}
	
  
SOAP1.1方式:
	public static void postSoap1() throws Exception {
		// 创建一个post请求,类似Post请求
		PostMethod postMethod = new PostMethod("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx");
		// 设置传送信息的格式
		postMethod.setRequestHeader("Content-Type","text/xml; charset=utf-8");
               //a.txt是请求体的内容---》依赖XML的地方
		postMethod.setRequestBody(new FileInputStream("C:/a.txt"));
		int code = http.executeMethod(postMethod);
		System.out.println("消息码为:" + code);
		System.out.println("返回的消息为:" + postMethod.getResponseBodyAsString());
		postMethod.releaseConnection();
	}

	public static void main(String[] args) throws Exception{
		MobileCodeService ws=new MobileCodeService();
		ws.get("18333333333", "");
		ws.post("18333333333", "");
                ws.postSoap1();
	}

}

eg:get方法返回的数据

GET /WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode=string&userID=string HTTP/1.1
Host: ws.webxml.com.cn
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://WebXml.com.cn/">我们所需要的信息(电话号码18333333333归属地)</string>

使用这种方式会有问题:

  • 如何解析结果(因为依赖soap返回的是XML,但是我们只需要String)
  • 如何传递对象参数 (每个方法要写解析器,因为每个XML的标签不一样)

 

*推荐访问方式 wsimport 生成本地代理(本地有文件)(jdk6之后)

就是把提供服务的代码(class文件)下载到本地

wsimport命令位置:C:\Program Files (x86)\Java\jdk1.8.0_161\bin

- 要求:

  •        jdk的 版本要在 jdk 1.6.21及以上 
  •       操作系统安装的jdk版本 与 Eclispe 及 默认指定的版本要一致

记得设置jdk\bin  环境变量  指定path 

 

语法  wsimport [opations] <wsdl_uri>

  • wsdl_uri:wsdl 的统一资源标识符
  • -d  :指定要输出的文件的位置
  • -s  :表示要解析java的源码 ,默认解析出的是class字节码 
  • -p  : 指定输出的包名

 

 

 

3.WSDL语法


3.1 eg:

 

3.2 @WebService 修改WSDL文件

WebService的注解包括:

  • @WebService-定义服务   --类上
  • @WebMethod-定义方法   方法
  • @WebResult-定义返回值 返回值
  • @WebParam-定义参数 参数

 

WebService注解的使用

  1. 通过WebService的注解,可以更加形像的描述Web服务。从而生成WSDL文档。
  2. 当修改了WebService注解之后,同时会影响客户端生成的代码。
  3. 调用的方法名和参数名也发生了变化。
  4. 即使是没有修改源代码,只修改了注解,客户端的代码也必须要重新生成(注意是生成而不是下载)。否则调用将会失败。
  5. 生成本地调用代码,依然使用wsimport工具

 

@WebService注解:

  1. @WebService 标注要暴露为Web Services的类或接口 ,用于修饰类或接口,包含的属性有:
  2. targetNamespace属性:定义命名空间,默认为”http://”+”包名倒排
  3. name属性:Web Service 的名称,默认为发布服务的类名。
  4. serviceName: ws服务的名词,默认在类名后面添加了service
  5. endpointInterface属性:定义服务抽象 Web Service 协定的服务端点接口的完整名称,接口也必须声明WebService注解,包括方法的注解必须也要添加到接口中,否则会无效, 而且WS在没有注解的情况下.生成WS的时候会自动生成一个注解.所以可以不用指定接口

 

@WebMethod

  1. 此注解用在方法上,用于修改对外暴露的方法
  2. operationName属性:与此方法匹配的 wsdl:operation 的名称
  3. exclude属性:标注此方法是否被暴露,默认为false

 

注意:如果所有方法上都没有指定@WebMethod,则默认是所有的方法都是对外暴露的方法。如果有任一方法指定了@WebMethod,则只有指定这个注解的才是对外暴露的方法。

 

@WebResult

@WebResult 定义返回值,返回值类型不能为接口类或抽象类,而且必须有个不带参的构造函数,包含属性

name属性:返回值的名称

 

4.CXF框架


 

4.1 CXF介绍

  • SOA的框架
  • Cxf 是 Celtrix (ESB框架)和 XFire(webserivice) 合并而成,并且捐给了apache  
  • CxF的核心是org.apache.cxf.Bus(总线),类似于Spring的 ApplicationContext
  • CXF默认是依赖于Spring
  • Apache CXF 发行包中的jar,如果全部放到lib中,需要 JDK1.6 及以上,否则会报JAX-WS版本不一致的问题
  • CXF 内置了Jetty服务器 ,它是servlet容器,好比tomcat

4.1.1 什么是SOA

- Soa  :面向服务的架构,它是一种思想,IBM大力倡导
               service 1   、service2  、Service3  , 服务都是面向web的 ,而且是即插即用的
               IBM大力提倡,希望以组装电脑的方式来开发应用
- 组成:
            1. 面向web的服务,面向web的组件  :WebService : 硬盘、cpu、内存条
            2. 企业服务总线 (EnterPrise Service Bus :ESB)。主板

 

4.2 为什么要使用CXF

通过Jdk  
需要声明 :@Webservice
发布使用 :EndPoint (Endpoint.publish(address, new Service()))
不足: 希望tomcat启动时,webservice服务能够开启 ,最好与Spring集成
            希望有一个webservice的服务列表 
   通过Webservice框架来实现 :axis2  、xfire

CXF XFire Axis2 JWS都是些什么:https://blog.csdn.net/TypantK/article/details/83964419

 

4.3 CXF不整合Spring发布WebService

/**通过cxf框架发布webservice
	 *  1. ServerFactoryBean
	 *    - 不设置注解也可以发布webservice服务, 不支持注解
	 *    - 不支持拦截器的添加
	 *  2. JaxWsServerFactoryBean
	 *    - 支持注解
	 *    - 可以添加拦截器
	 * @param args
*/	
	public static void main(String[] args) {
		LanguageService languageService=new LanguageServiceImpl();
		ServerFactoryBean bean=new ServerFactoryBean();
		//Endpoint :地址  , 实现对象
		bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService");
		bean.setServiceClass(LanguageService.class);//对外提供webservcie的业务类或者接口
		bean.setServiceBean(languageService);//服务的实现bean
		bean.create();//创建,发布webservice
		System.out.println("wsdl地址:http://192.168.114.10:9999/ws/cxf/languangeService?WSDL");
	}
	
	public static void main(String[] args) {
		LanguageService languageService=new LanguageServiceImpl();
		JaxWsServerFactoryBean bean=new JaxWsServerFactoryBean();
		//Endpoint :地址  , 实现对象
		bean.setAddress("http://192.168.114.10:9999/ws/cxf/languangeService");
		bean.setServiceClass(LanguageService.class);//对外提供webservcie的业务类或者接口
		bean.setServiceBean(languageService);//服务的实现bean
		//添加输入拦截器  :输入显示日志信息的拦截器
		bean.getInInterceptors().add(new LoggingInInterceptor());
		//添加输出拦截器  :输出显示日志信息的拦截器
		bean.getOutInterceptors().add(new LoggingOutInterceptor());
		
		bean.create();//创建,发布webservice
		System.out.println("wsdl地址:http://192.168.114.10:9999/ws/cxf/languangeService?WSDL");
	}

 

4.4 CXF整合Spring发布WebService

主要就是添加一个CXF请求的 Servlet,用来处理webservice的请求 (web.xml)

<servlet>
  <servlet-name>cxf</servlet-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  <load-on-startup>0</load-on-startup>
  </servlet>
  <servlet-mapping>
   <servlet-name>cxf</servlet-name>
   <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

还有配置CXF的bean在applicationContext.xml中

	...
xmlns:jaxws="http://cxf.apache.org/jaxws"
    ...

<bean id="employeeManagerImpl" class="cn.it.ws.cxf.b.EmployeeManagerImpl"></bean>
<!-- 配置cxf   
     地址:      http://192.168.114.10:8080/CXF_Server/ws/employeeManager
     组成 :  http://192.168.114.10:8080 +CXF_Server( 项目名)+ws(过滤的路径)+/employeeManager(自定义部分)
     服务类 :
     服务的实现类:
     拦截器  
      -->
  <jaxws:server address="/employeeManager" serviceClass="cn.it.ws.cxf.b.EmployeeManager">
   <jaxws:serviceBean>
    <ref bean="employeeManagerImpl"/>
   </jaxws:serviceBean>
   <!-- 配置输入显示日志信息的拦截器   -->
   <jaxws:inInterceptors>
    <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
   </jaxws:inInterceptors>
   <jaxws:outInterceptors>
    <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
   </jaxws:outInterceptors>
  </jaxws:server>

 

源码:

Employee.java  (bean)

package cn.it.ws.cxf.bean;

public class Employee {
	private Integer  id;
	private String name;
	private Integer age;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}

}

EmployeeManagerImpl.java

package cn.it.ws.cxf.b;

import java.util.ArrayList;
import java.util.List;

import cn.it.ws.cxf.bean.Employee;


public class EmployeeManagerImpl implements EmployeeManager {
	private List<Employee> employees=new ArrayList<>();
	@Override
	public void add(Employee employee){
		//添加到集合中
		employees.add(employee);
	}
	@Override
	public List<Employee> query(){
		return employees;
	}

}

EmplyeeManager.java

package cn.it.ws.cxf.b;

import java.util.List;

import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

import cn.it.ws.cxf.bean.Employee;
@WebService(serviceName="EmployeeService")
public interface EmployeeManager {

	public abstract void add(@WebParam(name="employee")Employee employee);

	public abstract @WebResult(name="employees")List<Employee> query();

}

 

5. webservice 访问流程:


 

  1. 检测本地代理描述的wsdl是否与服务端的wsdl一致 ,俗称为握手
  2. 通过soap协议实现通信 ,采用的是post请求 , 数据封装在满足soap规约的xml中
  3. 返回数据 同样采用的是soap通信,  数据封装在满足soap规约的xml中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值