先看两个概念:
1.android连接数据库的方式有两种
1.通过连接服务器,再由服务器读取数据库来实现数据的增删改查,这也是我们常用的方式。
2.android直接连接数据库,这种方式非常耗手机内存,而且容易被反编译造成安全隐患,所以在实际项目中不推荐使用。
2.连接服务器方式: http通信 、 Socket通信
Http通信:GET方式、POST方式
GET方式和POST方式的区别:
前者通过Http消息实体发送数据给服务器,安全性高,数据传输大小没有限制,后者通过URL的查询字符串传递给服务器参数,以明文显示在浏览器地址栏,保密性差,最多传输2048个字符。但是GET请求并不是一无是处——GET请求大多用于查询(读取资源),效率高。POST请求用于注册、登录等安全性较高且向数据库中写入数据的操作。
除了POST和GET,http通信还有其他方式!请参见http请求的方法。
Http与Scoket区别:
简单理解:一个单向,一个双向。(具体了解,自行google)
开发环境部署:
程序结构:
android+servlet+service+mysql
仅供参考:能实现相关功能即可
操作系统:win10
数据库:mysql 数据库工具:Navicat for MySql
服务器:tomcat 服务器工具: eclipse
安卓端:genymotion虚拟机 安卓端工具:Android Studio
数据库设计:
服务器设计:
1、新建Web Project,命名为HelloWeb
2、项目结构图如下:
LogLet类和RegLet类分别用于处理客户端的登陆和注册请求;Service类用于完成servlet对数据库的具体操作;DBManager类用于进行数据库基本操作;
左侧是项目图,右侧是web.xml配置文件截图。
3、项目代码:
DBManager.java
<2> 定义数据库连接、关闭以及增删改查的基本操作,返回结果集。
package com.db;
import java.sql.*;
public class DBManager {
// 数据库连接常量
public static final String DRIVER = "com.mysql.jdbc.Driver";
public static final String USER = "root";
public static final String PASS = "root";
public static final String URL = "jdbc:mysql://localhost:3306/test";
// 静态成员,支持单态模式
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;
}
}
LogLet.java
一个简单的Servlet,用于处理Http请求(get/post)。
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 LogLet extends HttpServlet{
private static final long serialVersionUID = 9036889586892331384L;
@Override
protected 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");
password = new String(password.getBytes("ISO-8859-1"),"UTF-8");
System.out.println(username + ":" + password);
//新建服务对象
Service service = new Service();
//验证处理
boolean log = service.login(username, password);
if( log ){
System.out.println("log success");
//request.getSession().setAttribute("username", username);
}else{
System.out.println("log fail");
}
//返回信息到客户端
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
if( log ){
out.print("用户名:" + username);
out.print("密码: " + password);
}else{
out.print("false");
}
out.flush();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO 自动生成的方法存根
}
}
RegLet.java
一个简单的Servlet,用于处理Http请求(get/post)。
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 = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO 自动生成的方法存根
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO 自动生成的方法存根
//接受客户端信息
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
String password = request.getParameter("password");
System.out.println(username + ":" + password);
//新建服务对象
Service service = new Service();
//验证处理
boolean reg = service.register(username, password);
if( reg ){
System.out.println("reg success");
//request.getSession().setAttribute("username", username);
}else{
System.out.println("reg fail");
}
//返回信息到客户端
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
if(reg){
out.print("true");
}else{
out.print("false");
}
out.flush();
out.close();
}
}
客户端设计:
现在开始思考需要什么东西...
<1> 登陆和注册页面:布局文件
login.xml , register.xml
<2> 登陆和注册页面对应的Activity组件,在activity中进行具体操作
login.java , register.java
<3> 能够实现Http以get/post方式通信的类
WebService.java , WebServicePost.java
<4> 网络通信权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
项目结构和AndroidMainfest.xml:
界面(极为简陋,按个人自行喜好设定):
登陆界面:
注册界面:
在服务器端编程时我们了解到:服务器端接收客户端发送的信息,对信息进行一系列处理后,最终信息返回到客户端。
首先要想的,就是获取信息并发送出去,然后接收信息并显示出来。
(网络服务由于耗时问题,放在主线程很可能由于网络故障导致ANR;所以要开辟子线程留给http网络服务。当然不使用主线程也可以,只是不推荐)
代码:
Login.java
第一个是在子线程中,不能更改主线程的页面值,这里用了handle解决。
第二个是这里有get/post两种http请求方式,两个实现类,。
package android.zdd.com.consql;
import android.app.ProgressDialog;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.zdd.com.web.WebServiceGet;
public class Login extends AppCompatActivity implements View.OnClickListener{
private EditText username;
private EditText password;
private Button login;
private TextView info;
private TextView register;
//提示框
private ProgressDialog dialog;
//服务器返回的数据
private String infoString;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//初始化信息
username = (EditText)findViewById(R.id.username);
password = (EditText)findViewById(R.id.password);
login = (Button)findViewById(R.id.btn_login);
info = (TextView)findViewById(R.id.info);
register = (TextView)findViewById(R.id.register);
//设置按钮监听器
login.setOnClickListener(this);
register.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_login:
//设置提示框
dialog = new ProgressDialog(Login.this);
dialog.setTitle("正在登陆");
dialog.setMessage("请稍后");
dialog.setCancelable(false);//设置可以通过back键取消
dialog.show();
//设置子线程,分别进行Get和Post传输数据
new Thread(new MyThread()).start();
break;
case R.id.register:
//跳转注册页面
Intent intent = new Intent(Login.this,Register.class);
startActivity(intent);
break;
}
}
public class MyThread implements Runnable{
@Override
public void run() {
infoString = WebServiceGet.executeHttpGet(username.getText().toString(),password.getText().toString(),"LogLet");//获取服务器返回的数据
//更新UI,使用runOnUiThread()方法
showResponse(infoString);
}
}
private void showResponse(final String response){
runOnUiThread(new Runnable() {
//更新UI
@Override
public void run() {
if(response.equals("false")){
Toast.makeText(Login.this,"登陆失败!", Toast.LENGTH_SHORT).show();
}else {
info.setText(response);
}
dialog.dismiss();
}
});
}
}
Register.java
package android.zdd.com.consql;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.preference.DialogPreference;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.zdd.com.web.WebServiceGet;
import android.zdd.com.web.WebServicePost;
public class Register extends AppCompatActivity implements View.OnClickListener{
private EditText regUserName;
private EditText regPassWord;
private Button btn_reg;
ProgressDialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
//修改标题栏title
ActionBar ac = getSupportActionBar();
ac.setTitle("注册");
//初始化
regUserName = (EditText)findViewById(R.id.regUserName);
regPassWord = (EditText)findViewById(R.id.regPassWord);
btn_reg = (Button)findViewById(R.id.btn_reg);
btn_reg.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_reg:
dialog = new ProgressDialog(Register.this);
dialog.setTitle("正在注册");
dialog.setMessage("请稍后");
dialog.show();
new Thread(new RegThread()).start();
break;
}
}
public class RegThread implements Runnable{
@Override
public void run() {
//获取服务器返回数据
//String RegRet = WebServiceGet.executeHttpGet(regUserName.getText().toString(),regPassWord.getText().toString(),"RegLet");
String RegRet = WebServicePost.executeHttpPost(regUserName.getText().toString(),regPassWord.getText().toString(),"RegLet");
//更新UI,界面处理
showReq(RegRet);
}
}
private void showReq(final String RegRet){
runOnUiThread(new Runnable() {
@Override
public void run() {
if(RegRet.equals("true")){
dialog.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(Register.this);
builder.setTitle("注册信息");
builder.setMessage("注册成功");
builder.setCancelable(false);
builder.setPositiveButton("OK",new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Register.this,Login.class);
startActivity(intent);
}
});
builder.show();
}else{
dialog.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(Register.this);
builder.setTitle("注册信息");
builder.setMessage("注册失败");
builder.setCancelable(false);
builder.setPositiveButton("OK",new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent intent = new Intent(Register.this,Login.class);
startActivity(intent);
}
});
builder.show();
}
}
});
}
}
WebServiceGet.java (Get实现)
这里的IP是你的服务器IP,就是你电脑的IP,cmd -> ipconfig查看本机IP地址。
import android.util.Log;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 使用get方法获取Http服务器数据
*/
public class WebServiceGet {
public static String executeHttpGet(String username,String password,String address){
HttpURLConnection connection = null;
InputStream in = null;
try{
String Url = "http://169.254.58.31:8080/HelloWeb/" + address;
String path = Url + "?username=" + username + "&password=" + password;
try {
URL url = new URL(path);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000);//建立连接超时
connection.setReadTimeout(8000);//传递数据超时
in = connection.getInputStream();
return parseInfo(in);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}catch (Exception e){
e.printStackTrace();
}finally {
//意外退出时,连接关闭保护
if(connection != null){
connection.disconnect();
}
if(in != null){
try{
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
return null;
}
//得到字节输入流,将字节输入流转化为String类型
public static String parseInfo(InputStream inputStream){
BufferedReader reader = null;
String line = "";
StringBuilder response = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(inputStream));
while((line = reader.readLine()) != null){
response.append(line);
}
return response.toString();
}catch (Exception e){
e.printStackTrace();
}finally {
if(reader != null){
try{
reader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
return null;
}
}
WebServicePost.java (Post实现)
这里的IP是你的服务器IP,就是你电脑的IP,cmd -> ipconfig查看本机IP地址。
package android.zdd.com.web;
import android.util.Log;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
/**
* 使用Post方法获取Http服务器数据
*/
public class WebServicePost {
public static String executeHttpPost(String username,String password,String address){
HttpURLConnection connection = null;
InputStream in = null;
try{
String Url = "http://169.254.58.31:8080/HelloWeb/" + address;
try {
URL url = new URL(Url);
connection = (HttpURLConnection)url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setReadTimeout(8000);//传递数据超时
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
connection.connect();
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
String data = "username=" + URLEncoder.encode(username,"UTF-8") + "&password=" + URLEncoder.encode(password,"UTF-8");
out.writeBytes(data);
out.flush();
out.close();
int resultCode = connection.getResponseCode();
if(HttpURLConnection.HTTP_OK == resultCode) {
in = connection.getInputStream();
return parseInfo(in);
}
return null;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}catch (Exception e){
e.printStackTrace();
}finally {
//意外退出时,连接关闭保护
if(connection != null){
connection.disconnect();
}
if(in != null){
try{
in.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
return null;
}
//得到字节输入流,将字节输入流转化为String类型
public static String parseInfo(InputStream inputStream){
BufferedReader reader = null;
String line = "";
StringBuilder response = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(inputStream));
while((line = reader.readLine()) != null){
Log.d("RegisterActivity",line);
response.append(line);
}
Log.d("RegisterActivity","response.toString():"+response.toString());
return response.toString();
}catch (Exception e){
e.printStackTrace();
}finally {
if(reader != null){
try{
reader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
return null;
}
}
运行效果:
略。。。经测试可以成功,记得服务器本地附上mysql-jdbc.jar包