springboot企业级抽奖项目业务一(登录模块)

开发流程

该业务基于rouyi生成好了mapper和service的代码,现在需要在controller层写接口

实际操作流程:

看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试

接口文档

在登录模块有登录和登出方法

登录分出登录成功、账号密码错误、密码多次错误三种情况

登出点了一定登出成功

controller里定义

在注解框架里加上login和logout两个函数

@RestController
@RequestMapping(value = "/api")
@Api(tags = {"登录模块"})
public class LoginController {
    @Autowired
    private CardUserService userService;

    @Autowired
    private RedisUtil redisUtil;

    @PostMapping("/login")
    @ApiOperation(value = "登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name="account",value = "用户名",required = true),
            @ApiImplicitParam(name="password",value = "密码",required = true)
    })
    public ApiResult login(HttpServletRequest request, @RequestParam String account,@RequestParam String password) {
        //TODO

        return null;
    }

    @GetMapping("/logout")
    @ApiOperation(value = "退出")
    public ApiResult logout(HttpServletRequest request) {
        //TODO
        return null;
    }

}

看给出的工具类

找该模块附近的common和util包

补全controller里的函数

login部分

首先拿到用户(基于rouyi使用的mybatis-plus)

QueryWrapper<CardUser> wrapper = new QueryWrapper<>();
wrapper.eq("uname",account).eq("passwd",PasswordUtil.encodePassword(password));
List<CardUser> users = userService.list(wrapper);
  1. QueryWrapper<CardUser> wrapper = new QueryWrapper<>();

    创建一个 QueryWrapper 对象 wrapper,用于构建查询条件。
  2. wrapper.eq("uname",account).eq("passwd",PasswordUtil.encodePassword(password));

    使用 wrapper 对象的 eq 方法添加查询条件,这里表示查询条件为用户名("uname" 字段)等于 account 变量的值,并且密码("passwd" 字段)等于经过加密后的 password 变量的值。
  3. List<CardUser> users = userService.list(wrapper);

    通过 UserService 的 list 方法传入包含查询条件的 wrapper 对象,执行数据库查询操作,返回符合条件的 CardUser 对象列表 users。这里为什么要用wrapper获取满足条件的用户列表,再取第一个呢?可以直接CardUser user = userService.getOne(wrapper);吗?这是一种保护措施。万一数据有多条不会出错。getOne的话就报错了。用getOne然后捕获异常也可以的。

然后处理登录成功的情况

if (users != null && users.size() > 0) {
    CardUser user = users.get(0);
    user.setIdcard(null);
    user.setPasswd(null);
    HttpSession session = request.getSession();
    session.setAttribute("user", user);
    return new ApiResult(1, "登录成功", user);
}

         if (users != null && users.size() > 0)

  1. users != null: 这一部分是为了确保 users 不为 null,即确保查询返回的用户列表对象不为空。如果 users 为 null,那么调用 users.size() 方法将会导致空指针异常。因此,这一部分判断是为了避免空指针异常。

  2. users.size() > 0: 这一部分判断是为了确保 users 列表中至少包含一个用户。即使 users 不为 null,但如果其中没有任何用户,也不应该继续处理和返回登录成功的信息,因为没有符合条件的用户。

  1. CardUser user = users.get(0);

    从查询到的用户列表中获取第一个用户对象,并赋值给 user 变量。
  2. user.setIdcard(null);

    将用户对象的身份证号字段设置为 null,出于安全考虑避免将密码信息传递到前端。
  3. user.setPasswd(null);

    将用户对象的密码字段设置为 null,同样可能是出于安全考虑。
  4. HttpSession session = request.getSession();

    通过 request 对象获取 HttpSession 对象,用于存储用户的会话信息。
  5. session.setAttribute("user", user);

    将处理后的用户对象存储到 HttpSession 中,以键值对 "user"-"user" 的形式保存。
  6. return new ApiResult(1, "登录成功", user);

    最后返回一个 ApiResult 对象,其中包含了状态码、消息和用户对象,用于向前端传递登录成功的信息和用户数据。

