Android通过HTTP(TomCat)连接MySQL实现登陆与注册数据交互

在基本学完JDBC、TomCat、MySQL后,能做一个Android登陆注册交互客户端一直是令人期待的吧。在多处查找后,终于在云中仙客的cnblogs博客中找到一篇详细的教程,不过似乎原作者并没有把注册和server部分写完,我在下文中已经补上,并修改了Service中的部分代码使其使得服务器能正常访问。


一、开发环境的部署

程序结构:Android + TomCat + MySQL
服务端:MySQL、TomCat
客户端:Eclipse、Android Studio(可选)
一部Android真机或Genymotion虚拟机

二、配置MySQL数据库

create database test;
use test;
CREATE TABLE `student` (  `id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(20) NOT NULL, `password` varchar(20) NOT NULL,  PRIMARY KEY (`id`)  ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;

三、服务器端的搭建

新建名为HelloWeb的Web Project

项目布局如下图

分别新建 LogLet类和RegLet类分别用于处理客户端的登陆和注册请求;Service类用于完成servlet对数据库的具体操作;DBManager类用于进行数据库基本操作;

修改web.xml 配置文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<servlet>
<servlet-name>LogLet</servlet-name>
<servlet-class>com.servlet.LogLet</servlet-class>
</servlet>
<servlet>
<servlet-name>RegLet</servlet-name>
<servlet-class>com.servlet.RegLet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>LogLet</servlet-name>
<url-pattern>/LogLet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>RegLet</servlet-name>
<url-pattern>/RegLet</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


项目代码

DBManager.java

 <1> 单例模式构建DBManager对象;

 <2> 定义数据库连接、关闭以及增删改查的基本操作,返回结果集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.db;

import java.sql.*;

public class DBManager {

// 数据库连接常量
public static final String DRIVER = "com.mysql.jdbc.Driver";
public static final String USER = "MySQL-USER";
public static final String PASS = "MySQL-PASS";
public static final String URL = "jdbc:mysql://localhost:3306/test";
//把MySQL-USER和MySQL-PASS改为你的服务器mysql账户和密码

// 静态成员,支持单态模式
private static DBManager per = null;
private Connection conn = null;
private Statement stmt = null;

// 单态模式-懒汉模式
private DBManager() {
}

public static DBManager createInstance() {
if (per == null) {
per = new DBManager();
per.initDB();
}
return per;
}

// 加载驱动
public void initDB() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
}
}

// 连接数据库,获取句柄+对象
public void connectDB() {
System.out.println("Connecting to database...");
try {
conn = DriverManager.getConnection(URL, USER, PASS);
stmt = conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("SqlManager:Connect to database successful.");
}

// 关闭数据库 关闭对象,释放句柄
public void closeDB() {
System.out.println("Close connection to database..");
try {
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("Close connection successful");
}

// 查询
public ResultSet executeQuery(String sql) {
ResultSet rs = null;
try {
rs = stmt.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}

// 增添/删除/修改
public int executeUpdate(String sql) {
int ret = 0;
try {
ret = stmt.executeUpdate(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return ret;
}
}

Service.java

 下一个类会通过调用本类方法完成登陆/注册的服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 package com.service;

import java.sql.ResultSet;
import java.sql.SQLException;

import com.db.DBManager;

public class Service {

public Boolean login(String username, String password) {

// 获取Sql查询语句
String logSql = "select * from student where username ='" + username
+ "' and password ='" + password +"'";

// 获取DB对象
DBManager sql = DBManager.createInstance();
sql.connectDB();

// 操作DB对象
try {
ResultSet rs = sql.executeQuery(logSql);
if (rs.next()) {
sql.closeDB();
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
sql.closeDB();
return false;
}

public Boolean register(String username, String password) {

// 获取Sql查询语句
String regSql = "insert into student (username,password) values('"
+ username + "','" + password + "') ";


// 获取DB对象
DBManager sql = DBManager.createInstance();
sql.connectDB();

int ret = sql.executeUpdate(regSql);
// System.out.println("test"+ ret);
if (ret != 0) {
sql.closeDB();
return true;
}
sql.closeDB();

return false;
}
}

LogLet.java

  一个简单的Servlet,用于处理Http请求(get/post)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.omg.CORBA.PUBLIC_MEMBER;

import com.service.Service;

public class LogLet extends HttpServlet {

private static final long serialVersionUID = 369840050351775312L;

/**
* The doGet method of the Server let.
*/


public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

// 接收信息
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
String password = request.getParameter("password");
String confirm;
System.out.println(username + "--" + password);

// 新建服务对象
Service serv = new Service();

// 验证处理
boolean loged = serv.login(username, password);
if (loged) {
System.out.print("Succss");
confirm = "\n登陆成功";
request.getSession().setAttribute("username", username);
// response.sendRedirect("welcome.jsp");
} else {
System.out.print("Failed");
confirm = "\n账号或密码不正确";
}

// 返回信息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("用户名:" + username);
out.print("密码:" + password);
out.print(confirm);
out.flush();
out.close();

}

/**
* The doPost method of the Server let.
*/


public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

// 测试为何手机端中文乱码,电脑正常
// System.out.println("u1--"+username);
// System.out.println("u2--"+username);

}

}

RegLet.java
与LogLet类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.service.Service;

public class RegLet extends HttpServlet {

private static final long serialVersionUID = -4415294210787731608L;

/**
* The doGet method of the Server let.
*/


public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {


// 新建服务对象
Service serv = new Service();

// 接收注册信息
// String username = request.getParameter("r_name");
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
String password = request.getParameter("password");
String confirm;
// String password = request.getParameter("r_password");
System.out.println("test");
// 验证处理
boolean reged = serv.register(username,password);
System.out.println("test" + reged);
if (reged) {
System.out.print("Succss");
confirm="\n注册成功";
request.getSession().setAttribute("username", username);
//response.sendRedirect("welcome.jsp");
}else {
System.out.print("Failed");
confirm="\n注册失败,似乎您已注册";
}


// 返回信息
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("用户名:" + username);
out.print("密码:" + password);
out.print(confirm);
out.flush();
out.close();
}

/**
* The doPost method of the Server let.
*/


public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

// 测试为何手机端中文乱码,电脑正常
// System.out.println("u1--"+username);
// System.out.println("u2--"+username);

}

}

四、客户端设计


1、新建Android App Project,命名为AndroidHTTPDemo

2、现在开始思考需要什么东西…

<1> 登陆和注册页面:布局文件

   login.xml , register.xml

 <2> 登陆和注册页面对应的Activity组件,在activity中进行具体操作

   login.java , register.java

 <3> 能够实现Http以get/post方式通信的类

   WebService.java , WebServicePost.java

 <4> 网络通信权限

1
2
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

3、Login.java 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.httpdemo;
import com.rxz.androidhttpdemo.R;
import com.web.WebService;
import com.web.WebServicePost;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class Login extends Activity implements OnClickListener {

// 登陆按钮
private Button logbtn;
// 调试文本,注册文本
private TextView infotv, regtv;
// 显示用户名和密码
EditText username, password;
// 创建等待框
private ProgressDialog dialog;
// 返回的数据
private String info;
// 返回主线程更新数据
private static Handler handler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);

// 获取控件
username = (EditText) findViewById(R.id.user);
password = (EditText) findViewById(R.id.pass);
logbtn = (Button) findViewById(R.id.login);
regtv = (TextView) findViewById(R.id.register);
infotv = (TextView) findViewById(R.id.info);

// 设置按钮监听器
logbtn.setOnClickListener(this);
regtv.setOnClickListener(this);

}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.login:
// 检测网络 这里我用的Wlan测试,但此方法只允许网络流量,只能先禁掉。
// if (!checkNetwork()) {
// Toast toast = Toast.makeText(Login.this,"网络未连接", Toast.LENGTH_SHORT);
// toast.setGravity(Gravity.CENTER, 0, 0);
// toast.show();
// break;
// }
// 提示框
dialog = new ProgressDialog(this);
dialog.setTitle("提示");
dialog.setMessage("正在登陆,请稍后...");
dialog.setCancelable(false);
dialog.show();
// 创建子线程,分别进行Get和Post传输
new Thread(new MyThread()).start();
break;
case R.id.register:
Intent regItn = new Intent(Login.this, Register.class);
// overridePendingTransition(anim_enter);
startActivity(regItn);
break;
}
;
}

// 子线程接收数据,主线程修改数据
public class MyThread implements Runnable {
@Override
public void run() {
info = WebService.executeHttpGet("LogLet",username.getText().toString(), password.getText().toString());
// info =
// WebServicePost.executeHttpPost(username.getText().toString(),
// password.getText().toString());
handler.post(new Runnable() {
@Override
public void run() {
// 最好返回一个固定键值,根据键值判断是否登陆成功,有键值就保存该info跳转,没键值就是错误信息直接toast
infotv.setText(info);
dialog.dismiss();
Toast toast = Toast.makeText(Login.this, info, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
});
}
}

// 检测网络
private boolean checkNetwork() {
ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connManager.getActiveNetworkInfo() != null) {
return connManager.getActiveNetworkInfo().isAvailable();
}
return false;
}

}

4.、Register.java 
与login.java类似,略有修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package com.httpdemo;
import com.httpdemo.Register.MyThread;
import com.rxz.androidhttpdemo.R;
import com.web.WebService;
import com.web.WebServicePost;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class Register extends Activity implements OnClickListener{

// 登陆按钮
private Button logbtn;
// 调试文本,注册文本
private TextView infotv, regtv;
// 显示用户名和密码
EditText username, password;
// 创建等待框
private ProgressDialog dialog;
// 返回的数据
private String info;
// 返回主线程更新数据
private static Handler handler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.register);

// 获取控件
username = (EditText) findViewById(R.id.user);
password = (EditText) findViewById(R.id.pass);
logbtn = (Button) findViewById(R.id.register);
regtv = (TextView) findViewById(R.id.register);
infotv = (TextView) findViewById(R.id.info);




// 设置按钮监听器
logbtn.setOnClickListener(this);
regtv.setOnClickListener(this);
}

@Override
public void onClick(View v) {

dialog = new ProgressDialog(this);
dialog.setTitle("提示");
dialog.setMessage("正在登陆,请稍后...");
dialog.setCancelable(false);
dialog.show();
// 创建子线程,分别进行Get和Post传输
new Thread(new MyThread()).start();

}

// 子线程接收数据,主线程修改数据
public class MyThread implements Runnable {
@Override
public void run() {
info = WebService.executeHttpGet("RegLet", username.getText().toString(), password.getText().toString());
// info =
// WebServicePost.executeHttpPost(username.getText().toString(),
// password.getText().toString());
handler.post(new Runnable() {
@Override
public void run() {
// 最好返回一个固定键值,根据键值判断是否登陆成功,有键值就保存该info跳转,没键值就是错误信息直接toast
infotv.setText(info);
dialog.dismiss();
Toast toast = Toast.makeText(Register.this, info, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
});
}
}

// 检测网络
private boolean checkNetwork() {
ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (connManager.getActiveNetworkInfo() != null) {
return connManager.getActiveNetworkInfo().isAvailable();
}
return false;
}

}

5.、WebService.java 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class WebService {
// IP地址
private static String IP = "TOMCATURL:8080";
//把TOMCATURL改为你的服务器地址

/**
* 通过Get方式获取HTTP服务器数据
*
* @return
*/

public static String executeHttpGet(String url,String username, String password) {
HttpURLConnection conn = null;
InputStream is = null;

try {
// 用户名 密码
// URL 地址
String path = "http://" + IP + "/HelloWeb/";
path = path + url + "?username=" + username + "&password=" + password;

conn = (HttpURLConnection) new URL(path).openConnection();
conn.setConnectTimeout(3000); // 设置超时时间
conn.setReadTimeout(3000);
conn.setDoInput(true);
conn.setRequestMethod("GET"); // 设置获取信息方式
conn.setRequestProperty("Charset", "UTF-8"); // 设置接收数据编码格式

if (conn.getResponseCode() == 200) {
is = conn.getInputStream();
return parseInfo(is);
}
return null;

}catch (Exception e) {
e.printStackTrace();
} finally {
// 意外退出时进行连接关闭保护
if (conn != null) {
conn.disconnect();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
return "服务器连接超时...";
}

// 将输入流转化为 String 型
private static String parseInfo(InputStream inStream) throws Exception {
byte[] data = read(inStream);
// 转化为字符串
return new String(data, "UTF-8");
}

// 将输入流转化为byte型
public static byte[] read(InputStream inStream) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
inStream.close();
return outputStream.toByteArray();
}
}

五、运行效果


以上工作完成后,只需要讲服务器端发布到本地,安卓端发布到手机,确保局域网内部,ip正确,即可正常访问。

六、源码


注意:因为原作者的代码使用Eclipse开发,而我自己是用AS开发的,所以源码中有两份客户端的代码,根据IDE选择就好了,服务器的代码都是一样的。
https://github.com/jazzyin/android-HTTP-demo