Flutter集成Sqflite实现注册登录点击注册无响应问题求助
问题说明
基于Sqflite开发Flutter应用注册/登录数据库模块时,点击注册按钮无响应。开发者有MySQL使用经验,正在学习Flutter与Sqflite技术栈,附数据库实现、注册逻辑代码如下,排查问题。
原有数据库实现代码
class DbHelper { static const String DB_Name = 'test.db'; static const String Table_User = 'user'; static const int Version = 1; static const String _Email = 'email'; static const String _Password = 'password'; static const String _Name = 'name'; static Database? _db; Future<Database?> get db async { if (_db != null) { return _db; } _db = await initDb(); return _db; } initDb () async { io.Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join (documentsDirectory.path, DB_Name); var db = await openDatabase(path , version: Version, onCreate: _onCreate); return db; } _onCreate (Database db, int intVersion) async { await db.execute("CREATE TABLE $Table_User (" "$_Email TEXT ," "$_Password TEXT ," "$_Name TEXT ," " PRIMARY KEY ($_Email)" " )"); } Future<int> saveData(UserModel user) async{ var dbClient = await db; var res = await dbClient!.insert(Table_User, user.toMap()); return res; } Future<UserModel?> getLoginUser(String email, String password) async { var dbClient = await db; var res = await dbClient!.rawQuery("SELECT * FROM $Table_User WHERE " "$_Email = '$email' AND " "$_Password = '$password'"); if (res.length > 0) { return UserModel.fromMap(res.first); } return null; } }
原有注册功能代码
signUp() async { final form = _formKey.currentState; String uEmail = _Email.text; String password = _Password.text; String cpassword = _CPassword.text; String uname = _Name.text; if(form != null && !form.validate ()){ if (password != cpassword) { alertDialog(context, "Password Mismatch"); } else{ _formKey.currentState?.save(); UserModel uModel = UserModel(uEmail, password, uname); await dbHelper.insert(uModel).then((userData) { alertDialog(context, "Success"); Navigator.push(context, MaterialPageRoute(builder: (_) => LoginForm())); }).catchError((error){ print(error); alertDialog(context, "Error: Data Save Fail"); }); } } }
问题根因
一共3个直接导致功能异常的bug,1个安全隐患:
- 表单校验逻辑写反:判断条件用了
!form.validate(),只有表单校验不通过时才会进入后续注册流程,表单正常填完符合校验规则时,整个逻辑块完全不执行,这是点击按钮无响应的核心原因 - 方法调用不匹配:
DbHelper中定义的插入方法名为saveData(),注册逻辑中调用的是不存在的dbHelper.insert(),就算表单逻辑正常,这里也会直接抛方法不存在的异常 - 业务逻辑位置错误:两次密码输入一致性校验被放在「表单校验不通过」的分支中,正常注册流程完全不会校验两次密码是否相同
- SQL拼接风险:登录查询直接用字符串拼接参数,容易出现特殊字符转义失败、SQL注入问题
修复方案
修正注册逻辑
把表单判断条件改对,调整密码校验位置,调用正确的插入方法,修正后代码如下:
signUp() async { final form = _formKey.currentState; // 取输入值时去掉首尾空格,避免误输入空格导致异常 String uEmail = _Email.text.trim(); String password = _Password.text.trim(); String cpassword = _CPassword.text.trim(); String uname = _Name.text.trim(); // 表单存在且校验通过时才走注册流程 if(form != null && form.validate()){ // 先校验两次密码是否一致 if (password != cpassword) { alertDialog(context, "Password Mismatch"); return; } _formKey.currentState?.save(); UserModel uModel = UserModel(uEmail, password, uname); // 调用DbHelper中实际存在的saveData方法 await dbHelper.saveData(uModel).then((userData) { alertDialog(context, "Success"); Navigator.push(context, MaterialPageRoute(builder: (_) => LoginForm())); }).catchError((error){ print(error); alertDialog(context, "Error: Data Save Fail"); }); } }
优化数据库查询逻辑
把登录的SQL查询改成参数化形式,避免转义和注入问题:
Future<UserModel?> getLoginUser(String email, String password) async { var dbClient = await db; // 用?作为参数占位符,参数通过arguments数组传递,sqflite会自动处理转义 var res = await dbClient!.rawQuery( "SELECT * FROM $Table_User WHERE $_Email = ? AND $_Password = ?", [email.trim(), password.trim()] ); if (res.isNotEmpty) { return UserModel.fromMap(res.first); } return null; }
额外优化建议
- 因为表结构中设置email为主键,插入重复邮箱会直接抛异常,注册前可以先查询邮箱是否已经存在,提前给用户提示
- 不要明文存储密码,建议对密码做哈希处理(比如用bcrypt)后再存入数据库,提升安全性
- 初始化数据库、插入数据的逻辑中可以加打印日志,方便后续调试时快速定位问题
内容的提问来源于stack exchange,提问作者luffy
相关产品推荐
相关产品推荐

