使用 python 开发 Web Service

使用 python 开发 Web Service

Python 是一种强大的面向对象脚本语言,用 python 开发应用程序往往十分快捷,非常适用于开发时间要求苛刻的原型产品。使用 python 开发 web service 同样有语言本身的简捷高速的特点,能使您快速地提供新的网络服务,从而适应快速发展的网络商业环境。本文将用实例一步步描述如何用 Python 开发 web service。

刘 明 (ovis_poly@sina.com), 软件工程师, 上海交通大学电子与通信工程系

陈 华泉 (chenhuaquan@21cn.com), 软件工程师, 上海交通大学软件工程学院

 

  • +内容

搭建开发环境

一个基本的 python web service 开发环境由以下这些工具组成:

Python2.4,Eclipse WTP,PyDev plug-in,Python ZSI包。

安装 python2.4

Python2.4 可以在网站 http://www.python.org/download/realses/2.4,下载安装包,安装过程非常简单,在此不再赘述。

安装 Eclipse WTP

Eclipse WTP 可以在 http://download.eclipse.org/webtools/downloads/ 下载。

安装 pyDev

在 http://pydev.sourceforge.net/download.html 下载 pyDev 插件,解压后将 features 目录和 plugin 目录下的所有文件都拷贝到 Eclipse 的相同目录下就可以了。本文中使用的是 release1.3.9。

安装 python ZSI

从 ZSI 的网站上下载最新的安装包,在写这篇文章的时候,最新的 ZSI 版本为 2.0。解压缩后运行如下命令:

图 1.
图片示例

ZSI 还依赖与一些其它的 python 开源包:SOAPpy,pyXML。本文在后面列出了它们的下载地址。必须安装这些 python 包 ZSI2.0 才能正常运行。

本文提供的 Web service 描述

在本文中我们将利用 python 提供几个 web service,然后用 Java 客户端调用它们。作为演示,我们仅设计了三个简单的 web service:

getTime():返回代表当前时间的字符串。没有输入参数。

sayHello(username):返回一个字符串,内容为“Hello username”,其中 username 为传入参数。

showUser(username):根据输入的 username 返回一个复杂数据类型 userInfo,描述用户的年龄,性别,联系地址。

创建工程

首先创建一个工程。打开 Eclipse,选择 File->New Project。当 pyDev 插件安装好后,会有一个 pyDev project 的选项。选择该选项并创建一个 pyDev 工程。

编写 wsdl 文件

Wsdl 是一个 XML 文件,它主要用来描述所提供的网络服务的细节。用户通过 wsdl 文件就可以了解您所提供的网络服务的调用接口的所有细节。

感谢 Eclipse WTP 提供的 WSDL Editor,它使得编写 WSDL 文件变成了一件轻松的事情。WSDL Editor 提供了可视化的编辑界面。利用 WSDL Editor,用户可以完全从服务本身来思考,无需深入了解 WSDL 的细节。

首先要在工程中增加一个 WSDL 文件,点击菜单 File->New 选择 Other,在弹出的对话框中选择WSDL文件。如下图所示:

图 2.
图片示例

单击 next,给新文件命名为 myServices.wsdl。选择缺省选项并点击 finish 按钮就会生成一个缺省的空 wsdl 文件。此时,将看到如下所示的编辑界面:

图 3.
图片示例

缺省的 WSDL 包含了三个部分 Service,Binding 和 operation。对于一般的应用,只需修改 operation,即上图中最右边的方框。为了提供前面所描述的三个网络服务,我们需要在这个方框中增加三个新的 operation。

第一个网络服务是 getTime。将缺省 wsdl 文件的 operation 方框中的第一个表项修改一下,就可以完成 getTime 的定义了。首先单击标题 NewOperation,将名字高亮选中,如下图所示:

图 4.
图片示例

将其重新命名为 getTime。getTime 服务没有入口参数。但有一个返回值,我们定义返回值为一个表示时间的字符串。注意图二中方框外右边的两个箭头,双击它们就可以分别进入定义入口和出口参数的窗口。首先双击 Input 后面的箭头 (上图中用红色圆圈标出),可以进入如下图所示的参数定义窗口:

图 5.
图片示例

在新打开的 Inline Schema of myServices.wsdl 窗口中,我们可以设置 getTime 的入口参数。getTime 不需要入口参数,因此将缺省的入口参数 in 删除:

