项目设计之用户注册与登录

流程

表设计

create table if not exists kanyuServer.user_db
(id bigint unsigned auto_increment comment '主键'primary key,phone varchar(11) not null comment '手机号码',password varchar(128) default '' null comment '密码,加密存储',user_name varchar(32) default '' null comment '昵称,默认是用户id',create_time timestamp default CURRENT_TIMESTAMP not null comment '创建时间',update_time timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',constraint uniqe_key_phoneunique (phone)
);

功能设计

用户注册功能

用户注册的流程如下

1,用户输入手机号和名称

2,后端校验是否注册过

3,数据库插入数据

代码

用户实体类

package com.kanyuServer.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;import java.io.Serializable;
import java.time.LocalDateTime;@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("user_db")
public class User implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Long id;/*** 手机号码*/private String phone;/*** 密码,需加密存储*/private String password;/*** 昵称,默认是随机字符*/private String userName;/*** 创建时间*/private LocalDateTime createTime;/*** 更新时间*/private LocalDateTime updateTime;}

注册控制器

package com.kanyuServer.controller;import cn.hutool.json.JSON;
import com.kanyuServer.common.Result;
import com.kanyuServer.dto.RegisterForm;
import com.kanyuServer.entity.User;
import com.kanyuServer.service.LoginService;
import com.kanyuServer.service.RegisterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpSession;/*** 登录控制器*/
@Slf4j
@RestController
@RequestMapping("/register")
public class RegisterController {@ResourceRegisterService registerService;@PostMapping("user")public Result sendCode(@RequestBody RegisterForm registerForm, HttpSession session) {//打印日志log.info("用户注册信息"+ registerForm.toString());Result result = registerService.register(registerForm,session);return result;}}

mapper

package com.kanyuServer.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kanyuServer.entity.User;public interface UserMapper extends BaseMapper<User> {
}

service

package com.kanyuServer.service.impl;import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kanyuServer.common.Result;
import com.kanyuServer.dto.RegisterForm;
import com.kanyuServer.entity.User;
import com.kanyuServer.mapper.UserMapper;
import com.kanyuServer.service.LoginService;
import com.kanyuServer.service.RegisterService;
import com.kanyuServer.utils.Validate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.kanyuServer.utils.PasswordUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;import static com.kanyuServer.constant.RedisConstants.LOGIN_CODE_KEY;
import static com.kanyuServer.constant.RedisConstants.LOGIN_CODE_TTL;
import static com.kanyuServer.constant.ResponseConstant.*;@Slf4j
@Service
public class RegistererviceImpl extends ServiceImpl<UserMapper, User> implements RegisterService {//引入redis工具类@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result register(RegisterForm registerForm, HttpSession session) {// 1.校验手机号String phone = registerForm.getPhone();if (Validate.isPhoneInvalid(phone)) {// 2.如果不符合,返回错误信息return Result.fail("手机号格式错误!",400);}User user_query = query().eq("phone", phone).one();if (user_query!=null){return Result.fail("用户已注册过,请登录",400);}registerForm.setPassword(PasswordUtil.hashPassword(registerForm.getPassword()));User user = new User();user.setPassword(registerForm.getPassword());user.setUserName(registerForm.getUserName());user.setPhone(registerForm.getPhone());save(user);return Result.ok();}
}

用户登录功能

密码登录

@Overridepublic Result loginWithPassward(LoginForm loginForm, HttpSession session) {// 1.校验手机号String phone = loginForm.getPhone();if (Validate.isPhoneInvalid(phone)) {// 2.如果不符合,返回错误信息return Result.fail("手机号格式错误!",400);}User user = query().eq("phone", loginForm.getPhone()).one();if (user==null){//返回用户不存在 这里预期进入注册网页return Result.fail(USER_NOT_FOUND,USER_NOT_FOUNT_CODE);}//校验密码是否正确 这里直接对比原始的密码与加密的密码是否相同boolean flag = PasswordUtil.checkPassword(loginForm.getPassword(),user.getPassword());//不正确if (!flag){return Result.fail(USER_PASSWORD_NOT_CORRECT,USER_PASSWORD_NOT_CORRECT_CODE);}// 保存用户信息到 redis中// 随机生成token,作为登录令牌String token = UUID.randomUUID().toString(true);// 将User对象转为HashMap存储LoginForm loginForm1 = BeanUtil.copyProperties(user, LoginForm.class);System.out.println(loginForm1);log.info(loginForm1.toString());loginForm1.setCode("");Map<String, Object> userMap = BeanUtil.beanToMap(loginForm1, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));// 存储String tokenKey = LOGIN_USER_KEY + token;stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);// 设置token有效期stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);Map<String,Object> result = new HashMap<>();result.put("token",token);result.put("user",user);//返回tokenreturn Result.ok(result);}

验证码登录

@Overridepublic Result loginWithCode(LoginForm loginForm, HttpSession session) {//校验手机号String phone = loginForm.getPhone();if (Validate.isPhoneInvalid(phone)) {// 如果不符合,返回错误信息return Result.fail("手机号格式错误!",400);}//获取验证码String code = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + loginForm.getPhone());String code_user = loginForm.getCode();//redis拿不到相关验证码,说明过期或者手机号不存在if (code==null){return Result.fail(USER_NOT_FOUND,USER_NOT_FOUNT_CODE);}//redis保存的验证码与输入的验证码不匹配if (!code.equals(code_user)){return Result.fail(CODE_NOT_MATCH,CODE_NOT_MATCH_OCDE);}User user = query().eq("phone", loginForm.getPhone()).one();log.info("user");log.info(user.toString());if (user==null){//返回用户不存在 这里预期进入注册网页return Result.fail(USER_NOT_FOUND,USER_NOT_FOUNT_CODE);}// 保存用户信息到 redis中// 随机生成token,作为登录令牌String token = UUID.randomUUID().toString(true);// 将User对象转为HashMap存储LoginForm loginForm1 = BeanUtil.copyProperties(user, LoginForm.class);log.info("loginForm1");log.info(loginForm1.toString());loginForm1.setCode("");//把null置为""空字符串类型Map<String, Object> userMap = BeanUtil.beanToMap(loginForm1, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));// 存储String tokenKey = LOGIN_USER_KEY + token;log.info(userMap.toString());stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);//设置token有效期stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);//返回tokenreturn Result.ok(token);}

验证码的详细redis实现可以参考我之前的这边文章

redis实际开发应用简单实现-CSDN博客

接口

注册

http://localhost:8081/register/user

入参

{"userName":"t","phone":13689663339,"password":3
}

密码登录

http://localhost:8081/user/login

入参

{"phone":13610137901,"password":3
}

发送验证码

http://localhost:8081/user/code?phone=13610197901

路径参数phone

验证码登录

http://localhost:8081/user/login/code

入参

{"phone":13610137901,"password":3
}

已开源 可下载

可以帮点个star呗,感谢

GitHub - enjoykanyu/kanyu_server: 网站后端服务

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

贪吃蛇身匀速运动模型

通用运动模型 我们已知斜线为移动的距离 d d d&#xff0c; x x x轴总偏移量为 d x dx dx&#xff0c; y y y轴总偏移量为 d y dy dy&#xff0c;在一帧当中&#xff0c;我们也知道能走的距离为 m d md md。那么作为一般的运动模型&#xff0c;该如何确定我们进行移动的方向呢&…

项目管理工具 Maven

目录 1.Maven的概念 1.1​​​​​什么是Maven 1.2什么是依赖管理 1.3什么是项目构建 1.4Maven的应用场景 1.5为什么使用Maven 1.6Maven模型 2.初识Maven 2.1Maven安装 2.1.1安装准备 2.1.2Maven安装目录分析 2.1.3Maven的环境变量 2.2Maven的第一个项目 2.2.1按照约…

SSM架构 +Nginx+FFmpeg实现rtsp流转hls流,在前端html上实现视频播放

序言&#xff1a; 本文介绍通过SSM架构 NginxFFmpeg实现rtsp流转hls流&#xff0c;在前端html上实现视频播放功能。此方法可用于网络摄像头RTSP视频流WEB端实时播放。&#xff08;海康和大华都可以&#xff09;&#xff0c;我使用的是海康 步骤一&#xff1a;安装软件 FFmpeg…

超链接打开新页签传递参数

背景 有一个需求&#xff0c;网站1点击按钮后跳转到页面2&#xff0c;页面1和页面2的域名不同&#xff0c;并且需要传递参数A&#xff0c;再 那么最简单的就是 在url上带参数A 比如 https://xx.com?Axxx &#xff0c;从url上的queryParam上就能获取参数 但很可惜&#xff0c…

【入门级篇】保姆级教程:零基础实现DeepSeek本地部署的两种终极方案(附避坑指南)

关于DeepSeek的革命性冲击的看法 大家好,前阵子在忙着DeepSeek的一些本地化部署和一些开发工具,工作流的工作,最近刚好有空,借助零散时间给大家分享下DeepSeek的一些应用,为此我写了一篇专栏,从浅入深的介绍DeepSeek的一些技术,应用,以及DeepSeek的论文分析。 首先我们…

nginx简单命令启动,关闭等

启动命令 #启动nginx start nginx重启命令 比如修改了配置文件&#xff0c;用这个命令重启生效 #重启nginx nginx -s reload3&#xff0c;查看端口占用 #查看端口占用 netstat -aon4&#xff0c;关闭nginx 如果使用cmd命令窗口启动nginx&#xff0c; 关闭cmd窗口是不能…

强化学习(赵世钰版)-学习笔记(2.状态值与贝尔曼方程)

这是本课程的第二章&#xff0c;讲述状态值与贝尔曼&#xff08;Bellman&#xff09;方程的相关概念。 回报值&#xff08;Return&#xff09;的重要性&#xff1a;计算回报值可以用于评估各策略的优劣&#xff0c;可以量化分析。 回报值的计算方法&#xff1a;设Vi为某策略下起…

STM32——定时器

定时器有 捕获脉冲宽度、计算PWM占空比、输出PWM波形以及编码器计数等各种功能。 定时器又能分为 基本定时器&#xff1a;TIM6和TIM7通用定时器&#xff1a;TIM2、TIM3、TIM4和TIM5高级定时器&#xff1a;TIM1、TIM8 一、计数和分频 每当一个方波信号的上升沿经过寄存器&…

链表双指针经典习题

链表双指针经典习题 链表的分解删除排序链表中的重复元素2&#xff08;重复元素彻底删除&#xff09;方法一&#xff1a;分解链表方式二&#xff1a;快慢指针递归解法 链表的合并丑数2有序矩阵中第k小的元素查找和最小的k对数字两数相加两数相加2 回文单链表回文链表 迭代和递归…

2025年主流原型工具测评:墨刀、Axure、Figma、Sketch

2025年主流原型工具测评&#xff1a;墨刀、Axure、Figma、Sketch 要说2025年国内产品经理使用的主流原型设计工具&#xff0c;当然是墨刀、Axure、Figma和Sketch了&#xff0c;但是很多刚入行的产品经理不了解自己适合哪些工具&#xff0c;本文将从核心优势、局限短板、协作能…

RISC-V双核锁步高性能抗辐照MCU芯片技术解析与应用

1. 概念名词解析 安全冗余设计 AS32X601系列通过硬件ECC&#xff08;Error Correction Code&#xff09;保护存储系统&#xff08;内置SRAM、Flash等&#xff09;&#xff0c;并在DMA模块中提供“可选的双核锁步安全备份”机制&#xff0c;支持高可靠性场景下的数据传输容错。…

2024爱分析·央国企数字化应用实践报告

报告综述“央国企KPI”驱动央国企数字化投入稳中有进 在民营企业推进数字化转型的过程中&#xff0c;其核心驱动力往往聚焦于降本增效与开源节流。然而&#xff0c;对于央国企而言&#xff0c;尽管降本增效等因素亦在其考量范围之内&#xff0c;但其推进数字化转型的根本动因则…

Kubernetes 的正式安装

1.基础的网络结构说明 软件路由器 ikuai 当然同一个仅主机模式 相当于在 同一个我们所谓的广播域内 所以相当于它们的几张网卡 是被连接起来的 为了防止出现问题 我们可以把第二块网卡临时关闭一下 2.准备路由器 ikuai 爱快 iKuai-商业场景网络解决方案提供商 (ikuai8.com)…

OpenCV计算摄影学(18)平滑图像中的纹理区域同时保留边缘信息函数textureFlattening()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::textureFlattening 是 OpenCV 中用于图像处理的一个函数&#xff0c;旨在平滑图像中的纹理区域&#xff0c;同时保留边缘信息。该技术特别适…

关于eMMC存储器在各种情况下的分区编号和名字的问题

前言 关于eMMC的分区编号和名字问题&#xff0c;表面上看是个小问题&#xff0c;事实上在程序开发中&#xff0c;没有小问题&#xff0c;一个变量值设置不对&#xff0c;可能整个程序或系统就跑不起来。eMMC的分区编号和名字问题就是一个事关嵌入式系统烧写和正常启动的关键问…

nuxt2-vue2:通过编程方式调用对话框 el-dialog

一、背景 1.1、需求 项目&#xff1a;nuxt2 vue2 希望通过编程方式的调用打开对话框&#xff0c;展现我们想要的内容。 1.2、效果 二、代码 2.1、插件 plugins/dialog.js import Vue from vue; import { Dialog } from element-ui; // 本文使用了Dialog组件&#xff0c;…

记录一些面试遇到的问题

重载和重写的区别 重载是overload&#xff0c;覆盖是override 重载属于编译时多态&#xff0c;覆盖属于运行时多态 运行时多态和编译时多态 运行时多态指的是在运行的时候才知道要调用哪一个函数&#xff0c;编译时多态是指在编译的时候就知道调用哪一个函数。 运行时多态…

【为什么会有 map、weakmap 类型?】

为什么会有 map、weakmap 类型? 传统对象的局限性催生 Map‌1. 键类型单一性‌2. 有序性与迭代支持‌3. 性能优化场景‌ 内存管理需求催生 WeakMap‌1.弱引用机制‌2. 私有数据存储‌3. 规避循环引用问题‌ 总结 传统对象的局限性催生 Map‌ 1. 键类型单一性‌ 传统对象&…

Django下防御Race Condition

目录 漏洞原因 环境搭建 复现 A.无锁无事务时的竞争攻击 B.无锁有事务时的竞争攻击 防御 A.悲观锁加事务防御 B.乐观锁加事务防御 总结 漏洞原因 Race Condition 发生在多个执行实体&#xff08;如线程、进程&#xff09;同时访问共享资源时&#xff0c;由于执行顺序…

课题推荐——无人机在UWB环境下基于TOA/TDOA/AOA的室内定位与精度对比

随着无人机在工业检测、仓储物流、应急救援等室内场景的广泛应用&#xff0c;高精度室内定位技术成为关键支撑。超宽带&#xff08;UWB&#xff09;技术凭借其高时间分辨率、强抗多径能力等优势&#xff0c;成为室内定位的主流方案。然而&#xff0c;不同的定位方法&#xff08…