接下来处理登录失败的情况

对于密码错误5次的处理

Integer errortimes = (Integer) redisUtil.get(RedisKeys.USERLOGINTIMES + account);
if (errortimes != null && errortimes >= 5) {
    return new ApiResult(0, "密码错误5次,请5分钟后再登录", null);
}

从 Redis 中获取用户登录错误次数 errortimes,然后判断如果 errortimes 不为 null 而且大于等于 5,则返回一个包含错误提示信息的 ApiResult 对象,告知用户密码错误达到5次,需要等待5分钟后再尝试登录。

redisUtil.get(RedisKeys.USERLOGINTIMES + account) 表示根据用户账号构建的键名从 Redis 中获取该用户的登录错误次数信息。如果 Redis 中存储了该信息,则返回相应的错误次数;如果不存在或者 Redis 出现问题,则可能返回 null。。

  • RedisKeys.USERLOGINTIMES: 这是一个 Redis Key 的前缀,用于标识存储用户登录错误次数的键名。
  • account: 这是用户的账号信息,用于构建特定用户的登录错误次数的键名。

然后在判断流程增加密码错误的处理

else {
    redisUtil.incr(RedisKeys.USERLOGINTIMES + account, 1);
    redisUtil.expire(RedisKeys.USERLOGINTIMES + account, 60 * 5);
    return new ApiResult(0, "账户名或密码错误", null);
}

如果用户登录失败(且不满足之前判断的密码错误次数达到5次的条件),则会将该用户的登录错误次数加1,并设置该键的过期时间为5分钟。然后返回一个包含账户名或密码错误信息的 ApiResult 对象。

完整代码

@Autowired
private CardUserService userService;

@Autowired
private RedisUtil redisUtil;

@PostMapping("/login")
@ApiOperation(value = "登录")
@ApiImplicitParams({
        @ApiImplicitParam(name="account",value = "用户名",required = true),
        @ApiImplicitParam(name="password",value = "密码",required = true)
})
public ApiResult login(HttpServletRequest request, @RequestParam String account, @RequestParam String password) {
    Integer errortimes = (Integer) redisUtil.get(RedisKeys.USERLOGINTIMES + account);
    if (errortimes != null && errortimes >= 5) {
        return new ApiResult(0, "密码错误5次,请5分钟后再登录", null);
    }
    QueryWrapper<CardUser> wrapper = new QueryWrapper<>();
    wrapper.eq("uname", account).eq("passwd", PasswordUtil.encodePassword(password));
    List<CardUser> users = userService.list(wrapper);
    if (users != null && users.size() > 0) {
        CardUser user = users.get(0);
        user.setIdcard(null);
        user.setPasswd(null);
        HttpSession session = request.getSession();
        session.setAttribute("user", user);
        return new ApiResult(1, "登录成功", user);
    } else {
        redisUtil.incr(RedisKeys.USERLOGINTIMES + account, 1);
        redisUtil.expire(RedisKeys.USERLOGINTIMES + account, 60 * 5);
        return new ApiResult(0, "账户名或密码错误", null);
    }
}

logout部分

非常简单粗暴

HttpSession session = request.getSession();
if (session != null) {
    session.invalidate();
}
return new ApiResult(1, "退出登录", null);

首先通过HttpServletRequest获取HttpSession对象,然后检查session是否为null,如果不为null,则调用invalidate()方法使session失效。最后返回一个表示成功退出登录的ApiResult对象。

让session失效是为了确保用户在退出登录后,其会话信息得到及时清理,从而避免可能存在的安全风险和信息泄漏问题。一旦会话失效,用户在该会话中的所有状态和数据都会被清除,包括登录凭证、用户信息等,以确保用户的隐私和安全。

完整代码

@GetMapping("/logout")
@ApiOperation(value = "退出")
public ApiResult logout(HttpServletRequest request) {
    HttpSession session = request.getSession();
    if (session != null) {
        session.invalidate();
    }
    return new ApiResult(1, "退出登录", null);
}

