J2ME与Web Service-KSOAP的快速上手

  1、服务端
  这次要发布的web service非常简单。它的功能是把从客户端传入的字符串中的小写字母转变成大写字母,再返回给客户端。
  Soap服务器采用apache的AXIS(可以从http://ws.apache.org/axis/下载),应用服务器可以选用各种servlet容器,我这里采用的是weblogic。
  1.1实现类的源代码:
  //StringProcessor.java
  package com.jagie.j2me.ws;
  public class StringProcessor
  {
  public StringProcessor()
  {
  }
  public String process(String name)
  {
  return name.toUpperCase();
  }
  }
  1.2发布步骤
  1.准备一个目录作为web application的发布目录,我这里的这个目录叫jagiews,这个目录的全路径中最好不要有空格和中文。我的发布目录结构如下:
  2.编译StringProcessor.java,把生成的StringProcessor.class置于:\jagiews\WEB-INF\classes\com\jagie\j2me\ws目录下。
  3.在jagiews\WEB-INF\lib文件夹中置入以下axis服务器需要的jar文件axis.jar,axis-ant.jar,commons-discovery.jar,commons-logging.jar,jaxrpc.jar,log4j-1.2.8.jar,saaj.jar,wsdl4j.jar。这些文件可以在http://ws.apache.org/axis/下载。
  4.在jagiews\WEB-INF目录下增加2个发布描述文件:
  server-config.wsdd,web.xml。
  #server-config.wsdd
  <?xml version="1.0"encoding="UTF-8"?>
  <deployment xmlns=
  "http://xml.apache.org/axis/wsdd/"
  xmlns:java=
  "http://xml.apache.org/axis/wsdd/providers/java">
  <globalConfiguration>
  <parameter name=
  "adminPassword"value="admin"/>
  <parameter name=
  "attachments.Directory"
  value="C:\Program Files
  \Apache Tomcat 4.0\webapps
  \axis\WEB-INF\attachments"/>
  <parameter name=
  "attachments.implementation"
  value="org.apache.axis.
  attachments.AttachmentsImpl"/>
  <parameter name=
  "sendXsiTypes"
  value="true"/>
  <parameter name=
  "sendMultiRefs"
  value="true"/>
  <parameter name=
  "sendXMLDeclaration"
  value="true"/>
  <parameter name=
  "axis.sendMinimizedElements"
  value="true"/>
  <requestFlow>
  <handler type=
  "java:org.apache.axis.handlers.JWSHandler">
  <parameter
  name="scope"
  value="session"/>
  </handler>
  <handler type=
  "java:org.apache.axis.handlers.JWSHandler">
  <parameter
  name="scope"
  value="request"/>
  <parameter
  name="extension"
  value=".jwr"/>
  </handler>
  </requestFlow>
  </globalConfiguration>
  <handler name=
  "LocalResponder"
  type="java:org.apache.axis.
  transport.local.LocalResponder"/>
  <handler name="URLMapper"
  type="java:org.apache.axis.
  handlers.http.URLMapper"/>
  <handler name="RPCDispatcher"
  type="java:org.apache.axis.
  providers.java.RPCProvider"/>
  <handler name="Authenticate"
  type="java:org.apache.axis.
  handlers.SimpleAuthenticationHandler"/>
  <handler name="MsgDispatcher"
  type="java:org.apache.axis.
  providers.java.MsgProvider"/>
  <service name="AdminService"
  provider="java:MSG">
  <parameter name="allowedMethods"
  value="AdminService"/>
  <parameter name="enableRemoteAdmin"
  value="false"/>
  <parameter name="className"
  value="org.apache.axis.utils.Admin"/>
  <namespace>
  http://xml.apache.org/axis/wsdd/
  </namespace>
  </service>
  <service name="Version"
  provider="java:RPC">
  <parameter name="allowedMethods"
  value="getVersion"/>
  <parameter name="className"
  value="org.apache.axis.Version"/>
  </service>
  <!--your service begin-->
  <service name="StringProcess"
  provider="java:RPC">
  <parameter name="allowedMethods"
  value="process"/>
  <parameter name="className"
  value="com.jagie.j2me.
  ws.StringProcessor"/>
  </service>
  <!--your service end-->
  <transport name="http">
  <requestFlow>
  <handler type="URLMapper"/>
  <handler type=
  "java:org.apache.axis.handlers.
  http.HTTPAuthHandler"/>
  </requestFlow>
  </transport>
  <transport name="local">
  <responseFlow>
  <handler type="java:org.apache.axis.
  transport.local.LocalResponder"/>
  </responseFlow>
  </transport>
  </deployment>
  #web.xml
  <?xml version="1.0"
  encoding="ISO-8859-1"?>
  <!DOCTYPE web-app
  PUBLIC"-//Sun Microsystems,
  Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com
  /j2ee/dtds/web-app_2.2.dtd">
  <web-app>
  <display-name>Apache-Axis</display-name>
  <servlet>
  <servlet-name>AxisServlet</servlet-name>
  <display-name>Apache-Axis
  Servlet</display-name>
  <servlet-class>
  org.apache.axis.transport.http.AxisServlet
  </servlet-class>
  </servlet>
  <servlet>
  <servlet-name>AdminServlet</servlet-name>
  <display-name>Axis Admin Servlet</display-name>
  <servlet-class>
  org.apache.axis.transport.http.AdminServlet
  </servlet-class>
  <load-on-startup>100</load-on-startup>
  </servlet>
  <servlet>
  <servlet-name>SOAPMonitorService</servlet-name>
  <display-name>SOAPMonitorService</display-name>
  <servlet-class>
  org.apache.axis.monitor.SOAPMonitorService
  </servlet-class>
  <init-param>
  <param-name>SOAPMonitorPort</param-name>
  <param-value>5001</param-value>
  </init-param>
  <load-on-startup>100</load-on-startup>
  </servlet>
  <servlet-mapping>
  <servlet-name>AxisServlet</servlet-name>
  <url-pattern>/servlet/AxisServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
  <servlet-name>AxisServlet</servlet-name>
  <url-pattern>*.jws</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
  <servlet-name>AxisServlet</servlet-name>
  <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
  <servlet-name>SOAPMonitorService</servlet-name>
  <url-pattern>/SOAPMonitor</url-pattern>
  </servlet-mapping>
  <!--uncomment this if you want the admin servlet-->
  <!--
  <servlet-mapping>
  <servlet-name>AdminServlet</servlet-name>
  <url-pattern>/servlet/AdminServlet
  </url-pattern>
  </servlet-mapping>
  -->
  <!--currently the W3C havent settled
  on a media type for WSDL;
  http://www.w3.org/TR/2003/
  WD-wsdl12-20030303/#ietf-draft
  for now we go with the basic
  ''it''s XML''response-->
  <mime-mapping>
  <extension>wsdl</extension>
  <mime-type>text/xml</mime-type>
  </mime-mapping>
  <mime-mapping>
  <extension>xsd</extension>
  <mime-type>text/xml</mime-type>
  </mime-mapping>
  </web-app>
  5.开启你的application server,把目录jagiews发布为一个名叫jagiews的web application。
  6.测试:打开浏览器,输入网址(这里使用的是weblogic,其他的服务器请酌情修改):http://localhost:7001/jagiews/services/StringProcess?method=process&name=qqqq,如果浏览器能在返回的xml文档中显示字符串"QQQQ",恭喜你,你的web service发布成功了。如果发布不成功,请按以上发布步骤检查一下。
  2、客户端
  客户端自然是用MIDlet了,不过用什么方式来访问web service呢?其实有3种访问方式
  直接用HttpConnection访问http://localhost:7001/jagiews/services/StringProcess?method=process&name=qqqq,得到xml的返回数据,然后用kxml(http://kxml.enhydra.org/)解析,得到返回值。
  如果你的手机支持MIDP2.0的话,可以考虑使用JSR172。
  用ksoap api。
  这里讲述第三种方式。使用之前,你需要从http://ksoap.enhydra.org/software/downloads/index.html下载稳定的ksoap包,置于你的classpath中。
  2.1客户端源代码
  2.1.1 WSClientMIDlet.java
  package com.jagie.j2me.ws;
  import javax.microedition.midlet.*;
  import javax.microedition.lcdui.*;
  /**
  *<p>Title:</p>
  *<p>Description:</p>
  *<p>Copyright:Copyright(c)
  2004</p>
  *<p>Company:</p>
  * author not attributable
  * version 1.0
  */
  public class WSClientMIDlet
  extends MIDlet
  {
  static WSClientMIDlet instance;
  public WSClientMIDlet()
  {
  instance=this;
  }
  public void startApp()
  {
  Display display=
  Display.getDisplay(this);
  DisplayForm displayable=
  new DisplayForm();
  display.setCurrent(displayable);
  }
  public void pauseApp()
  {
  }
  public void destroyApp
  (boolean unconditional)
  {
  }
  public static void quitApp()
  {
  instance.destroyApp(true);
  instance.notifyDestroyed();
  instance=null;
  }
  }
  2.1.2 DisplayForm.java
  package com.jagie.j2me.ws;
  import javax.microedition.lcdui.*;
  /**
  *<p>Title:</p>
  *<p>Description:</p>
  *<p>Copyright:Copyright(c)
  2004</p>
  *<p>Company:</p>
  * author not attributable
  * version 1.0
  */
  public class DisplayForm
  extends Form
  implements CommandListener,
  Runnable
  {
  private TextField textField1;
  private Thread t;
  public DisplayForm()
  {
  super("字符转换webservice测试");
  try
  {
  jbInit();
  }
  catch(Exception e)
  {
  e.printStackTrace();
  }
  }
  private void jbInit()
  throws Exception
  {
  //Set up this Displayable
  to listen to command events
  textField1=new TextField
  ("","",15,TextField.ANY);
  this.setCommandListener(this);
  textField1.setLabel
  ("待处理的字符串是:");
  textField1.setConstraints
  (TextField.ANY);
  textField1.setInitialInputMode
  ("Tester");
  setCommandListener(this);
  //add the Exit command
  addCommand(new Command
  ("Exit",Command.EXIT,1));
  addCommand(new Command
  ("Process",Command.OK,1));
  this.append(textField1);
  }
  public void commandAction
  (Command command,
  Displayable displayable)
  {
  if(command.getCommandType
  ()==Command.EXIT)
  {
  WSClientMIDlet.quitApp();
  }
  else if(command.getCommandType()
  ==Command.OK)
  {
  t=new Thread(this);
  t.start();
  }
  }
  public void run()
  {
  String s1=
  textField1.getString();
  String s2=
  new StringProcessorStub().process(s1);
  StringItem resultItem=
  new StringItem("处理后的字符串是:",s2);
  this.append(resultItem);
  }
  }
  2.1.3 StringProcessorStub.java
  package com.jagie.j2me.ws;
  import org.ksoap.*;
  import org.ksoap.transport.HttpTransport;
  /**
  *<p>Title:</p>
  *<p>Description:</p>
  *<p>Copyright:Copyright(c)2004</p>
  *<p>Company:</p>
  * author not attributable
  * version 1.0
  */
  public class StringProcessorStub
  {
  public StringProcessorStub()
  {
  }
  public String process(String name)
  {
  String result=null;
  try
  {
  SoapObject rpc=
  new SoapObject
  ("http://localhost:
  7001/jagiews/services/StringProcess",
  "process");
  rpc.addProperty("name",name);
  HttpTransport ht=
  new HttpTransport
  ("http://localhost:7001/
  jagiews/services/StringProcess",
  "");
  result=(String)ht.call(rpc);
  }
  catch(Exception e){
  e.printStackTrace();
  }
  return result;
  }
  }
  总结
  有了ksoap,手机上调用web service就很容易了。不过要注意的是,使用网络连接这种费时操作的时候,一定要单独开线程进行,不要直接写在commandAction()方法里,否则出现画面被锁住的情况。