@ -26,34 +26,81 @@ import java.util.concurrent.TimeUnit;
* @CONTACT 317758022 @qq.com
* @DESC 登 陆 错 误 code = 1 , msg = xxx 登 陆 成 功 code = 0 , data = UserRespVO
* /
// @Service注解用于将当前类标记为Spring框架中的服务层组件, 表明该类是一个业务逻辑处理类, 会被Spring容器管理,
// 方便在其他组件(如控制器层)中通过依赖注入的方式进行调用,实现业务逻辑与其他层的解耦。
@Service
// @Slf4j注解是lombok提供的一个便捷方式, 用于自动在类中生成一个名为log的日志记录器对象,
// 可以通过它方便地记录不同级别( 如info、error等) 的日志信息, 便于在程序运行过程中对业务流程、异常情况等进行记录和跟踪, 方便后续的调试与监控。
@Slf4j
public class UserServiceImpl implements IUserService {
// 该类实现了IUserService接口, 意味着它需要按照接口中定义的方法契约来实现具体的业务逻辑,
// 这样的设计符合面向接口编程的原则,使得代码结构更加清晰,便于替换不同的实现类(例如在测试环境或不同业务场景下使用不同的实现逻辑),
// 同时也方便其他代码依赖于接口进行调用,而不用关心具体的实现细节。
public class UserServiceImpl implements IUserService {
// 通过Spring的依赖注入机制, 使用@Autowired注解自动装配一个UserMapper类型的实例。
// UserMapper通常是一个MyBatis的Mapper接口, 定义了与数据库中用户表进行交互的各种方法, 比如查询用户信息、插入用户记录等操作,
// 在这里被注入后,就可以在业务逻辑方法中调用它的方法来实现与数据库的数据交互,以完成诸如登录验证、注册用户等业务功能。
@Autowired
private UserMapper userMapper ;
// 同样使用@Autowired注解注入CuratorFramework类型的实例, CuratorFramework是一个用于与Zookeeper进行交互的客户端框架相关的类,
// 在本代码中可能是用于实现分布式锁功能( 结合后续代码逻辑来看) , 通过与Zookeeper的协作来保证在分布式环境下关键业务操作( 如用户注册) 的原子性和并发控制,
// 避免多个实例同时操作产生的数据不一致等问题。
@Autowired
private CuratorFramework zkClient ;
// 注入CommonCacheUtil类型的实例, CommonCacheUtil是一个用于缓存操作的工具类,
// 大概率是用于和缓存系统( 如Redis) 进行交互, 实现对常用数据( 比如用户登录状态信息、临时验证信息等) 的缓存管理,
// 通过缓存数据可以减少对数据库的频繁访问,提高系统的整体性能和响应速度。
@Autowired
private CommonCacheUtil commonCacheUtil ;
/ * *
* 此 方 法 实 现 了 用 户 登 录 的 业 务 逻 辑 , 整 体 流 程 包 含 以 下 几 个 关 键 步 骤 :
*
* 步 骤 一 : 参 数 校 验
* 首 先 对 传 入 的 用 户 名 和 密 码 参 数 进 行 非 空 校 验 , 通 过 StringUtils . isEmpty 方 法 判 断 , 如 果 用 户 名 或 密 码 为 空 字 符 串 ,
* 则 抛 出 SnailmallException 异 常 , 并 给 出 相 应 的 提 示 信 息 “ 温 馨 提 示 : 用 户 名 或 密 码 不 能 为 空 ” , 确 保 登 录 操 作 的 基 础 参 数 完 整 。
*
* 步 骤 二 : 用 户 名 存 在 性 校 验
* 在 参 数 非 空 的 基 础 上 , 调 用 userMapper 的 selectByUsername 方 法 , 根 据 传 入 的 用 户 名 去 数 据 库 中 查 询 对 应 的 用 户 记 录 ,
* 该 方 法 返 回 的 结 果 是 匹 配 该 用 户 名 的 记 录 数 量 。 如 果 查 询 到 的 记 录 数 量 为 0 , 意 味 着 数 据 库 中 不 存 在 该 用 户 名 对 应 的 用 户 ,
* 此 时 抛 出 SnailmallException 异 常 , 提 示 “ 温 馨 提 示 : 用 户 名 不 存 在 ” , 说 明 用 户 输 入 的 用 户 名 有 误 , 无 法 进 行 后 续 登 录 验 证 。
*
* 步 骤 三 : 密 码 校 验
* 当 确 认 用 户 名 存 在 后 , 将 传 入 的 密 码 通 过 MD5Util . MD5EncodeUtf8 方 法 进 行 MD5 加 密 处 理 ,
* 然 后 使 用 加 密 后 的 密 码 和 原 始 用 户 名 再 次 调 用 userMapper 的 selectByUsernameAndPasswd 方 法 去 数 据 库 中 查 询 用 户 记 录 ,
* 目 的 是 验 证 用 户 输 入 的 密 码 是 否 正 确 。 如 果 查 询 结 果 为 null , 即 没 有 找 到 匹 配 用 户 名 和 加 密 后 密 码 的 用 户 记 录 ,
* 则 抛 出 SnailmallException 异 常 , 提 示 “ 温 馨 提 示 : 用 户 名 或 者 密 码 不 正 确 , 请 重 试 ” , 告 知 用 户 登 录 信 息 有 误 。
*
* 步 骤 四 : 构 建 返 回 结 果
* 若 前 面 的 用 户 名 和 密 码 校 验 都 通 过 , 说 明 用 户 登 录 成 功 。 此 时 创 建 一 个 UserResVO 对 象 ,
* 将 从 数 据 库 查 询 到 的 用 户 记 录 ( resultUser ) 中 的 相 关 信 息 ( 如 用 户 ID 、 用 户 名 、 邮 箱 、 电 话 、 角 色 、 问 题 、 答 案 、 创 建 时 间 等 )
* 分 别 设 置 到 UserResVO 对 象 的 对 应 属 性 中 , 其 中 更 新 时 间 设 置 为 当 前 日 期 ( new Date ( ) ) ,
* 最 后 通 过 ServerResponse . createBySuccess 方 法 构 建 一 个 表 示 成 功 的 ServerResponse 对 象 , 将 提 示 信 息 “ 用 户 登 陆 成 功 ” 和 封 装 好 的 UserResVO 对 象 作 为 参 数 传 入 ,
* 返 回 给 调 用 者 , 通 常 这 个 调 用 者 可 能 是 控 制 器 层 , 然 后 再 将 结 果 返 回 给 前 端 客 户 端 , 告 知 用 户 登 录 成 功 以 及 返 回 相 关 的 用 户 信 息 。
*
* @param username 客 户 端 传 入 的 用 户 名 , 不 能 为 空 , 用 于 在 数 据 库 中 查 找 对 应 的 用 户 记 录 进 行 登 录 验 证 。
* @param password 客 户 端 传 入 的 用 户 密 码 , 不 能 为 空 , 需 要 与 数 据 库 中 存 储 的 密 码 进 行 比 对 验 证 用 户 身 份 。
* @return 返 回 一 个 ServerResponse < UserResVO > 类 型 的 对 象 , 包 含 登 录 操 作 的 结 果 状 态 ( 成 功 则 为 “ 用 户 登 陆 成 功 ” 提 示 信 息 ) 以 及 登 录 成 功 后 的 用 户 详 细 信 息 ( 封 装 在 UserResVO 对 象 中 ) ,
* 方 便 前 端 根 据 返 回 结 果 进 行 页 面 跳 转 、 显 示 用 户 信 息 等 后 续 操 作 。
* /
@Override
public ServerResponse < UserResVO > login ( String username , String password ) {
//1.校验参数不能为空
if ( StringUtils . isEmpty ( username ) | | StringUtils . isEmpty ( password ) ) {
public ServerResponse < UserResVO > login ( String username , String password ) {
// 1.校验参数不能为空
if ( StringUtils . isEmpty ( username ) | | StringUtils . isEmpty ( password ) ) {
throw new SnailmallException ( "温馨提示:用户名或密码不能为空" ) ;
}
//2.根据用户名去取用户信息(本系统用户名不能重复)
// 2.根据用户名去取用户信息(本系统用户名不能重复)
int resultCount = userMapper . selectByUsername ( username ) ;
if ( resultCount = = 0 ) {
if ( resultCount = = 0 ) {
throw new SnailmallException ( "温馨提示:用户名不存在" ) ;
}
//3.走到这一步,说明存在该用户,下面就执行登陆校验
// 3.走到这一步,说明存在该用户,下面就执行登陆校验
String md5Passwd = MD5Util . MD5EncodeUtf8 ( password ) ;
User resultUser = userMapper . selectByUsernameAndPasswd ( username , md5Passwd ) ;
if ( resultUser = = null ) {
User resultUser = userMapper . selectByUsernameAndPasswd ( username , md5Passwd ) ;
if ( resultUser = = null ) {
throw new SnailmallException ( "温馨提示:用户名或者密码不正确,请重试" ) ;
}
//4.走到这一步,说明用户名密码正确,应该返回成功
// 4.走到这一步,说明用户名密码正确,应该返回成功
UserResVO userResVO = new UserResVO ( ) ;
userResVO . setId ( resultUser . getId ( ) ) ;
userResVO . setUsername ( resultUser . getUsername ( ) ) ;
@ -65,58 +112,96 @@ public class UserServiceImpl implements IUserService{
userResVO . setCreateTime ( resultUser . getCreateTime ( ) ) ;
userResVO . setUpdateTime ( new Date ( ) ) ;
return ServerResponse . createBySuccess ( "用户登陆成功" , userResVO ) ;
return ServerResponse . createBySuccess ( "用户登陆成功" , userResVO ) ;
}
/ * *
* 该 方 法 用 于 处 理 用 户 注 册 的 业 务 逻 辑 , 整 体 逻 辑 较 为 复 杂 , 主 要 涉 及 以 下 几 个 重 要 部 分 :
*
* 1. 参 数 校 验
* 首 先 对 传 入 的 User 对 象 中 的 关 键 属 性 ( 用 户 名 、 邮 箱 、 密 码 、 问 题 、 答 案 ) 进 行 非 空 校 验 ,
* 通 过 StringUtils . isBlank 方 法 判 断 , 如 果 这 些 属 性 中 有 任 何 一 个 为 空 字 符 串 , 就 抛 出 SnailmallException 异 常 ,
* 并 提 示 “ 参 数 不 能 为 空 , 请 仔 细 填 写 ” , 确 保 用 户 注 册 时 提 供 的 必 要 信 息 完 整 , 避 免 后 续 因 数 据 缺 失 导 致 的 问 题 。
*
* 2. 分 布 式 锁 获 取 与 处 理
* - 初 始 化 分 布 式 锁 对 象 : 创 建 一 个 InterProcessLock 类 型 的 锁 对 象 ( 具 体 实 现 为 InterProcessMutex , 通 过 zkClient 和 指 定 的 锁 路 径 Constants . USER_REGISTER_DISTRIBUTE_LOCK_PATH 来 构 造 ) ,
* 用 于 在 分 布 式 环 境 下 对 用 户 注 册 操 作 进 行 并 发 控 制 , 避 免 多 个 线 程 或 实 例 同 时 进 行 注 册 导 致 的 数 据 冲 突 ( 比 如 用 户 名 或 邮 箱 重 复 注 册 等 问 题 ) 。
* - 尝 试 获 取 锁 的 循 环 : 进 入 一 个 do - while 循 环 , 不 断 尝 试 获 取 分 布 式 锁 , 通 过 调 用 lock . acquire 方 法 , 并 设 置 超 时 时 间 为 3000 毫 秒 ( 以 TimeUnit . MILLISECONDS 为 单 位 ) ,
* 如 果 成 功 获 取 到 锁 , 就 执 行 以 下 操 作 :
* - 记 录 获 取 锁 的 日 志 信 息 : 通 过 log . info 方 法 记 录 当 前 正 在 注 册 的 用 户 邮 箱 以 及 获 取 锁 的 线 程 名 称 , 方 便 后 续 查 看 日 志 排 查 问 题 , 了 解 锁 的 获 取 情 况 以 及 注 册 操 作 的 执 行 线 程 。
* - 用 户 名 重 复 性 校 验 : 调 用 this . checkValid 方 法 , 传 入 用 户 名 和 Constants . USERNAME 常 量 , 校 验 用 户 名 是 否 已 经 在 数 据 库 中 存 在 ,
* 如 果 返 回 的 ServerResponse 对 象 表 示 校 验 不 成 功 ( 即 用 户 名 已 存 在 ) , 则 直 接 将 该 响 应 对 象 返 回 , 终 止 当 前 注 册 流 程 , 告 知 客 户 端 用 户 名 重 复 不 能 注 册 。
* - 邮 箱 重 复 性 校 验 : 同 样 调 用 this . checkValid 方 法 , 传 入 邮 箱 和 Constants . EMAIL 常 量 , 校 验 邮 箱 是 否 已 经 存 在 于 数 据 库 中 ,
* 若 返 回 结 果 表 示 校 验 不 成 功 ( 即 邮 箱 已 存 在 ) , 则 返 回 该 响 应 对 象 , 结 束 注 册 流 程 , 提 示 客 户 端 邮 箱 已 被 使 用 不 能 注 册 。
* - 插 入 用 户 数 据 : 当 用 户 名 和 邮 箱 的 重 复 性 校 验 都 通 过 后 , 设 置 用 户 的 角 色 为 普 通 用 户 ( 通 过 Constants . Role . ROLE_CUSTOME 常 量 指 定 ) ,
* 并 对 用 户 密 码 进 行 MD5 加 密 处 理 ( 使 用 MD5Util . MD5EncodeUtf8 方 法 ) , 然 后 调 用 userMapper 的 insert 方 法 将 用 户 信 息 插 入 到 数 据 库 中 , 完 成 用 户 注 册 的 核 心 操 作 ,
* 最 后 将 循 环 控 制 变 量 retry 设 置 为 false , 跳 出 循 环 , 结 束 尝 试 获 取 锁 和 注 册 操 作 的 循 环 过 程 。
* 如 果 在 尝 试 获 取 锁 的 过 程 中 失 败 ( 即 没 有 在 超 时 时 间 内 获 取 到 锁 ) , 则 通 过 log . info 方 法 记 录 “ 【 获 取 锁 失 败 , 继 续 尝 试 . . . 】 ” 的 日 志 信 息 ,
* 提 示 后 续 会 继 续 尝 试 获 取 锁 来 进 行 注 册 操 作 ( 虽 然 代 码 中 此 处 没 有 明 确 体 现 等 待 或 延 迟 等 具 体 的 重 试 策 略 , 但 逻 辑 上 会 不 断 循 环 尝 试 获 取 锁 ) 。
*
* 3. 锁 释 放 与 异 常 处 理
* 在 finally 块 中 , 无 论 是 否 成 功 获 取 锁 以 及 是 否 完 成 注 册 操 作 , 都 会 对 锁 进 行 释 放 操 作 , 以 避 免 锁 资 源 一 直 被 占 用 导 致 的 死 锁 等 问 题 。
* 如 果 锁 对 象 lock 不 为 null , 就 调 用 lock . release 方 法 释 放 锁 , 并 通 过 log . info 方 法 记 录 释 放 锁 的 日 志 信 息 , 包 括 释 放 锁 的 用 户 邮 箱 和 线 程 名 称 , 方 便 查 看 锁 的 释 放 情 况 。
* 如 果 在 释 放 锁 的 过 程 中 出 现 异 常 , 通 过 e . printStackTrace 方 法 打 印 异 常 堆 栈 信 息 , 便 于 排 查 锁 释 放 环 节 出 现 的 问 题 , 不 过 这 种 情 况 属 于 异 常 情 况 , 正 常 情 况 下 应 该 能 顺 利 释 放 锁 。
*
* 4. 返 回 注 册 结 果
* 如 果 整 个 注 册 流 程 顺 利 完 成 ( 即 没 有 因 为 参 数 问 题 、 用 户 名 或 邮 箱 重 复 问 题 以 及 锁 相 关 的 异 常 等 情 况 中 断 ) ,
* 最 后 通 过 ServerResponse . createBySuccessMessage 方 法 构 建 一 个 表 示 注 册 成 功 的 ServerResponse 对 象 , 返 回 “ 注 册 成 功 ” 的 提 示 信 息 给 客 户 端 , 告 知 用 户 注 册 操 作 已 成 功 完 成 。
*
* @param user 包 含 用 户 注 册 信 息 的 User 对 象 , 由 客 户 端 传 入 , 其 关 键 属 性 ( 用 户 名 、 邮 箱 、 密 码 、 问 题 、 答 案 等 ) 需 满 足 非 空 校 验 要 求 ,
* 用 于 在 数 据 库 中 插 入 新 的 用 户 记 录 以 及 进 行 相 关 的 业 务 逻 辑 判 断 ( 如 重 复 性 校 验 等 ) 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 用 户 注 册 操 作 的 结 果 状 态 ( 成 功 则 返 回 “ 注 册 成 功 ” 提 示 信 息 ) 以 及 相 应 的 提 示 信 息 ,
* 方 便 客 户 端 根 据 返 回 结 果 提 示 用 户 注 册 是 否 成 功 , 并 进 行 相 应 的 后 续 操 作 ( 如 跳 转 到 登 录 页 面 等 ) 。
* /
@Override
public ServerResponse register ( User user ) {
//1.校验参数是否为空
if ( StringUtils . isBlank ( user . getUsername ( ) ) | |
// 1.校验参数是否为空
if ( StringUtils . isBlank ( user . getUsername ( ) ) | |
StringUtils . isBlank ( user . getEmail ( ) ) | |
StringUtils . isBlank ( user . getPassword ( ) ) | |
StringUtils . isBlank ( user . getQuestion ( ) ) | |
StringUtils . isBlank ( user . getAnswer ( ) ) ) {
StringUtils . isBlank ( user . getAnswer ( ) ) ) {
throw new SnailmallException ( "参数不能为空,请仔细填写" ) ;
}
//---开启锁
// ---开启锁
InterProcessLock lock = null ;
try {
lock = new InterProcessMutex ( zkClient , Constants . USER_REGISTER_DISTRIBUTE_LOCK_PATH ) ;
boolean retry = true ;
do {
if ( lock . acquire ( 3000 , TimeUnit . MILLISECONDS ) ) {
log . info ( user . getEmail ( ) + Thread . currentThread ( ) . getName ( ) + "获取锁" ) ;
//2.参数没问题的话,就校验一下名字是否已经存在
ServerResponse response = this . checkValid ( user . getUsername ( ) , Constants . USERNAME ) ;
if ( ! response . isSuccess ( ) ) {
//说明用户名已经重复了
if ( lock . acquire ( 3000 , TimeUnit . MILLISECONDS ) ) {
log . info ( user . getEmail ( ) + Thread . currentThread ( ) . getName ( ) + "获取锁" ) ;
// 2.参数没问题的话,就校验一下名字是否已经存在
ServerResponse response = this . checkValid ( user . getUsername ( ) , Constants . USERNAME ) ;
if ( ! response . isSuccess ( ) ) {
// 说明用户名已经重复了
return response ;
}
//3.再校验一下邮箱是否存在
response = this . checkValid ( user . getEmail ( ) , Constants . EMAIL ) ;
if ( ! response . isSuccess ( ) ) {
//说明用户名已经重复了
// 3.再校验一下邮箱是否存在
response = this . checkValid ( user . getEmail ( ) , Constants . EMAIL ) ;
if ( ! response . isSuccess ( ) ) {
// 说明用户名已经重复了
return response ;
}
//4.重复校验通过之后就可以塞入这条数据了
user . setRole ( Constants . Role . ROLE_CUSTOME ) ; //普通用户
// 4.重复校验通过之后就可以塞入这条数据了
user . setRole ( Constants . Role . ROLE_CUSTOME ) ; // 普通用户
user . setPassword ( MD5Util . MD5EncodeUtf8 ( user . getPassword ( ) ) ) ;
userMapper . insert ( user ) ;
//跳出循环
// 跳出循环
retry = false ;
}
log . info ( "【获取锁失败,继续尝试...】" ) ;
// 可以适当休息一会
} while ( retry ) ;
} catch ( Exception e ) {
log . error ( "【校验用户所填的用户名或者密码出现问题】" , e ) ;
// 可以适当休息一会
} while ( retry ) ;
} catch ( Exception e ) {
log . error ( "【校验用户所填的用户名或者密码出现问题】" , e ) ;
throw new SnailmallException ( "分布式锁校验出错" ) ;
} finally {
// ---释放锁
if ( lock ! = null ) {
} finally {
// ---释放锁
if ( lock ! = null ) {
try {
lock . release ( ) ;
log . info ( user . getEmail ( ) + Thread . currentThread ( ) . getName ( ) + "释放锁" ) ;
log . info ( user . getEmail ( ) + Thread . currentThread ( ) . getName ( ) + "释放锁" ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
@ -125,23 +210,50 @@ public class UserServiceImpl implements IUserService{
return ServerResponse . createBySuccessMessage ( "注册成功" ) ;
}
/ * *
* 此 方 法 用 于 校 验 传 入 的 字 符 串 ( 代 表 用 户 名 或 邮 箱 ) 在 数 据 库 中 的 唯 一 性 , 具 体 逻 辑 如 下 :
*
* 1. 参 数 校 验
* 首 先 通 过 StringUtils . isBlank 方 法 检 查 传 入 的 参 数 str ( 待 校 验 的 用 户 名 或 邮 箱 ) 和 type ( 用 于 表 明 str 代 表 的 是 用 户 名 还 是 邮 箱 的 类 型 标 识 ) 是 否 为 空 字 符 串 。
* 如 果 其 中 任 意 一 个 参 数 为 空 , 则 抛 出 SnailmallException 异 常 , 并 提 示 “ 参 数 有 问 题 ” , 以 此 确 保 后 续 校 验 操 作 能 基 于 有 效 的 输 入 参 数 进 行 。
*
* 2. 根 据 类 型 校 验 唯 一 性
* 如 果 传 入 的 type 参 数 在 忽 略 大 小 写 的 情 况 下 与 Constants . USERNAME 相 等 , 说 明 此 次 校 验 针 对 的 是 用 户 名 的 唯 一 性 。
* 此 时 调 用 userMapper 的 selectByUsername 方 法 , 传 入 str 作 为 用 户 名 去 数 据 库 中 查 询 匹 配 的 用 户 记 录 数 量 。
* 若 查 询 得 到 的 结 果 数 量 大 于 0 , 意 味 着 数 据 库 中 已 经 存 在 使 用 该 用 户 名 的 用 户 , 那 么 就 通 过 ServerResponse . createByErrorMessage 方 法 创 建 一 个 表 示 错 误 信 息 的 ServerResponse 对 象 ,
* 返 回 “ 用 户 已 经 存 在 ” 的 提 示 信 息 给 调 用 者 , 告 知 该 用 户 名 已 被 占 用 , 无 法 进 行 相 应 操 作 ( 比 如 注 册 新 用 户 时 使 用 该 用 户 名 ) 。
*
* 若 type 参 数 与 Constants . EMAIL 相 等 , 表 明 此 次 校 验 针 对 的 是 邮 箱 的 唯 一 性 。
* 相 应 地 , 调 用 userMapper 的 selectByEmail 方 法 , 以 str 作 为 邮 箱 地 址 去 数 据 库 查 询 匹 配 的 用 户 记 录 数 量 。
* 当 查 询 结 果 数 量 大 于 0 时 , 说 明 该 邮 箱 已 被 其 他 用 户 使 用 , 同 样 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 邮 箱 已 经 存 在 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 提 示 该 邮 箱 不 能 再 用 于 当 前 操 作 ( 例 如 注 册 时 使 用 该 邮 箱 ) 。
*
* 3. 返 回 校 验 成 功 结 果
* 如 果 经 过 上 述 针 对 用 户 名 或 邮 箱 的 唯 一 性 校 验 后 , 均 未 发 现 重 复 情 况 ( 即 对 应 查 询 结 果 数 量 都 不 大 于 0 ) ,
* 则 通 过 ServerResponse . createBySuccess 方 法 创 建 一 个 表 示 成 功 的 ServerResponse 对 象 , 返 回 “ 校 验 成 功 , 用 户 名 和 邮 箱 都 合 法 ” 的 提 示 信 息 给 调 用 者 ,
* 意 味 着 传 入 的 用 户 名 或 邮 箱 可 以 用 于 后 续 操 作 ( 如 注 册 时 可 继 续 插 入 数 据 等 ) 。
*
* @param str 要 校 验 的 用 户 名 或 邮 箱 字 符 串 , 不 能 为 空 , 其 具 体 代 表 的 含 义 由 type 参 数 确 定 , 用 于 在 数 据 库 中 查 询 验 证 其 唯 一 性 。
* @param type 用 于 标 识 str 代 表 的 是 用 户 名 还 是 邮 箱 的 类 型 参 数 , 取 值 应 为 预 定 义 的 相 关 常 量 ( 如 Constants 类 中 定 义 的 常 量 ) , 不 能 为 空 , 以 此 决 定 具 体 的 校 验 逻 辑 走 向 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 了 校 验 操 作 的 结 果 状 态 ( 如 用 户 名 或 邮 箱 已 存 在 、 校 验 成 功 等 情 况 ) 以 及 相 应 的 提 示 信 息 , 方 便 调 用 者 根 据 返 回 结 果 进 行 后 续 操 作 决 策 。
* /
@Override
public ServerResponse checkValid ( String str , String type ) {
//校验参数是否为空
if ( StringUtils . isBlank ( str ) | | StringUtils . isBlank ( type ) ) {
if ( StringUtils . isBlank ( str ) | | StringUtils . isBlank ( type ) ) {
throw new SnailmallException ( "参数有问题" ) ;
}
if ( Constants . USERNAME . equalsIgnoreCase ( type ) ) {
if ( Constants . USERNAME . equalsIgnoreCase ( type ) ) {
//如果是username类型, 那么就根据str为username去数据库查询
int resultCount = userMapper . selectByUsername ( str ) ;
if ( resultCount > 0 ) {
if ( resultCount > 0 ) {
//说明数据库已经存在这个username的用户了, 返回用户已存在
return ServerResponse . createByErrorMessage ( "用户已经存在" ) ;
}
} else if ( Constants . EMAIL . equals ( type ) ) {
} else if ( Constants . EMAIL . equals ( type ) ) {
//如果是email类型, 就根据str为email去数据库查询
int resultCount = userMapper . selectByEmail ( str ) ;
if ( resultCount > 0 ) {
if ( resultCount > 0 ) {
//说明数据库已经存在这个email的用户了, 返回用户已存在
return ServerResponse . createByErrorMessage ( "邮箱已经存在" ) ;
}
@ -149,120 +261,289 @@ public class UserServiceImpl implements IUserService{
return ServerResponse . createBySuccess ( "校验成功,用户名和邮箱都合法" ) ;
}
/ * *
* 该 方 法 用 于 根 据 传 入 的 用 户 名 获 取 对 应 的 找 回 密 码 问 题 , 执 行 逻 辑 如 下 :
*
* 1. 参 数 校 验
* 通 过 StringUtils . isBlank 方 法 检 查 传 入 的 用 户 名 参 数 是 否 为 空 字 符 串 。
* 如 果 为 空 , 则 通 过 ServerResponse . createByErrorMessage 方 法 创 建 并 返 回 一 个 包 含 “ 用 户 名 不 能 为 空 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 告 知 调 用 者 需 要 提 供 有 效 的 用 户 名 才 能 进 行 后 续 操 作 , 避 免 因 空 用 户 名 导 致 的 异 常 情 况 。
*
* 2. 查 询 用 户 信 息
* 若 用 户 名 参 数 非 空 , 调 用 userMapper 的 getUserByUsername 方 法 , 传 入 用 户 名 去 数 据 库 中 查 询 对 应 的 用 户 信 息 , 将 查 询 结 果 赋 值 给 User 类 型 的 user 对 象 。
* 如 果 查 询 结 果 为 null , 意 味 着 数 据 库 中 不 存 在 该 用 户 名 对 应 的 用 户 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 用 户 不 存 在 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 说 明 无 法 获 取 到 对 应 的 找 回 密 码 问 题 , 因 为 用 户 本 身 不 存 在 。
*
* 3. 获 取 并 校 验 问 题
* 若 成 功 查 询 到 用 户 信 息 ( 即 user 对 象 不 为 null ) , 则 获 取 该 用 户 设 置 的 找 回 密 码 问 题 , 通 过 user . getQuestion 方 法 获 取 对 应 的 问 题 字 符 串 。
* 再 次 通 过 StringUtils . isBlank 方 法 检 查 该 问 题 字 符 串 是 否 为 空 , 如 果 为 空 , 说 明 该 用 户 没 有 设 置 对 应 的 找 回 密 码 问 题 ,
* 于 是 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 该 用 户 没 有 设 置 对 应 的 问 题 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 告 知 调 用 者 无 法 获 取 到 有 效 的 问 题 用 于 找 回 密 码 操 作 。
*
* 4. 返 回 问 题 成 功 获 取 结 果
* 如 果 经 过 上 述 步 骤 , 成 功 获 取 到 了 非 空 的 找 回 密 码 问 题 字 符 串 , 则 通 过 ServerResponse . createBySuccess 方 法 创 建 并 返 回 一 个 包 含 该 问 题 字 符 串 的 ServerResponse 对 象 给 调 用 者 ,
* 表 示 成 功 获 取 到 了 对 应 的 找 回 密 码 问 题 , 方 便 调 用 者 ( 通 常 是 前 端 相 关 代 码 ) 展 示 该 问 题 给 用 户 , 以 便 用 户 进 行 后 续 的 回 答 操 作 来 找 回 密 码 。
*
* @param username 要 获 取 找 回 密 码 问 题 的 用 户 名 , 不 能 为 空 , 用 于 在 数 据 库 中 查 找 对 应 的 用 户 信 息 及 设 置 的 问 题 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 了 获 取 问 题 操 作 的 结 果 状 态 ( 如 成 功 获 取 到 问 题 、 用 户 不 存 在 、 未 设 置 问 题 等 情 况 ) 以 及 相 应 的 提 示 信 息 或 获 取 到 的 问 题 内 容 ,
* 方 便 调 用 者 根 据 返 回 结 果 进 行 后 续 展 示 等 操 作 。
* /
@Override
public ServerResponse getQuestionByUsername ( String username ) {
//1.校验参数
if ( StringUtils . isBlank ( username ) ) {
if ( StringUtils . isBlank ( username ) ) {
return ServerResponse . createByErrorMessage ( "用户名不能为空" ) ;
}
//2.根据username去获取题目
User user = userMapper . getUserByUsername ( username ) ;
if ( user = = null ) {
if ( user = = null ) {
return ServerResponse . createByErrorMessage ( "用户不存在" ) ;
}
String question = user . getQuestion ( ) ;
if ( StringUtils . isBlank ( question ) ) {
if ( StringUtils . isBlank ( question ) ) {
return ServerResponse . createByErrorMessage ( "该用户没有设置对应的问题" ) ;
}
return ServerResponse . createBySuccess ( question ) ;
}
/ * *
* 此 方 法 用 于 校 验 用 户 输 入 的 找 回 密 码 答 案 是 否 正 确 , 并 根 据 情 况 生 成 或 获 取 相 应 的 忘 记 密 码 token , 具 体 逻 辑 如 下 :
*
* 1. 参 数 校 验
* 首 先 通 过 StringUtils . isBlank 方 法 分 别 检 查 传 入 的 用 户 名 、 问 题 和 答 案 参 数 是 否 为 空 字 符 串 。
* 如 果 其 中 任 意 一 个 参 数 为 空 , 则 通 过 ServerResponse . createByErrorMessage 方 法 创 建 并 返 回 一 个 包 含 “ 参 数 有 问 题 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 确 保 后 续 的 校 验 及 token 相 关 操 作 基 于 完 整 有 效 的 参 数 进 行 , 避 免 因 参 数 缺 失 导 致 的 异 常 情 况 。
*
* 2. 验 证 答 案 并 处 理 token
* 在 参 数 都 非 空 的 情 况 下 , 调 用 userMapper 的 getUserByUsernameQuestionAnswer 方 法 , 传 入 用 户 名 、 问 题 和 答 案 去 数 据 库 中 查 询 对 应 的 用 户 信 息 ,
* 将 查 询 结 果 赋 值 给 User 类 型 的 user 对 象 。 如 果 user 对 象 不 为 null , 说 明 数 据 库 中 存 在 匹 配 该 用 户 名 、 问 题 和 答 案 的 用 户 , 意 味 着 用 户 输 入 的 答 案 可 能 是 正 确 的 , 接 下 来 进 行 以 下 token 相 关 操 作 :
*
* - 首 先 尝 试 从 Redis 缓 存 中 获 取 对 应 的 忘 记 密 码 token , 通 过 调 用 commonCacheUtil 的 getCacheValue 方 法 , 传 入 由 Constants . TOKEN_PREFIX 和 用 户 名 拼 接 而 成 的 字 符 串 作 为 key 去 获 取 token 值 ,
* 将 获 取 到 的 token 值 赋 值 给 forgetToken 变 量 。
* - 接 着 通 过 StringUtils . isNotBlank 方 法 检 查 获 取 到 的 forgetToken 是 否 为 非 空 字 符 串 , 如 果 是 , 说 明 Redis 中 存 在 未 过 期 的 有 效 token ,
* 则 通 过 ServerResponse . createBySuccess 方 法 创 建 并 返 回 一 个 包 含 该 有 效 token 的 ServerResponse 对 象 给 调 用 者 ,
* 此 时 就 可 以 直 接 使 用 该 token 进 行 后 续 找 回 密 码 相 关 操 作 ( 例 如 验 证 等 ) , 无 需 重 新 生 成 token 。
* - 如 果 从 Redis 中 获 取 到 的 forgetToken 为 空 字 符 串 , 说 明 缓 存 中 不 存 在 对 应 的 token 或 者 token 已 过 期 , 并 且 由 于 前 面 已 经 验 证 了 用 户 输 入 的 答 案 是 正 确 的 ( 通 过 查 询 到 了 对 应 的 用 户 信 息 ) ,
* 那 么 就 需 要 重 新 生 成 一 个 token 。 通 过 UUID . randomUUID ( ) . toString 方 法 生 成 一 个 唯 一 的 字 符 串 作 为 新 的 token ,
* 然 后 调 用 commonCacheUtil 的 cacheNxExpire 方 法 , 将 新 生 成 的 token 以 Constants . TOKEN_PREFIX 和 用 户 名 拼 接 的 字 符 串 作 为 key , 缓 存 到 Redis 中 , 并 设 置 过 期 时 间 为 60 * 60 * 12 秒 ( 12 小 时 ) ,
* 最 后 通 过 ServerResponse . createBySuccess 方 法 创 建 并 返 回 一 个 包 含 新 生 成 token 的 ServerResponse 对 象 给 调 用 者 , 方 便 后 续 找 回 密 码 操 作 使 用 该 新 token 。
*
* 3. 返 回 答 案 错 误 结 果
* 如 果 经 过 数 据 库 查 询 , 发 现 没 有 匹 配 传 入 用 户 名 、 问 题 和 答 案 的 用 户 信 息 ( 即 user 对 象 为 null ) , 说 明 用 户 输 入 的 答 案 有 误 ,
* 则 通 过 ServerResponse . createByErrorMessage 方 法 创 建 并 返 回 一 个 包 含 “ 问 题 答 案 有 误 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 , 告 知 调 用 者 答 案 不 正 确 , 无 法 进 行 后 续 找 回 密 码 操 作 。
*
* @param username 要 校 验 找 回 密 码 答 案 的 用 户 名 , 不 能 为 空 , 用 于 在 数 据 库 中 查 找 对 应 的 用 户 信 息 进 行 答 案 验 证 以 及 token 相 关 操 作 。
* @param question 找 回 密 码 时 用 户 需 要 回 答 的 问 题 , 不 能 为 空 , 与 用 户 名 和 答 案 一 起 用 于 数 据 库 查 询 验 证 。
* @param answer 用 户 输 入 的 找 回 密 码 答 案 , 不 能 为 空 , 用 于 验 证 是 否 与 数 据 库 中 存 储 的 对 应 用 户 的 答 案 一 致 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 了 校 验 答 案 及 token 操 作 的 结 果 状 态 ( 如 答 案 正 确 并 获 取 到 token 、 答 案 错 误 等 情 况 ) 以 及 相 应 的 提 示 信 息 或 获 取 到 的 token 值 ,
* 方 便 调 用 者 根 据 返 回 结 果 进 行 后 续 找 回 密 码 等 相 关 操 作 。
* /
@Override
public ServerResponse checkAnswer ( String username , String question , String answer ) {
//1.校验参数是否正确
if ( StringUtils . isBlank ( username ) | | StringUtils . isBlank ( question ) | | StringUtils . isBlank ( answer ) ) {
if ( StringUtils . isBlank ( username ) | | StringUtils . isBlank ( question ) | | StringUtils . isBlank ( answer ) ) {
return ServerResponse . createByErrorMessage ( "参数有问题" ) ;
}
//2.参数没有问题之后,就可以去校验答案是否正确了
User user = userMapper . getUserByUsernameQuestionAnswer ( username , question , answer ) ;
if ( user ! = null ) {
User user = userMapper . getUserByUsernameQuestionAnswer ( username , question , answer ) ;
if ( user ! = null ) {
//首先根据规则key去redis取, 如果还有没有过期的key, 就可以直接拿来用了, 不用再重新生成
String forgetToken = commonCacheUtil . getCacheValue ( Constants . TOKEN_PREFIX + username ) ;
if ( StringUtils . isNotBlank ( forgetToken ) ) {
String forgetToken = commonCacheUtil . getCacheValue ( Constants . TOKEN_PREFIX + username ) ;
if ( StringUtils . isNotBlank ( forgetToken ) ) {
return ServerResponse . createBySuccess ( forgetToken ) ;
}
//取不到值,并且答案是对的,那么就重新生成一下吧!
forgetToken = UUID . randomUUID ( ) . toString ( ) ;
commonCacheUtil . cacheNxExpire ( Constants . TOKEN_PREFIX + username , forgetToken , 60 * 60 * 12 ) ;
commonCacheUtil . cacheNxExpire ( Constants . TOKEN_PREFIX + username , forgetToken , 60 * 60 * 12 ) ;
return ServerResponse . createBySuccess ( forgetToken ) ;
}
return ServerResponse . createByErrorMessage ( "问题答案有误" ) ;
}
/ * *
* 该 方 法 用 于 处 理 用 户 通 过 忘 记 密 码 流 程 重 置 密 码 的 业 务 逻 辑 , 主 要 步 骤 如 下 :
*
* 1. 参 数 校 验
* 通 过 StringUtils . isBlank 方 法 分 别 检 查 传 入 的 用 户 名 、 新 密 码 和 忘 记 密 码 token 参 数 是 否 为 空 字 符 串 。
* 如 果 其 中 任 意 一 个 参 数 为 空 , 则 通 过 ServerResponse . createByErrorMessage 方 法 创 建 并 返 回 一 个 包 含 “ 参 数 有 误 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 确 保 后 续 的 密 码 重 置 操 作 基 于 完 整 有 效 的 参 数 进 行 , 避 免 因 参 数 缺 失 导 致 的 异 常 情 况 。
*
* 2. 查 询 用 户 信 息
* 在 参 数 都 非 空 的 情 况 下 , 调 用 userMapper 的 getUserByUsername 方 法 , 传 入 用 户 名 去 数 据 库 中 查 询 对 应 的 用 户 信 息 , 将 查 询 结 果 赋 值 给 User 类 型 的 user 对 象 。
* 如 果 查 询 结 果 为 null , 意 味 着 数 据 库 中 不 存 在 该 用 户 名 对 应 的 用 户 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 用 户 名 不 存 在 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 说 明 无 法 进 行 密 码 重 置 操 作 , 因 为 用 户 本 身 不 存 在 。
*
* 3. 验 证 token 是 否 过 期
* 若 成 功 查 询 到 用 户 信 息 ( 即 user 对 象 不 为 null ) , 接 着 从 Redis 缓 存 中 获 取 对 应 的 token , 通 过 调 用 commonCacheUtil 的 getCacheValue 方 法 , 传 入 由 Constants . TOKEN_PREFIX 和 用 户 名 拼 接 而 成 的 字 符 串 作 为 key 去 获 取 token 值 ,
* 将 获 取 到 的 token 值 赋 值 给 redisToken 变 量 。
* 如 果 获 取 到 的 redisToken 为 null , 说 明 Redis 中 不 存 在 对 应 的 token 或 者 token 已 过 期 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ token 已 经 过 期 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 告 知 调 用 者 由 于 token 过 期 无 法 进 行 密 码 重 置 操 作 。
*
* 4. 验 证 token 一 致 性
* 若 成 功 获 取 到 了 非 空 的 redisToken , 通 过 StringUtils . equals 方 法 检 查 前 端 传 过 来 的 forgetToken 与 从 Redis 中 获 取 到 的 redisToken 是 否 相 等 。
* 如 果 两 者 不 相 等 , 说 明 token 不 一 致 , 可 能 存 在 安 全 风 险 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ token 错 误 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 提 示 调 用 者 token 不 匹 配 , 不 能 进 行 密 码 重 置 操 作 。
*
* 5. 密 码 重 复 性 校 验
* 若 token 验 证 通 过 , 将 传 入 的 新 密 码 通 过 MD5Util . MD5EncodeUtf8 方 法 进 行 MD5 加 密 处 理 , 得 到 加 密 后 的 密 码 MD5Passwd 。
* 通 过 user . getPassword ( ) . equals 方 法 检 查 加 密 后 的 新 密 码 与 数 据 库 中 存 储 的 用 户 原 密 码 是 否 相 等 , 如 果 相 等 , 说 明 新 密 码 与 原 密 码 重 复 ,
* 则 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 不 要 使 用 重 复 密 码 ! ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 提 示 调 用 者 不 能 使 用 重 复 密 码 进 行 重 置 操 作 , 应 更 换 新 密 码 。
*
* 6. 重 置 密 码
* 如 果 经 过 前 面 的 各 项 验 证 都 通 过 , 说 明 可 以 进 行 密 码 重 置 操 作 。 通 过 user . setPassword 方 法 将 用 户 对 象 的 密 码 属 性 设 置 为 加 密 后 的 新 密 码 MD5Passwd ,
* 然 后 调 用 userMapper 的 updateByPrimaryKeySelective 方 法 , 传 入 更 新 后 的 user 对 象 , 根 据 用 户 的 主 键 ( 通 常 是 用 户 ID ) 去 数 据 库 中 更 新 对 应 的 用 户 密 码 信 息 。
* 该 方 法 返 回 一 个 表 示 更 新 记 录 数 量 的 整 数 result , 如 果 result 大 于 0 , 说 明 密 码 更 新 成 功 , 通 过 ServerResponse . createBySuccessMessage 方 法 创 建 并 返 回 一 个 包 含 “ 修 改 密 码 成 功 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 告 知 调 用 者 密 码 重 置 操 作 已 成 功 完 成 。
*
* 7. 返 回 密 码 重 置 失 败 结 果
* 如 果 密 码 更 新 操 作 没 有 成 功 ( 即 result 不 大 于 0 ) , 则 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 修 改 密 码 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 提 示 调 用 者 密 码 重 置 操 作 出 现 问 题 , 未 成 功 完 成 。
*
* @param username 要 重 置 密 码 的 用 户 名 , 不 能 为 空 , 用 于 在 数 据 库 中 查 找 对 应 的 用 户 信 息 以 及 验 证 token 等 相 关 操 作 。
* @param passwordNew 用 户 输 入 的 新 密 码 , 不 能 为 空 , 用 于 更 新 用 户 在 数 据 库 中 的 密 码 信 息 , 且 需 要 经 过 加 密 及 重 复 性 等 校 验 。
* @param forgetToken 用 户 在 忘 记 密 码 流 程 中 获 取 到 的 用 于 验 证 身 份 的 token , 不 能 为 空 , 用 于 验 证 操 作 的 合 法 性 以 及 与 Redis 中 缓 存 的 token 进 行 比 对 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 了 重 置 密 码 操 作 的 结 果 状 态 ( 如 密 码 重 置 成 功 、 token 错 误 、 密 码 重 复 等 各 种 情 况 ) 以 及 相 应 的 提 示 信 息 ,
* 方 便 调 用 者 根 据 返 回 结 果 了 解 密 码 重 置 操 作 是 否 成 功 , 并 进 行 相 应 的 后 续 操 作 ( 如 提 示 用 户 操 作 结 果 等 ) 。
* /
/ * *
* 此 方 法 用 于 处 理 用 户 通 过 忘 记 密 码 流 程 重 置 密 码 的 业 务 逻 辑 , 具 体 步 骤 如 下 :
*
* 1. 参 数 校 验
* 首 先 使 用 StringUtils . isBlank 方 法 对 传 入 的 用 户 名 ( username ) 、 新 密 码 ( passwordNew ) 和 忘 记 密 码 的 token ( forgetToken ) 这 三 个 参 数 进 行 非 空 校 验 。
* 如 果 其 中 任 意 一 个 参 数 为 空 字 符 串 , 意 味 着 参 数 不 完 整 , 不 符 合 密 码 重 置 的 基 本 要 求 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 创 建 一 个 表 示 错 误 信 息 的 ServerResponse 对 象 ,
* 返 回 “ 参 数 有 误 , 修 改 密 码 操 作 失 败 ” 的 提 示 信 息 给 调 用 者 , 告 知 调 用 者 参 数 存 在 问 题 , 无 法 进 行 后 续 的 密 码 重 置 操 作 。
*
* 2. 查 询 用 户 信 息
* 在 参 数 都 通 过 非 空 校 验 后 , 调 用 userMapper 的 getUserByUsername 方 法 , 传 入 用 户 名 作 为 参 数 去 数 据 库 中 查 询 对 应 的 用 户 信 息 , 并 将 查 询 结 果 赋 值 给 User 类 型 的 user 对 象 。
* 如 果 查 询 返 回 的 user 对 象 为 null , 说 明 数 据 库 中 不 存 在 该 用 户 名 对 应 的 用 户 , 那 么 就 无 法 进 行 密 码 重 置 操 作 ,
* 通 过 ServerResponse . createByErrorMessage 方 法 创 建 一 个 包 含 “ 用 户 名 不 存 在 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 返 回 给 调 用 者 , 告 知 调 用 者 找 不 到 对 应 的 用 户 , 重 置 密 码 操 作 不 能 继 续 。
*
* 3. 验 证 token 是 否 过 期
* 若 成 功 查 询 到 了 用 户 信 息 ( 即 user 对 象 不 为 null ) , 接 着 调 用 commonCacheUtil 的 getCacheValue 方 法 , 传 入 由 Constants . TOKEN_PREFIX 和 用 户 名 拼 接 而 成 的 字 符 串 作 为 key ,
* 从 Redis 缓 存 中 获 取 对 应 的 token 值 , 并 将 获 取 到 的 值 赋 给 redisToken 变 量 。
* 如 果 redisToken 为 null , 意 味 着 在 Redis 中 没 有 找 到 对 应 的 token , 可 能 是 token 已 经 过 期 或 者 不 存 在 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ token 已 经 过 期 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 提 示 调 用 者 由 于 token 问 题 无 法 进 行 密 码 重 置 操 作 , 因 为 token 在 忘 记 密 码 流 程 中 起 着 验 证 身 份 的 关 键 作 用 , 过 期 或 不 存 在 则 无 法 确 认 操 作 合 法 性 。
*
* 4. 验 证 token 一 致 性
* 在 成 功 从 Redis 获 取 到 非 空 的 redisToken 后 , 使 用 StringUtils . equals 方 法 比 较 前 端 传 过 来 的 forgetToken 和 从 Redis 中 获 取 到 的 redisToken 是 否 相 等 。
* 如 果 两 者 不 相 等 , 说 明 token 不 一 致 , 存 在 安 全 风 险 或 者 不 符 合 操 作 流 程 要 求 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ token 错 误 , 修 改 密 码 操 作 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 告 知 调 用 者 token 不 匹 配 , 不 能 继 续 进 行 密 码 重 置 操 作 , 以 此 保 证 只 有 持 有 正 确 token 的 用 户 才 能 进 行 密 码 修 改 。
*
* 5. 判 断 密 码 是 否 重 复
* 当 token 验 证 通 过 后 , 将 传 入 的 新 密 码 passwordNew 通 过 MD5Util . MD5EncodeUtf8 方 法 进 行 MD5 加 密 处 理 , 得 到 加 密 后 的 密 码 MD5Passwd 。
* 然 后 使 用 user . getPassword ( ) . equals 方 法 比 较 加 密 后 的 新 密 码 MD5Passwd 和 数 据 库 中 存 储 的 用 户 原 密 码 ( 通 过 user 对 象 获 取 ) 是 否 相 等 。
* 如 果 两 者 相 等 , 说 明 新 密 码 与 原 密 码 重 复 , 不 符 合 密 码 修 改 的 要 求 , 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 不 要 使 用 重 复 密 码 ! ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 提 示 调 用 者 不 能 使 用 重 复 密 码 进 行 重 置 操 作 , 需 要 重 新 输 入 一 个 与 原 密 码 不 同 的 新 密 码 。
*
* 6. 重 置 密 码
* 如 果 前 面 的 各 项 验 证 ( 参 数 完 整 性 、 用 户 存 在 性 、 token 有 效 性 以 及 密 码 重 复 性 校 验 ) 都 通 过 , 说 明 可 以 进 行 密 码 重 置 操 作 。
* 首 先 通 过 user . setPassword 方 法 将 user 对 象 的 密 码 属 性 设 置 为 加 密 后 的 新 密 码 MD5Passwd , 然 后 调 用 userMapper 的 updateByPrimaryKeySelective 方 法 ,
* 传 入 更 新 后 的 user 对 象 , 根 据 用 户 的 主 键 ( 通 常 就 是 用 户 ID , 此 处 通 过 前 面 查 询 用 户 时 已 确 定 对 应 的 用 户 ) 去 数 据 库 中 更 新 对 应 的 用 户 密 码 信 息 。
* 该 方 法 会 返 回 一 个 表 示 更 新 操 作 影 响 的 记 录 数 量 的 整 数 updateCount , 如 果 updateCount 大 于 0 , 说 明 密 码 更 新 成 功 ,
* 通 过 ServerResponse . createBySuccessMessage 方 法 创 建 并 返 回 一 个 包 含 “ 修 改 密 码 成 功 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 , 告 知 调 用 者 密 码 重 置 操 作 已 顺 利 完 成 。
*
* 7. 返 回 密 码 重 置 失 败 结 果
* 如 果 密 码 更 新 操 作 没 有 成 功 ( 即 updateCount 不 大 于 0 ) , 意 味 着 在 数 据 库 更 新 密 码 时 出 现 问 题 , 可 能 是 数 据 库 连 接 异 常 、 数 据 更 新 语 句 执 行 失 败 等 原 因 ,
* 此 时 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 修 改 密 码 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 , 提 示 调 用 者 密 码 重 置 操 作 没 有 达 到 预 期 效 果 , 出 现 了 故 障 。
*
* @param username 要 重 置 密 码 的 用 户 名 , 由 客 户 端 传 入 , 不 能 为 空 , 用 于 在 数 据 库 中 查 找 对 应 的 用 户 信 息 以 及 后 续 与 token 相 关 的 验 证 操 作 , 是 整 个 密 码 重 置 流 程 的 关 键 标 识 之 一 。
* @param passwordNew 用 户 输 入 的 新 密 码 , 同 样 不 能 为 空 , 是 要 更 新 到 数 据 库 中 替 换 原 密 码 的 内 容 , 且 需 要 经 过 一 系 列 校 验 ( 如 重 复 性 校 验 等 ) 确 保 其 合 法 性 和 安 全 性 。
* @param forgetToken 用 户 在 忘 记 密 码 流 程 中 获 取 到 的 用 于 验 证 身 份 的 token , 不 能 为 空 , 用 于 和 Redis 缓 存 中 的 token 进 行 比 对 以 及 确 认 本 次 密 码 重 置 操 作 的 合 法 性 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 了 重 置 密 码 操 作 的 结 果 状 态 ( 如 密 码 重 置 成 功 、 token 错 误 、 密 码 重 复 等 各 种 情 况 ) 以 及 相 应 的 提 示 信 息 ,
* 方 便 调 用 者 ( 如 前 端 界 面 或 者 其 他 调 用 该 服 务 的 模 块 ) 根 据 返 回 结 果 知 晓 密 码 重 置 操 作 是 否 成 功 , 并 进 行 相 应 的 后 续 处 理 ( 如 提 示 用 户 操 作 结 果 、 跳 转 到 相 应 页 面 等 ) 。
* /
@Override
public ServerResponse forgetResetPasswd ( String username , String passwordNew , String forgetToken ) {
//1.校验参数
if ( StringUtils . isBlank ( username ) | | StringUtils . isBlank ( passwordNew ) | | StringUtils . isBlank ( forgetToken ) ) {
if ( StringUtils . isBlank ( username ) | | StringUtils . isBlank ( passwordNew ) | | StringUtils . isBlank ( forgetToken ) ) {
return ServerResponse . createByErrorMessage ( "参数有误,修改密码操作失败" ) ;
}
//2.根据username去获取用户
User user = userMapper . getUserByUsername ( username ) ;
if ( user = = null ) {
if ( user = = null ) {
return ServerResponse . createByErrorMessage ( "用户名不存在,修改密码操作失败" ) ;
}
//3.从redis中获取token, 看是否超时
String redisToken = commonCacheUtil . getCacheValue ( Constants . TOKEN_PREFIX + username ) ;
if ( redisToken = = null ) {
String redisToken = commonCacheUtil . getCacheValue ( Constants . TOKEN_PREFIX + username ) ;
if ( redisToken = = null ) {
return ServerResponse . createByErrorMessage ( "token已经过期, 修改密码操作失败" ) ;
}
//4.看前端传过来的token与redis中取出来的token是否相等
if ( ! StringUtils . equals ( redisToken , forgetToken ) ) {
if ( ! StringUtils . equals ( redisToken , forgetToken ) ) {
return ServerResponse . createByErrorMessage ( "token错误, 修改密码操作失败" ) ;
}
//5.判断密码是否重复
String MD5Passwd = MD5Util . MD5EncodeUtf8 ( passwordNew ) ;
if ( user . getPassword ( ) . equals ( MD5Passwd ) ) {
if ( user . getPassword ( ) . equals ( MD5Passwd ) ) {
return ServerResponse . createByErrorMessage ( "不要使用重复密码!" ) ;
}
//6.重置密码
user . setPassword ( MD5Passwd ) ;
int result = userMapper . updateByPrimaryKeySelective ( user ) ;
if ( result > 0 ) {
int updateCoun t = userMapper . updateByPrimaryKeySelective ( user ) ;
if ( updateCount > 0 ) {
return ServerResponse . createBySuccessMessage ( "修改密码成功" ) ;
}
return ServerResponse . createByErrorMessage ( "修改密码失败" ) ;
}
@Override
public ServerResponse resetPasswd ( String passwordOld , String passwordNew , int userId ) {
//1.校验参数
if ( StringUtils . isBlank ( passwordOld ) | | StringUtils . isBlank ( passwordNew ) ) {
return ServerResponse . createByErrorMessage ( "参数有误" ) ;
}
User user = userMapper . selectByPrimaryKey ( userId ) ;
if ( user = = null ) {
return ServerResponse . createByErrorMessage ( "无用户登陆" ) ;
}
//2.校验老的密码
String passwordOldMD5 = MD5Util . MD5EncodeUtf8 ( passwordOld ) ;
if ( ! StringUtils . equals ( passwordOldMD5 , user . getPassword ( ) ) ) {
return ServerResponse . createByErrorMessage ( "老密码输错啦..." ) ;
}
//3.重置新的密码
user . setPassword ( MD5Util . MD5EncodeUtf8 ( passwordNew ) ) ;
int updateCount = userMapper . updateByPrimaryKeySelective ( user ) ;
if ( updateCount > 0 ) {
return ServerResponse . createBySuccessMessage ( "更新密码成功" ) ;
}
return ServerResponse . createByErrorMessage ( "更新密码失败" ) ;
}
/ * *
* 该 方 法 用 于 更 新 用 户 的 信 息 , 具 体 实 现 逻 辑 如 下 :
*
* 1. 获 取 当 前 登 录 用 户
* 首 先 调 用 userMapper 的 selectByPrimaryKey 方 法 , 传 入 用 户 ID ( userId ) 作 为 参 数 去 数 据 库 中 查 询 对 应 的 用 户 信 息 , 将 查 询 结 果 赋 值 给 User 类 型 的 user 对 象 。
* 如 果 查 询 返 回 的 user 对 象 为 null , 说 明 根 据 传 入 的 用 户 ID 在 数 据 库 中 找 不 到 对 应 的 用 户 , 可 能 是 用 户 不 存 在 或 者 传 入 的 ID 有 误 等 原 因 ,
* 此 时 通 过 ServerResponse . createByErrorMessage 方 法 创 建 一 个 包 含 “ 获 取 当 前 登 陆 用 户 失 败 , 请 重 新 登 陆 ” 提 示 信 息 的 ServerResponse 对 象 返 回 给 调 用 者 ,
* 告 知 调 用 者 无 法 获 取 到 要 更 新 信 息 的 用 户 , 建 议 重 新 登 录 操 作 , 以 确 保 后 续 能 正 确 获 取 到 用 户 信 息 进 行 更 新 。
*
* 2. 参 数 校 验
* 在 成 功 获 取 到 用 户 信 息 后 , 使 用 StringUtils . isBlank 方 法 对 传 入 的 邮 箱 ( email ) 、 电 话 ( phone ) 、 问 题 ( question ) 和 答 案 ( answer ) 这 几 个 参 数 进 行 非 空 校 验 。
* 如 果 这 些 参 数 中 有 任 何 一 个 为 空 字 符 串 , 意 味 着 要 更 新 的 数 据 不 完 整 , 不 符 合 更 新 用 户 信 息 的 要 求 ,
* 通 过 ServerResponse . createByErrorMessage 方 法 创 建 一 个 包 含 “ 更 新 的 数 据 不 能 存 在 空 值 ! ” 提 示 信 息 的 ServerResponse 对 象 返 回 给 调 用 者 ,
* 提 示 调 用 者 需 要 提 供 完 整 的 非 空 信 息 才 能 进 行 用 户 信 息 更 新 操 作 。
*
* 3. 校 验 邮 箱 是 否 重 复
* 由 于 考 虑 到 修 改 用 户 信 息 这 个 操 作 并 发 量 不 大 , 所 以 这 里 没 有 使 用 锁 机 制 ( 与 一 些 高 并 发 场 景 下 的 操 作 有 所 区 别 ) 。
* 接 着 调 用 userMapper 的 checkEmailValid 方 法 , 传 入 要 更 新 的 邮 箱 地 址 ( email ) 和 用 户 ID ( userId ) 作 为 参 数 , 去 数 据 库 中 查 询 是 否 存 在 其 他 用 户 已 经 使 用 了 该 邮 箱 地 址 ( 排 除 当 前 要 更 新 的 这 个 用 户 本 身 ) 。
* 如 果 查 询 返 回 的 记 录 数 量 queryCount 大 于 0 , 说 明 这 个 邮 箱 已 经 被 其 他 用 户 占 用 了 , 不 符 合 唯 一 性 要 求 , 此 时 不 能 使 用 该 邮 箱 进 行 更 新 操 作 ,
* 通 过 ServerResponse . createByErrorMessage 方 法 创 建 一 个 包 含 “ 此 邮 箱 已 经 被 占 用 , 换 个 试 试 ~ ” 提 示 信 息 的 ServerResponse 对 象 返 回 给 调 用 者 , 告 知 调 用 者 需 要 更 换 一 个 未 被 使 用 的 邮 箱 地 址 。
*
* 4. 构 建 更 新 用 户 对 象 并 执 行 更 新 操 作
* 如 果 邮 箱 校 验 通 过 ( 即 没 有 被 其 他 用 户 占 用 ) , 创 建 一 个 新 的 User 对 象 updateUser , 通 过 相 应 的 set 方 法 设 置 其 ID 为 传 入 的 用 户 ID ( userId ) ,
* 以 及 设 置 要 更 新 的 邮 箱 ( email ) 、 电 话 ( phone ) 、 问 题 ( question ) 和 答 案 ( answer ) 等 属 性 值 , 以 此 构 建 出 一 个 包 含 了 更 新 后 信 息 的 用 户 对 象 。
* 然 后 调 用 userMapper 的 updateByPrimaryKeySelective 方 法 , 传 入 这 个 updateUser 对 象 , 根 据 用 户 的 主 键 ( userId ) 去 数 据 库 中 更 新 对 应 的 用 户 信 息 ,
* 该 方 法 会 返 回 一 个 表 示 更 新 操 作 影 响 的 记 录 数 量 的 整 数 updateCount 。
*
* 5. 返 回 更 新 结 果
* 如 果 updateCount 大 于 0 , 说 明 用 户 信 息 更 新 成 功 , 通 过 ServerResponse . createBySuccessMessage 方 法 创 建 并 返 回 一 个 包 含 “ 更 新 信 息 成 功 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 ,
* 告 知 调 用 者 用 户 信 息 已 成 功 更 新 , 可 以 进 行 后 续 相 关 操 作 ( 如 刷 新 页 面 展 示 新 信 息 等 ) 。
* 如 果 updateCount 不 大 于 0 , 意 味 着 在 数 据 库 更 新 用 户 信 息 时 出 现 问 题 , 可 能 是 数 据 库 连 接 异 常 、 数 据 更 新 语 句 执 行 失 败 等 原 因 ,
* 通 过 ServerResponse . createByErrorMessage 方 法 返 回 一 个 包 含 “ 更 新 用 户 信 息 失 败 ” 提 示 信 息 的 ServerResponse 对 象 给 调 用 者 , 提 示 调 用 者 用 户 信 息 更 新 操 作 没 有 达 到 预 期 效 果 , 出 现 了 故 障 。
*
* @param email 要 更 新 的 用 户 邮 箱 地 址 , 由 客 户 端 传 入 , 不 能 为 空 ( 经 过 参 数 校 验 ) , 且 需 要 确 保 其 在 数 据 库 中 的 唯 一 性 ( 经 过 邮 箱 重 复 校 验 ) , 用 于 更 新 用 户 在 数 据 库 中 的 邮 箱 信 息 。
* @param phone 要 更 新 的 用 户 电 话 号 码 , 同 样 不 能 为 空 , 用 于 更 新 用 户 在 数 据 库 中 的 电 话 信 息 。
* @param question 要 更 新 的 用 户 找 回 密 码 相 关 问 题 , 不 能 为 空 , 用 于 更 新 用 户 在 数 据 库 中 设 置 的 对 应 问 题 信 息 。
* @param answer 要 更 新 的 用 户 找 回 密 码 相 关 问 题 的 答 案 , 不 能 为 空 , 用 于 更 新 用 户 在 数 据 库 中 设 置 的 对 应 答 案 信 息 。
* @param userId 用 户 的 唯 一 标 识 , 用 于 在 数 据 库 中 准 确 查 找 对 应 的 用 户 信 息 以 及 作 为 更 新 操 作 的 主 键 依 据 , 确 保 更 新 的 是 正 确 的 用 户 记 录 。
* @return 返 回 一 个 ServerResponse 对 象 , 包 含 了 更 新 用 户 信 息 操 作 的 结 果 状 态 ( 如 更 新 成 功 、 邮 箱 重 复 、 更 新 失 败 等 各 种 情 况 ) 以 及 相 应 的 提 示 信 息 ,
* 方 便 调 用 者 根 据 返 回 结 果 知 晓 用 户 信 息 更 新 操 作 是 否 成 功 , 并 进 行 相 应 的 后 续 处 理 ( 如 提 示 用 户 操 作 结 果 、 刷 新 页 面 等 ) 。
* /
@Override
public ServerResponse updateInfomation ( String email , String phone , String question , String answer , Integer userId ) {
//1.获取当前登陆用户
User user = userMapper . selectByPrimaryKey ( userId ) ;
if ( user = = null ) {
if ( user = = null ) {
return ServerResponse . createByErrorMessage ( "获取当前登陆用户失败,请重新登陆" ) ;
}
//2.校验参数
if ( StringUtils . isBlank ( email ) | | StringUtils . isBlank ( phone ) | | StringUtils . isBlank ( question ) | | StringUtils . isBlank ( answer ) ) {
if ( StringUtils . isBlank ( email ) | | StringUtils . isBlank ( phone ) | | StringUtils . isBlank ( question ) | | StringUtils . isBlank ( answer ) ) {
return ServerResponse . createByErrorMessage ( "更新的数据不能存在空值!" ) ;
}
//2.修改用户信息应该并发不大,所以不用加锁了,这里校验邮箱是否重复
Integer queryCount = userMapper . checkEmailValid ( email , userId ) ;
if ( queryCount > 0 ) {
Integer queryCount = userMapper . checkEmailValid ( email , userId ) ;
if ( queryCount > 0 ) {
//说明这个邮箱已经被其他用户占用了,所以不能使用
return ServerResponse . createByErrorMessage ( "此邮箱已经被占用,换个试试~" ) ;
}
@ -276,18 +557,32 @@ public class UserServiceImpl implements IUserService{
int updateCount = userMapper . updateByPrimaryKeySelective ( updateUser ) ;
if ( updateCount > 0 ) {
if ( updateCount > 0 ) {
return ServerResponse . createBySuccessMessage ( "更新信息成功" ) ;
}
return ServerResponse . createByErrorMessage ( "更新用户信息失败" ) ;
}
/ * *
* 此 方 法 用 于 从 数 据 库 中 根 据 用 户 ID 获 取 用 户 的 详 细 信 息 , 并 封 装 到 UserResVO 对 象 中 返 回 , 具 体 实 现 过 程 如 下 :
*
* 首 先 创 建 一 个 UserResVO 类 型 的 对 象 userResVO , 用 于 封 装 要 返 回 的 用 户 信 息 。
* 接 着 调 用 userMapper 的 selectByPrimaryKey 方 法 , 传 入 用 户 ID ( userId ) 作 为 参 数 去 数 据 库 中 查 询 对 应 的 用 户 信 息 , 将 查 询 结 果 赋 值 给 User 类 型 的 userDB 对 象 。
* 如 果 查 询 返 回 的 userDB 对 象 不 为 null , 说 明 找 到 了 对 应 的 用 户 记 录 , 此 时 将 用 户 的 相 关 信 息 ( 如 用 户 ID 、 用 户 名 、 邮 箱 、 角 色 、 电 话 、 问 题 、 答 案 、 创 建 时 间 、 更 新 时 间 等 )
* 通 过 userResVO 对 象 的 相 应 set 方 法 分 别 设 置 到 该 对 象 的 对 应 属 性 中 , 构 建 出 一 个 包 含 完 整 用 户 信 息 的 UserResVO 对 象 。
* 最 后 将 这 个 封 装 好 用 户 信 息 的 userResVO 对 象 返 回 给 调 用 者 , 方 便 调 用 者 ( 如 前 端 界 面 或 者 其 他 业 务 逻 辑 层 代 码 ) 获 取 用 户 详 细 信 息 进 行 后 续 的 展 示 、 处 理 等 操 作 。
* 如 果 查 询 返 回 的 userDB 对 象 为 null , 意 味 着 没 有 找 到 对 应 的 用 户 记 录 , 此 时 直 接 返 回 一 个 空 的 UserResVO 对 象 , 调 用 者 可 以 根 据 返 回 的 对 象 情 况 进 行 相 应 的 判 断 和 处 理 。
*
* @param userId 用 户 的 唯 一 标 识 , 用 于 在 数 据 库 中 准 确 查 找 对 应 的 用 户 信 息 , 不 能 为 空 , 是 获 取 用 户 详 细 信 息 的 关 键 依 据 。
* @return 返 回 一 个 UserResVO 对 象 , 该 对 象 封 装 了 从 数 据 库 中 查 询 到 的 对 应 用 户 ID 的 用 户 详 细 信 息 ( 如 果 用 户 存 在 ) , 方 便 调 用 者 进 行 后 续 相 关 操 作 ,
* 若 用 户 不 存 在 则 返 回 一 个 空 的 UserResVO 对 象 , 调 用 者 可 据 此 判 断 并 做 相 应 处 理 。
* /
@Override
public UserResVO getUserInfoFromDB ( Integer userId ) {
UserResVO userResVO = new UserResVO ( ) ;
User userDB = userMapper . selectByPrimaryKey ( userId ) ;
if ( userDB ! = null ) {
if ( userDB ! = null ) {
userResVO . setId ( userId ) ;
userResVO . setUsername ( userDB . getUsername ( ) ) ;
userResVO . setEmail ( userDB . getEmail ( ) ) ;
@ -299,7 +594,4 @@ public class UserServiceImpl implements IUserService{
userResVO . setUpdateTime ( userDB . getUpdateTime ( ) ) ;
}
return userResVO ;
}
}
}