运行测试

运行springboot项目后访问http://localhost:9001/doc.html

密码正确的情况

密码错误的情况

密码错5次及以上的情况

使用nginx部署前端后,进行前后端联调:

登录成功还没跳转

登录失败:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/473112.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在windows上安装Jenkins

jenkins安装 下载jenkins 官网&#xff1a;Jenkins download and deployment 官方文档说明&#xff1a;Jenkins User Documentation 安装jenkins1.点击下载好的安装包&#xff0c;点击Next 2.选择一个安装路径 如果系统是windows家庭版打不开策略就创建一个txt文件&#xff0c…

Android分区存储到底该怎么做

文章目录 一、Android存储结构二、什么是分区存储&#xff1f;三、私有目录和公有目录三、存储权限和分区存储有什么关系&#xff1f;四、我们应该该怎么做适配&#xff1f;4.1、利用File进行操作4.2、使用MediaStore操作数据库 一、Android存储结构 Android存储分为内部存储和…

NBlog Java定时任务-备份MySQL数据

NBlog部署维护流程记录&#xff08;持续更新&#xff09;&#xff1a;https://blog.csdn.net/qq_43349112/article/details/136129806 为了避免服务器被攻击&#xff0c;给博客添加了一个MySQL数据备份功能。 此功能是配合博客写的&#xff0c;有些方法直接用的已有的&#xf…

Matlab中inv()函数的使用

在Matlab中&#xff0c;inv()函数是用来求解矩阵的逆矩阵的函数。逆矩阵是一个与原矩阵相乘后得到单位矩阵的矩阵。在数学中&#xff0c;矩阵A的逆矩阵通常用A^-1表示。 什么是逆矩阵 在数学中&#xff0c;对于一个n阶方阵A&#xff0c;如果存在一个n阶方阵B&#xff0c;使得…

Gradio官方文档

文章目录 构建您的第一个demo分享您的demo进度条受密码保护的应用程序The Interface class&#xff08;接口类&#xff09;Components Attributes&#xff08;组件属性&#xff09;多个输入和输出组件图像示例嵌套列表描述性内容手风琴中的附加输入The 4 Kinds of Gradio Inter…

Android: Gradle 命令

一、查看整个项目依赖传递关系 x.x.x (*) 该依赖已经有了&#xff0c;将不再重复依赖。x.x.x -> x.x.x 该依赖的版本被箭头所指的版本代替。x.x.x -> x.x.x(*) 该依赖的版本被箭头所指的版本代替&#xff0c;并且该依赖已经有了&#xff0c;不再重复依赖。 1. gradlew ap…

冰岛人[天梯赛]

文章目录 题目描述思路AC代码 题目描述 输入样例 15 chris smithm adam smithm bob adamsson jack chrissson bill chrissson mike jacksson steve billsson tim mikesson april mikesdottir eric stevesson tracy timsdottir james ericsson patrick jacksson robin patrickss…

2024年最新Anaconda3 2024版中Jupyter Notebook安装

一、 Anaconda3 2024版下载 1.下载&#xff1a;Free Download | Anaconda 2.等待 解释&#xff1a;默认选择等等下载 &#xff0c;时间可能数分钟 3.安装 解释&#xff1a;打开刚刚下载的Anaconda Navigator&#xff0c;并如图安装低版本&#xff0c;高版本会直接报错 4. …

[zdyz]FreeRTOS笔记

FreeRTOS基础知识 1&#xff0c;任务调度器简介 调度器就是使用相关的调度算法来决定当前需要执行的哪个任务 抢占式调度 时间片调度 协程式调度 略 2&#xff0c;任务状态 运行态 正在执行的任务&#xff0c;该任务就处于运行态&#xff0c;注意在STM32中&#xff0c;同…

【Web】记录[长城杯 2022 高校组]b4bycoffee题目复现

