使用 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,一经查实,立即删除!

相关文章

python中输出n开始的5个奇数_送你99道Python经典练习题,练完直接上手做项目,免费送了来拿吧...

学python没练习题怎么行、今天,给大家准备一个项目: 99道编程练习,这些题如果能坚持每天至少完成一道,一定可以帮大家轻松 get Python 的编程技能。目前,这个项目已经获得了 2924 Stars,2468 Forks。首先&a…

java 基础5

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

TFS(Team Foundation Server)介绍和入门

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

逆函数求导公式_反函数求导法则

反函数的求导法则是:反函数的导数是原函数导数的倒数。例题:求yarcsinx的导函数。首先,函数yarcsinx的反函数为xsiny,所以:y‘1/sin’y1/cosy,因为xsiny,所以cosy√1-x2,所以y‘1/√…

SpringXML方式配置bean的懒加载lazy-init

lazy-init&#xff08;懒加载&#xff09;&#xff0c;表示该bean在容器初始化的时候不进行初始化。例如&#xff1a;<bean name"role1" class"com.fz.entity.Role" lazy-init"true">以上配置表示&#xff1a;spring容器在初始化的时候不会…

windows下system函数的使用

system函数 是可以调用一些DOS命令,比如system("cls");//清屏,等于在DOS上使用cls命令写可执行文件路径&#xff0c;可以运行它 下面列出常用的DOS命令,都可以用system函数调用: ASSOC 显示或修改文件扩展名关联。AT 计划在计算机上运行的命令和程序。ATTRIB 显示或更…

WWDC2017 笔记 - Cocoa Touch 中的新特性

这篇文章是 What’s New in Cocoa Touch / UIKit Session 201 的一些整理。【基于OC】 转自我的 Blog: Dannys Dream Drag Drop 新的交互方式 拖拽 Drag 需要 Drag 的对象要 add 一个 UIDragInteraction &#xff0c;用法类似于 UIGestureRecognizer 。UIDragInteraction 有一个…

[Hadoop] - 自定义Mapreduce InputFormatOutputFormat

在MR程序的开发过程中&#xff0c;经常会遇到输入数据不是HDFS或者数据输出目的地不是HDFS的&#xff0c;MapReduce的设计已经考虑到这种情况&#xff0c;它为我们提供了两个组建&#xff0c;只需要我们自定义适合的InputFormat和OutputFormat&#xff0c;就可以完成这个需求&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;进行分段回归。这就像我们高中学习的分段函数。但是对于大样本、面板数据如何寻…

【数论】[CF258C]Little elephant and LCM

题目 分析&#xff1a;枚举最大数&#xff0c;然后找出它所有因数p1…….pk&#xff0c; 从中任意选取一些数&#xff0c;这些数的LCM|这个数且&#xff0c;这些数的最大LCM就是枚举的这个数&#xff0c;且若pi<aj<pi1则前i个数可以放在j这个位置&#xff0c;即j这个位置…

为普通Object添加类似AttachedProperty的属性

为普通Object添加类似AttachedProperty的属性 周银辉 我们知道&#xff0c;在WPF中对应一个DependencyObject&#xff0c;我们很容易通过AttachedProperty来为类型附加一个属性。但对于普通的Object而言&#xff0c;这就不可行了。 我现在遇到这样一个问题&#xff0c;下面有一…

python 操作RabbitMQ

pip install pika使用API操作RabbitMQ基于Queue实现生产者消费者模型View Code 对于RabbitMQ来说&#xff0c;生产和消费不再针对内存里的一个Queue对象&#xff0c;而是某台服务器上的RabbitMQ Server实现的消息队列。#!/usr/bin/env python import pika# ###################…

python和嵌入式哪个容易_嵌入式与python选哪个

从概念上来说&#xff0c;嵌入式和Python的区别还是比较明显的&#xff0c;嵌入式是一个开发领域&#xff0c;而Python则是一门编程语言。嵌入式开发是开发领域的一个重要分支&#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…

BZOJ1050 [HAOI2006]旅行

Description 给你一个无向图&#xff0c;N(N<500)个顶点, M(M<5000)条边&#xff0c;每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T &#xff0c;求一条路径&#xff0c;使得路径上最大边和最小边的比值最小。如果S和T之间没有路径&#xff0c;输出”IMPOSSIBLE”&…

biosrecovery什么意思_BIOS中的每个中文是什么意思

BIOS中的每个中文是什么意思&#xff0c;请对照的翻译一下Time/System Time时间/系统时间Date/System Date日期/系统日期Level 2 Cache二级缓存System Memory系统内存Video Controller视频控制器Panel Type液晶屏型号Audio Controller音频控制器Modem Controller调制解调器(Mod…