图 6.
图片示例

关闭新打开的窗口,回到图一所示的 wsdl 编辑界面。双击 getTime 的 output 后面的箭头,定义返回值。将缺省的返回值名字 out 修改为 timeStr,类型 string,不需要改变:

图 7.
图片示例

这样 getTime 就设计好了。下面回到主窗口,添加 sayHello 的定义。在 Operation 方框上单击鼠标右键,选择 Add Operation:

图 8.
图片示例

同样,双击方框右边的箭头,分别设置其入口参数和返回值。sayHello 的入口参数为字符型,名字为 username。返回值也是 string 类型。

添加新的 operation,命名为 showUser。这个服务的入口参数也是用户名,类型为 string,但是它的返回值是一个复杂类型。用 WSDL Editor 可以方便地定义复杂类型。进入返回值设计窗口(双击 output 后的箭头),在 element 上单击鼠标右键,弹出菜单中选择 Set Type->New。在弹出对话框中选择 Complex Type,并将新类型命名为 userInfo。

在eclipse的outline 窗口中选中 types->userInfo,定义 userInfo。

图 9.
图片示例

主窗口显示出 userInfo 的设计界面,鼠标右键单击 userInfo,选择弹出菜单的 add element,增加三个 string 类型的元素 name, gender 和 address。如下图所示:

图 10.
图片示例

现在可以存盘了,三个服务都已经设计好。下一步,我们将用 python ZSI 提供的脚本处理 WSDL 文件,并生成服务代码框架。

编写 web service 服务端代码

ZSI 包提供了两个脚本用来根据 wsdl 文件生成相应的 server 端和 client 端的 python 代码框架。下面的命令生成 server 端代码:

图 11.
图片示例

脚本 wsdl2py 的 -b 选项会生成一些辅助代码,后面的描述中将会看到这些辅助代码能简化编程。运行以上两条命令后,会生成三个文件:

myServices_services.py , myServices_services_server.py , myServices_services_types.py

这三个 python 文件就是服务端的代码框架。为了提供最终的 web 服务,我们还需要添加一个文件,用来实现每个 web 服务的具体代码。将新文件命名为 serviceImpl.py(完整的源代码可以在文章最后下载)。仅实现 getTime 的 serviceImpl.py 如下:

from myServices_services_server import *
from time import time,ctime
from ZSI.ServiceContainer import AsServer
class mySoapServices(myServices):def soap_getTime(self,ps):try:rsp = myServices.soap_getTime(self, ps)request = self.requestrsp.set_element_timeStr(ctime())except Exception, e:print str(e)return rsp

首先导入 myServices_services_server,它是由 wsdl2py 脚本生成的 Web 服务框架代码。类 myServices 是 web 服务的基础类,每一个 web 服务都对应其中的一个方法。getTime 对应 myServices 类中的 soap_getTime 方法。缺省的 soap_getTime 方法只是一个基本框架,但完成了 soap 解析并且能返回该服务的入口参数对象。

为了实现 getTime,我们需要重载 soap_getTime 方法。定义新类 mySoapServices,继承自 myServices。在 mySoapServices 类中重载父类的 soap_getTime() 方法。

getTime 的主要功能是返回一个表示当前时间的字符串。python 系统函数 ctime,就可以得到当前的系统时间。重载 soap_getTime() 函数中,首先调用父类的 soap_getTime() 方法,得到返回值对象rsp。

调用返回值对象 rsp 的 set_element_xxx() 方法,就可以对返回值对象中的元素进行赋值。这个方法是由 wsdl2py 的 -b 选项生成的。

set_element_timeStr(ctime()) 将返回值的 timeStr 元素赋值为代表当前时间的字符串。

sayHello() 的代码与此类似。但是与 getTime 不同,sayHello 服务还需要处理客户端调用时传入的入口参数。sayHello 方法的源代码:

    def soap_sayHello(self,ps):try:rsp = myServices.soap_sayHello(self,ps)request = self.requestusrName = request.get_element_userName()rsp.set_element_helloStr("Hello "+usrName)except Exception, e:print str(e)return rsp

request 代表入口参数对象。对于 sayHello 服务,入口参数只有一个元素 userName。调用 request 对象的 get_element_userName() 方法就可以得到该元素的值。

调用返回值对象 rsp 的 set_element_helloStr 将返回字符串赋值给 helloStr 元素。

