Android客户端程序通过Web Service实现对服务器端数据库的查询

来源:互联网 发布:写小说 软件 编辑:程序博客网 时间:2024/05/21 06:26

本人刚刚接触Android开发,想做一个查询成绩的app,因为只涉及数据库的查询而不进行增删改之类的操作,所以打算用Web service作为手机app和服务器端的桥梁,来对服务器数据库的进行查询。经过一段时间在书上和网上查找资料终于完成了这个app,我把整个过程记录下来希望能和大家分享。

一、参考文献

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.郭霖大侠的《第一行代码Android》 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;} elsereturn -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"; // 连接服务器和数据库sampleString 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;}}};

这样客户端程序也搞定了。

手机运行测试如图:


总结

从刚接触Android开发到在自己手机上运行了自己写的程序,我花费了不少时间自学完成了这个应用。当然我这个应用还有很多不足,比如查询成绩可以一次查询所有科目的成绩,不用分别查询,界面也太过于简陋等,这都还需要进一步的完善。写这篇文章主要是提供了解决这一问题的整体思路,也是对自己进步的一个记录和对其中不足的督促。欢迎看到文章的各位能给我提供更好的建议,我希望能和更多的人交流,学习更多Android开发的知识。


0 0
原创粉丝点击