大二毕设.3-网盘系统-用户模块讲解

目录

模块功能介绍

具体实现讲解

constants层:存放用户模块常量类

entity层:存放实体类,与数据库中的属性值基本保持一致

mapper层:对数据库进行数据持久化操作

service层:业务逻辑层,主要是针对具体的问题的操作

controller层:负责请求转发,接收页面过来的参数,传给service处理,接到返回值,并再次传给页面

po层:controller层向外接参的实体对象

context层:上下文的实体对象

vo层:视图对象,用于展示层,把某个指定页面的所有数据封装起来,方便前端获取数据

converter层:实体对象转换器


项目演示博客

模块功能介绍

  • 用户注册
    • 接口幂等性
    • 全局唯一的用户名称
  • 用户登录
    • 使用缓存实现单机登录
    • 使用jwt token实现时效性以及分布式的问题
  • 用户登出
  • 用户忘记密码
    • 校验用户名称
    • 校验用户密保问题的答案
    • 修改用户密码
  • 用户在线修改密码
    • 校验旧密码
    • 修改密码
  • 查询用户的基本信息

具体实现讲解

  • 用户模块下共分有9层,分别是:
    *

    constants层:存放用户模块常量类
    entity层:存放实体类,与数据库中的属性值基本保持一致
    • 用户信息表(RPanUser)
    • 用户搜索历史表(RPanUserSearchHistory)
    mapper层:对数据库进行数据持久化操作
    • 针对用户信息表的数据库操作Mapper(RPanUserMapper)
    • 针对用户搜索历史表的数据库操作Mapper(RPanUserSearchHistoryMapper)
    service层:业务逻辑层,主要是针对具体的问题的操作
    • 针对用户信息表的数据库操作Service(IUserService)
      • 首先需要把 转换器,针对用户文件信息表的数据库操作Service,缓存管理器CacheManager,用户模块缓存业务处理类 注入进来
      • 用户注册的业务实现(register):
        • 需要实现的功能点:
          • 1、注册用户信息
          • 2、创建新用户的根本目录信息
        • 需要实现的技术难点:
          • 1、该业务是幂等的
          • 2、要保证用户名全局唯一
        • 实现技术难点的处理方案:幂等性通过数据库表对于用户名字段添加唯一索引,上游业务捕获对应的冲突异常,转化返回
        • 它只有1个参数:即UserRegisterContext
        • 首先需要实例化用户信息表的实体对象(实体转化,由上下文信息转化成用户实体,封装进上下文)(assembleUserEntity)
          • 它只有1个参数:即UserRegisterContext
          • 首先通过converter的映射方法来完成实体转换得到entity用户实体对象
          • 然后通过PasswordUtil的MessageDigestUtil.md5获取盐值信息(随机生成盐值),同时利用PasswordUtil的MessageDigestUtil.sha256传入盐值和上下文对象传来的密码进行密码加密
          • 然后对entity进行属性设置(UserId通过雪花算法id生成器生成,创建时间与更新时间通过new Date()来生成)
          • 最后将这个entity封装进上下文对象中
        • 然后实现注册用户的业务(需要捕获数据库的唯一索引冲突异常,来实现全局用户名称唯一)(doRegister)
          • 它只有1个参数:即UserRegisterContext
          • 首先从上下文实体对象(UserRegisterContext)中获取用户实体对象得到entity
          • 然后对entity进行判空处理,如果是空则抛出对应错误提示
          • 如果不是空则首先需要捕获DuplicateKeyException异常,表示在数据库中插入或更新数据时,违反了唯一性约束,即出现了重复的键值
          • 然后抛出"用户名已存在"
          • 然后调用mybatisplus的save,如果保存失败也抛出对应异常
        • 然后创建用户的根目录信息(createUserRootFolder)
          • 它只有1个参数:即UserRegisterContext
          • 首先需要创建一个文件夹上下文实体对象
          • 然后设置它的3个属性(它的userid就是上下文实体对象(UserRegisterContext)中entity的userid)
          • 最后调用IUserFileService的创建文件夹信息(createFolder)方法传入设置好的文件夹上下文实体对象来完成创建
        • 最后返回这个上下文对象里的entity里的userid
      • 用户登录的业务实现(login):
        • 需要实现的功能:
          • 1、用户的登录信息校验
          • 2、生成一个具有时效性的accessToken
          • 3、将accessToken缓存起来,去实现单机登录
        • 它只有1个参数:即UserLoginContext
        • 首先要校验传入的信息,即校验用户名密码(checkLoginInfo)
          • 它只有1个参数:即UserLoginContext
          • 首先要通过传入的UserLoginContext上下文对象获取用户名和密码
          • 然后通过用户名获取用户实体信息(getRPanUserByUsername)entity
            • 它只有1个参数:即username
            • 通过QueryWrapper进行eq实现
          • 如果查询出来的entity用户实体信息是null,则抛出对应异常
          • 然后用户名校验通过后,则校验密码信息
          • 首先要获取到它的盐值(entity的盐值),然后通过PasswordUtil传入盐值和上下文对象获取到的密码进行加密
          • 同时获取到用户实体信息entity的密码
          • 加密后的密码和数据库中的密码(用户实体信息entity的密码)进行比较,不相等则抛出对应异常
          • 最后用户名和密码都通过后,UserLoginContext上下文对象设置用户实体对象为entity,方便下游使用
        • 然后生成并保存登陆之后的凭证(generateAndSaveAccessToken)
          • 它只有1个参数:即UserLoginContext
          • 首先要通过传入的UserLoginContext上下文对象获取用户实体对象entity
          • 然后向Jwt工具类传入 entity的username,常量key值,entity的userid和过期时间 进行token生成
          • 然后通过CacheManager获取到服务端公用缓存cache
          • 以 用户登录缓存前缀+entity的userid 为键,缓存token
          • 最后UserLoginContext上下文对象设置登陆成功之后的凭证信息为token
        • 最后将UserLoginContext上下文对象中的Token返回出去
      • 用户退出登录的业务实现(exit):
        • 只需清除用户的登录凭证缓存即可
        • 它只有1个参数:即当前登录用户的userid
        • 首先通过CacheManager获取到服务端公用缓存cache
        • 然后以 用户登录缓存前缀+当前登录用户的userid 为键,清除token即可
      • 用户忘记密码-校验用户名称的业务实现(checkUsername):
        • 它只有1个参数:即CheckUsernameContext
        • 首先从context中获取Username,通过Username在数据库中查询对应的密保问题
        • 如果查询为空则抛出对应异常"没有此用户",查询成功则返回查询到的密保问题供后续服务使用
      • 用户忘记密码-校验密保答案的业务实现(checkAnswer):
        • 它只有1个参数:即CheckAnswerContext
        • 首先从context中获取Username,Question,Answer,通过Username,Question,Answer在数据库中进行对应的查询并进行eq
        • eq失败则抛出对应异常"密保答案错误",成功则生成用户忘记密码-校验密保答案通过的临时token并返回,token的失效时间为五分钟
      • 用户忘记密码-重置用户密码的业务实现(resetPassword):
        • 它只有1个参数:即ResetPasswordContext
        • 首先验证忘记密码的token是否有效(checkForgetPasswordToken):
          • 它只有1个参数:即ResetPasswordContext
          • 首先通过context把token取出来
          • 然后通过JwtUtil分析这个token,返回一个value(Username)
          • 如果这个value为空则说明token过期了,抛出对应异常
          • 如果没有过期解析成功了就把这个token转为string,然后与context中的Username进行对比,不等则抛出对应异常"token错误"
        • 然后校验用户信息并重置用户密码(checkAndResetUserPassword):
          • 它只有1个参数:即ResetPasswordContext
          • 首先通过context把Username和Password取出来
          • 然后通过传入Username进getRPanUserByUsername来判断user实体entity是否存在,不存在则抛出对应异常"用户信息不存在"
          • 如果存在则进行密码的重置
          • 然后对Password进行加密,加密完成后重新设置entity的Password和UpdateTime属性
          • 最后传入处理好的entity进updateById进行修改
      • 用户在线修改密码的业务实现(changePassword):
        • 它只有1个参数:即ChangePasswordContext
        • 首先需要校验旧密码(checkOldPassword):
          • 它只有1个参数:即ChangePasswordContext
          • 首先需要从context中获取userId和oldPassword
          • 然后通过getById查询userId得到用户的实体信息entity
          • 如果entity为空则抛出对应异常"用户信息不存在"
          • 查询成功则将用户的实体信息entity封装到上下文对象context中
          • 然后要获取到它的盐值(entity的盐值),然后通过PasswordUtil传入盐值和上下文对象获取到的密码进行加密
          • 同时获取到用户实体信息entity的密码
          • 加密后的密码和数据库中的密码(用户实体信息entity的密码)进行比较,不相等则抛出对应异常"旧密码不正确"
        • 然后需要重置新密码(doChangePassword):
          • 它只有1个参数:即ChangePasswordContext
          • 首先需要从context中获取newPassword和entity
          • 然后要获取到它的盐值(entity的盐值),然后通过PasswordUtil传入盐值和新密码newPassword重新进行加密
          • 然后用加密密码覆盖掉entity原有密码
          • 最后通过向updateById传入entity进行修改,失败则抛出对应异常"修改用户密码失败"
        • 最后退出当前的登录状态(exitLoginStatus):
          • 它只有1个参数:即ChangePasswordContext
          • 直接调用exit传入context中的UserId完成退出
      • 查询在线用户的基本信息的业务实现(info):
        • 它只有1个参数:即userId
        • 首先通过getById查询用户的基本信息实体entity,对其进行判空处理,查询失败则抛出对应异常"用户信息查询失败"
        • 然后查询用户的根文件夹信息(getUserRootFileInfo):
          • 它只有1个参数:即userId
          • 委托给文件模块的IUserFileService的getUserRootFile进行处理
        • 查询失败则抛出对应异常"查询用户根文件夹信息失败"
        • 最后通过converter的映射方法拼装VO对象(基本信息实体和根文件夹信息)返回
    • 针对用户搜索历史表的数据库操作Service(IUserSearchHistoryService)
      • 首先需要把 *** 注入进来
      • 查询用户的搜索历史记录,默认十条(getUserSearchHistories):
        • 它只有1个参数:即QueryUserSearchHistoryContext
        • 直接通过Context上下文通过baseMapper调用自定义Mapper操作进行数据库对应查询,并返回查询结果
    controller层:负责请求转发,接收页面过来的参数,传给service处理,接到返回值,并再次传给页面
    • 用户模块的控制器实体(UserController):
      • 首先需要把 *** 注入进来
      • register:
        • 它只有1个参数:即UserRegisterPO
        • 首先在调用service的register方法前,需要将这个po对象转换成上下文对象,通过converter的映射方法来完成转换
        • 转换了实体之后,调用service的register方法把这个context给它传进去完成调用,返回一个新注册的userid
        • 最后把这id加密下,返回给客户端去使用,返回相关状态码
      • login:
        • 它只有1个参数:即UserLoginPO
        • 首先在调用service的login方法前,需要将这个po对象转换成上下文对象,通过converter的映射方法来完成转换
        • 转换了实体之后,调用service的login方法把这个context给它传进去完成调用,返回一个有时效性的accessToken供后续服务使用,返回相关状态码
      • exit:
        • 没有参数
        • 由于每次请求,token放于header中,想要获取token,每次都要通过在control层获取header,才能获取到登录信息,很麻烦
        • 所以通过用户ID存储工具类里配置好的 ThreadLocal 获取到当前登录用户的userid
        • 然后调用service的exit方法把这个userid给它传进去完成调用,返回相关状态码即可
      • checkUsername:
        • 它只有1个参数:即CheckUsernamePO
        • 首先在调用service的checkUsername方法前,需要将这个po对象转换成上下文对象,通过converter的映射方法来完成转换
        • 转换了实体之后,调用service的checkUsername方法把这个context给它传进去完成调用,返回下一步需要校验的密保问题供后续服务使用,返回相关状态码
      • checkAnswer:
        • 它只有1个参数:即CheckAnswerPO
        • 首先在调用service的checkAnswer方法前,需要将这个po对象转换成上下文对象,通过converter的映射方法来完成转换
        • 转换了实体之后,调用service的checkAnswer方法把这个context给它传进去完成调用,返回token供后续服务使用,返回相关状态码
      • resetPassword:
        • 它只有1个参数:即ResetPasswordPO
        • 首先在调用service的resetPassword方法前,需要将这个po对象转换成上下文对象,通过converter的映射方法来完成转换
        • 转换了实体之后,调用service的resetPassword方法把这个context给它传进去完成调用,返回相关状态码即可
      • changePassword:
        • 它只有1个参数:即ChangePasswordPO
        • 首先在调用service的changePassword方法前,需要将这个po对象转换成上下文对象,通过converter的映射方法来完成转换
        • 然后需要获取当前线程的用户ID,用来设置上下文对象的UserId
        • 调用service的changePassword方法把这个context给它传进去完成调用,返回相关状态码即可
      • info:
        • 没有参数
        • 通过获取当前线程的用户ID,直接调用service的info查询在线用户的基本信息
        • 查询成功返回对应vo对象,同时返回相关状态码
    • 用户搜索历史模块的控制器实体(UserSearchHistoryController):
      • 首先需要把 *** 注入进来
      • 获取用户最新的搜索历史记录,默认十条(getUserSearchHistories):
        • 首先需要创建一个 用户查询搜索历史记录上下文实体(QueryUserSearchHistoryContext)
        • 然后通过 用户ID存储工具类获取当前线程的用户ID 进行Context属性设置
        • 最后调用service的 getUserSearchHistories 方法把这个context给它传进去完成调用,返回用户最新的搜索历史记录和相关状态码
    po层:controller层向外接参的实体对象
    • 注册用户参数实体对象(UserRegisterPO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加4个属性:用户名,密码,密保问题,密保答案
      • 最后利用@NotBlank 进行非空校验,@Pattern 进行用户名正则校验,@Length 进行长度校验
    • 登录用户参数实体对象(UserLoginPO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加2个属性:用户名,密码
      • 最后利用@NotBlank 进行非空校验,@Pattern 进行用户名正则校验,@Length 进行长度校验
    • 用户忘记密码-校验用户名称PO对象(CheckUsernamePO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加1个属性:用户名
      • 最后利用@NotBlank 进行非空校验,@Pattern 进行用户名正则校验
    • 用户忘记密码-校验密保答案PO对象(CheckAnswerPO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加3个属性:用户名,密保问题,密保答案
      • 最后利用@NotBlank 进行非空校验,@Pattern 进行用户名正则校验,@Length 进行长度校验
    • 用户忘记密码-重置用户密码PO对象(ResetPasswordPO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加3个属性:用户名,密码,验证通过提交重置密码的token
      • 最后利用@NotBlank 进行非空校验,@Pattern 进行用户名正则校验,@Length 进行长度校验
    • 用户在线修改密码PO对象(ChangePasswordPO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加2个属性:旧密码和新密码
      • 最后利用@NotBlank 进行非空校验,@Length 进行长度校验
    context层:上下文的实体对象
    • 用户注册业务的上下文实体对象(UserRegisterContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加5个属性:用户名,密码,密保问题,密保答案,用户实体对象(RPanUser)
    • 用户登录业务的上下文实体对象(UserLoginContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加4个属性:用户名,密码,用户实体对象(RPanUser),登陆成功之后的凭证信息
    • 用户忘记密码-校验用户名称业务的上下文实体对象(CheckUsernameContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加1个属性:用户名
    • 用户忘记密码-校验密保答案业务的上下文实体对象(CheckAnswerContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加3个属性:用户名,密保问题,密保答案
    • 用户忘记密码-重置用户密码业务的上下文实体对象(ResetPasswordContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加3个属性:用户名,密码,验证通过提交重置密码的token
    • 用户在线修改密码业务的上下文实体对象(ChangePasswordContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加4个属性:当前登录的用户ID,旧密码,新密码,当前登录用户的实体信息(RPanUser)
    • 用户查询搜索历史记录上下文实体(QueryUserSearchHistoryContext):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加1个属性:当前登录用户的ID
    vo层:视图对象,用于展示层,把某个指定页面的所有数据封装起来,方便前端获取数据
    • 用户基本信息实体(UserInfoVO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加3个属性:用户名称,用户根目录的加密ID,用户根目录名称
      • 同时通过@JsonSerialize 自定义序列化类对ID进行自动加密
    • 用户搜索历史返回实体(UserSearchHistoryVO):
      • 首先它要实现Serializable序列化接口
      • 然后给它添加序列化UID这一属性
      • 再添加1个属性:搜索文案
    converter层:实体对象转换器
    • 用户模块实体转化工具类(UserConverter)
      • 首先利用MapStruct的@Mapper 注解标记这个接口作为一个映射接口,并且是编译时MapStruct处理器的入口,简化不同的Java Bean之间映射的处理
      • 同时指定@Mapper 注解的componentModel属性为spring,这样生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired 方式进行注入
      • 然后添加若干映射方法,MapStruct会自动生成转换
相关推荐
葫芦和十三3 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp3 小时前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑4 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯5 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan7 小时前
多Agent之间的区别
后端
青石路9 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充9 小时前
1.面向对象设计思想
后端
IT_陈寒9 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro10 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗10 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端