Android客戶端程式通過Web Service實現對伺服器端資料庫的查詢
1.eclipse+webservice開發例項 http://blog.csdn.net/xw13106209/article/details/7049614/
2.java通過JDBC連結SQLServer2012 http://blog.csdn.net/stewen_001/article/details/19553173/
3.http://blog.csdn.net/guolin_blog/article/details/26365913
二、搭建Web service
先說說我對webservice的理解。webservice其實相當於一個與平臺無關的封裝好的web函式,不論是什麼方式建立的webservice都具有統一標準的訪問方式,任何平臺的任何語言都可以用特定的方法來“呼叫”這個“函式”。使用webservice查詢資料庫可以避免暴露資料庫的使用者名稱密碼之類的資訊,保證了一定的安全性,當然也僅限於查詢這個功能。就比如現在我做的查詢成績的app,只要在伺服器端搭建了封裝好查詢成績的webservice,從手機app中訪問webservice就是一個遠端呼叫函式的過程,同樣在電腦上可以直接訪問這個webservice,卻不知道具體資料庫查詢如何實現的。
搭建webservice有很多種方式,我用的是axis2方式,因為我的功能相對比較簡單,axis2可以直接把一個java類中的public方法生成webservice。
1.測試axis2搭建的webservice
為了測試webservice,我先新建了一個類:
public class CalculateService { // 加法 public float plus(float x, float y) { return x + y; } // 減法 public float minus(float x, float y) { return x - y; } // 乘法 public float multiply(float x, float y) { return x * y; } // 除法 public float divide(float x, float y) { if (y != 0) { return x / y; } else return -1; } }
把這個類中的public方法釋出成webservice:
此時在Configuration中選擇Web service runtime:Apache Axis2出現如下問題:
百度後發現是新建專案時Dynamic web module version不相容導致的,Tomcat8.0中axis2只支援3.0以下的,改成2.5之後解決了問題。如下圖:
但是Webservice釋出成功後,從本地瀏覽器打開發現是http返回碼500,無法訪問。搜尋後發現有很多種方法但是我試驗都不管用,後來看到有人說這個是用jdk1.8才出現的問題,把jdk從1.8換到1.7版本就可以解決。無奈之下我只能採取這種方案,我很希望有更好的解決方法,因為更改jdk實在是太麻煩了:不僅作業系統中配置的jdk各種變數需要更新,之前所有程式配置的jre也全部都需要更新。但是沒有別的辦法,我就硬著頭皮把jdk全部換成了1.7。還真的解決了問題(我也不知道是什麼原理,如果你有更好的解決方法請告訴我),測試頁面上出現了:
plus是要呼叫的方法,“?”表示分隔方法和引數,“&”用來分隔多個引數。這樣測試用的webservice就搭建成功了。
2.測試資料庫連線
資料庫我用的是sqlserver2012,新建了一個表作為測試:
連線資料庫很簡單,微軟提供了jdbc for sqlserver,下載sqljdbc41.jar後在build paht中Add External JARs:
新建一個類用於測試資料庫連線:
public class Dbtest {
public static void main(String[] args) {
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; // 載入JDBC驅動
String dbURL = "jdbc:sqlserver://localhost:1433; DatabaseName=student_database"; // 連線伺服器和資料庫
String userName = "sa"; // 使用者名稱
String userPwd = "123456"; // 密碼
Connection dbConn;
try {
Class.forName(driverName);
dbConn = DriverManager.getConnection(dbURL, userName, userPwd);
System.out.println("Connection Successful!");
Statement stmt = dbConn.createStatement();
ResultSet res = null;
String selecttarget = "104599411520046";// 這個String內容可以從APP裡面讀取
String sqlString = "select * from student where ksbh="
+ selecttarget;
res = stmt.executeQuery(sqlString);
while (res.next()) {
System.out.println("ksbh:" + res.getString("ksbh") + "\n"
+ "name:" + res.getString("name") + "\n" + "zzll:"
+ res.getString("zzll") + "\n" + "wgy:"
+ res.getString("wgy") + "\n" + "ywk1:"
+ res.getString("ywk1") + "\n" + "ywk2:"
+ res.getString("ywk2") + "\n" + "zf:"
+ res.getString("zf"));
}
dbConn.close();
stmt.close();
res.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果如下:
3.測試連線資料庫的webservice
單個java程式中的資料庫連線成功了,我就開始著手在webservice中連線資料庫了,為每一科成績查詢編寫一個方法,然後釋出成webservice,其中一科的程式碼如下:
public String selectzzll(String a) {
System.out.println(a);
String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; // 載入JDBC驅動
String dbURL = "jdbc:sqlserver://localhost:1433; DatabaseName=student_database"; // 連線伺服器和資料庫sample
String userName = "sa"; // 預設使用者名稱
String userPwd = "123456"; // 密碼
Connection dbConn = null;
Statement stmt = null;
ResultSet res = null;
int zzll = 0;
try {
Class.forName(driverName);
dbConn = DriverManager.getConnection(dbURL, userName, userPwd);
System.out.println("Connection Successful!");
String selecttarget = a + "";
// "104599411520046";// 這個String內容可以從APP裡面讀取
String sqlString = "select * from student where ksbh="
+ selecttarget;
stmt = dbConn.createStatement();
res = stmt.executeQuery(sqlString);
while (res.next()) {
zzll = Integer.parseInt(res.getString("zzll"));
;
}
System.out.println("zzll=" + zzll);
dbConn.close();
stmt.close();
res.close();
} catch (Exception e) {
e.printStackTrace();
}
return zzll + "";
}
但是這個時候呼叫webservice沒有返回正確的結果,java控制檯提示說找不到連線資料庫的類。這個問題困擾了我好久,我就一直納悶為什麼java裡面就可以連線資料庫而釋出成webservice就不能了?
又是經過一番搜尋,發現了原來是這樣:
釋出成webservice後,不僅僅build path中要包含jdbc41.jar,在WebContent\WEB-INF\lib這個目錄下也需要複製進這個檔案,這樣就不會出現找不到類的問題了。這樣連線資料庫的webservice就搭建完成了,測試結果如下:
三、Android客戶端程式
Android客戶端程式我是參考了《第一行程式碼Android》第十章的部分程式碼,用於訪問webservice的程式碼如下:
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(
"http://192.168.1.109:8080/GradeQueryService/services/QueryService/selectname?a="
+ a);
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
Log.d("MainActivity", "HttpGetSucceed");// 請求和響應都成功了
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity, "utf-8");
這樣就可以呼叫webservice了,得到的返回資料是一個xml資料。注意要在AndroidManifest.xml檔案中新增訪問網路的許可權,否則程式在執行到HttpResponse httpResponse = httpClient.execute(httpGet);這條語句時會進行不下去。
解析xml格式的文字,可以使用dom、sax和pull等方式。因為pull的函式庫較小,比較適合移動裝置,而且是谷歌官方推薦的方法,於是我就使用了pull方法進行xml解析:
private void parseXMLWithPull(String xmlData) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
int eventType = xmlPullParser.getEventType();
String result = "";
Log.d("MainActivity", "10");
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
// 開始解析某個結點
case XmlPullParser.START_TAG: {
if ("ns:return".equals(nodeName)) {
result = xmlPullParser.nextText();
Log.d("MainActivity", "id is " + result);
Looper.prepare();
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
Looper.loop();
}
break;
}
// 完成解析某個結點
case XmlPullParser.END_TAG: {
if ("/ns:sayHelloResponse".equals(nodeName)) {
Log.d("MainActivity", "id is " + result);
}
break;
}
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
Log.d("MainActivity", "ParseFailed");
}
}
解析xml資料後,應該把返回的結果顯示到手機螢幕上,android又規定了主執行緒不能訪問網路,因為會導致程式無響應的情況出現,而子執行緒又不能對ui進行操作,否則多個子執行緒同時對ui進行更改會產生混亂。所以還得需要用android的handler類來解決多執行緒的問題。
為每一個查詢方法開啟一個子執行緒,每個子執行緒中加入相應的訊息傳遞的程式碼:
Message message = new Message();
message.what = SHOW_NAME;
message.obj = name1.toString();
handler.sendMessage(message);
主執行緒中加入更改ui的方法:
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_NAME:
String response = (String) msg.obj;
name.setText("姓名 " + response);
break;
case SHOW_ZZLL:
response = (String) msg.obj;
zzll.setText("政治理論 " + response);
break;
case SHOW_WGY:
response = (String) msg.obj;
wgy.setText("外國語 " + response);
break;
case SHOW_YWK1:
response = (String) msg.obj;
ywk1.setText("業務課一 " + response);
break;
case SHOW_YWK2:
response = (String) msg.obj;
ywk2.setText("業務課二 " + response);
break;
case SHOW_ZF:
response = (String) msg.obj;
zf.setText("總分 " + response);
break;
default:
break;
}
}
};
這樣客戶端程式也搞定了。
手機執行測試如圖: