package com.example.kucun2.data;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.example.kucun2.entity.User;
import java.io.File;
@Database(entities = {User.class}, version = 2, exportSchema = false )
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
private static volatile AppDatabase INSTANCE;
public static AppDatabase getDatabase(Context context) {
return Room.databaseBuilder(context, AppDatabase.class, "users.db")
.addMigrations(MIGRATION_1_2)
.addCallback(new RoomDatabase.Callback() {
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
// 确保视图存在
db.execSQL("CREATE VIEW IF NOT EXISTS user_summary AS SELECT id, name FROM users");
}
})
.fallbackToDestructiveMigrationOnDowngrade()
.build();
}
private static void migrateFromLegacy(Context context) {
// 旧数据库迁移逻辑
SQLiteDatabase legacyDb = SQLiteDatabase.openDatabase(
context.getDatabasePath("users.db").getPath(),
null,
SQLiteDatabase.OPEN_READONLY);
Cursor cursor = legacyDb.rawQuery("SELECT * FROM users", null);
// 数据迁移到Room数据库
UserDao dao = INSTANCE.userDao();
// 使用事务保证迁移完整性
INSTANCE.runInTransaction(() -> {
while (cursor.moveToNext()) {
User user = new User(cursor.getInt(0),
cursor.getString(1),
cursor.getString(2),
cursor.getString(3),
cursor.getInt(4)
);
dao.insert(user);
}
cursor.close();
legacyDb.close();
});
}
private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
// 示例:添加新字段
// 示例:创建视图(不修改表结构)
db.execSQL("CREATE TABLE users_temp (id INTEGER PRIMARY KEY, " +
"name TEXT, " +
"andy TEXT, " +
"pass TEXT, " +
"role INTEGER)" +
"");
// 3. 迁移数据
db.execSQL("INSERT INTO users_temp (id, name, andy, pass, role) " +
"SELECT id, name, andy, pass, role FROM users");
// 4. 删除旧表并重命名
db.execSQL("DROP TABLE users");
db.execSQL("ALTER TABLE users_temp RENAME TO users");
// 5. 维护视图
db.execSQL("DROP VIEW IF EXISTS user_summary");
db.execSQL("CREATE VIEW user_summary AS SELECT id, name FROM users");
}
};
public static void deleteDatabase(Context context) {
// 1. 关闭现有连接
if (INSTANCE != null) {
INSTANCE.close();
INSTANCE = null;
}
// 2. 删除物理文件
context.deleteDatabase("users.db");
// 3. 清理残留文件(WAL/SHM)
File databaseDir = context.getDatabasePath("users.db").getParentFile();
if (databaseDir != null) {
for (File file : databaseDir.listFiles()) {
if (file.getName().startsWith("users.db")) {
file.delete();
}
}
}
}
}package com.example.kucun2.ui.moban;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import com.example.kucun2.Http.HttpApi;
import com.example.kucun2.Http.ReturnMethod;
import com.example.kucun2.R;
import com.example.kucun2.data.AppDatabase;
import com.example.kucun2.entity.User;
import com.example.kucun2.manager.AuthManager;
import java.io.File;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, View.OnFocusChangeListener, ViewTreeObserver.OnGlobalLayoutListener, TextWatcher {
private String TAG = "ifu25";
private ImageButton mIbNavigationBack;
private LinearLayout mLlLoginPull;
private View mLlLoginLayer;
private LinearLayout mLlLoginOptions;
private EditText mEtLoginUsername;
private EditText mEtLoginPwd;
private LinearLayout mLlLoginUsername;
private ImageView mIvLoginUsernameDel;
private Button mBtLoginSubmit;
private LinearLayout mLlLoginPwd;
private ImageView mIvLoginPwdDel;
private ImageView mIvLoginLogo;
private LinearLayout mLayBackBar;
private TextView mTvLoginForgetPwd;
private Button mBtLoginRegister;
private CheckBox cbAgree;
//全局Toast
private Toast mToast;
private int mLogoHeight;
private int mLogoWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}
//初始化视图
private void initView() {
//登录层、下拉层、其它登录方式层
mLlLoginPull = findViewById(R.id.ll_login_pull);
mLlLoginOptions = findViewById(R.id.ll_login_options);
//导航栏+返回按钮
mLayBackBar = findViewById(R.id.ly_retrieve_bar);
mIbNavigationBack = findViewById(R.id.ib_navigation_back);
//logo
mIvLoginLogo = findViewById(R.id.iv_login_logo);
//username
mLlLoginUsername = findViewById(R.id.ll_login_username);
mEtLoginUsername = findViewById(R.id.et_login_username);
mIvLoginUsernameDel = findViewById(R.id.iv_login_username_del);
//passwd
mLlLoginPwd = findViewById(R.id.ll_login_pwd);
mEtLoginPwd = findViewById(R.id.et_login_pwd);
mIvLoginPwdDel = findViewById(R.id.iv_login_pwd_del);
//提交、注册
mBtLoginSubmit = findViewById(R.id.bt_login_submit);
//忘记密码
mTvLoginForgetPwd = findViewById(R.id.tv_login_forget_pwd);
mTvLoginForgetPwd.setOnClickListener(this);
//注册点击事件
mLlLoginPull.setOnClickListener(this);
mIbNavigationBack.setOnClickListener(this);
mEtLoginUsername.setOnClickListener(this);
mIvLoginUsernameDel.setOnClickListener(this);
mBtLoginSubmit.setOnClickListener(this);
mEtLoginPwd.setOnClickListener(this);
mIvLoginPwdDel.setOnClickListener(this);
findViewById(R.id.ib_login_weibo).setOnClickListener(this);
findViewById(R.id.ib_login_qq).setOnClickListener(this);
findViewById(R.id.ib_login_wx).setOnClickListener(this);
//注册其它事件
mLayBackBar.getViewTreeObserver().addOnGlobalLayoutListener(this);
mEtLoginUsername.setOnFocusChangeListener(this);
mEtLoginUsername.addTextChangedListener(this);
mEtLoginPwd.setOnFocusChangeListener(this);
mEtLoginPwd.addTextChangedListener(this);
cbAgree = findViewById(R.id.cb_remember_login);
cbAgree.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
Toast.makeText(this, "已同意协议", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "请阅读并同意协议", Toast.LENGTH_SHORT).show();
}
});
}
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ib_navigation_back:
//返回
finish();
break;
case R.id.et_login_username:
mEtLoginPwd.clearFocus();
mEtLoginUsername.setFocusableInTouchMode(true);
mEtLoginUsername.requestFocus();
break;
case R.id.et_login_pwd:
mEtLoginUsername.clearFocus();
mEtLoginPwd.setFocusableInTouchMode(true);
mEtLoginPwd.requestFocus();
break;
case R.id.iv_login_username_del:
//清空用户名
mEtLoginUsername.setText(null);
break;
case R.id.iv_login_pwd_del:
//清空密码
mEtLoginPwd.setText(null);
break;
case R.id.bt_login_submit:
//登录
loginRequest();
break;
case R.id.tv_login_forget_pwd:
//忘记密码
startActivity(new Intent(MainActivity.this, ForgetPwdActivity.class));
break;
case R.id.ll_login_pull:
mLlLoginPull.animate().cancel();
mLlLoginLayer.animate().cancel();
int height = mLlLoginOptions.getHeight();
float progress = (mLlLoginLayer.getTag() != null && mLlLoginLayer.getTag() instanceof Float) ? (float) mLlLoginLayer.getTag() : 1;
int time = (int) (360 * progress);
if (mLlLoginPull.getTag() != null) {
mLlLoginPull.setTag(null);
glide(height, progress, time);
} else {
mLlLoginPull.setTag(true);
upGlide(height, progress, time);
}
break;
case R.id.ib_login_weibo:
weiboLogin();
break;
case R.id.ib_login_qq:
qqLogin();
break;
case R.id.ib_login_wx:
weixinLogin();
break;
default:
break;
}
}
//用户名密码焦点改变
@Override
public void onFocusChange(View v, boolean hasFocus) {
int id = v.getId();
if (id == R.id.et_login_username) {
if (hasFocus) {
mLlLoginUsername.setActivated(true);
mLlLoginPwd.setActivated(false);
}
} else {
if (hasFocus) {
mLlLoginPwd.setActivated(true);
mLlLoginUsername.setActivated(false);
}
}
}
/**
* menu glide
*
* @param height height
* @param progress progress
* @param time time
*/
private void glide(int height, float progress, int time) {
mLlLoginPull.animate()
.translationYBy(height - height * progress)
.translationY(height)
.setDuration(time)
.start();
mLlLoginLayer.animate()
.alphaBy(1 * progress)
.alpha(0)
.setDuration(time)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
if (animation instanceof ValueAnimator) {
mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue());
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (animation instanceof ValueAnimator) {
mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue());
}
mLlLoginLayer.setVisibility(View.GONE);
}
})
.start();
}
/**
* menu up glide
*
* @param height height
* @param progress progress
* @param time time
*/
private void upGlide(int height, float progress, int time) {
mLlLoginPull.animate()
.translationYBy(height * progress)
.translationY(0)
.setDuration(time)
.start();
mLlLoginLayer.animate()
.alphaBy(1 - progress)
.alpha(1)
.setDuration(time)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mLlLoginLayer.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationCancel(Animator animation) {
if (animation instanceof ValueAnimator) {
mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue());
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (animation instanceof ValueAnimator) {
mLlLoginLayer.setTag(((ValueAnimator) animation).getAnimatedValue());
}
}
})
.start();
}
//显示或隐藏logo
@Override
public void onGlobalLayout() {
final ImageView ivLogo = this.mIvLoginLogo;
Rect KeypadRect = new Rect();
mLayBackBar.getWindowVisibleDisplayFrame(KeypadRect);
int screenHeight = mLayBackBar.getRootView().getHeight();
int keypadHeight = screenHeight - KeypadRect.bottom;
//隐藏logo
if (keypadHeight > 300 && ivLogo.getTag() == null) {
final int height = ivLogo.getHeight();
final int width = ivLogo.getWidth();
this.mLogoHeight = height;
this.mLogoWidth = width;
ivLogo.setTag(true);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0);
valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(animation -> {
float animatedValue = (float) animation.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams();
layoutParams.height = (int) (height * animatedValue);
layoutParams.width = (int) (width * animatedValue);
ivLogo.requestLayout();
ivLogo.setAlpha(animatedValue);
});
if (valueAnimator.isRunning()) {
valueAnimator.cancel();
}
valueAnimator.start();
}
//显示logo
else if (keypadHeight < 300 && ivLogo.getTag() != null) {
final int height = mLogoHeight;
final int width = mLogoWidth;
ivLogo.setTag(null);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(400).setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(animation -> {
float animatedValue = (float) animation.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = ivLogo.getLayoutParams();
layoutParams.height = (int) (height * animatedValue);
layoutParams.width = (int) (width * animatedValue);
ivLogo.requestLayout();
ivLogo.setAlpha(animatedValue);
});
if (valueAnimator.isRunning()) {
valueAnimator.cancel();
}
valueAnimator.start();
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
//用户名密码输入事件
@Override
public void afterTextChanged(Editable s) {
String username = mEtLoginUsername.getText().toString().trim();
String pwd = mEtLoginPwd.getText().toString().trim();
//是否显示清除按钮
if (username.length() > 0) {
mIvLoginUsernameDel.setVisibility(View.VISIBLE);
} else {
mIvLoginUsernameDel.setVisibility(View.INVISIBLE);
}
if (pwd.length() > 0) {
mIvLoginPwdDel.setVisibility(View.VISIBLE);
} else {
mIvLoginPwdDel.setVisibility(View.INVISIBLE);
}
//登录按钮是否可用
if (!TextUtils.isEmpty(pwd) && !TextUtils.isEmpty(username)) {
mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit);
mBtLoginSubmit.setTextColor(ContextCompat.getColor(this,R.color.white));
} else {
mBtLoginSubmit.setBackgroundResource(R.drawable.bg_login_submit_lock);
mBtLoginSubmit.setTextColor(ContextCompat.getColor(this,R.color.account_lock_font_color));
}
}
//登录
private void loginRequest() {
AppDatabase.deleteDatabase(this);
// 验证是否删除成功
File dbFile = this.getDatabasePath("users.db");
if (!dbFile.exists()) {
Log.d("Database", "数据库已彻底删除");
}
String andy=mEtLoginUsername.getText().toString();
String pass=mEtLoginPwd.getText().toString();
Context context=this;
try {
HttpApi.HttpPost(getString(R.string.url_baidu), new User(0, null, andy, pass, 0), new ReturnMethod() {
@Override
public void Success(String data) {
Log.d("success",data);
// Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
User user =new User(0,"12323123","3211231","12312",0);
AuthManager Auth=new AuthManager(context);
Auth.register(user) ;
Log.d("sql",""+ user.toString());
Log.d("sql",""+ Auth.login(user.getAndy(),user.getPass()) );
}
@Override
public void failed(String data) {
}
@Override
public void error(Exception e) {
// Toast.makeText(MainActivity.this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
Log.d("error",e.getLocalizedMessage());
}
});
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
//微博登录
private void weiboLogin() {
}
//QQ登录
private void qqLogin() {
}
//微信登录
private void weixinLogin() {
}
/**
* 显示Toast
*
* @param msg 提示信息内容
*/
private void showToast(int msg) {
if (null != mToast) {
mToast.setText(msg);
} else {
mToast = Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT);
}
mToast.show();
}
}
package com.example.kucun2.entity;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
private Integer id;
private String name;
private String andy;
private String pass;
private Integer role;
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getAndy() {
return andy;
}
public String getPass() {
return pass;
}
public int getRole() {
return role;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAndy(String andy) {
this.andy = andy;
}
public void setPass(String pass) {
this.pass = pass;
}
public void setRole(int role) {
this.role = role;
}
@Ignore
public User(int id, String name, String andy, String pass, int role) {
this.id = id;
this.name = name;
this.andy = andy;
this.pass = pass;
this.role = role;
}
public User() {
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
// 处理属性名
sb.append("\"id\": ");
// 处理不同数据类型
// 其他对象类型
sb.append((id != null) ? id : "null");
sb.append(",");
// 处理属性名
sb.append("\"name\": ");
// 处理不同数据类型
// 字符串类型处理(含转义)
sb.append("\"")
.append(name
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t"))
.append("\"");
sb.append(",");
// 处理属性名
sb.append("\"andy\": ");
// 处理不同数据类型
// 字符串类型处理(含转义)
sb.append("\"")
.append(andy
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t"))
.append("\"");
sb.append(",");
// 处理属性名
sb.append("\"pass\": ");
// 处理不同数据类型
// 字符串类型处理(含转义)
sb.append("\"")
.append(pass
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t"))
.append("\"");
sb.append(",");
// 处理属性名
sb.append("\"role\": ");
// 处理不同数据类型
// 其他对象类型
sb.append((role != null) ? role : "null");
sb.append("}");
return sb.toString();
}
}
package com.example.kucun2.manager;
import android.content.Context;
import androidx.room.Room;
import com.example.kucun2.data.AppDatabase;
import com.example.kucun2.data.UserDao;
import com.example.kucun2.entity.User;
import at.favre.lib.crypto.bcrypt.BCrypt;
public class AuthManager {
private final BCrypt.Hasher hasher = BCrypt.with(BCrypt.Version.VERSION_2Y);
private final UserDao userDao;
public AuthManager(Context context) {
AppDatabase db = Room.databaseBuilder(
context,
AppDatabase.class,
"app-db"
).build();
userDao = db.userDao();
}
public boolean register(User user) {
// 密码强度校验
if (!validatePassword(user.getPass())) return false;
// 生成BCrypt哈希(自动处理盐值)
String hash = hasher.hashToString(12, user.getPass().toCharArray());
// 异步插入数据库
new Thread(() -> {
User us = new User(0,"000000",user.getAndy(),hash,0);
userDao.insertUser(us);
}).start();
return true;
}
private boolean validatePassword(String password) {
return password.length() >= 8
&& password.matches(".*[A-Z].*")
&& password.matches(".*\\d.*");
}
public boolean login(String username, String password) {
User user = userDao.findUserByUsername(username);
if (user == null) return false;
BCrypt.Result result = BCrypt.verifyer().verify(
password.toCharArray(),
user.getPass()
);
return result.verified;
}
}