showUser 服务与前面两个服务的不同在于返回值是一个复杂对象,该复杂对象在 python 中可以用下面这个类来表示:

class userInfo:def __init__(self,nm,gen,addr):self.name = nmself.gender = genself.address = addr

showUser 服务根据客户端传入的用户名在数据库中查找该用户的详细信息并填充 userInfo 对象,相应代码如下:

    def soap_showUser(self,ps):try:rsp = myServices.soap_showUser(self,ps)request = self.requestuName = request.get_element_userName()userDetail = rsp.new_user()nm=self.users[uName].nameuserDetail.set_element_name(nm)gender=self.users[uName].genderuserDetail.set_element_gender(gender)addr=self.users[uName].addressuserDetail.set_element_address(addr)rsp.set_element_user(userDetail)except Exception, e:print str(e)return rsp

调用 request 对象的 get_element_userName 方法得到入口参数,并赋值给 uName。然后在数据库中查找用户uName的详细信息,将详细信息填充到 userInfo 类对象中,并返回。作为演示,我们并没有真的到数据库中查询,而是在内存中建立一个字典:

        u1 = userInfo("u1","M","Shanghai")u2 = userInfo("u2","F","Beijing")self.users={}self.users["u1"]=u1self.users["u2"]=u2

该字典中有两个用户:u1 和 u2。演示代码在该字典中查询用户,将查选结果返回用户。

调用 rsp 对象的 new_element_user() 方法创建一个新的返回对象,并用 userDetail 保存。

调用 userDetail.set_element_gender 将用户性别信息设置到返回值对象的 gender 元素中。同样方法设置用户名和地址。

最后将新建的 userDetail 对象设置到返回值 rsp 中:rsp.set_elememnt_user(userDetail)。

发布 web service

所有 web 服务代码都已经写好了,需要服务器代码来发布它们。在复杂并且有较高要求的应用环境中,用户可能需要用 apache 等强大的 web server 来发布 web services。限于篇幅,本文不打算介绍如何在 apache 上发布 python web services。本文将使用 ZSI 自带的 SOAP server。

正如下图所示,使用 ZSI soap server 只需要很少的几行代码:

from ZSI.ServiceContainer import AsServer
from serviceImpl import mySoapServices
from ZSI import dispatch
if __name__ == "__main__":port = 8888AsServer(port,(mySoapServices('test'),))

这段代码无需太多解释。port 定义了 web service 发布的端口号。ZSI 包的 AsServer 方法只有两个参数:一个是端口;另外一个是包含了 web 服务实现代码的类,在我们的实验中就是 mySoapServices。字符串 test,表示 web 服务发布时的虚拟路径。当上述代码成功运行之后,就会在 localhost 上开启一个 web server,并在端口 8888 发布 myServices 服务。一切都非常简单,体现了用 python 语言的最吸引人的特点,快速而强大!

我们将在本机访问 myServices,相应的 URL 为 http://localhost/test?wsdl。

编写 java 客户端

现在我们使用 eclipse 集成环境来开发 web services 的客户端程序,调用前面章节描述的那些 web services。

Eclipse 提供了一个简单的方法来创建 web service 应用程序,即 Web Service Wizard。

首先创建一个 Web Project。

打开 File->New->Other…->Dynamic Web Project,创建一个新的工程。

图 12.
图片示例

然后就可以创建 java 客户端。选择 File -> New -> Other... -> Web Services -> Web Service Client

图 13.
图片示例

选择 Next,在下一个窗口中的 Service Definition 中填写相应的 webservice 的发布地址 URL。在本文中为: http://localhost:8888/test?wsdl

图 14.
图片示例

选择 Finish 按钮。将自动生成 java 代码。包括以下几个文件: MyService_PortType.java MyService_Service.java MyService_ServiceLocatior.java MyServiceProxy.java MyServiceSOAPStub.java

另外 showUser() 返回一个复杂对象,所以 eclipse 还创建了一个 java 类表示该复杂对象类,文件名为 UserInfo.java

作为测试,我们写了一个 java 小程序,调用 getTime。

import org.example.www.myService.MyServiceProxy;
public class HelloClient {public static void main(String[] args){try {System.out.println("Step1");MyServiceProxy hello = new MyServiceProxy();System.out.println("Step2");java.lang.String str = hello.getTime();System.out.println("step over");System.out.println(str);} catch (Exception ex){System.out.println(ex.getMessage());}}
}

