安卓开发之图片分享应用1:使用MySQL数据库实现登录功能
一、开发过程中踩中的坑以及解决方案
1. 连接云端MySQL出现java.lang.NoClassDefFoundError: Failed resolution of: Ljava/sql/SQLTy
问题分析: 我使用的mysql-connector-java-8.0
版本号过高
解决方案: 将版本换成mysql-connector-java-5.1
左右的即可
官网下载地址:https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.49
2. 数据库连接池的连接connect只能使用一次com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed
.
问题分析: 原因很简单, 这里数据库的连接connection
是一个static
的,程序共享这一个connection
。所以第一次对数据库操作没问题,当把connection
关闭后,第二次还想操作数据库时connection
肯定不存在了,如果一个程序中使用一个共同的static
的connection
时,这种问题就很容易出现。
解决方案: 使用conn.isValid(int timeout)
方法判断该连接是否失效, 失效则重新获取连接即可 , timeout 单位是秒, 失效则返回false
, 有效则返回true
。
if(!conn.isValid(1)){
conn = DriverManager.getConnection(url,user,pwd);
}
二、建立数据库以及用户信息表
1. 建立数据库
2. 建立用户信息表语句
建完数据库之后,在刚刚建立的数据库中建立用户信息表
create table users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) Not NULL,
password VARCHAR(100) Not NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
3. 往用户信息表插入信息
我们往该用户信息表中插入一条用户信息,该用户用来测试登录功能。
insert into users(username,password)
VALUES ('admin','666666');
三、登录功能的实现
我们使用Android Studio
的loginActivity
模板连接云端MySQL
来进行登录功能的开发, 当然使用本地MySQL
也是可以的, 也就是改一下ip地址而已。
1. 创建LoginActivity
新建一个空项目(想必各位都会), 然后鼠标右键点击app->New->Activity->Login Activity进行创建, 如下图所示
创建好之后就会发现多了这些东西,一个是data
文件夹,另一个是ui.login
文件夹,以及layout布局里面的activity_login.xml
登录布局, 虽然文件很多, 但是对我们要改的却是很少, 我们只需要修改ui.login
里面的LoginActivity
, LoginViewModel
, 以及data
里面的LoginDataSource
即可。
下面是Android Studio
生成的Login Activity
界面
2. 设置权限
如果是使用云端MySQL需要添加网络权限,在AndroidManifest
里面添加下面代码即可
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
3. 创建MySQL数据库连接池进行登录信息验证
最好还是使用接口,直接连接数据库进行操作是不符合开发模式的
注意: 按理说MySQL连接和SQL语句查询是分开的,为了方便我将他们放在一个文件里了
3.1 添加MySQL连接依赖
下载MySQL依赖包: https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.49
选择Project查看模式
然后找到app下面的libs文件夹,将下载好的MySQL依赖包添加进去
鼠标右键点击添加的MySQL依赖,选择Add As Library
可以打开这个依赖说明添加成功了
3.2 Mysql连接工具类
鼠标右键New一个DButils
数据库连接工具类
然后输入数据库的ip地址、用户名以及密码。
如果是本地的数据库可以使用localhost
或者127.0.0.1
import android.util.Log;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class DBUtils {
private static final String driver = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://(你云端MySQL的IP地址或者是本地IP地址):3306/picture_app?useUnicode=true&characterEncoding=UTF-8";
private static final String user = "(输入你数据库的用户名)";
private static final String pwd = "(输入你数据库的密码)";
private static Connection conn=null;
private static int jumper=111;
private static String userid;
private static String nickname;
static{
try {
Class.forName(driver);
Log.e("驱动加载: ","成功!");//测试用的
}
catch (Exception e){
Log.e("驱动加载: ","失败!");
e.printStackTrace();
}
try {
conn=DriverManager.getConnection(url, user, pwd);
Log.e("连接数据库: ","成功!");
}
catch (Exception e){
Log.e("连接数据库: ","失败!");
e.printStackTrace();
}
}
public static void linkLoginsql(String username, String password) {
try {
//验证是否用户名以及密码是否正确
String logSql = "Select * from users where username='"+ username+ "'and password='"+ password+ "'";
//判断连接是否失效,失效则重新获取连接
if(!conn.isValid(1)){
conn = DriverManager.getConnection(url,user,pwd);
}
PreparedStatement stmt = conn.prepareStatement(logSql);
ResultSet rs = stmt.executeQuery(logSql);
// 获取跳转判断
if(rs.next()){
jumper=233;
userid=rs.getString("username");
nickname=rs.getString("nickname");
}else{
jumper=777;
}
System.out.println(jumper);
rs.close();
stmt.close();
}
catch (Exception e){
e.printStackTrace();
}
//关闭数据库
if(conn!=null){
try {
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
//获取跳转判断
public static int getjumper(){
return jumper;
}
//获取用户ID
public static String getuserid(){
return userid;
}
//获取用户昵称
public static String getnickname(){
return nickname;
}
}
4. 将Login Activity与MySQL工具类连接起来
我们只需要修改ui.login
里面的LoginActivity
, LoginViewModel
, 以及data
里面的LoginDataSource
即可
4.1 改写LoginActivity
1. 改写登录按钮监听器:
点击登录按钮时,会对输入的username和password进行验证,那么就需要调用MySQL连接工具类的DBUtils.linkLoginsql
方法,如果查询成功则DBUtils
里面的jumper
就会被赋值233,否则赋值777,这个是判断是否登录成功的标志。我们看到在代码的结尾调用了loginViewModel.login
方法,所以我们还需要到LoginViewModel
该类里面进行登录判断的编写。
代码如下:
LoginActivity:
//设置点击事件
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//在线程中调用数据库
Thread t1 = new Thread(new Runnable() {
public void run() {
DBUtils.linkLoginsql(usernameEditText.getText().toString(),passwordEditText.getText().toString());
}
});
t1.start();
//在数据库连接完成之前暂停其他活动
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
loadingProgressBar.setVisibility(View.VISIBLE);
loginViewModel.login(usernameEditText.getText().toString(),passwordEditText.getText().toString());
}
});
2. 改写登录验证成功后的事件:
当验证用户名和密码正确时,也就是登录成功,我们需要从登录界面跳转到首页
代码如下:
LoginActivity:
loginViewModel.getLoginResult().observe(this, new Observer<LoginResult>() {
@Override
public void onChanged(@Nullable LoginResult loginResult) {
if (loginResult == null) {
return;
}
loadingProgressBar.setVisibility(View.GONE);
if (loginResult.getError() != null) {
//显示登录失败
showLoginFailed(loginResult.getError());
}
if (loginResult.getSuccess() != null) {
updateUiWithUser(loginResult.getSuccess());
//添加登录跳转,登录成功就跳转到首页
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
LoginActivity.this.startActivity(intent);
updateUiWithUser(loginResult.getSuccess());
}
setResult(Activity.RESULT_OK);
//Complete and destroy login activity once successful
//finish();这个注释掉,不然会结束掉这个activity,也就是登录界面消失
}
});
4.2 改写LoginViewModel
代码如下:
LoginViewModel:
public void login(String username, String password) {
// can be launched in a separate asynchronous job
Result<LoggedInUser> result = loginRepository.login(username, password);
//判断是否登录成功
if (DBUtils.getjumper() == 233) {
//登录成功
LoggedInUser data = ((Result.Success<LoggedInUser>) result).getData();
loginResult.setValue(new LoginResult(new LoggedInUserView(data.getDisplayName())));
} else {
//登录失败
loginResult.setValue(new LoginResult(R.string.login_failed));
}
}
4.3 改写LoginDataSource
用于显示登录成功后的用户名
代码如下:
LoginDataSource:
public class LoginDataSource {
public Result<LoggedInUser> login(String username, String password) {
try {
// TODO: handle loggedInUser authentication
LoggedInUser fakeUser =
new LoggedInUser(
//修改显示的用户昵称
java.util.UUID.randomUUID().toString(),
DBUtils.getnickname());
return new Result.Success<>(fakeUser);
} catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e));
}
}
public void logout() {
// TODO: revoke authentication
}
}
5. 登录成功后跳转的主页面MainActivity
效果演示
也就是为了查看登录成功后能不能跳转到首页而随便写的,所以很丑
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="14dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/editText"
android:text="首页"
android:textSize="64dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
tools:ignore="MissingConstraints" />
<Button
android:id="@+id/button_Send"
android:text="登录"
app:layout_constraintStart_toStartOf="@id/editText"
app:layout_constraintTop_toBottomOf="@id/editText"
android:layout_marginLeft="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity:
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.example.pictureapp.ui.login.LoginActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//登录按钮,在首页点击后重新回到登录页面
Button btn_Send = findViewById(R.id.button_Send);
btn_Send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"正在进入...",Toast.LENGTH_LONG).show();
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
}
});
}
}
6. 实现启动APP后直接跳转到登录界面
其实很简单,只需要在
AndroidManifest
里面讲LoginActivity与MainActivity的位置交换,也就是将启动第一次呈现的页面变成登录页面
交换后
最后大功告成,启动App即可。
想对Android Studio的LoginActivity进一步了解的可以查看相关的资料。