笨笨的博主在捣鼓了快一周之后,终于成功实现了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,会出现注册成功!
然后再用这个账户和密码点登录,就会显示登陆成功!
如果改一下密码,就会显示错误!
到这里我想你就要落泪了,真的不容易呜呜呜呜呜。
跑起来了,就有信心去研究代码啦~冲鸭!!!