9. 实现业务功能--用户登录

news2024/12/23 18:05:07

目录

1. 顺序图 

2. 参数要求

3. 创建 Service 接口

4. 实现 Service 接口

5. 单体测试

6. 实现 Controller 

7. 实现前端


在用户登录部分特别注意的是需要进行密码校验:

1. MD5(MD5(用户提交的原密码)+数据库查出来的用户的盐)= 密码的密文

2. 用上面的生成的密码的密文和数据库中用户的 password 字段的密码作比较,如果相等,则校验通过,否则失败。

1. 顺序图 

2. 参数要求

登录时需要用户提交的参数列表:

参数名描述类型默认值条件
username用户名String必须
password密码String必须

3. 创建 Service 接口

根据用户名查询用户信息:

public interface IUserService {
    /**
     * 根据用户名查询用户信息
     * @param username 用户名
     * @return
     */
    User selectByName(String username);

    /**
     * 创建普通用户
     *
     * @param user 用户名
     */
    void createNormalUser(User user);

    /**
     * ⽤⼾登录
     * @param username ⽤⼾名
     * @param password 密码
     * @return
     */
    User login(String username, String password);
}

4. 实现 Service 接口

@Slf4j // 日志
@Service // 交给 Spring 管理
public class UserServiceImpl implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public User selectByName(String username) {
        // 非空校验
        if(StringUtils.isEmpty(username)){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 根据用户名查询用户信息
        User user = userMapper.selectByName(username);
        // 返回结果
        return user;
    }