sayHello 和 showUser 的调用代码与上面的示例类似。

总结

用 Eclipse 的 WTP 开发 WSDL 文件,用 python 实现 Web 服务都比较简单而快速。用这两个强大的工具能够迅速地开发 Web 服务应用,适用于原型产品的快速开发。 这样就能抓住先机,比对手更快的推出新的Web应用,从而在市场上立于不败之地。

参考资料

  • ZSI online document http://pywebsvcs.sourceforge.net/zsi.html
  • SOAPy download page : http://soapy.sourceforge.net
  • pyXML download page: http://pyxml.sourceforge.net

条评论

转载于:https://www.cnblogs.com/L-H-R-X-hehe/p/3815450.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 基础5

一、 什么是数组及其作用? 定义:具有相同数据类型的一个集合 作用:存储连续的具有相同类型的数据 二、 java中如何声明和定义数组 2.1 声明和定义的语法: 数据类型[ ] 数组名;( int[ ] nums ; ) 或 数…

TFS(Team Foundation Server)介绍和入门

在本文的两个部分中,我将介绍Team Foundation Server的一些核心特征,重点介绍在本产品的日常应用中是怎样将这些特性结合在一起使用的。 作为一名软件开发者,在我的职业生涯中,我常常会用到支持软件开发过程的大量开发工具&#x…

[Hadoop] - 自定义Mapreduce InputFormatOutputFormat

在MR程序的开发过程中,经常会遇到输入数据不是HDFS或者数据输出目的地不是HDFS的,MapReduce的设计已经考虑到这种情况,它为我们提供了两个组建,只需要我们自定义适合的InputFormat和OutputFormat,就可以完成这个需求&a…

PS 色调——老照片效果

