本節摘要:之前在一篇博客中介紹過如何寫一個webservice(http://www.cnblogs.com/java-pan/archive/2011/11/25/axis_webservice.html),不過那個webservice是在工作項目中直接添加的,中間少了很多麻煩,不是白手起家總感覺前面一步一步的過程不清楚。myeclipse自帶的也有如何新建一個webservice工程,這也不是我要說的,項目中這個也不實用,項目中都是在當前開發的web工程中寫一個webservice,誰會再去新建一個工程,那不是扯淡嗎?本節在一個已經存在的web工程中,來新建類、新建配置文件,發布webservice、訪問webservice。基於axis1.4的版本來完成的。
preparation
1.在閱讀本機之前你需要看以下相關知識:
JDBC;
JDBC的介紹這里就不說了,網上忒多的資料了,這個也是做java接觸數據庫時必會的
ibatis;
可以參考我之前的博客http://www.cnblogs.com/java-pan/archive/2012/03/21/ibatis.html
XStream;
可以參考我之前的博客http://www.cnblogs.com/java-pan/archive/2011/10/25/Object_xml.html
axis;
可以參考我之前的博客http://www.cnblogs.com/java-pan/archive/2011/11/25/axis_webservice.html
2.項目結構
myeclipse:6.5 tomcat:5.0 system:win7 JDK:項目的版本是1.5 編譯采用的是1.4

說明:本節介紹的是基於axis的webservice,采用的版本為axis1.4
3.下載項目中用到的jar包
http://files.cnblogs.com/java-pan/lib-axis1.4.rar
以上鏈接包含下面的所有包。下載的jar包主要包含以下幾部分:
(1)oracle數據庫驅動包 :classes12.jar
(2)ibatis包:ibatis-2.3.4.jar
(3)xstream-1.2.1.jar
(4)axis包(從以下鏈接下載http://mirror.bjtu.edu.cn/apache/ws/axis/1_4/ 下載后解壓把lib下所有包導入)
(5)activation.jar和mail.jar 建議導入的包
以上除最后一個jar包外,其它的程序運行必須導入。(可能axis不需要導入所有的包,不過我們就全部導入好了)
項目jar包的詳細列表如下:

說明:lib下一共中13個jar包,截圖的圖片也有13個jar包,但是博客發布后顯示的只有8個jar包,可以圖片另存為看到所有的jar包。
4.class&mthod
JDBC:DriverManager、Connection、PreparedStatement、ResultSet
DriverManager:
getConnection(String url, String user, String password)獲得一個Connection對象,參數依次為數據庫驅動的url、用戶名、密碼
Connection:
prepareStatement(String sql)獲得一個預處理對象PreparedStatement
PreparedStatement:
executeQuery()執行查詢操作,返回一個結果集對象ResultSet,不要傳入任何參數
ResultSet:
next()返回一個布爾類型的值,用於判斷是否還有記錄
Ibatis:SqlMapClient、SqlMapClientBuilder
SqlMapClient:
SqlMapClient buildSqlMapClient(Reader reader)傳入一個reader對象,創建一個SqlMapClient 對象
startTransaction();開始事務
getCurrentConnection()獲取當前連接,回滾事務的時候用到
endTransaction結束事務
SqlMapClientBuilder:
queryForObject(String s, Object obj)第一個參數為實體類對應的配置文件的id屬性,第二個為傳入的參數,此方法的返回值是一個Object對象
xstream:XStream
XStream:
alias(String name, Class type)設置節點的別名
alias(String name, Class type)設置某一元素節點的別名
toXML(Object obj)把對應的obj轉換為xml格式的字符串
其他類:Reader、Resources、StringBuffer
Reader:java I/O對象,用於讀取字符流的抽象類,這里就不再介紹,請查看JDK幫助文檔
Resources:此類為ibatis的jar包中的類,非JDK的類
getResourceAsReader(String resource)對於resource路徑的文件,獲得一個Reader對象
StringBuffer:線程安全的可變字符序列
append(String str)將指定的字符串追加到此字符序列
toString()返回此序列中數據的字符串表示形式
start
新建一個web工程,項目命名為WebService,按照工程目錄新建對應的文件如下:
實體類-Dept.java
Dept
1 package com.bean; 2 3 /** 4 * 5 *Module: Dept.java 6 *Description: 寫一個oracle數據庫自帶的部門表dept的javabean 7 *Company: 8 *Author: pantp 9 *Date: May 1, 2012 10 */ 11 public class Dept { 12 public int deptNo; 13 public String dName; 14 public String loc; 15 16 public int getDeptNo() { 17 return deptNo; 18 } 19 20 public void setDeptNo(int deptNo) { 21 this.deptNo = deptNo; 22 } 23 24 public String getDName() { 25 return dName; 26 } 27 28 public void setDName(String name) { 29 dName = name; 30 } 31 32 public String getLoc() { 33 return loc; 34 } 35 36 public void setLoc(String loc) { 37 this.loc = loc; 38 } 39 }
數據庫連接文件-ConnectDataBase.java
ConnectDataBase
1 package com.cn; 2 3 import java.io.IOException; 4 import java.io.Reader; 5 6 import java.sql.Connection; 7 import java.sql.DriverManager; 8 import java.sql.SQLException; 9 10 import com.ibatis.common.resources.Resources; 11 import com.ibatis.sqlmap.client.SqlMapClient; 12 import com.ibatis.sqlmap.client.SqlMapClientBuilder; 13 14 /** 15 * 16 *Module: ConnectDataBase.java 17 *Description: 數據庫連接類,采用兩種方式:1.JDBC 2.Ibatis框架 18 *Company: 19 *Author: pantp 20 *Date: May 1, 2012 21 */ 22 public class ConnectDataBase { 23 24 //采用JDBC的方式連接數據 25 private final static String USERNAME = "scott"; 26 private final static String PASSWORD = "orcl"; 27 private final static String URL = "jdbc:Oracle:thin:@localhost:1521:orcl"; 28 private final static String DRIVER = "oracle.jdbc.driver.OracleDriver"; 29 static Connection conn = null; 30 31 // 獲取連接 32 static { 33 // 加載驅動 34 try { 35 Class.forName(DRIVER); 36 } catch (ClassNotFoundException e) { 37 e.printStackTrace(); 38 } 39 // 獲得連接對象conn 40 try { 41 conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); 42 } catch (SQLException e) { 43 e.printStackTrace(); 44 } 45 } 46 47 //提供一個方法供外部調用,獲得JDBC連接對象conn 48 public static Connection getConnection() { 49 return conn; 50 } 51 52 53 // 定義ibatis映射文件的位置,寫配置文件的完整路徑 54 private static String resource = "com/ibatis/SqlMapConfig.xml"; 55 private static SqlMapClient sqlMapClient = null; 56 static { 57 try { 58 Reader reader = Resources.getResourceAsReader(resource); 59 sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader); 60 reader.close(); 61 } catch (IOException e) { 62 e.printStackTrace(); 63 } 64 } 65 66 //提供一個方法供外部調用,獲得Ibatis的連接對象sqlMapClient 67 public static SqlMapClient getSqlMapClient(){ 68 return sqlMapClient; 69 } 70 71 72 }
實體類對應的映射文件-Dept.xml
Dept
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- 3 author:pantp 4 date:2012/05/01 5 description:javabean對應的xml配置文件 6 --> 7 <!DOCTYPE sqlMap 8 PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" 9 "http://ibatis.apache.org/dtd/sql-map-2.dtd"> 10 11 <sqlMap> 12 <typeAlias alias="Dept" type="com.bean.Dept" /> 13 14 <!-- 精確查詢 按照條件查詢記錄 按照部門編號DEPTNO查詢 --> 15 <select parameterClass="int" resultClass="Dept" id="selectById"> 16 select deptno,dname,loc from dept where deptno=#deptNo# 17 </select> 18 19 </sqlMap>
數據庫連接屬性文件-SqlMap.properties
SqlMap.properties
1 driver=oracle.jdbc.driver.OracleDriver 2 url=jdbc:Oracle:thin:@127.0.0.1:1521:orcl 3 username=scott 4 password=orcl
ibatis核心配置文件-SqlMapConfig.xml
SqlMapConfig.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- 3 author:pantp 4 date:2012/05/01 5 description:Ibatis框架的核心配置文件,主要是數據庫連接屬性文件和實體類和表的映射文件引入進來 6 --> 7 <!DOCTYPE sqlMapConfig 8 PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" 9 "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> 10 11 <sqlMapConfig> 12 13 <!-- 數據庫連接的屬性文件 --> 14 <properties resource="com/ibatis/SqlMap.properties" /> 15 <transactionManager type="JDBC"> 16 <dataSource type="SIMPLE"> 17 <property value="${driver}" name="JDBC.Driver" /> 18 <property value="${url}" name="JDBC.ConnectionURL" /> 19 <property value="${username}" name="JDBC.Username" /> 20 <property value="${password}" name="JDBC.Password" /> 21 </dataSource> 22 </transactionManager> 23 24 <!-- 實體類和數據庫表的映射 --> 25 <sqlMap resource="com/ibatis/Dept.xml" /> 26 27 </sqlMapConfig>
定義查詢服務的接口文件-IQueryInfoSV.java
IQueryInfoSV
1 package com.interfaces; 2 3 import java.sql.SQLException; 4 5 /** 6 * 7 *Module: IQueryInfoSV.java 8 *Description: 定義查詢的接口 9 *Company: 10 *Author: pantp 11 *Date: May 1, 2012 12 */ 13 public interface IQueryInfoSV { 14 15 //JDBC 16 public abstract String queryDept1(int deptNo) throws SQLException; 17 18 //ibatis 19 public abstract String queryDept2(int deptNo) throws SQLException; 20 21 }
定義查詢服務的實現類-QueryInfoSVImpl.java
QueryInfoSVImpl
1 package com.impl; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import com.bean.Dept; 7 import com.cn.ConnectDataBase; 8 import com.ibatis.sqlmap.client.SqlMapClient; 9 import com.interfaces.IQueryInfoSV; 10 import com.thoughtworks.xstream.XStream; 11 import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer; 12 import com.thoughtworks.xstream.io.xml.XppDriver; 13 14 import java.sql.SQLException; 15 16 /** 17 * 18 *Module: QueryInfoSVImpl.java 19 *Description: 根據部門編號查詢oracle自帶的dept表,提供兩種查詢方式:1.JDBC 2.Ibatis 20 *Company: 21 *Author: pantp 22 *Date: May 1, 2012 23 */ 24 public class QueryInfoSVImpl implements IQueryInfoSV { 25 26 // 采用JDBC方式連接數據庫的查詢操作 27 public String queryDept1(int deptNo) throws SQLException { 28 // 獲取JDBC的連接 29 Connection conn = ConnectDataBase.getConnection(); 30 // 拼裝SQL語句 31 String sql = "select deptno,dname,loc from dept where deptno=" + deptNo; 32 // 獲得預處理對象pst 33 PreparedStatement pst = conn.prepareStatement(sql); 34 // 查詢結果集 35 ResultSet rs = pst.executeQuery(); 36 37 // 采用next()方法取得數據庫數據,deptNo是逐漸采用deptNo查詢,要么沒有查到數據,要么只能查到一條數據 38 String result = ""; 39 Dept dept = null; 40 while (rs.next()) { 41 dept = new Dept(); 42 dept.deptNo = deptNo; 43 dept.dName = rs.getString("dName"); 44 dept.loc = rs.getString("loc"); 45 } 46 result = getXML(dept); 47 return result; 48 } 49 50 // 采用ibatis連接數據庫並按部門編號精確查找 51 public String queryDept2(int deptNo) throws SQLException { 52 // 獲得ibatis的連接對象sqlMapClient 53 SqlMapClient sqlMapClient = ConnectDataBase.getSqlMapClient(); 54 Dept dept = null; 55 try { 56 sqlMapClient.startTransaction();// 開始事務 57 // 執行查詢 此處的"selectById"對應Dept.xml文件中select標簽的id屬性 58 dept = (Dept) sqlMapClient.queryForObject("selectById", 59 new Integer(deptNo)); 60 sqlMapClient.commitTransaction();// 提交事務 61 } catch (SQLException e) { 62 try { 63 sqlMapClient.getCurrentConnection().rollback();// 回滾事務 64 } catch (SQLException e1) { 65 e1.printStackTrace(); 66 } 67 e.printStackTrace(); 68 } finally { 69 try { 70 sqlMapClient.endTransaction();// 結束事務 71 } catch (SQLException e) { 72 e.printStackTrace(); 73 } 74 } 75 // 組裝xml報文並返回 76 return getXML(dept); 77 } 78 79 // 采用XStream方式組裝XML 80 public static String getXML(Dept dept) { 81 // 用於保存XML的內容 82 String xmlbody = ""; 83 // 用於保存XML的頭部 84 String xmlhead = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; 85 86 if (null != dept) { 87 // 構造一個xstream對象,此種構造方式解決下划線站兩個字符的問題 88 XStream xstream = new XStream(new XppDriver( 89 new XmlFriendlyReplacer("-_", "_"))); 90 91 // 設置別名,不設置的話顯示為Dept_Info顯示為com.bean.Dept 92 xstream.alias("DEPT_INFO", Dept.class); 93 xstream.aliasField("DEPTNO", Dept.class, "deptNo"); 94 xstream.aliasField("DNAME", Dept.class, "dName"); 95 xstream.aliasField("LOC", Dept.class, "loc"); 96 97 // 把實體類轉換為XML 98 xmlbody = xstream.toXML(dept); 99 } else { 100 // 處理根據編號沒有查詢到數據的情況 101 StringBuffer sb = new StringBuffer(); 102 sb 103 .append("<DEPT_INFO><DEPTNO></DEPTNO><DNAME></DNAME><LOC></LOC></DEPT_INFO>"); 104 xmlbody = sb.toString(); 105 } 106 return xmlhead + xmlbody; 107 } 108 }
測試類-Test1.java 用於測試JDBC和ibatis的數據庫連接是否正常
Test1
1 package com.test; 2 3 import java.sql.SQLException; 4 import com.impl.QueryInfoSVImpl; 5 import com.interfaces.IQueryInfoSV; 6 7 /** 8 * 9 *Module: Test1.java 10 *Description: 測試JDBC和Ibatis數據庫查詢是否正常 11 *Company: 12 *Author: ptp 13 *Date: May 1, 2012 14 */ 15 public class Test1 { 16 17 // 測試數據庫是可以正常查詢 18 public static void main(String[] args) throws SQLException { 19 int deptNo = 10; 20 test1(deptNo); 21 test2(deptNo); 22 } 23 24 //測試JDBC方式連接數據庫是否正常 25 public static void test1(int deptNo) throws SQLException { 26 IQueryInfoSV query = new QueryInfoSVImpl(); 27 String dept = query.queryDept1(deptNo); 28 29 System.out 30 .println("\n===============采用JDBC方式查詢數據庫連接正常 author<pantp>=======\n"); 31 System.out.println(dept); 32 System.out 33 .println("\n===============采用JDBC方式查詢數據庫連接正常==================\n"); 34 } 35 36 //測試ibatis方式連接數據庫是否正常 37 public static void test2(int deptNo) throws SQLException { 38 IQueryInfoSV query = new QueryInfoSVImpl(); 39 String dept = query.queryDept2(deptNo); 40 41 System.out 42 .println("\n===============采用ibatis方式查詢數據庫連接正常 author<pantp>========\n"); 43 System.out.println(dept); 44 System.out 45 .println("\n===============采用ibatis方式查詢數據庫連接正常==================\n"); 46 } 47 48 }
測試類-Test2.java 用於測試webservice服務是否可以正常調用
Test2
1 package com.test; 2 3 import java.net.MalformedURLException; 4 import java.net.URL; 5 import java.rmi.RemoteException; 6 7 import javax.xml.rpc.ParameterMode; 8 import javax.xml.rpc.ServiceException; 9 10 import org.apache.axis.client.Call; 11 import org.apache.axis.encoding.XMLType; 12 13 /** 14 * 15 *Module: Test2.java 16 *Description: 項目中常用調用webservice方式有兩種,stub樁的形式和動態調用,本次測試就用動態調用的方式 17 *Company: 18 *Author: pantp 19 *Date: May 1, 2012 20 */ 21 public class Test2 { 22 23 // 調用webservice 24 public static void main(String[] args) { 25 test2(); 26 } 27 28 /** 29 * 動態調用接口訪問webservice服務的步驟如下: 30 * 1.創建service對象 31 * 2.創建url對象 32 * 3.創建call對象, 33 * 4.調用webservice的方法 34 * 5.處理返回結果 35 */ 36 public static void test2() { 37 try { 38 // 1.創建service對象,通過axis自帶的類創建 39 org.apache.axis.client.Service service = new org.apache.axis.client.Service(); 40 41 // 2.創建url對象 42 String wsdlUrl = "http://127.0.0.1:8080/WebService/services/queryInfo?WSDL";// 請求服務的URL 43 URL url = new URL(wsdlUrl);// 通過URL類的構造方法傳入wsdlUrl地址創建URL對象 44 45 // 2.創建服務方法的調用者對象call,設置call對象的屬性 46 Call call = (Call) service.createCall(); 47 call.setTargetEndpointAddress(url);// 給call對象設置請求的URL屬性 48 String serviceName = "queryDept2";//webservice的方法名 49 call.setOperationName(serviceName);// 給call對象設置調用方法名屬性 50 call.addParameter("deptNo", XMLType.XSD_INT, ParameterMode.IN);// 給call對象設置方法的參數名、參數類型、參數模式 51 call.setReturnType(XMLType.SOAP_STRING);// 設置調用方法的返回值類型 52 // call.setTimeout(new Integer(5000));//設置超時限制 53 54 // 4.通過invoke方法調用webservice 55 Integer deptNo = new Integer(50); 56 String dept = (String) call.invoke(new Object[] { deptNo });// 調用服務方法 57 58 //5.打印返回結果 59 System.out 60 .println("\n===============調用webservice成功(無安全機制) author<pantp>=======\n"); 61 System.out.println(dept); 62 System.out 63 .println("\n===============調用webservice成功(無安全機制)==================\n"); 64 65 } catch (MalformedURLException e) { 66 e.printStackTrace(); 67 } catch (ServiceException e) { 68 e.printStackTrace(); 69 } catch (RemoteException e) { 70 e.printStackTrace(); 71 } 72 } 73 74 }
web.xml-項目配置文件
Web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 5 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 6 <servlet> 7 <servlet-name>AxisServlet</servlet-name> 8 <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class> 9 </servlet> 10 <servlet-mapping> 11 <servlet-name>AxisServlet</servlet-name> 12 <url-pattern>/services/*</url-pattern> 13 </servlet-mapping> 14 <mime-mapping> 15 <extension>wsdl</extension> 16 <mime-type>text/xml</mime-type> 17 </mime-mapping> 18 <mime-mapping> 19 <extension>xsd</extension> 20 <mime-type>text/xml</mime-type> 21 </mime-mapping> 22 23 </web-app>
server-config.wsdd-webservice服務部署的配置文件
server-config.wsdd
1 <?xml version="1.0" encoding="UTF-8"?> 2 <deployment name="defaultClientConfig" 3 xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" 4 xmlns:handler="http://xml.apache.org/axis/wsdd/providers/handler" xmlns="http://xml.apache.org/axis/wsdd/"> 5 6 <globalConfiguration name="GlobalConfiguration1" type="" regenerateElement="false"> 7 <requestFlow name="RequestFlow1" type="" regenerateElement="false"> 8 <handler name="Handler1" 9 type="java:org.apache.axis.handlers.JWSHandler" regenerateElement="false"> 10 <parameter name="scope" value="session" regenerateElement="false"/> 11 </handler> 12 <handler name="Handler2" 13 type="java:org.apache.axis.handlers.JWSHandler" regenerateElement="false"> 14 <parameter name="scope" value="request" regenerateElement="false"/> 15 <parameter name="extension" value=".jwr" regenerateElement="false"/> 16 </handler> 17 </requestFlow> 18 </globalConfiguration> 19 20 <handler name="URLMapper" 21 type="java:org.apache.axis.handlers.http.URLMapper" regenerateElement="false"/> 22 <handler name="LocalResponder" 23 type="java:org.apache.axis.transport.local.LocalResponder" regenerateElement="false"/> 24 <handler name="Authenticate" 25 type="java:org.apache.axis.handlers.SimpleAuthenticationHandler" regenerateElement="false"/> 26 <transport name="http" type="" regenerateElement="false"> 27 <requestFlow name="RequestFlow1" type="" regenerateElement="false"> 28 <handler name="Handler1" type="URLMapper" regenerateElement="false"/> 29 <handler name="Handler2" 30 type="java:org.apache.axis.handlers.http.HTTPAuthHandler" regenerateElement="false"/> 31 </requestFlow> 32 </transport> 33 <transport name="local" type="" regenerateElement="false"> 34 <responseFlow name="ResponseFlow1" type="" regenerateElement="false"> 35 <handler name="Handler1" type="LocalResponder" regenerateElement="false"/> 36 </responseFlow> 37 </transport> 38 39 <service name="queryInfo" provider="java:RPC"> 40 <!-- 服務類名 --> 41 <parameter name="className" value="com.impl.QueryInfoSVImpl" /> 42 <!-- 允許訪問所有方法 --> 43 <parameter name="allowedMethods" value="*" /> 44 </service> 45 </deployment>
---把博客貼出來主要是請大家幫看看后面的問題,關於配置文件的介紹后面會加上詳細的說明---
result
發布項目,啟動tomcat。
運行Test1.java中的main方法,測試JDBC和ibatis數據庫查詢是否正常,查詢結果如下:

在瀏覽器訪問發布的wsdl
輸入如下地址:http://127.0.0.1:8080/WebService/services/queryInfo?WSDL
訪問界面如圖:

運行Test2類中的main方法,測試結果如下圖:

webservice服務存在以下2個問題:
(1)如上圖所示,按說在瀏覽器中可以正常的訪問wsdl的話,就說明服務已經發布好了。為什么客戶端調用會報如此錯誤呢?
(2)如果我把訪問的127.0.0.1改為localhost就不能正常的訪問wsdl了,這個是什么原因呢?
急需大蝦出現解決小弟的問題,我也在努力的查找中。跪求ing。
為方便各位大俠幫小弟查問題,源碼下載地址如下:http://files.cnblogs.com/java-pan/WebService.rar
modified by pantp 2012/08/22
問題定位及解決方法:
關於此博客中的問題一直未解決,心中的石頭也一直未落地;
經過這兩天的再一次拿出來查找問題、定位問題,終於得到了答案。
解決方式:把ConnectDataBase類中采用ibatis操作數據庫的代碼給去掉,然后再一次重新發布工程,啟動tomcat,
此時,在IE瀏覽器可以正常的訪問wsdl地址,采用webservice客戶端形式(包括動態調用和stub樁的形式)也可以正常的調用webservice服務。
初步分析原因,可能是ibatis和axis的版本不兼容導致。
