1. 程式人生 > >Android客戶端程式通過Web Service實現對伺服器端資料庫的查詢

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;
			}
		}

	};

這樣客戶端程式也搞定了。

手機執行測試如圖: