笨笨的博主在搗鼓了快一週之後,終於成功實現了Servlet+安卓端的註冊登錄操作!!!可歌可泣嗚嗚嗚嗚。在網上找了很多例子,但是代碼都沒跑通,加上自己真的很菜(Java編程啥的沒什麼經驗),所以踩了很多坑。現在寫一篇小教程,要注意的細節我儘量提及!讓大家都能體會到自己實現這個的激動心情。
好,廢話不多說,咱們開始!
文章目錄
準備工作
安裝Eclipse、mysql、AndroidStudio、Navicat,並且可以實現用Sevlet對mysql數據庫的讀寫操作。看到這裏你可能準備告辭了,但是不管在哪你都得先學會這些吖!我也是從0(真的是24k純0!!)起步的,推薦去跟着【一步一個腳印】Tomcat+MySQL爲自己的APP打造服務器這個教程學,不懂的可以問我!(趁着我剛學過還有印象)這個教程系列你從(1)服務器環境搭建學到(2-3)Servlet連接MySQL數據庫,學完就可以來看我這篇了,我這篇其實就是原教程的(3-1)Android 和 Service 的交互之GET方式,只是原教程有很多基礎的地方都沒講(原博主大神估計覺得這些基礎到不用講,我眼淚掉下來),導致我很多地方都不知道要改,或者不知道怎麼操作。
所以!!!!將心比心,天下小白是一家,我這篇博客就力求做到無微不至吧!!!
害,廢話還是說了這麼多,咱們現在真的真的要開始了!
用Navicat連接mysql數據庫
通過這個可以比較方便地在mysql的可視化窗口(就是Navicat)裏面創建表格。
因爲這次交互是想達到:註冊的話,就在表格裏添加賬號和密碼;登陸的話,就驗證賬號和密碼是否匹配。所以我們先用Navicat連接上數據庫,怎麼創建連接和創建庫參考這篇文章。
連接好之後,在你創建的新連接(建議小白們都和我取一樣的名字,免得後面不知道怎麼改代碼,我的新連接名是localhost_3306)下面自己建的一個庫(我的庫名叫first_mysql_test)下面建一個表格,如下:
輸入如下的信息,輸入好之後,再點擊空白區域:
會出現藍色塊(不一定是account,有藍色塊出現就行),右鍵它,選擇“添加欄位”:
輸入password欄,如下,然後點擊保存。
名字叫table_id。(如果是0基礎小白就不要起別的名字了,免得複製我後面給的代碼之後又不知道去哪改,我勸你對自己好一點)
好啦,數據庫的創建工作告一段落,下面是Eclipse的內容~
用Eclipse連接mysql數據庫
新建項目
首先,右鍵file,選new,然後選others。
在Web文件夾下找到dynamic web project。
這裏說明一下,博主的Eclipse是JavaEE的,直接就有dynamic web project,其他版本的好像還要裝插件之類的。避免麻煩可以再裝一個我這個版本的(建議這樣做),反正Eclipse是免安裝的直接用。諾,鏈接在這,密碼:qpxu。
找到.jar文件
找到一個類似這個名字的文件,mysql-connector-java-版本號-bin.jar,
如果沒有的話,就去官網下載,
如果你和我一樣是windows就選platform independent。
下載就開始辣!會hin慢,如果不嫌棄的話可以嘗試直接用我的,不過版本不是最新的,是5.1.40。諾,鏈接在這,提取碼:ox4o。
把.jar文件複製到對應目錄下:
然後add to build path,具體操作可以參考這篇文章。
至此Eclipse和數據庫的連接就搞定辣!下一步!
Eclipse創建RegisterServlet1和LoginServlet
爲什麼是個1,因爲我創建過RegisterServlet,然後沒成功,後來修改RegisterServlet1成功了我就不敢改回去,萬一又不行我就生氣氣了。所以,就麻煩你也耐着性子把servlet的名字設成RegisterServlet1叭,免得後面代碼出錯!好啦操作如下:
參數設置:
加載一會之後,在主頁面左側的欄上看到ServletTest1.
新建一個DBUtil.java類
這個是一些配置信息。新建一個類:在src文件夾右鍵,new——other——class。
簡單粗暴,把這段代碼貼上去(記得修改用戶名和密碼!!!):
DBUtil.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
// table
public static final String Table_Account="table_id";
// connect to MySql database
public static Connection getConnect() {
String url = "jdbc:mysql://localhost:3306/first_mysql_test"; // 數據庫的Url
Connection connecter = null;
try {
Class.forName("com.mysql.jdbc.Driver"); // java反射,固定寫法
//劃重點!!下面的root和password要改成你創建連接時候用的用戶名和密碼!!!
connecter = (Connection) DriverManager.getConnection(url, "root", "password");
} 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 connecter;
}
}
用戶名和密碼就是你創建連接時候用的那個:
新建註冊servlet
省點事兒,直接finish:
RegisterServlet1.java
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class RegisterServlet1
*/
@WebServlet(description = "用來和客戶端交互", urlPatterns = { "/RegisterServlet1" })
public class RegisterServlet1 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public void RegisterServlet() {
log("RegisterServlet construct...");
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getMethod();
if ("GET".equals(method)) {
log("請求方法:GET");
doGet(request, response);
} else if ("POST".equals(method)) {
log("請求方法:POST");
doPost(request, response);
} else {
log("請求方法分辨失敗!");
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* 先設置請求、響應報文的編碼格式 */
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String code = "";
String message = "";
String account = request.getParameter("account");
String password = request.getParameter("password");
log(account + ";" + password);
Connection connect = DBUtil.getConnect();
try {
Statement statement = connect.createStatement();
String sql = "select account from " + DBUtil.Table_Account + " where account='" + account + "'";
log(sql);
ResultSet result = statement.executeQuery(sql);
if (result.next()) { // 能查到該賬號,說明已經註冊過了
code = "100";
message = "該賬號已存在";
} else {
String sqlInsert = "insert into " + DBUtil.Table_Account + "(account, password) values('"
+ account + "', '" + password + "')";
log(sqlInsert);
if (statement.executeUpdate(sqlInsert) > 0) { // 否則進行註冊邏輯,插入新賬號密碼到數據庫
code = "200";
message = "註冊成功";
} else {
code = "300";
message = "註冊失敗";
}
}
} catch (SQLException e) {
e.printStackTrace();
}
response.getWriter().append("code:").append(code).append(";message:").append(message);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
@Override
public void destroy() {
log("RegisterServlet destory.");
super.destroy();
}
}
咳咳,這裏默認你會Tomcat了哈,不會的回去看前面的【準備工作】。
新建登錄Servlet
和新建RegisterServlet1一樣的,名字改一下就行
LoginServlet.java
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 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 {
/* 先設置請求、響應報文的編碼格式 */
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String code = "";
String message = "";
String account = request.getParameter("account");
String password = request.getParameter("password");
log(account + ";" + password);
Connection connect = DBUtil.getConnect();
try {
Statement statement = connect.createStatement();
String sql = "select account from " + DBUtil.Table_Account + " where account='" + account
+ "' and password='" + password + "'";
log(sql);
ResultSet result = statement.executeQuery(sql);
if (result.next()) { // 能查到該賬號,說明已經註冊過了
code = "200";
message = "登陸成功";
} else {
code = "100";
message = "登錄失敗,密碼不匹配或賬號未註冊";
}
} catch (SQLException e) {
e.printStackTrace();
}
response.getWriter().append("code:").append(code).append(";message:").append(message);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
log("不支持POST方法");
}
}
測試一下
然後,我們再點LoginServlet,運行。
好了!服務器端終於搞掂了,接下來就是安卓端!堅持住姐妹們!!!
安卓端
建個項目,名字隨便取,
來到你的AndroidStudio界面,建個新項目,主界面file——new——new project
欸其實就是一路next直到finish,但是體諒到一些糾結的姐妹我還是耐心地全貼出來,你們也耐心地跟着康康…(抱拳!)
主頁面佈局
項目創建成功之後,點左側的project1。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
//賬號輸入框
<EditText
android:id="@+id/et_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入賬號" />
//密碼輸入框
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入登錄密碼"
android:inputType="textPassword" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="horizontal">
//註冊按鈕
<Button
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Register" />
//登錄按鈕
<Button
android:id="@+id/btn_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Login" />
</LinearLayout>
<!-- 用來顯示報文返回結果 -->
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
配置文件
新建一個類,命名爲constant。
第一行的package代碼保留你自己的,然後把下面的代碼粘貼上去(記得修改192.168.13.1爲你自己的IP地址!)<:
Constant.java
public class Constant {
public static String URL = "http://192.168.13.1:8080/ServletTest1/"; // IP地址請改爲你自己的IP
public static String URL_Register = URL + "RegisterServlet1";
public static String URL_Login = URL + "LoginServlet";
}
不知道自己IP地址咋看的參考這篇文章。
主Activity文件
MainActivity.java
同樣,保留第一行的package代碼,後面的代碼如下:
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class MainActivity extends Activity {
private EditText etAccount;
private EditText etPassword;
private TextView tvResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etAccount = (EditText) findViewById(R.id.et_account);
etPassword = (EditText) findViewById(R.id.et_password);
tvResult = (TextView) findViewById(R.id.tv_result);
Button btnRegister = (Button) findViewById(R.id.btn_register);
//註冊監聽,點擊運行register()
btnRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!TextUtils.isEmpty(etAccount.getText().toString())
&& !TextUtils.isEmpty(etPassword.getText().toString())) {
Log.e("WangJ", "都不空");
register(etAccount.getText().toString(), etPassword.getText().toString());
} else {
Toast.makeText(MainActivity.this, "賬號、密碼都不能爲空!", Toast.LENGTH_SHORT).show();
}
}
});
Button btnLogin = (Button) findViewById(R.id.btn_login);
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!TextUtils.isEmpty(etAccount.getText().toString())
&& !TextUtils.isEmpty(etPassword.getText().toString())) {
Log.e("WangJ", "都不空");
login(etAccount.getText().toString(), etPassword.getText().toString());
} else {
Toast.makeText(MainActivity.this, "賬號、密碼都不能爲空!", Toast.LENGTH_SHORT).show();
}
}
});
}
private void register(String account, String password) {
String registerUrlStr = Constant.URL_Register + "?account=" + account + "&password=" + password;
new MyAsyncTask(tvResult).execute(registerUrlStr);
}
private void login(String account, String password) {
String registerUrlStr = Constant.URL_Login + "?account=" + account + "&password=" + password;
new MyAsyncTask(tvResult).execute(registerUrlStr);
}
/**
* AsyncTask類的三個泛型參數:
* (1)Params: 開始異步任務執行時傳入的參數類型,對應excute()中傳遞的參數
* (2)Progress:後臺任務執行過程中,如果需要在UI上先是當前任務進度,則使用這裏指定的泛型作爲進度單位
* (3)Result:任務執行完畢後,如果需要對結果進行返回,則這裏指定返回的數據類型
*/
public static class MyAsyncTask extends AsyncTask<String, Integer, String> {
private TextView tv; // 舉例一個UI元素,後邊會用到
public MyAsyncTask(TextView v) {
tv = v;
}
@Override
protected void onPreExecute() {
Log.w("WangJ", "task onPreExecute()");
}
/**
* @param params 這裏的params是一個數組,即AsyncTask在激活運行時調用execute()方法傳入的參數
*/
@Override
protected String doInBackground(String... params) {
Log.w("WangJ", "task doInBackground()");
HttpURLConnection connection = null;
StringBuilder response = new StringBuilder();
try {
URL url = new URL(params[0]); // 聲明一個URL,注意如果用百度首頁實驗,請使用https開頭,否則獲取不到返回報文
connection = (HttpURLConnection) url.openConnection(); // 打開該URL連接
connection.setRequestMethod("GET"); // 設置請求方法,“POST或GET”,我們這裏用GET,在說到POST的時候再用POST
connection.setConnectTimeout(8000); // 設置連接建立的超時時間
connection.setReadTimeout(8000); // 設置網絡報文收發超時時間
InputStream in = connection.getInputStream(); // 通過連接的輸入流獲取下發報文,然後就是Java的流處理
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response.toString(); // 這裏返回的結果就作爲onPostExecute方法的入參
}
@Override
protected void onProgressUpdate(Integer... values) {
// 如果在doInBackground方法,那麼就會立刻執行本方法
// 本方法在UI線程中執行,可以更新UI元素,典型的就是更新進度條進度,一般是在下載時候使用
}
/**
* 運行在UI線程中,所以可以直接操作UI元素
* @param s
*/
@Override
protected void onPostExecute(String s) {
Log.w("WangJ", "task onPostExecute()");
tv.setText(s);
}
}
}
添加聯網權限
在AndroidManifest.xml文件裏面添加兩句:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
測試
賬號或密碼爲空時,直接點REGISTER或者LOGIN,都會彈出下面的消息。
隨便填一個賬戶和密碼,點擊REGISTER,會出現註冊成功!
然後再用這個賬戶和密碼點登錄,就會顯示登陸成功!
如果改一下密碼,就會顯示錯誤!
到這裏我想你就要落淚了,真的不容易嗚嗚嗚嗚嗚。
跑起來了,就有信心去研究代碼啦~衝鴨!!!