用户注册与登录功能实现——玩具店购物应用开发实战(二)
用户注册与登录功能实现——玩具店购物应用开发实战(二)
在上一篇文章中,我们完成了玩具店购物应用的项目规划与环境搭建。本篇文章将详细介绍用户注册和登录功能的实现,包括用户输入验证、密码加密、登录状态管理等。
一、功能概述
1. 功能需求
-
用户注册:
-
用户可以通过邮箱和密码注册新账号。
-
注册时需要对输入的信息进行验证,如邮箱格式、密码强度等。
-
注册成功后,自动登录并跳转到商品列表页。
-
-
用户登录:
-
已注册用户可以通过邮箱和密码登录。
-
登录时需要验证用户输入的邮箱和密码是否正确。
-
登录成功后,保存登录状态,方便下次自动登录。
-
-
用户注销:
-
用户可以退出登录状态,清除本地的登录信息。
-
2. 技术难点
-
输入验证:如何有效地验证用户输入的信息,确保数据的有效性和安全性。
-
密码加密:如何对用户的密码进行加密存储,防止明文存储导致的安全问题。
-
登录状态管理:如何在应用中保存和管理用户的登录状态,实现自动登录。
二、数据库设计与实现
在第一篇文章中,我们已经设计了users表,用于存储用户信息。现在,我们需要完善数据库的初始化和连接。
1. 数据库初始化
在common/utils/DatabaseHelper.ets中,已经创建了DatabaseHelper类,用于数据库的初始化。现在,我们需要完善用户表的创建和密码加密。
// common/utils/DatabaseHelper.ets
import rdb from '@ohos.data.rdb';
export class DatabaseHelper {
private static instance: rdb.RdbStore;
static async getRdbStore(): Promise<rdb.RdbStore> {
if (!this.instance) {
const config = {
name: 'ToyStore.db',
version: 1,
onCreate: (db: rdb.RdbStore) => {
// 创建用户表
db.executeSql(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE,
password TEXT
)
`);
// 其他表的创建...
},
};
this.instance = await rdb.getRdbStore(config);
}
return this.instance;
}
}2. 密码加密存储
为了保证用户密码的安全性,我们需要对密码进行加密存储。这里我们使用SHA-256算法进行哈希处理。
创建加密工具类
在common/utils目录下,创建CryptoHelper.ets,用于密码的加密。
// common/utils/CryptoHelper.ets
import crypto from '@ohos.cryptographic';
export class CryptoHelper {
static hashPassword(password: string): string {
const messageDigest = crypto.createMessageDigest('SHA-256');
messageDigest.update(new Uint8Array(crypto.stringToUint8Array(password)));
const hash = messageDigest.digest();
return crypto.uint8ArrayToHex(hash);
}
}三、用户注册功能实现
1. 注册页面布局
在pages/RegisterPage.ets中,创建注册页面的UI布局。
// pages/RegisterPage.ets
@Entry
@Component
struct RegisterPage {
@State email: string = '';
@State password: string = '';
@State confirmPassword: string = '';
build() {
Column({ space: 16 }) {
Text('用户注册').fontSize(24).margin({ top: 32 });
TextField({ placeholder: '邮箱', text: this.email })
.onChange((value) => this.email = value)
.type(TextInputType.EmailAddress);
TextField({ placeholder: '密码', text: this.password })
.onChange((value) => this.password = value)
.type(TextInputType.Password);
TextField({ placeholder: '确认密码', text: this.confirmPassword })
.onChange((value) => this.confirmPassword = value)
.type(TextInputType.Password);
Button('注册')
.onClick(() => this.register())
.margin({ top: 16 });
Button('已有账号?登录')
.onClick(() => Router.replace({ uri: 'LoginPage' }))
.type(ButtonType.Normal);
}.padding(16);
}
}2. 输入验证
在register()方法中,添加对用户输入的验证。
import prompt from '@ohos.prompt';
import { DatabaseHelper } from '../common/utils/DatabaseHelper';
import { CryptoHelper } from '../common/utils/CryptoHelper';
@Component
struct RegisterPage {
// 前面的代码
private store: rdb.RdbStore;
aboutToAppear() {
this.initDatabase();
}
async initDatabase() {
this.store = await DatabaseHelper.getRdbStore();
}
async register() {
// 输入验证
if (!this.email || !this.password || !this.confirmPassword) {
prompt.showToast({ message: '请填写完整信息' });
return;
}
if (!this.validateEmail(this.email)) {
prompt.showToast({ message: '邮箱格式不正确' });
return;
}
if (this.password !== this.confirmPassword) {
prompt.showToast({ message: '两次密码输入不一致' });
return;
}
if (this.password.length < 6) {
prompt.showToast({ message: '密码长度至少为6位' });
return;
}
// 检查邮箱是否已注册
const query = 'SELECT * FROM users WHERE email = ?';
const resultSet = await this.store.query(query, [this.email]);
if (resultSet.goToFirstRow()) {
prompt.showToast({ message: '邮箱已注册' });
resultSet.close();
return;
}
resultSet.close();
// 密码加密
const hashedPassword = CryptoHelper.hashPassword(this.password);
// 插入新用户
const values = {
'email': this.email,
'password': hashedPassword,
};
await this.store.insert('users', values);
prompt.showToast({ message: '注册成功' });
// 自动登录,保存登录状态
AppStorage.SetOrCreate('isLoggedIn', true);
AppStorage.SetOrCreate('userEmail', this.email);
// 跳转到商品列表页
Router.replace({ uri: 'ProductListPage' });
}
validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}3. 解释
-
输入验证:检查邮箱格式、密码长度、两次密码是否一致等。
-
邮箱唯一性:在数据库中查询是否已有相同的邮箱注册。
-
密码加密:使用
CryptoHelper.hashPassword()对密码进行哈希处理。 -
保存登录状态:使用
AppStorage保存登录状态和用户邮箱。 -
页面跳转:注册成功后,跳转到商品列表页。
四、用户登录功能实现
1. 登录页面布局
在pages/LoginPage.ets中,创建登录页面的UI布局。
// pages/LoginPage.ets
@Entry
@Component
struct LoginPage {
@State email: string = '';
@State password: string = '';
build() {
Column({ space: 16 }) {
Text('用户登录').fontSize(24).margin({ top: 32 });
TextField({ placeholder: '邮箱', text: this.email })
.onChange((value) => this.email = value)
.type(TextInputType.EmailAddress);
TextField({ placeholder: '密码', text: this.password })
.onChange((value) => this.password = value)
.type(TextInputType.Password);
Button('登录')
.onClick(() => this.login())
.margin({ top: 16 });
Button('没有账号?注册')
.onClick(() => Router.replace({ uri: 'RegisterPage' }))
.type(ButtonType.Normal);
}.padding(16);
}
}2. 登录逻辑实现
import prompt from '@ohos.prompt';
import { DatabaseHelper } from '../common/utils/DatabaseHelper';
import { CryptoHelper } from '../common/utils/CryptoHelper';
@Component
struct LoginPage {
// 前面的代码
private store: rdb.RdbStore;
aboutToAppear() {
this.initDatabase();
}
async initDatabase() {
this.store = await DatabaseHelper.getRdbStore();
}
async login() {
if (!this.email || !this.password) {
prompt.showToast({ message: '请输入邮箱和密码' });
return;
}
// 密码加密
const hashedPassword = CryptoHelper.hashPassword(this.password);
// 查询用户
const query = 'SELECT * FROM users WHERE email = ? AND password = ?';
const resultSet = await this.store.query(query, [this.email, hashedPassword]);
if (resultSet.goToFirstRow()) {
prompt.showToast({ message: '登录成功' });
resultSet.close();
// 保存登录状态
AppStorage.SetOrCreate('isLoggedIn', true);
AppStorage.SetOrCreate('userEmail', this.email);
// 跳转到商品列表页
Router.replace({ uri: 'ProductListPage' });
} else {
prompt.showToast({ message: '邮箱或密码错误' });
resultSet.close();
}
}
}3. 解释
-
密码加密对比:将用户输入的密码进行哈希处理,与数据库中的加密密码进行比较。
-
保存登录状态:登录成功后,使用
AppStorage保存登录状态。 -
错误提示:登录失败时,给出友好的提示信息。
五、登录状态管理
1. 自动登录实现
在app.ets中,应用启动时检查登录状态,决定跳转的页面。
// app.ets
import router from '@ohos.router';
@Entry
@Component
struct App {
build() {
// 检查登录状态
if (AppStorage.Get('isLoggedIn')) {
router.replace({ uri: 'ProductListPage' });
} else {
router.replace({ uri: 'LoginPage' });
}
}
}2. 用户注销功能
在商品列表页或个人中心页,添加“注销”按钮,用户可以退出登录。
// 在商品列表页或其他页面添加注销功能
Button('注销')
.onClick(() => this.logout())
.margin({ top: 16 });
logout() {
// 清除登录状态
AppStorage.Set('isLoggedIn', false);
AppStorage.Delete('userEmail');
prompt.showToast({ message: '已退出登录' });
Router.replace({ uri: 'LoginPage' });
}六、完善用户体验
1. 异常处理
-
数据库异常:在数据库操作中,添加
try...catch,捕获异常并提示用户。 -
网络异常:如果有网络请求,需处理网络不可用或超时的情况。
2. 输入提示
-
在用户输入不符合要求时,使用
prompt.showToast()给出明确的提示信息,指导用户正确输入。
3. 界面优化
-
布局美化:使用合理的间距、字体大小和颜色,提升界面美观度。
-
按钮样式:自定义按钮的样式,使其更加符合应用的风格。
七、测试与调试
1. 测试用例
-
注册流程测试
:
-
输入有效的邮箱和密码,注册成功。
-
输入已注册的邮箱,提示邮箱已注册。
-
输入不匹配的密码和确认密码,提示错误。
-
-
登录流程测试
:
-
输入正确的邮箱和密码,登录成功。
-
输入错误的邮箱或密码,提示登录失败。
-
-
自动登录测试
:
-
登录成功后,关闭应用再打开,自动跳转到商品列表页。
-
-
注销功能测试
:
-
点击注销按钮,成功退出登录,回到登录页。
-
2. 调试方法
-
日志输出:使用
console.log()或console.error()输出调试信息。 -
断点调试:在DevEco Studio中设置断点,逐步检查代码执行流程。
-
查看数据库:在开发过程中,可以使用数据库浏览工具查看数据库内容,验证数据是否正确写入。
目前我们实现了玩具店购物应用的用户注册和登录功能。通过对用户输入的验证、密码的加密存储以及登录状态的管理,确保了用户数据的安全性和应用的易用性。在下一篇文章中,我们将实现商品列表和商品详情展示,包括从数据库或网络加载商品数据、商品的搜索和筛选等功能。
- 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
- 如您发布的内容为转载内容,请注明内容来源。
我要发帖子





































苏公安网备 32011402010933号