使用 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.pswp.cn/news/258458.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258458.shtml
英文地址,請注明出處:http://en.pswp.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…