目录 前言 环境准备 简单分析 EXP(两种打法) 生成Payload 恶意类 ①Spring命令执行回显类 ②Filter型内存马 前言 本地jar包运行打通了&#xff0c;远程500&#xff0c;nss靶机有问题&#xff0c;换了bugku就可( 主要记录下做题过程&#xff0c;纯菜狗&#xff0c;小…

深圳库卡机器人KR460控制柜维修快速解决

一、库卡机器人KR460控制柜常见故障类型 库卡机器人KR460控制柜可能出现的故障类型多种多样&#xff0c;常见的包括电源故障、通信故障、过热保护以及电路板损坏等。这些故障可能导致机器人不能启动、运行不稳定或突然停机等问题。 二、库卡机器人KR460控制柜维修前的准备 在开…

代码随想录刷题day29|非递减子序列全排列全排列II

文章目录 day29学习内容一、非递减子序列1.1、代码-错误写法1.1.1 多了一个return语句。1.1.2、nums[i-1] > nums[i]&#xff0c;这个条件写错了&#xff0c;为什么呢&#xff1f;1. 忽略了回溯算法的动态决策过程2. 限制了可能的递增子序列的探索 1.2、代码-正确写法 二、全…

javaSwing超级玛丽

一、摘要 摘要 近年来&#xff0c;Java作为一种新的编程语言&#xff0c;以其简单性、可移植性和平台无关性等优点&#xff0c;得到了广泛地应用。J2SE称为Java标准版或Java标准平台。J2SE提供了标准的SDK开发平台。利用该平台可以开发Java桌面应用程序和低端的服务器应用程序…

小白学视觉 | 超详细!Python中 pip 常用命令

本文来源公众号“小白学视觉”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;超详细&#xff01;Python中 pip 常用命令 相信对于大多数熟悉Python的人来说&#xff0c;一定都听说并且使用过pip这个工具&#xff0c;但是对它的了…

C语言例3-35:长度运算的例子

长度运算符的表现形式&#xff1a; sizeof(数据类型符&#xff09; 或 sizeof(变量&#xff09; 长度运算符的优先级&#xff1a; 与单目算术运算符、单目逻辑运算符、自增和自减运算符的优先级相同。上述优先级相同的运算符的结合性都是从右至左。 长度运算的例子 代码如…

python网络爬虫实战教学——urllib的使用(2)

文章目录 专栏导读1、前言2、URLError3、HTTPError4、urlparse5、urlunparse 专栏导读 ✍ 作者简介&#xff1a;i阿极&#xff0c;CSDN 数据分析领域优质创作者&#xff0c;专注于分享python数据分析领域知识。 ✍ 本文录入于《python网络爬虫实战教学》&#xff0c;本专栏针对…

SpringWEB组件及运行流程

SpringWEB组件 前端控制器&#xff1a; DispatcherServlet&#xff08;不需要程序员开发&#xff09;,由框架提供&#xff0c;在 web.xml 中配置。 作用&#xff1a;统一处理请求和响应&#xff0c;整个流程控制的中心&#xff0c;由它调用其它组件处理 用户的请求. 处理…

基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动

原链接 前言 这是一个Qt平台的基于QGraphicsView类的图像显示控件&#xff0c;支持输入QPixmap、QImage、opencv的从cv::Mat类。 实现平台&#xff1a;Windows 10 x64 Qt 6.2.3 MSVC 2019 opencv 4.5 先来看演示视频 控件类实现 ImageViewer.h文件 #ifndef IMAGEVIEWER…

力扣刷题Days23-35.搜索插入的位置(js)

1&#xff0c;题目 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。 2&#xff0c;代码 /*** param {number[]} nums*…

Autosar Crypto Driver学习笔记(二)

文章目录 Crypto DriverFunction definitionsGeneral APICrypto_InitCrypto_GetVersionInfo Job Processing InterfaceCrypto_ProcessJob Job Cancellation InterfaceKey Management InterfaceKey Setting Interface密钥设置接口Crypto_KeyElementSetCrypto_KeySetValid Key Ex…