如果使用GOOGLE、BAIDU等搜尋工具,搜尋WebService的相關知識,可以查到N多的網頁,我就是通過這些網頁的學習,逐漸掌握了些WebService的相關知識。這裡對那些無私奉獻知識的人一併表示感謝。 網上關於WebService的例子,多是一些簡單得不能再簡單的hello world的例子,簡單得以至於你對WebService沒有什麼感覺。有了WebService的基本知識後,我一直再想,可以把什麼樣的即簡單又實用的東東做成WebService,開展示一下其功能特點。今天終於想到一個:計數器,計數器用得比較多,功能比較獨立,做成WebService可以一勞永逸為不同系統(不管是JSP還ASP,這是WebService的突出優點)、不同應用節省此類編碼工作,可以說以後再也不用寫計數器了。只要用就行了。 說了這麼多廢話,下面我們開始。本教程介紹一下WebService環境搭建、服務部署的相關知識,然後介紹一個計數器的開發。 運行圖:
二、基礎工作 1.開發環境 我使用axis做為Web Service引擎,它是Apache的一個開源web service引擎。它目前最為成熟的開源web service引擎之一。下面我主要介紹一下如何使用Axis搭建web service 服務的環境。 ①安裝tomcat5.0應用伺服器(也可以裝5.5,不過我一直在用5.0); ②解壓下載( http://ws.apache.org/Axis)後的axis包,將包中axis目錄複寫到tomcat目錄下的webapps目錄下; ③將axis/WEB-INF/lib目錄下類檔案複製到tomcat目錄下的common/lib目錄下; ④重新啟動tomcat,訪問http://localhost:8080/axis/happyaxis.jsp,如果能訪問,表示安裝成功; 注意,axis有幾個可選的包,如email.jar....,你可以找來放到tomcat目錄下的common/lib目錄下,如果不使用相關的功能也可以不用。 這樣,開發環境就搭建好了。 2.如何部署Web Service 部署有三種方式:Dynamic Invocation Interface(DII)、Stubs方式、Dynamic Proxy方式;這裡就介紹一下簡單,也是我使用的方式:DII。 DII方式中,先寫好服務的JAVA檔案(假設名字為helloworld.java),然後把它(注意是源檔案)拷貝到webapps/axis目錄中,尾碼改成jws(此時檔案名稱為:helloworld.jws),然後訪問串連http://localhost:8080/Axis/helloworld.jws?wsdl,頁面顯示Axis自動產生的wsdl,這樣一個Web Service就部署好了。怎麼樣,是不是很簡。 我的計數器服務就是以這種方式部署的,下文中我會只說將計數器服務部署好,你可不要說:怎麼部署,我不會呀。那在古代就要被打手板了。所以我想,古代只學四書五經也是件好事呀。現在要學這麼多東西,半天學不會,手要被打爛了。 三、計數器服務的編寫 計數器大家都知道了,比較簡單。我的計數器也同樣簡單,有以下功能及特點:提供四種計數器(總數器、月計數器、周計數器及日計數器);考慮到Web Service要服務於多種應用,這個計數器還支援多個使用者;使用XML檔案來記錄資料。 記錄檔案名稱為:d:\counter.xml。注意,此檔案在服務裡是寫入程式碼,如果修改名字,請在服務程式中也進行相應的修改。檔案內容格式如下: <?xml version="1.0" encoding="UTF-8"?> <counter> <item> <name>wallimn</name> <password>123</password> <dc>59</dc> <wc>59</wc> <mc>59</mc> <tc>59</tc> <rt>2007-4-16 16:01:29</rt> </item> <counter> 說是計數器服務,其實跟編寫普通的JAVA應用沒有什麼兩樣。我的計數器代碼比較簡單,我就不做過多的介紹了,把它貼在下面,源碼中有少量注釋,相信大家不看注釋也看得懂。服務有只有一個介面:Counter(String name, String password),以後在用戶端拿來用就可以了。還多說一句,我和程式使用到了dom4j解析xml包,要調試的請自行準備好jar包。部署方法請參照上文。 import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; /** *功能:提供計數器服務的WebService,可以為多使用者提供服務。<br/> * @version : V1.0 * @author : 王力猛(Email: wallimn@sohu.com QQ: 54871876) * @date : 2007-4-16 下午04:32:45 */ public class WsCounterByWallimn { //計數器文檔,注意名字名路徑。 private final String FileN = "d:/counter.xml"; private final static DateFormat DATEFORMATER = DateFormat.getDateTimeInstance(); //出錯的情況下返回的值 private final static String ERRORINFO="-1;-1;-1;-1"; public WsCounterByWallimn(){ } /** *功能:開啟計數器文檔<br/> *編碼:王力猛 時間:2007-4-16 下午04:44:29<br/> */ private Document openDocument(){ Document doc=null; SAXReader reader = new SAXReader(); try { File xmlfile = new File(FileN); doc = reader.read(xmlfile); xmlfile=null; } catch (DocumentException e) { e.printStackTrace(); } return doc; } /** *功能:取指定名稱計數器的詳細資料,並設定計數器加1。<br/> *編碼:王力猛 時間:2007-4-16 下午04:49:57<br/> */ private synchronized String countertick( String name, String password){ Document doc = openDocument(); Date currdt = new java.util.Date(); //mc:month counter(月計數器); dc: day counter(日計數器); //tc: total counter(總計數器); wc: week counter(周計數器); //rt: registe time登記時間 String mc="-1",dc="-1",tc="-1",wc="-1",rt="-1"; Element root = doc.getRootElement(); Element selitem=null,item=null; for(Iterator it = root.elementIterator("item"); it.hasNext();){ item = (Element)it.next(); if(name.equals(item.element("name").getText())){ selitem=item; String pwd = item.elementText("password"); if(!password.equals(pwd)){ return ERRORINFO;//密碼不對,直接返回 } mc=item.element("mc").getText(); dc=item.element("dc").getText(); tc=item.element("tc").getText(); wc=item.element("wc").getText(); rt=item.element("rt").getText(); break; } } //如果selitem為空白,說明沒有個名字的計數器。則添加一個。 if(selitem==null){ //System.out.println("沒有找到這個名字的計數器:"+name); rt=DATEFORMATER.format(currdt); selitem = doc.getRootElement().addElement("item"); selitem.addElement("name").setText(name); selitem.addElement("tc").setText("0"); selitem.addElement("mc").setText("0"); selitem.addElement("wc").setText("0"); selitem.addElement("dc").setText("0"); selitem.addElement("rt").setText(rt); selitem.addElement("password").setText(password); mc="0"; wc="0"; dc="0"; tc="0"; } //處理計數器加一操作。 Calendar currcr=Calendar.getInstance(); //總數器總是加1。 tc =String.valueOf(Integer.parseInt(tc)+1); selitem.element("tc").setText(tc); Date lastdt = null; try { lastdt = DATEFORMATER.parse(rt); } catch (ParseException e) { lastdt = new java.util.Date(); } Calendar lastcr = Calendar.getInstance(); lastcr.setTime(lastdt); currcr.setTime(currdt); //System.out.println("上次登記時間:"+DATEFORMATER.format(lastdt)); //System.out.println("本次登記時間:"+DATEFORMATER.format(currdt)); if(lastcr.get(Calendar.YEAR)==currcr.get(Calendar.YEAR)){ //月相同,月計數加1 if(lastcr.get(Calendar.MONTH)==currcr.get(Calendar.MONTH)){ mc = String.valueOf(Integer.parseInt(mc)+1); } else{ mc="1"; } //日相同,日計數加1 if(lastcr.get(Calendar.DAY_OF_YEAR)==currcr.get(Calendar.DAY_OF_YEAR)) dc = String.valueOf(Integer.parseInt(dc)+1); else dc = "1"; if(lastcr.get(Calendar.WEEK_OF_YEAR)==currcr.get(Calendar.WEEK_OF_YEAR)) wc = String.valueOf(Integer.parseInt(wc)+1); else wc = "1"; } else{//年不一樣,則月計數器、周計數器日計數器肯定也不一樣。 mc="1"; dc="1"; wc="1"; } selitem.element("mc").setText(mc); selitem.element("wc").setText(wc); selitem.element("dc").setText(dc); //登記記錄時間 selitem.element("rt").setText(DATEFORMATER.format(currdt)); try { XMLWriter xw = new XMLWriter(new FileWriter(FileN)); xw.write(doc); xw.close(); } catch (IOException e) { e.printStackTrace(); } return tc+";"+mc+";"+wc+";"+dc; } /** *功能:服務暴露的介面,也就是指定名稱、密碼,返回指定的計數,並將計數器加1。<br/> *編碼:王力猛 時間:2007-4-17 上午10:05:22<br/> */ public String Counter(String name, String password){ if(password==null || name==null)return ERRORINFO; return countertick(name, password); } } 四、用戶端編寫 用戶端是個頁面,為了條理清晰,我先寫個調用Web Service的類,其內容如下: package com.wallimn.WebService;//調試請注意包名 import org.apache.axis.client.Call; import org.apache.axis.client.Service; public class CounterServiceClient { private String counterarr[]; public boolean getCounter(String CounterName, String password) { boolean res = false; try { String endpoint = "http://localhost:8080/axis/WsCounterByWallimn.jws";//此處注意,請與你的開發環境匹配 Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new java.net.URL(endpoint)); call.setOperationName("Counter"); // 填寫你要調用的方法名稱 String counter = (String) call.invoke(new Object[] { CounterName, password }); counterarr = counter.split(";"); res = (counterarr != null && counterarr.length == 4); } catch (Exception e) { } return res; } public String getDc() { return counterarr[3]; } public String getMc() { return counterarr[1]; } public String getTc() { return counterarr[0]; } public String getWc() { return counterarr[2]; } } 到頁面(test.jsp)上就簡單了,我也把它貼在下面: <%@ page language="java" import="com.wallimn.WebService.CounterServiceClient" pageEncoding="GB18030"%> <% CounterServiceClient client = new CounterServiceClient(); client.getCounter("hello","123"); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>計數器測試頁面</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="wallimn,計數器,WebService"> <meta http-equiv="description" content="計數器使用樣本"> </head> <body> <h2 align="center">計數器詳情</h2> <hr/> 總訪問量:<%=client.getTc()%> <br/> 今天訪問量:<%=client.getDc()%> <br/> 本周訪問量:<%=client.getWc()%> <br/> 本月訪問量:<%=client.getMc()%> <br/> <hr/> <p>歡迎交流<br/>部落格:http://blog.csdn.net/wallimn<br/>電郵:wallimn@sohu.com</p> </body> </html> 五、結束語 至此一個完整計數器的Web Service開發、使用的程式的全部完成了。將上面的類、及頁面部署到任意的一個上下文中,通過瀏覽器開啟test.jsp,就可以看了結果了。 歡迎訪問我的部落格(http://blob.csdn.net/wallimn)留言或發郵件(wallimn@sohu.com)交流。 |