1. 程式人生 > >安卓端通過http對Mysql進行增刪改查

安卓端通過http對Mysql進行增刪改查

name 交流 shm != 用戶 習慣 cti -perm 得到

各類it學習視頻,大家都可以看看哦!我自己本人都是通過這些來學習it只知識的!
下面是視頻鏈接
轉自:http://www.cnblogs.com/wangying222/p/5492935.html https:
//shop61408405.taobao.com/?spm=a1z10.5-c.0.0.cAfZMN&qq-pf-to=pcqq.group Android通過Http連接MySQL 實現登陸/註冊(數據庫+服務器+客戶端) 時間 2015-08-22 11:31:00 博客園-原創精華區 原文 http://www.cnblogs.com/yzxk/p/4749440.html 主題 MySQL HTTP 寫在最前: 在實際開發中,相信每個項目都會有 用戶登陸註冊 功能,這個實現的方法很多,下面是我實現的方法,供大家交流。 新人發帖,萬分緊張,怎麽樣才能裝作一副經常發帖的樣子不被別人看出來呢
-,- ? 好了,下面進入正題。 一、開發環境的部署 程序結構: android+servlet+service+mysql 僅供參考:能實現相關功能即可 操作系統:ubuntu 14.10 數據庫:mysql-5.5 數據庫工具:emma 服務器:tomcat 服務器工具:Myeclipse 10 安卓端:真機 android4.4 安卓段工具:eclipse+adt 註意: 程序調試過程可能會產生亂碼,只需保持所有工具編碼方式相同即可。 二、數據庫設計 數據庫名稱:test 表名稱:student 建表語句: CREATE TABLE `student` ( `Id`
int(11) NOT NULL AUTO_INCREMENT, `username` char(20) NOT NULL DEFAULT ‘‘, `password` char(20) NOT NULL DEFAULT ‘‘, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 表格視圖: 三、服務器端設計 1、新建Web Project,命名為HelloWeb,同時刪除掉WebRoot的index.jsp 2、項目結構圖如下: 這裏我們采用servlet編程,所以不需要任何jsp頁面。 LogLet類和RegLet類分別用於處理客戶端的登陸和註冊請求;Service類用於完成servlet對數據庫的具體操作;DBManager類用於進行數據庫基本操作; 左側是項目圖,右側是web.xml配置文件截圖。
3、項目代碼: DBManager.java <1> 私有化DBManager的構造函數,定義一個靜態的成員變量,在一個共有方法中實例化該成員變量。若要實例化對象調用此方法即可。 同一時間該類只能存在一個對象。符合sql對象習慣。 (此方式有缺陷,具體自行搜索) <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; } } Service.java 這個簡單,根據傳參得到sql語句,通過DBManager類的 createInstance() 方法實例化對象,調用本類的操作方法,完成數據操作。 寫到這裏,可以預見:下一個類會通過調用本類方法完成登陸/註冊的服務。 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 user 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 values(‘"+ username+ "‘,‘"+ password+ "‘) "; // 獲取DB對象 DBManager sql = DBManager.createInstance(); sql.connectDB(); int ret = sql.executeUpdate(regSql); if (ret != 0) { sql.closeDB(); return true; } sql.closeDB(); return false; } } LogLet.java 一個簡單的Servlet,用於處理Http請求(get/post)。果然,實例化上一個類的對象,並調用了 login方法,返回值為布爾類型。 RegLet.java和該類近乎相同,只是在 serv.login(username, password); 換成了 serv.register(username, password); 此處省去~ 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 = 369840050351775312L; 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"); System.out.println(username + "--" + password); // 新建服務對象 Service serv = new Service(); // 驗證處理 boolean loged = serv.login(username, password); if (loged) { System.out.print("Succss"); request.getSession().setAttribute("username", username); // response.sendRedirect("welcome.jsp"); } else { System.out.print("Failed"); } // 返回信息到客戶端 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print("用戶名:" + username); out.print("密碼:" + password); out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } 四、客戶端設計 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> 網絡通信權限 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> OK,項目結構出爐,右側是Manifeast配置文件的主要內容 3、現在,我們開始關註具體的代碼。 <1> 首先要做的,登陸註冊界面,這個不用多說。我直接放圖, 大致就是下面這個樣子 ,大家可以按照自己愛好設計。 (註意一點,因為登陸和註冊的xml、activity都是近乎完全一樣,最不一樣的sql語句我們在之前已經處理過了,所以這裏只寫其中的一個即可) <2> 在服務器端編程時我們了解到:服務器端接收客戶端發送的信息,對信息進行一系列處理後,最終信息返回到客戶端。 首先要想的,就是獲取信息並發送出去,然後接收信息並顯示出來。 獲取信息好辦,getText()嘛,不好辦的是發送,還有發送所需的線程。 (網絡服務由於耗時問題,放在主線程很可能由於網絡故障導致ANR;所以要開辟子線程留給http網絡服務。當然不使用主線程也可以,只是不推薦) <3> Login.java 有三點需要註意 第一個是檢測網絡狀態,只能檢測流量,無法檢測wifi; 第二個是在子線程中,我們利用獲得的用戶名密碼調用了http通信類最後返回的info值,不能直接在子線程中更改主線程的頁面值,這裏用了handle解決。 第三個是這裏有get/post兩種http請求方式,兩個實現類,我們需要那一個,只要把另一個註釋掉即可,返回的數據都是一樣的。 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: // 檢測網絡,無法檢測wifi 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(username.getText().toString(), password.getText().toString()); // info = WebServicePost.executeHttpPost(username.getText().toString(), password.getText().toString()); handler.post(new Runnable() { @Override public void run() { infotv.setText(info); dialog.dismiss(); } }); } } // 檢測網絡 private boolean checkNetwork() { ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); if (connManager.getActiveNetworkInfo() != null) { return connManager.getActiveNetworkInfo().isAvailable(); } return false; } } <4> WebService.java 這裏的IP是你的服務器IP,不確定時看下是否能用手機ping工具ping通。 因為我用的是真機,所以模擬器我還真不太清楚,我簡單說一下真機與windows/linux下的服務器網絡連接流程,詳情請百度。 ① 你的服務器端程序已發布到互聯網:這好辦,就是你的IP地址。 ② 你是在本地電腦上,這要求你的真機和你的電腦在同一個局域網。兩種較方便的方法:路由器/筆記本的無線網卡 是個人都能看出來第二種方便,誰也不能到哪都帶個路由器吧,那麽好,筆記本開啟無線熱點,手機wifi連接熱點,這是客戶端和服務器就在一個局域網內。 查看筆記本ip地址中的無線網卡地址([win]ipconfig/[lnx]ifconfig -- wlan),加上你的服務器端口號(服務器為開啟狀態),訪問即可。 conn.setConnectTimeout(3000); 需要設置超時時間,否則會執行默認超時時間,30s ? 接收到的輸入流需要先轉換成比特位,在轉換成string類型。 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 { private static String IP = "10.42.0.1:8080"; // 通過Get方式獲取HTTP服務器數據 public static String executeHttpGet(String username, String password) { HttpURLConnection conn = null; InputStream is = null; try { // 用戶名 密碼 // URL 地址 String path = "http://" + IP + "/HelloWeb/servlet/MyServlet"; path = path + "?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); } }catch (Exception e) { e.printStackTrace(); } finally { // 意外退出時進行連接關閉保護 if (conn != null) { conn.disconnect(); } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } // 將輸入流轉化為 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(); } } <5> WebServicePost.java 和上一個大同小異,只不過參數不是放在url中,而是在HashMap中傳輸,數據傳輸方式略有不同。 處理方式不變,還有註意別忘了設置超時。 package com.web; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.CoreConnectionPNames; public class WebServicePost { private static String IP = "10.42.0.1:8080"; // 通過 POST 方式獲取HTTP服務器數據 public static String executeHttpPost(String username, String password) { try { String path = "http://" + IP + "/HelloWeb/servlet/MyServlet"; // 發送指令和信息 Map<String, String> params = new HashMap<String, String>(); params.put("username", username); params.put("password", password); return sendPOSTRequest(path, params, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return null; } // 處理發送數據請求 private static String sendPOSTRequest(String path, Map<String, String> params, String encoding) throws Exception { List<NameValuePair> pairs = new ArrayList<NameValuePair>(); if (params != null && !params.isEmpty()) { for (Map.Entry<String, String> entry : params.entrySet()) { pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, encoding); HttpPost post = new HttpPost(path); post.setEntity(entity); DefaultHttpClient client = new DefaultHttpClient(); // 請求超時 client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 5000); // 讀取超時 client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 5000); HttpResponse response = client.execute(post); // 判斷是否成功收取信息 if (response.getStatusLine().getStatusCode() == 200) { return getInfo(response); } // 未成功收取信息,返回空指針 return null; } // 收取數據 private static String getInfo(HttpResponse response) throws Exception { HttpEntity entity = response.getEntity(); InputStream is = entity.getContent(); // 將輸入流轉化為byte型 byte[] data = WebService.read(is); // 轉化為字符串 return new String(data, "UTF-8"); } } 五、運行效果 以上工作完成後,只需要講服務器端發布到本地( 附上--mysql-jdbc驅動地址-- ),安卓端發布到手機,確保局域網內部,ip正確,即可正常訪問。 客戶端截圖:測試成功 服務器端截圖:測試成功 六、源碼 以上不足之處,還望大家多多指正。 如有問題歡迎給我留言。 代碼並未涉及到Session保持,自動登陸等,正在改進中,最終效果應該類似於虎牙直播的登陸註冊(剛好舉個例子)

安卓端通過http對Mysql進行增刪改查