/***********本人原创,欢迎转载,转载请保留本人信息*************/
作者:王力猛 (wallimn)
电邮:wallimn@sohu.com
博客:http://blog.csdn.net/wallimn
时间:2007-04-17
/***********本人原创,欢迎转载,转载请保留本人信息*************/

一、前言
   本文假定你有一定的J2EE开发经验,这个教程没有过多的涉及基础知识和开发细节。如果在阅读过程出有什么问题,还请与我联系交流。
  如果使用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包。部署方法请参照上文。 


 

  1. import java.io.File;
  2. import java.io.FileWriter;
  3. import java.io.IOException;
  4. import java.text.DateFormat;
  5. import java.text.ParseException;
  6. import java.util.Calendar;
  7. import java.util.Date;
  8. import java.util.Iterator;
  9. import org.dom4j.Document;
  10. import org.dom4j.DocumentException;
  11. import org.dom4j.Element;
  12. import org.dom4j.io.SAXReader;
  13. import org.dom4j.io.XMLWriter;
  14. /**
  15. *功能:提供计数器服务的WebService,可以为多用户提供服务。<br/>
  16. * @version : V1.0
  17. * @author : 王力猛(Email: wallimn@sohu.com QQ: 54871876)
  18. * @date : 2007-4-16 下午04:32:45
  19. */
  20. public class WsCounterByWallimn {
  21. //计数器文档,注意名字名路径。
  22. private final String FileN = "d:/counter.xml";
  23. private final static DateFormat DATEFORMATER = DateFormat.getDateTimeInstance();
  24. //出错的情况下返回的值
  25. private final static String ERRORINFO="-1;-1;-1;-1";
  26. public WsCounterByWallimn(){ }
  27. /**
  28. *功能:打开计数器文档<br/>
  29. *编码:王力猛 时间:2007-4-16 下午04:44:29<br/>
  30. */
  31. private Document openDocument(){
  32. Document doc=null;
  33. SAXReader reader = new SAXReader();
  34. try {
  35. File xmlfile = new File(FileN);
  36. doc = reader.read(xmlfile);
  37. xmlfile=null;
  38. }
  39. catch (DocumentException e) {
  40. e.printStackTrace();
  41. }
  42. return doc;
  43. }
  44. /**
  45. *功能:取指定名称计数器的详细信息,并设置计数器加1。<br/>
  46. *编码:王力猛 时间:2007-4-16 下午04:49:57<br/>
  47. */
  48. private synchronized String countertick( String name, String password){
  49. Document doc = openDocument();
  50. Date currdt = new java.util.Date();
  51. //mc:month counter(月计数器); dc: day counter(日计数器);
  52. //tc: total counter(总计数器); wc: week counter(周计数器);
  53. //rt: registe time登记时间
  54. String mc="-1",dc="-1",tc="-1",wc="-1",rt="-1";
  55. Element root = doc.getRootElement();
  56. Element selitem=null,item=null;
  57. for(Iterator it = root.elementIterator("item"); it.hasNext();){
  58. item = (Element)it.next();
  59. if(name.equals(item.element("name").getText())){
  60. selitem=item;
  61. String pwd = item.elementText("password");
  62. if(!password.equals(pwd)){
  63. return ERRORINFO;//密码不对,直接返回
  64. }
  65. mc=item.element("mc").getText();
  66. dc=item.element("dc").getText();
  67. tc=item.element("tc").getText();
  68. wc=item.element("wc").getText();
  69. rt=item.element("rt").getText();
  70. break;
  71. }
  72. }
  73. //如果selitem为空,说明没有个名字的计数器。则添加一个。
  74. if(selitem==null){
  75. //System.out.println("没有找到这个名字的计数器:"+name);
  76. rt=DATEFORMATER.format(currdt);
  77. selitem = doc.getRootElement().addElement("item");
  78. selitem.addElement("name").setText(name);
  79. selitem.addElement("tc").setText("0");
  80. selitem.addElement("mc").setText("0");
  81. selitem.addElement("wc").setText("0");
  82. selitem.addElement("dc").setText("0");
  83. selitem.addElement("rt").setText(rt);
  84. selitem.addElement("password").setText(password);
  85. mc="0";
  86. wc="0";
  87. dc="0";
  88. tc="0";
  89. }
  90. //处理计数器加一操作。
  91. Calendar currcr=Calendar.getInstance();
  92. //总数器总是加1。
  93. tc =String.valueOf(Integer.parseInt(tc)+1);
  94. selitem.element("tc").setText(tc);
  95. Date lastdt = null;
  96. try {
  97. lastdt = DATEFORMATER.parse(rt);
  98. }
  99. catch (ParseException e) {
  100. lastdt = new java.util.Date();
  101. }
  102. Calendar lastcr = Calendar.getInstance();
  103. lastcr.setTime(lastdt);
  104. currcr.setTime(currdt);
  105. //System.out.println("上次登记时间:"+DATEFORMATER.format(lastdt));
  106. //System.out.println("本次登记时间:"+DATEFORMATER.format(currdt));
  107. if(lastcr.get(Calendar.YEAR)==currcr.get(Calendar.YEAR)){
  108. //月相同,月计数加1
  109. if(lastcr.get(Calendar.MONTH)==currcr.get(Calendar.MONTH)){
  110. mc = String.valueOf(Integer.parseInt(mc)+1);
  111. }
  112. else{
  113. mc="1";
  114. }
  115. //日相同,日计数加1
  116. if(lastcr.get(Calendar.DAY_OF_YEAR)==currcr.get(Calendar.DAY_OF_YEAR))
  117. dc = String.valueOf(Integer.parseInt(dc)+1);
  118. else
  119. dc = "1";
  120. if(lastcr.get(Calendar.WEEK_OF_YEAR)==currcr.get(Calendar.WEEK_OF_YEAR))
  121. wc = String.valueOf(Integer.parseInt(wc)+1);
  122. else
  123. wc = "1";
  124. }
  125. else{//年不一样,则月计数器、周计数器日计数器肯定也不一样。
  126. mc="1"; dc="1"; wc="1";
  127. }
  128. selitem.element("mc").setText(mc);
  129. selitem.element("wc").setText(wc);
  130. selitem.element("dc").setText(dc);
  131. //登记记录时间
  132. selitem.element("rt").setText(DATEFORMATER.format(currdt));
  133. try {
  134. XMLWriter xw = new XMLWriter(new FileWriter(FileN));
  135. xw.write(doc);
  136. xw.close();
  137. }
  138. catch (IOException e) {
  139. e.printStackTrace();
  140. }
  141. return tc+";"+mc+";"+wc+";"+dc;
  142. }
  143. /**
  144. *功能:服务暴露的接口,也就是指定名称、密码,返回指定的计数,并将计数器加1。<br/>
  145. *编码:王力猛 时间:2007-4-17 上午10:05:22<br/>
  146. */
  147. public String Counter(String name, String password){
  148. if(password==null || name==null)return ERRORINFO;
  149. return countertick(name, password);
  150. }
  151. }