这篇文章实在是耽搁了太久了,唉,人生呐,怎一个懒字了得!都不好意思扯会儿淡了,进入正题吧。
上篇我们将 Android 和 Servlet 进行 POST 方式进行数据交互搞通了,但是在例子中传输的数据是以最简单的 String 类型来举例的,下边我们就来用现在流行的 JSON 格式跑一个。Json,是个轻量级的数据交换格式,但具体有什么优劣、使用场景有哪些、或者和别的数据格式对比如何,这些不是我们本次的讨论内容,我单单说,怎么在 Android 和 Servlet 之间使用 Json 进行数据交互。开始吧——
动手前我们需要先考虑考虑:使用 Json 在 Android 和 Servlet 进行数据交互是一个什么样的构造?(“构造”这个词想了几分钟,觉得还比较恰当,因为如果直接用“过程”就太直接,因为可能我们还没有想到他就是一个数据格式转化的过程)
… …
留两行空间
留点自主思考的时间
… …
其实,使用 Json 格式进行数据交互,无非就是在数据在网络发送前转成 Json 格式,接收到后数据后用 Json 格式恢复,然后根据需要再转换成相应的数据格式方便使用,就是这个一个简单的过程。
所以,我们需要在 Android端 和 服务端 都加入对 Json 的支持,下面我们从服务端工程开始:
Java本身是不提供 Json这种数据结构,需要引入第三方jar包 或者 添加依赖库,在此我们也不讨论这些库的优劣,只以最经典的 json-lib(如有需要,点我免积分下载) 为例来使用 json。
还是以简单的登陆逻辑为例,首先我们在服务端工程中加入json-lib需要的几个包:
然后全部 Add to Build Path,此时 JsonObject、JsonArray等类就可以使用了,直接看代码吧:
/**
* Servlet implementation class LoginServlet
*/
@WebServlet(description = "登录", urlPatterns = { "/LoginServlet" })
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("不支持GET方法;");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BufferedReader read = request.getReader();
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = read.readLine()) != null) {
sb.append(line);
}
String req = sb.toString();
System.out.println(req);
// 第一步:获取 客户端 发来的请求,恢复其Json格式——>需要客户端发请求时也封装成Json格式
JSONObject object = JSONObject.fromObject(req);
// 第二步:将Json转化为别的数据结构方便使用或者直接使用(此处直接使用),进行业务处理,生成结果
// 拼接SQL查询语句
String sql = String.format("SELECT * FROM %s WHERE account='%s'",
DBNames.Table_Account,
object.getString("name"));
System.out.println(sql);
// 自定义的结果信息类
CommonResponse res = new CommonResponse();
try {
ResultSet result = DatabaseUtil.query(sql); // 数据库查询操作
if (result.next()) {
if (result.getString("password").equals(object.getString("password"))) {
res.setResult("0", "登陆成功");
res.getProperty().put("custId", result.getString("_id"));
} else {
res.setResult("100", "登录失败,登录密码错误");
}
} else {
res.setResult("200", "该登陆账号未注册");
}
} catch (SQLException e) {
res.setResult("300", "数据库查询错误");
e.printStackTrace();
}
// 第三步:将结果封装成Json格式准备返回给客户端,但实际网络传输时还是传输json的字符串
// 和我们之前的String例子一样,只是Json提供了特定的字符串拼接格式
String resStr = JSONObject.fromObject(res).toString();
System.out.println(resStr);
// response.getWriter().append(EncryptUtil.getEDSEncryptStr(resStr)); // 可以对字符串进行加密操作,相应的到了客户端就需要解密
response.getWriter().append(resStr).flush();
}
}
另外附上DatebaseUtil.java的代码:
public class DatabaseUtil {
private static Connection mConnection;
/**
* 获取数据库连接
*
* @return 唯一数据库连接
*/
private static Connection getConnection() {
if (mConnection == null) {
String url = "jdbc:mysql://localhost:3306/db_myworld"; // 数据库的Url
try {
Class.forName("com.mysql.jdbc.Driver"); // java反射,固定写法
mConnection = (Connection) DriverManager.getConnection(url, "root", "wang,jie.");
LogUtil.log("创建数据库连接");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
System.out.println("SQLException: " + e.getMessage());
System.out.println("SQLState: " + e.getSQLState());
System.out.println("VendorError: " + e.getErrorCode());
}
}
return mConnection;
}
/**
* 查询操作
*
* @param querySql
* 查询操作SQL语句
* @return 查询
* @throws SQLException
*/
public static ResultSet query(String querySql) throws SQLException {
Statement stateMent = (Statement) getConnection().createStatement();
return stateMent.executeQuery(querySql);
}
/**
* 插入、更新、删除操作
*
* @param insertSql
* 插入操作的SQL语句
* @return
* @throws SQLException
*/
public static int update(String insertSql) throws SQLException {
Statement stateMent = (Statement) getConnection().createStatement();
return stateMent.executeUpdate(insertSql);
}
/**
* 关闭数据库连接
*/
public static void closeConnection() {
if (mConnection != null) {
try {
mConnection.close();
mConnection = null;
} catch (SQLException e) {
LogUtil.log("数据库关闭异常:[" + e.getErrorCode() + "]" + e.getMessage());
}
}
}
}
为了明了,数据库表格中就这么一条数据:
好了,服务端的处理就处理完了;
接下来该 Android 客户端的处理了:
Android 使用 Json 比服务端要简单很多,因为(据说,未经考证)自 Android 2.3起,Google 将Json加入 Android 源码,所以在 Android 2.3 及更高版本可以直接使用 Json 各类(Json 在 org.json 包下)而不用加入第三方jar包或额外添加依赖。
因为之前的文章中已经说的够清楚了,这里就不再粘贴大篇幅的代码,只将不同的不分贴出来:
参考 【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-1)Android 和 Service 的交互之GET方式 末尾 AsyncTask 类的使用,只要修改其中
@Override
protected void onPostExecute(String result) {
if (!"".equals(result)) {
LogUtil.logResponse(result); // 日志输出原始应答报文
try {
JSONObject resultJson = new JSONObject(result); // 此处就可以将服务端返回的Json的字符串还原成Json格式的数据
// 下边就可以根据需求将Json转化合适的数据结构来使用了
// ... ...自己的业务逻辑
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("WangJ", "结果为空!");
}
}
其实,说白了就是多了一步——在获取到服务端返回的报文后,将读取到的报文体字符串重新恢复 Json 格式(因为我们在 Servlet 中将信息封装成 Json 格式的返回给了 Android 客户端)。之后就可以根据自己的业务逻辑,将这个 Json 转成需要的数据结构,然后就是任你摆布了!
到此,使用 Json 进行数据交互的过程就可以说完成了。
但是,你肯定会觉得,这样的代码还真是不堪入目啊,毫无美感可言,甚至可以说是真烂真丑,我承认,确实。因为我们没有进行任何的封装,所以这些代码用起来真心不好用,也不好看,所以我们需要再用一篇来收个尾,把这个过程封装一下,也给这个系列画个句号——敬请期待,完结篇。
水平有限,如有不足,敬请指正,程序猿大人先行谢过!