这就是通过调色使照片显得发黄。 R_new0.393*R0.769*G0.189*B; G_new0.349*R0.686*G0.168*B; B_new0.272*R0.534*G0.131*B; clc; clear all; Imageimread(9.jpg); Imagedouble(Image); Image_newImage; Image_new(:,:,1)0.393*Image(:,:,1)0.769*Image(:,:,2)0.189*Image(:,:,3…

jsp出现错误

昨天在调试页面时发生了如图显示的异常&#xff0c;它出现的原因是当<jsp:forward>或<jsp:include>标签没有参数时&#xff0c;开始标签和结束标签</jsp:forward>或</jsp:include>之间不能有空格&#xff0c;不能换行。解决办法&#xff1a;删除标签之…

门限回归模型的思想_Stata+R:门槛回归教程

来源 | 数量经济学综合整理转载请联系进行回归分析&#xff0c;一般需要研究系数的估计值是否稳定。很多经济变量都存在结构突变问题&#xff0c;使用普通回归的做法就是确定结构突变点&#xff0c;进行分段回归。这就像我们高中学习的分段函数。但是对于大样本、面板数据如何寻…

二阶传递函数的推导及几种求解方法的比较

二阶系统是指那些可用二阶微分方程描述的系统&#xff0c;其电路形式是由两个独立动态元器件组成的电路。 二阶系统电路包括二阶低通电路、二阶高通电路、二阶带通电路和二阶带阻电路。 下面分别给出以上二阶系统传递函数的推导过程&#xff0c;并以二阶低通电路的冲激响应为例…

前端技术-调试工具(上)

页面制作之调试工具 常用的调试工具有Chrome浏览器的调试工具&#xff0c;火狐浏览器的Firebug插件调试工具&#xff0c;IE的开发人员工具等。它们的功能与使用方法大致相似。Chrome浏览器简洁快速&#xff0c;功能强大这里主要介绍Chrome浏览器的调试工具。 打开 Google Chrom…

新版Microsoft Edge支持跨平台跨设备浏览

之前一直使用Google Chrome浏览器&#xff0c;可以随意安装插件扩展程序&#xff0c;无广告&#xff0c;这是我钟爱她的原因。但是之后不能登录Google账号&#xff0c;不能实现跨设备应用&#xff0c;就想找一款好用的替代品&#xff0c;近期发现了新版的Microsoft Edge&#x…

百度网盘7.3.1.10版本增加工作空间功能,可实现百度网盘与电脑文件夹同步

百度网盘新增的工作空间是一款文件同步的产品&#xff0c;支持电脑本地与云端之间的文件同步&#xff0c;多设备间文件自动保持同步、支持查看文件每次都修改的历史版本。功能类似于onedrive。如果有同步需求的小伙伴可以尝试下载最新版的百度网盘试用该功能哦。下载网址&#…

ubuntu+idea intellij配置android开发环境

最近对移动开发产生兴趣&#xff0c;决定在未来几年内利用空余时间开发一些app或游戏什么的&#xff0c;鉴于ios开发成本较高&#xff0c;且自身对java相对熟悉&#xff0c;因此选择了学习android。都说android市场不很很好&#xff0c;收益较难&#xff0c;但是仍觉得只要功夫…

LTI系统的物理可实现性与希尔伯特变换

产品的设计一般为线性时不变系统&#xff0c;要求系统具有物理可实现性&#xff0c;从时域上看&#xff0c;h(t)具有因果性&#xff1b;从频域上看&#xff0c;|H(jw)|符合佩利—维纳准则。任何具有因果性的系统&#xff0c;|H(jw)|的实部R(w)满足希尔伯特变换&#xff0c;|H(j…

垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想

Delphi 是一个基本上被我遗忘的工具&#xff0c; 要不是在使用RapidSql , 我是收不到Embarcadero 公司发出的邀请来參加Delphi XE5的公布会的。 有人可能要问为什么是Embarcadero &#xff08;名称很拗口&#xff09;而不是Borland 开Delphi 公布会&#xff0c; 这是由于Borla…

ubuntu下安装国际版QQ

在网上看到了好多的ubuntu下安装QQ的方法 好多 下面是看别人的文章 来测试的一篇 ubuntu下 安装国际版QQhttp://www.ubuntukylin.com/applications/showimg.php?langcn&id23下载 地址网盘:http://yun.baidu.com/share/link?shareid2983202140&uk202032639下载好以后 …

傅里叶变换应用——信号调制与解调

傅里叶变换的典型应用主要用于通信的信号调制与解调&#xff0c;信号调制的目的是将信号进行变换&#xff0c;使其便于传输。频率调制是将低频信号调制到高频载波信号上。同步信号解调是接受系统产生同步的高频载波信号进行解调&#xff0c;从调制信号中恢复原信号的过程。调制…

连续时间系统与离散时间系统的时域分析对比

通过学习离散时间系统的时域分析&#xff0c;发现其与连续时间系统的时域分析有很多相似之处&#xff0c;自己做了一个专题拓展&#xff0c;从数学模型描述到时域分析方法对两大系统进行横向对比&#xff0c;总结两者之间的联系和异同点。

[SQL Server]重命名数据库【转】

原文链接&#xff1a;http://www.cnblogs.com/Ryan_j/archive/2011/04/03/2004428.html 重命名数据库很简单&#xff0c;选择数据库--右键--重命名数据库 或者 sp_renamedb oldDB ,newDB 但是你再新建的相同名字的数据库就会报错&#xff0c;提示数据库已经存在 比如test数据库…

DCOS实践分享(4):如何基于DC/OS整合SMACK(Spark, Mesos, Akka, Cassandra, Kafka)

这篇文章入选CSDN极客头条 http://geek.csdn.net/news/detail/71572 当前&#xff0c;要保证业务的市场竞争力&#xff0c;仅靠设计一个可用并且好看的产品&#xff0c;已经完全不能满足要求。全球消费者都希望产品能够足够的智能化&#xff0c;通过大数据分析来改善他们的用户…

连续系统的卷积积分与离散系统的卷积和

在LTI连续系统中&#xff0c;以冲激函数为基本信号&#xff0c;将任意信号分解&#xff0c;从而得到连续系统的零状态响应等于激励与系统冲激响应的卷积积分 &#x1d466;&#x1d467;&#x1d460;&#x1d461;&#x1d453;&#x1d461;∗h&#x1d461; 在LTI离散…

【数据结构】图的深度优先搜索

图的深度优先搜索类似于树的深度优先搜索。不同的是&#xff0c;图中可能包括循环&#xff0c;即我们有可能重复访问节点。为了避免访问已经访问过的节点&#xff0c;我们要使用一个布尔变量的数组。 例如&#xff0c;在下图中&#xff0c;我们从节点2开始访问。当访问到节点0&…