Android通过Http连接MySQL 实现登陆/注册(数据库+服务器+客户端)
各类it学习视频,大家都可以看看哦!我自己本人都是通过这些来学习it只知识的!
下面是视频链接
https://shop61408405.taobao.com/?spm=a1z10.5-c.0.0.cAfZMN&qq-pf-to=pcqq.group
1 Android通过Http连接MySQL 实现登陆/注册(数据库+服务器+客户端) 2 时间 2015-08-22 11:31:00 博客园-原创精华区 3 原文 4 http://www.cnblogs.com/yzxk/p/4749440.html 5 主题 MySQL HTTP 6 7 写在最前: 8 9 在实际开发中,相信每个项目都会有 用户登陆注册 功能,这个实现的方法很多,下面是我实现的方法,供大家交流。 10 11 新人发帖,万分紧张,怎么样才能装作一副经常发帖的样子不被别人看出来呢-,- ? 12 13 好了,下面进入正题。 14 15 一、开发环境的部署 16 17 程序结构: 18 19 android+servlet+service+mysql 20 21 仅供参考:能实现相关功能即可 22 23 操作系统:ubuntu 14.10 24 25 数据库:mysql-5.5 数据库工具:emma 26 27 服务器:tomcat 服务器工具:Myeclipse 10 28 29 安卓端:真机 android4.4 安卓段工具:eclipse+adt 30 31 注意: 32 33 程序调试过程可能会产生乱码,只需保持所有工具编码方式相同即可。 34 35 二、数据库设计 36 37 数据库名称:test 38 39 表名称:student 40 41 建表语句: 42 43 CREATE TABLE `student` ( 44 `Id` int(11) NOT NULL AUTO_INCREMENT, 45 `username` char(20) NOT NULL DEFAULT '', 46 `password` char(20) NOT NULL DEFAULT '', 47 PRIMARY KEY (`Id`) 48 ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 49 50 表格视图: 51 52 三、服务器端设计 53 54 1、新建Web Project,命名为HelloWeb,同时删除掉WebRoot的index.jsp 55 56 2、项目结构图如下: 57 58 这里我们采用servlet编程,所以不需要任何jsp页面。 59 60 LogLet类和RegLet类分别用于处理客户端的登陆和注册请求;Service类用于完成servlet对数据库的具体操作;DBManager类用于进行数据库基本操作; 61 62 左侧是项目图,右侧是web.xml配置文件截图。 63 64 3、项目代码: 65 66 DBManager.java 67 68 <1> 私有化DBManager的构造函数,定义一个静态的成员变量,在一个共有方法中实例化该成员变量。若要实例化对象调用此方法即可。 69 70 同一时间该类只能存在一个对象。符合sql对象习惯。 (此方式有缺陷,具体自行搜索) 71 72 <2> 定义数据库连接、关闭以及增删改查的基本操作,返回结果集。 73 74 package com.db; 75 import java.sql.*; 76 public class DBManager { 77 // 数据库连接常量 78 public static final String DRIVER = "com.mysql.jdbc.Driver"; 79 public static final String USER = "root"; 80 public static final String PASS = "root"; 81 public static final String URL = "jdbc:mysql://localhost:3306/test"; 82 // 静态成员,支持单态模式 83 private static DBManager per = null; 84 private Connection conn = null; 85 private Statement stmt = null; 86 // 单态模式-懒汉模式 87 private DBManager() { 88 } 89 public static DBManager createInstance() { 90 if (per == null) { 91 per = new DBManager(); 92 per.initDB(); 93 } 94 return per; 95 } 96 // 加载驱动 97 public void initDB() { 98 try { 99 Class.forName("com.mysql.jdbc.Driver"); 100 } catch (Exception e) { 101 e.printStackTrace(); 102 } 103 } 104 // 连接数据库,获取句柄+对象 105 public void connectDB() { 106 System.out.println("Connecting to database..."); 107 try { 108 conn = DriverManager.getConnection(URL, USER, PASS); 109 stmt = conn.createStatement(); 110 } catch (SQLException e) { 111 e.printStackTrace(); 112 } 113 System.out.println("SqlManager:Connect to database successful."); 114 } 115 // 关闭数据库 关闭对象,释放句柄 116 public void closeDB() { 117 System.out.println("Close connection to database.."); 118 try { 119 stmt.close(); 120 conn.close(); 121 } catch (SQLException e) { 122 e.printStackTrace(); 123 } 124 System.out.println("Close connection successful"); 125 } 126 // 查询 127 public ResultSet executeQuery(String sql) { 128 ResultSet rs = null; 129 try { 130 rs = stmt.executeQuery(sql); 131 } catch (SQLException e) { 132 e.printStackTrace(); 133 } 134 return rs; 135 } 136 // 增添/删除/修改 137 public int executeUpdate(String sql) { 138 int ret = 0; 139 try { 140 ret = stmt.executeUpdate(sql); 141 } catch (SQLException e) { 142 e.printStackTrace(); 143 } 144 return ret; 145 } 146 } 147 148 Service.java 149 150 这个简单,根据传参得到sql语句,通过DBManager类的 createInstance() 方法实例化对象,调用本类的操作方法,完成数据操作。 151 152 写到这里,可以预见:下一个类会通过调用本类方法完成登陆/注册的服务。 153 154 package com.service; 155 import java.sql.ResultSet; 156 import java.sql.SQLException; 157 import com.db.DBManager; 158 public class Service { 159 public Boolean login(String username, String password) { 160 // 获取Sql查询语句 161 String logSql = "select * from user where username ='" + username 162 + "' and password ='" + password + "'"; 163 // 获取DB对象 164 DBManager sql = DBManager.createInstance(); 165 sql.connectDB(); 166 // 操作DB对象 167 try { 168 ResultSet rs = sql.executeQuery(logSql); 169 if (rs.next()) { 170 sql.closeDB(); 171 return true; 172 } 173 } catch (SQLException e) { 174 e.printStackTrace(); 175 } 176 sql.closeDB(); 177 return false; 178 } 179 public Boolean register(String username, String password) { 180 // 获取Sql查询语句 181 String regSql = "insert into student values('"+ username+ "','"+ password+ "') "; 182 183 // 获取DB对象 184 DBManager sql = DBManager.createInstance(); 185 sql.connectDB(); 186 int ret = sql.executeUpdate(regSql); 187 if (ret != 0) { 188 sql.closeDB(); 189 return true; 190 } 191 sql.closeDB(); 192 return false; 193 } 194 } 195 196 LogLet.java 197 198 一个简单的Servlet,用于处理Http请求(get/post)。果然,实例化上一个类的对象,并调用了 login方法,返回值为布尔类型。 199 200 RegLet.java和该类近乎相同,只是在 serv.login(username, password); 换成了 serv.register(username, password); 此处省去~ 201 202 package com.servlet; 203 import java.io.IOException; 204 import java.io.PrintWriter; 205 import javax.servlet.ServletException; 206 import javax.servlet.http.HttpServlet; 207 import javax.servlet.http.HttpServletRequest; 208 import javax.servlet.http.HttpServletResponse; 209 import com.service.Service; 210 public class LogLet extends HttpServlet { 211 private static final long serialVersionUID = 369840050351775312L; 212 public void doGet(HttpServletRequest request, HttpServletResponse response) 213 throws ServletException, IOException { 214 // 接收客户端信息 215 String username = request.getParameter("username"); 216 username = new String(username.getBytes("ISO-8859-1"), "UTF-8"); 217 String password = request.getParameter("password"); 218 System.out.println(username + "--" + password); 219 // 新建服务对象 220 Service serv = new Service(); 221 // 验证处理 222 boolean loged = serv.login(username, password); 223 if (loged) { 224 System.out.print("Succss"); 225 request.getSession().setAttribute("username", username); 226 // response.sendRedirect("welcome.jsp"); 227 } else { 228 System.out.print("Failed"); 229 } 230 // 返回信息到客户端 231 response.setCharacterEncoding("UTF-8"); 232 response.setContentType("text/html"); 233 PrintWriter out = response.getWriter(); 234 out.print("用户名:" + username); 235 out.print("密码:" + password); 236 out.flush(); 237 out.close(); 238 } 239 public void doPost(HttpServletRequest request, HttpServletResponse response) 240 throws ServletException, IOException { 241 } 242 } 243 244 四、客户端设计 245 246 1、新建Android App Project,命名为AndroidHTTPDemo 247 248 2、现在开始思考需要什么东西... 249 250 <1> 登陆和注册页面:布局文件 251 252 login.xml , register.xml 253 254 <2> 登陆和注册页面对应的Activity组件,在activity中进行具体操作 255 256 login.java , register.java 257 258 <3> 能够实现Http以get/post方式通信的类 259 260 WebService.java , WebServicePost.java 261 262 <4> 网络通信权限 263 264 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 265 266 <uses-permission android:name="android.permission.INTERNET" /> 267 268 OK,项目结构出炉,右侧是Manifeast配置文件的主要内容 269 270 3、现在,我们开始关注具体的代码。 271 272 <1> 首先要做的,登陆注册界面,这个不用多说。我直接放图, 大致就是下面这个样子 ,大家可以按照自己爱好设计。 273 274 (注意一点,因为登陆和注册的xml、activity都是近乎完全一样,最不一样的sql语句我们在之前已经处理过了,所以这里只写其中的一个即可) 275 276 <2> 在服务器端编程时我们了解到:服务器端接收客户端发送的信息,对信息进行一系列处理后,最终信息返回到客户端。 277 278 首先要想的,就是获取信息并发送出去,然后接收信息并显示出来。 279 280 获取信息好办,getText()嘛,不好办的是发送,还有发送所需的线程。 281 282 (网络服务由于耗时问题,放在主线程很可能由于网络故障导致ANR;所以要开辟子线程留给http网络服务。当然不使用主线程也可以,只是不推荐) 283 284 <3> Login.java 有三点需要注意 285 286 第一个是检测网络状态,只能检测流量,无法检测wifi; 287 288 第二个是在子线程中,我们利用获得的用户名密码调用了http通信类最后返回的info值,不能直接在子线程中更改主线程的页面值,这里用了handle解决。 289 290 第三个是这里有get/post两种http请求方式,两个实现类,我们需要那一个,只要把另一个注释掉即可,返回的数据都是一样的。 291 292 package com.httpdemo; 293 import com.rxz.androidhttpdemo.R; 294 import com.web.WebService; 295 import com.web.WebServicePost; 296 import android.app.Activity; 297 import android.app.ProgressDialog; 298 import android.content.Context; 299 import android.content.Intent; 300 import android.net.ConnectivityManager; 301 import android.os.Bundle; 302 import android.os.Handler; 303 import android.view.Gravity; 304 import android.view.View; 305 import android.view.View.OnClickListener; 306 import android.widget.Button; 307 import android.widget.EditText; 308 import android.widget.TextView; 309 import android.widget.Toast; 310 public class Login extends Activity implements OnClickListener { 311 // 登陆按钮 312 private Button logbtn; 313 // 调试文本,注册文本 314 private TextView infotv, regtv; 315 // 显示用户名和密码 316 EditText username, password; 317 // 创建等待框 318 private ProgressDialog dialog; 319 // 返回的数据 320 private String info; 321 // 返回主线程更新数据 322 private static Handler handler = new Handler(); 323 @Override 324 protected void onCreate(Bundle savedInstanceState) { 325 super.onCreate(savedInstanceState); 326 setContentView(R.layout.login); 327 // 获取控件 328 username = (EditText) findViewById(R.id.user); 329 password = (EditText) findViewById(R.id.pass); 330 logbtn = (Button) findViewById(R.id.login); 331 regtv = (TextView) findViewById(R.id.register); 332 infotv = (TextView) findViewById(R.id.info); 333 // 设置按钮监听器 334 logbtn.setOnClickListener(this); 335 regtv.setOnClickListener(this); 336 } 337 @Override 338 public void onClick(View v) { 339 switch (v.getId()) { 340 case R.id.login: 341 // 检测网络,无法检测wifi 342 if (!checkNetwork()) { 343 Toast toast = Toast.makeText(Login.this,"网络未连接", Toast.LENGTH_SHORT); 344 toast.setGravity(Gravity.CENTER, 0, 0); 345 toast.show(); 346 break; 347 } 348 // 提示框 349 dialog = new ProgressDialog(this); 350 dialog.setTitle("提示"); 351 dialog.setMessage("正在登陆,请稍后..."); 352 dialog.setCancelable(false); 353 dialog.show(); 354 // 创建子线程,分别进行Get和Post传输 355 new Thread(new MyThread()).start(); 356 break; 357 case R.id.register: 358 Intent regItn = new Intent(Login.this, Register.class); 359 // overridePendingTransition(anim_enter); 360 startActivity(regItn); 361 break; 362 } 363 ; 364 } 365 // 子线程接收数据,主线程修改数据 366 public class MyThread implements Runnable { 367 @Override 368 public void run() { 369 info = WebService.executeHttpGet(username.getText().toString(), password.getText().toString()); 370 // info = WebServicePost.executeHttpPost(username.getText().toString(), password.getText().toString()); 371 handler.post(new Runnable() { 372 @Override 373 public void run() { 374 infotv.setText(info); 375 dialog.dismiss(); 376 } 377 }); 378 } 379 } 380 // 检测网络 381 private boolean checkNetwork() { 382 ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 383 if (connManager.getActiveNetworkInfo() != null) { 384 return connManager.getActiveNetworkInfo().isAvailable(); 385 } 386 return false; 387 } 388 } 389 390 <4> WebService.java 391 392 这里的IP是你的服务器IP,不确定时看下是否能用手机ping工具ping通。 393 394 因为我用的是真机,所以模拟器我还真不太清楚,我简单说一下真机与windows/linux下的服务器网络连接流程,详情请百度。 395 396 ① 你的服务器端程序已发布到互联网:这好办,就是你的IP地址。 397 398 ② 你是在本地电脑上,这要求你的真机和你的电脑在同一个局域网。两种较方便的方法:路由器/笔记本的无线网卡 399 400 是个人都能看出来第二种方便,谁也不能到哪都带个路由器吧,那么好,笔记本开启无线热点,手机wifi连接热点,这是客户端和服务器就在一个局域网内。 401 402 查看笔记本ip地址中的无线网卡地址([win]ipconfig/[lnx]ifconfig -- wlan),加上你的服务器端口号(服务器为开启状态),访问即可。 403 404 conn.setConnectTimeout(3000); 需要设置超时时间,否则会执行默认超时时间,30s ? 405 406 接收到的输入流需要先转换成比特位,在转换成string类型。 407 408 package com.web; 409 import java.io.ByteArrayOutputStream; 410 import java.io.IOException; 411 import java.io.InputStream; 412 import java.net.HttpURLConnection; 413 import java.net.URL; 414 public class WebService { 415 private static String IP = "10.42.0.1:8080"; 416 // 通过Get方式获取HTTP服务器数据 417 public static String executeHttpGet(String username, String password) { 418 HttpURLConnection conn = null; 419 InputStream is = null; 420 try { 421 // 用户名 密码 422 // URL 地址 423 String path = "http://" + IP + "/HelloWeb/servlet/MyServlet"; 424 path = path + "?username=" + username + "&password=" + password; 425 conn = (HttpURLConnection) new URL(path).openConnection(); 426 conn.setConnectTimeout(3000); // 设置超时时间 427 conn.setReadTimeout(3000); 428 conn.setDoInput(true); 429 conn.setRequestMethod("GET"); // 设置获取信息方式 430 conn.setRequestProperty("Charset", "UTF-8"); // 设置接收数据编码格式 431 if (conn.getResponseCode() == 200) { 432 is = conn.getInputStream(); 433 return parseInfo(is); 434 } 435 }catch (Exception e) { 436 e.printStackTrace(); 437 } finally { 438 // 意外退出时进行连接关闭保护 439 if (conn != null) { 440 conn.disconnect(); 441 } 442 if (is != null) { 443 try { 444 is.close(); 445 } catch (IOException e) { 446 e.printStackTrace(); 447 } 448 } 449 } 450 return null; 451 } 452 // 将输入流转化为 String 型 453 private static String parseInfo(InputStream inStream) throws Exception { 454 byte[] data = read(inStream); 455 // 转化为字符串 456 return new String(data, "UTF-8"); 457 } 458 // 将输入流转化为byte型 459 public static byte[] read(InputStream inStream) throws Exception { 460 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 461 byte[] buffer = new byte[1024]; 462 int len = 0; 463 while ((len = inStream.read(buffer)) != -1) { 464 outputStream.write(buffer, 0, len); 465 } 466 inStream.close(); 467 return outputStream.toByteArray(); 468 } 469 } 470 471 <5> WebServicePost.java 和上一个大同小异,只不过参数不是放在url中,而是在HashMap中传输,数据传输方式略有不同。 472 473 处理方式不变,还有注意别忘了设置超时。 474 475 package com.web; 476 import java.io.InputStream; 477 import java.util.ArrayList; 478 import java.util.HashMap; 479 import java.util.List; 480 import java.util.Map; 481 import org.apache.http.HttpEntity; 482 import org.apache.http.HttpResponse; 483 import org.apache.http.NameValuePair; 484 import org.apache.http.client.entity.UrlEncodedFormEntity; 485 import org.apache.http.client.methods.HttpPost; 486 import org.apache.http.impl.client.DefaultHttpClient; 487 import org.apache.http.message.BasicNameValuePair; 488 import org.apache.http.params.CoreConnectionPNames; 489 public class WebServicePost { 490 private static String IP = "10.42.0.1:8080"; 491 // 通过 POST 方式获取HTTP服务器数据 492 public static String executeHttpPost(String username, String password) { 493 try { 494 String path = "http://" + IP + "/HelloWeb/servlet/MyServlet"; 495 // 发送指令和信息 496 Map<String, String> params = new HashMap<String, String>(); 497 params.put("username", username); 498 params.put("password", password); 499 return sendPOSTRequest(path, params, "UTF-8"); 500 } catch (Exception e) { 501 e.printStackTrace(); 502 } 503 return null; 504 } 505 // 处理发送数据请求 506 private static String sendPOSTRequest(String path, Map<String, String> params, String encoding) throws Exception { 507 List<NameValuePair> pairs = new ArrayList<NameValuePair>(); 508 if (params != null && !params.isEmpty()) { 509 for (Map.Entry<String, String> entry : params.entrySet()) { 510 pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); 511 } 512 } 513 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, encoding); 514 HttpPost post = new HttpPost(path); 515 post.setEntity(entity); 516 DefaultHttpClient client = new DefaultHttpClient(); 517 // 请求超时 518 client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000); 519 // 读取超时 520 client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 5000); 521 HttpResponse response = client.execute(post); 522 // 判断是否成功收取信息 523 if (response.getStatusLine().getStatusCode() == 200) { 524 return getInfo(response); 525 } 526 // 未成功收取信息,返回空指针 527 return null; 528 } 529 // 收取数据 530 private static String getInfo(HttpResponse response) throws Exception { 531 HttpEntity entity = response.getEntity(); 532 InputStream is = entity.getContent(); 533 // 将输入流转化为byte型 534 byte[] data = WebService.read(is); 535 // 转化为字符串 536 return new String(data, "UTF-8"); 537 } 538 } 539 540 五、运行效果 541 542 以上工作完成后,只需要讲服务器端发布到本地( 附上--mysql-jdbc驱动地址-- ),安卓端发布到手机,确保局域网内部,ip正确,即可正常访问。 543 544 客户端截图:测试成功 545 546 服务器端截图:测试成功 547 548 六、源码 549 550 以上不足之处,还望大家多多指正。 如有问题欢迎给我留言。 551 552 代码并未涉及到Session保持,自动登陆等,正在改进中,最终效果应该类似于虎牙直播的登陆注册(刚好举个例子)