    @Override
    public void createNormalUser(User user) {
        // 非空校验
        if(user == null || StringUtils.isEmpty(user.getUsername())
                || StringUtils.isEmpty(user.getNickname())
                || StringUtils.isEmpty(user.getPassword())
                || StringUtils.isEmpty(user.getSalt())){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 校验用户是否存在
        User existUser = selectByName(user.getUsername());
        if(existUser != null){
            // 打印日志
            log.warn(ResultCode.FAILED_USER_EXISTS.toString() + "username = " + user.getUsername());
            // 抛出异常,用户已存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }
        // 为属性设置默认值
        // 性别 0女 1男 2保密
        if(user.getGender() != null){
            if(user.getGender() < 0 || user.getGender() > 2){
                user.setGender((byte)2);
            }
        }else{
            user.setGender((byte)2);
        }
        // 发帖数
        user.setArticleCount(0);
        // 是否管理员
        user.setIsAdmin((byte)0);
        // 状态
        user.setState((byte)0);
        // 时间
        Date date = new Date();
        user.setCreateTime(date); // 创建时间
        user.setUpdateTime(date); // 更新时间

        // 写入数据库
        int row = userMapper.insertSelective(user);
        if(row != 1){
            // 打印日志
            log.warn(ResultCode.FAILED_CREATE.toString() + "注册用户失败,username = " + user.getUsername());
            // 抛出异常,用户已存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
    }

    @Override
    public User login(String username, String password) {
        // 非空校验
        if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常,用户已存在
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 根据用户名查询用户信息
        User user = selectByName(username);
        // 校验用户是否存在
        if (user == null) {
            // 打印日志
            log.info(ResultCode.FAILED_USER_NOT_EXISTS.toString()+",username = " + username);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 校验密码是否正确
        String encryptPassword = MD5Utils.md5Salt(password, user.getSalt());
        if (!encryptPassword.equalsIgnoreCase(user.getPassword())) {
            // 打印日志
            log.info("密码输入错误,username = " + username + ", password = " + password);
            // 密码不正确抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 校验通过,返回用户信息
        return user;
    }
}

5. 单体测试

编写测试代码:

@Test
    void login() throws JsonProcessingException {
        // 正确用户
        User user = userService.login("Danny","123");
        System.out.println(objectMapper.writeValueAsString(user));

        // 错误用户
        user = userService.login("123","123");
        System.out.println(objectMapper.writeValueAsString(user));

    }

测试结果如下: 

6. 实现 Controller 

在 UserControlle r中实现登录方法:

 因此在 Config 包下新建 AppConfig 类,添加全局变量:

public class AppConfig {
    /**
     * 为 session 中存储的 User 对象定义一个全局变量
     */
    public static final String SESSION_USER_KEY = "SESSION_USER_KEY";
}

继续编写 UserController 类中的方法:

/**
     * 用户登录
     *
     * @param request
     * @param username 用户名
     * @param password 密码
     * @return AppResult
     */
    @ApiOperation("⽤⼾登录")
    @PostMapping("/login")
    public AppResult login (HttpServletRequest request,
                            @ApiParam(value = "用户名") @RequestParam(value = "username") @NonNull String username,
                            @ApiParam(value = "密码") @RequestParam(value = "password") @NonNull String password) {
        // 调用 Service
        User user = userService.login(username, password);
        // 在 session 中保存当前登录的用户信息
        // 1. 获取 session 对象
        HttpSession session = request.getSession(true);
        // 2. 把用户信息保存在 session 中
        session.setAttribute(AppConfig.SESSION_USER_KEY, user);
        // 登录成功响应
        return AppResult.success("登录成功");
    }
启动程序,访问 API 页面 login 接口,分别提交错误和正确的用户名密码进行测试:
登录失败:

 登陆成功:

7. 实现前端

完整的前端代码:forum: 论坛项目 - Gitee.com

// 构造数据
        let postData = {
          username : $('#username').val(),
          password : $('#password').val()
        };
        // 发送AJAX请求,成功后跳转到index.html
        $.ajax({
          // 请求的方法类型
          type : 'POST',
          // API 的 URL
          url : 'user/login',
          //数据格式
          contentType : 'application/x-www-form-urlencoded',
          // 提交的数据
          data : postData,
          // 成功回调
          success : function(respData) {
          // ⽤状态码判断是否成功
            if (respData.code == 0) {
              // 成功
              location.assign('index.html');
            } else {
            // 失败
            $.toast({
              heading : '警告',
              text : respData.message,
              icon : 'Warning'
            });
           }
          },
          // 失败(HTTP)
          error: function() {
            $.toast({
              heading : '错误',
              text : '出错了,请联系管理员',
              icon : 'error'
            });
          }
        });
      });

登录后的界面如下: 


以上即为登录功能的实现,接下来在下篇博客中我们将实现在上面登录进去的界面中进行退出。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python办公自动化】PysimpleGUI中更新Listbox组件选定元素的格式

pysimplegui中更新Listbox组件选定元素的格式 背景问题解决创建窗口布局创建窗口背景 在进行打分时候,由于打分的指标较多,因此为了辨别已经打完分数的指标,可以考虑对打过分的指标进行标记,故可以采用格式修改的方法调整,比如添加一些特殊标记 问题解决 import PySim…

K8S应用笔记 —— 部署Dolphinscheduler及简单应用(一)

一、Dolphinscheduler简介 Apache DolphinScheduler 是一个分布式易扩展的可视化DAG工作流任务调度开源系统。适用于企业级场景&#xff0c;提供了一个可视化操作任务、工作流和全生命周期数据处理过程的解决方案。 Apache DolphinScheduler 旨在解决复杂的大数据任务依赖关系…

SpringBoot 基础篇

SpringBooot基本配置 Web容器基本配置 学习了SpringBoot框架之后&#xff0c;我们了解到SpringBoot内嵌了 Tomcat、Jetty、Undertow 三种容器&#xff0c;其默认嵌入的容器是 Tomcat&#xff0c;这个在我们启动 Spring Boot 项目的时候&#xff0c;在控制台上就能看到&#x…

使用 EasyExcel 实现 百万级数据导入导出

前言 在项目开发中往往需要使用到数据的导入和导出&#xff0c;导入就是从Excel中导入到DB中&#xff0c;而导出就是从DB中查询数据然后使用POI写到Excel上。 大数据的导入和导出&#xff0c;相信大家在日常的开发、面试中都会遇到。 很多问题只要这一次解决了&#xff0c;总…

调整数组使奇数全部都位于偶数前面

题目内容&#xff1a; 输入一个整数数组&#xff0c;实现一个函数&#xff0c; 来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分&#xff0c; 所有偶数位于数组的后半部分。 题目思路&#xff1a; 将奇数部分放在前半部分&#xff0c;偶数部分放在后半部分&am…

PySpark-核心编程

2. PySpark——RDD编程入门 文章目录 2. PySpark——RDD编程入门2.1 程序执行入口SparkContext对象2.2 RDD的创建2.2.1 并行化创建2.2.2 获取RDD分区数2.2.3 读取文件创建 2.3 RDD算子2.4 常用Transformation算子2.4.1 map算子2.4.2 flatMap算子2.4.3 reduceByKey算子2.4.4 Wor…

手把手教你制作印刷包装小程序商城

印刷包装行业越来越受到人们的重视&#xff0c;为了更好地满足消费者的需求&#xff0c;搭建一个专属的小程序商城是一种不错的选择。那么&#xff0c;接下来就让我们一起来学习如何搭建印刷包装小程序商城吧&#xff01; 第一步&#xff1a;登录【乔拓云】网后台&#xff0c;进…

学习笔记230818---对于promise失败状态处理的重要性

问题描述&#xff1a; 在项目中经常会出现如上的问题&#xff0c;这是因为&#xff0c;用promise封装的接口或第三方组件方法&#xff0c;如果只对成功的状态做处理&#xff0c;就会造成页面出错&#xff0c;报error。 解决方法 then()的末尾加上.catch(()>{})对失败的状态…

3.小程序的通信模型

通信主体 小程序中通信的主体是渲染层和逻辑层&#xff0c;其中&#xff1a; xxx.scss和xxx.wxml是渲染层 xxx.ts是逻辑层 通信模型 小程序的通信模型发为两部分&#xff1a; 渲染层和逻辑层之间的通信由微信客户端进行转发 逻辑层和第三方服务器之前的通信由微信客户端进行…

Maven介绍_下载_安装_使用_原理

文章目录 1 Maven介绍1.1 Maven是介绍1.2 Maven的作用 2 Maven下载与安装2.1 官网下载2.2 文件目录2.3 环境配置 3 Maven基础概念3.1 仓库分类3.2 依赖坐标3.3 坐标组成 4 Maven配置4.1 本地仓库配置4.2 远程仓库的设置4.3 镜像仓库配置4.4 IDEA配置Maven 5 Maven项目创建5.1 M…

robotframework如何做接口测试?

robotframework(后续简称为robot)是一款自动化测试框架&#xff0c;可能做各种类型的自动化测试。 本文介绍通过robotframework来做接口测试。 在robot当中&#xff0c;python语言的接口测试库名称为RequestsLibrary 安装语法如下&#xff1a; pip install -U requests pip …

AP5414 DC-DC升压恒流 升降压电源驱动IC

产品简介 AP5414 是一种输入电压范围宽&#xff08;0.8~5.5V&#xff09;&#xff0c;可调恒定电流和限定电流两种模式来 驱动白光 LED 而设计的升压型 DC/DC 变换器。该器件能利用单节或双节干电池驱动单 颗大功率白光 LED&#xff0c;同样可以利用一节锂电池驱动两颗、三颗…

基于Opencv的虚拟拖拽项目

预备知识 勾股定理 跟随移动算法 手势识别图解 项目源代码 """ 演示一个简单的虚拟拖拽 步骤&#xff1a; 1、opencv 读取视频流 2、在视频图像上画一个方块 3、通过mediapipe库获取手指关节坐标 4、判断手指是否在方块上 5、是&#xff0c;方块跟着移动 6、…

天津报web前端培训班一定要选贵的吗?

根据这几年数据显示&#xff0c;IT行业飞速发展&#xff0c;岗位需求增多&#xff0c;Web前端是个很新的职业&#xff0c;在国内乃至国际上真正开始受到重视的时间不超过五年&#xff0c;Web前端开发是从网页制作演变而来&#xff0c;名称是有很明显的时代特性。 Web前端就业形…

腾讯大佬用了8小时讲完的Python,整整315集,拿走不谢!

Python在近几年越来越受追捧&#xff0c;很多童鞋或者职场小伙伴想要提升技能-学习Python。 这是非常好的事情&#xff0c;但问题在于很多人不知道学Python做什么&#xff0c;所以什么零碎细末、艰难晦涩、长篇大论的都去看&#xff0c;很容易陷入学不下去的困境。必须要有针对…

C++笔记之std::move和右值引用的关系、以及移动语义

C笔记之std::move和右值引用的关系、以及移动语义 code review! 文章目录 C笔记之std::move和右值引用的关系、以及移动语义1.一个使用std::move的最简单C例子2.std::move 和 T&& reference_name expression;对比3.右值引用和常规引用的经典对比——移动语义和拷贝语…

基础数学问题

目录 P1143 进制转换 P1100 高低位交换 P1866 编号 P3913 车的攻击 P3383 【模板】线性筛素数 P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题 P1572 计算分数 P4057 [Code#1] 晨跑 P2651 添加括号III P2660 zzc 种田 P1403 [AHOI2005] 约数研究 P1469 找筷子 …

未来网络的选择:100G光模块与400G光模块的对比

随着互联网的快速发展和数据传输需求的不断增长&#xff0c;光通信技术在网络领域中扮演着至关重要的角色。光模块是光通信系统中的核心组件之一&#xff0c;而100G光模块和400G光模块是目前应用广泛的两种主要类型。本文将对这两种光模块进行详细的区别对比。 一、传输速率 …

亿级短视频,如何架构?

说在前面 在尼恩的&#xff08;50&#xff09;读者社群中&#xff0c;经常指导大家面试架构&#xff0c;拿高端offer。 前几天&#xff0c;指导一个年薪100W小伙伴&#xff0c;拿到字节面试邀请。 遇到一个 非常、非常高频的一个面试题&#xff0c;但是很不好回答&#xff0…

Python3的print用法

目录 一&#xff1a;print语法 二&#xff1a;print结尾参数end用法 三&#xff1a;print分隔符参数sep用法 四&#xff1a;print固定宽度字符输出 一&#xff1a;print语法 print(*objects, sep , end\n, filesys.stdout, flushFalse) 参数解释&#xff1a; &q…