【基于SprintBoot+Mybatis+Mysql】电脑商城项目之用户登录
🧸安清h:个人主页
🎥个人专栏:【Spring篇】【计算机网络】【Mybatis篇】
🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。

目录
🎯1.登录-持久层
🚦1.1规划需要执行的SQL语句
🚦1.2接口设计和抽象方法
🎯2.登录-业务层
🚦2.1规划异常
✨1.密码匹配失败异常
✨2.用户名没有被找到
✨3.异常的编写
🚦2.2设计业务层接口和抽象方法
🚦2.3抽象方法实现
🎯3.登录-控制层
🚦3.1处理异常
🚦3.2设计请求
🚦3.3处理请求
🎯4.登录-前端页面
🎯用户会话Session
🎯拦截器
当用户输入用户名和密码将数据提交给后台数据库进行查询,如果存在对应的用户名和密码则表示登录成功,登录成功之后跳转到系统的主页,就是index.html页面,跳转在前端使用jquery来完成。
🎯1.登录-持久层
🚦1.1规划需要执行的SQL语句
依据用户提交的用户名和密码做select查询。密码的比较在业务层执行。
select * from t_user where username=?
注意:如果在分析过程中发现某个功能模块已经被开发完成,所以就可以省略当前的开发步骤,这个分析过程不能够省略。 这个功能模块在用户注册部分已经实现过,所以在此无需重复进行了。
🚦1.2接口设计和抽象方法
不用重复开发。单元测试也无需单独执行了。
🎯2.登录-业务层
🚦2.1规划异常
✨1.密码匹配失败异常
用户名对应的密码错误:PasswordNotMatchExcepption异常,运行时异常,业务层异常。
//密码验证失败的异常
public class PasswordNotMatchException extends ServiceException{public PasswordNotMatchException() {super();}public PasswordNotMatchException(String message) {super(message);}public PasswordNotMatchException(String message, Throwable cause) {super(message, cause);}public PasswordNotMatchException(Throwable cause) {super(cause);}protected PasswordNotMatchException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}
}
✨2.用户名没有被找到
抛出异常:UsernameNotFoundException异常,运行时异常,业务层异常。
//用户数据不存在的异常
public class UserNotFoundException extends ServiceException{public UserNotFoundException() {super();}public UserNotFoundException(String message) {super(message);}public UserNotFoundException(String message, Throwable cause) {super(message, cause);}public UserNotFoundException(Throwable cause) {super(cause);}protected UserNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}
}
✨3.异常的编写
- 业务层异常需要继承ServiceException异常类。
- 在具体的异常类中定义构造方法(可以使用快捷键来生成,有5个构造方法)。
🚦2.2设计业务层接口和抽象方法
1.直接在IUserService接口中编写抽象方法,login(String username,String password)。将当前登录成功的用户数据以当前用户对象的形式进行返回。状态管理:可以将数据保存在cookie或者session中,可以避免重复度很高的数据多次频繁操作数据进行获取(用户名、用户id-存放在session中,用户的头像保存在cookie中,而cookie存储在了客户端上)。
//用户模块业务层接口
public interface IUserService {void reg(User user);
// 用户登录功能
// @param username 用户名
// @param password 用户的密码
// @return 当前匹配的用户数据,如果没有则返回null值User login(String username,String password);
}
🚦2.3抽象方法实现
1.需要在实现类中实现父接口的抽象方法。
@Overridepublic User login(String username, String password) {
//根据用户名称查询用户的数据是否存在,如果不在则抛出异常User result=userMapper.findByUsername(username);if(result == null){throw new UserNotFoundException("用户数据不存在");}
// 检测用户密码是否匹配
// 1.先获取到数据库中的加密之后的密码String oldPassword = result.getPassword();
// 2.和用户传递过来的密码进行比较
// 2.1先获取盐值:上一次注册时自动生成的盐值String salt=result.getSalt();
// 2.2将用户的密码按照相同的md5算法的规则进行加密String newMd5Password = getMD5Password(password,salt);
// 3.将密码进行比较if(!newMd5Password.equals(oldPassword)){throw new PasswordNotMatchException("用户密码错误");}// 判断is_delete字段值是否为1,为1表示被标记删除if(result.getIsDelete()==1){throw new UserNotFoundException("用户数据不存在");}// 调用mapper层的findByUsername来查询用户的数据,提升了系统的性能User user = new User();user.setUid(result.getUid());user.setUsername(result.getUsername());user.setAvatar(result.getAvatar());
// 将当前的用户数据返回,返回的数据是为了辅助其他页面做数据展示使用的(uid,username,avatar)return user;}
2.在测试类中测试业务层登录的方法是否可以执行通过。 在test-service-UserServiceTests中编写如下代码:
@Testpublic void login(){User user = userService.login("test01","123");System.out.println(user);}
3.如果一个类没有手动创建,直接将这个类复制到项目,idea找不到这个类。之前的缓存导致不能够正常的找到这类的符号。重新构建项目即可。Build->rebuild。
🎯3.登录-控制层
🚦3.1处理异常
业务层抛出的异常是什么,需要在统一的异常处理类中进行统一的捕获和处理,如果也曾抛出的异常已经在统一异常处理类中曾经处理过,则不需要重复添加。在BaseController类中添加如下代码:
else if(e instanceof UserNotFoundException){result.setState(5001);result.setMessage("用户数据不存在的异常");}else if(e instanceof PasswordNotMatchException){result.setState(5002);result.setMessage("用户密码错误的异常");}
🚦3.2设计请求
请求路径:/users/login
请求方式:POST
请求数据:String username,String password,HttpSession session
响应结果:JsonResult<User>
🚦3.3处理请求
在UserController类中编写处理请求的方法。
// 约定大于配置:开发思想来完成,省略大量的配置甚至注解编写// 1.接收数据方式:请求处理方法的参数列表设置为pojo类型来接受前端的数据,
// SpringBoot会将前端的url地址中的参数名和pojo类的属性名进行比较,
// 如果这两个名称相同,则将值注入到pojo类中对应的属性上// 2.接收数据方式:请求处理方法的参数列表设置为非pojo类型(本例中为String类型),
// SpringBoot会直接将请求的参数名和方法的参数名直接进行比较,
// 如果名称相同则自动完成值的依赖注入@RequestMapping("login")public JsonResult<User> login(String username,String password){User data = userService.login(username,password);return new JsonResult<User>(OK,data);}
}
🎯4.登录-前端页面
1.在login.html页面中依据前面所设置的请求来发送ajax请求。
<script>$("#btn-login").click(function (){$.ajax({url:"/users/login",type:"POST",data:$("#form-login").serialize(),dataType:"JSON",success:function (json){if(json.state==200){alert("登录成功");// 跳转到系统主页// 相对路径来确定跳转的页面location.href="index.html";}else{alert("登录失败");}},error:function (xhr){alert("登录时产生未知的异常"+xhr.message);}});});</script>
2.如果跳转不了,rebuild项目。
🎯用户会话Session
session对象主要存在服务器端,可以用于保存服务器的临时数据的对象,所保存的数据可以在整个项目中都可以通过访问来获取,把session中的数据看做一个共享的数据。首次登录的时候所获取到的用户数据,转移到session对象即可。session.getAttrbute("key")可以将获取session中的数据这种行为进行封装,封装在BaseController类中。
1.封装session对象中数据的获取(封装在父类中),数据的设置(当用户登录成功后进行数据的设置,设置到全局的session对象中)。
2.在父类中封装两个数据:获取uid和获取username对应的两个方法。用户头像暂时不考虑,将来封装在cookie中来使用。
// 方法不需要被修改,用final来修饰
// 获取session对象中的uid
// @param session session对象
// @return 当前登录的用户uid的值protected final Integer getuidFromSession(HttpSession session){return Integer.valueOf(session.getAttribute("uid").toString());}// 获取当前登录用户的username
// @param session session对象
// @return 当前登录用户的用户名protected final String getUsernameFromSession(HttpSession session){
// getAttribute返回的类型是object,所以加上toString转换成字符串return session.getAttribute("username").toString();}
3.在登录的方法中将数据封装在session对象中。服务本身自动创建有session对象,已经是一个全局的session对象。SpringBoot直接使用session对象,直接将HttpSession类型的对象做为请求处理方法的参数,会自动将全局的session对象注入到请求处理方法的session形参上。
@RequestMapping("login")public JsonResult<User> login(String username,String password,HttpSession session){User data = userService.login(username,password);
// 向session对象中完成数据的绑定(session全局的)session.setAttribute("uid",data.getUid());session.setAttribute("username",data.getUsername());
// 获取session中绑定的数据System.out.println(getuidFromSession(session));System.out.println(getUsernameFromSession(session));return new JsonResult<User>(OK,data);}
🎯拦截器
首先将所有的请求统一拦截到拦截器中,可以在拦截器中来定义过滤的规则,如果不满足系统的设置的过滤规则,统一的处理是重新去打开login.html页面(重定向和转发),推荐使用重定向。
在SpringBoot项目中拦截器的定义和使用。SpringBoot是依靠SPringMVC来完成的。SpringMVC提供了一个HandlerInterceptor接口,用于表示定义一个拦截器。受限制自定义个类,在这个类实现这个接口。
1.首先自定义一个类,在这个类实现HandlerInterceptor接口。
2.注册过滤器:添加白名单(哪些资源可以在不登录的情况下访问:login.html/register.html/login/reg/index.html/product.html),添加黑名单(在用户登录状态下才可以访问的页面资源)。
3.注册过滤器的技术:借助WebMvcConfigure接口,可以将用户定义的拦截器进行注册,注册后才可以保证拦截器能够生效和使用。定义一个类,然后让这个类实现WebMvcConfigure接口。配置信息,建议存放在项目的config包结构下。
//处理器拦截器的注册
@Configuration //加载当前的拦截器并进行注册
public class LoginInterceptorConfigurer implements WebMvcConfigurer {// 配置拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 创建自定义拦截器对象HandlerInterceptor interceptor = new LoginInterceptor();
// 配置白名单;存放在List集合中List<String> patterns = new ArrayList<>();patterns.add("/bootstrap3/**");patterns.add("/css/**");patterns.add("/images/**");patterns.add("/js/**");patterns.add("/web/register.html");patterns.add("/web/login.html");patterns.add("/web/index.html");patterns.add("/web/product.html");patterns.add("/users/reg");patterns.add("/users/login");// 拦截器的注册registry.addInterceptor(interceptor).addPathPatterns("/**") //表示要拦截的url是什么.excludePathPatterns(patterns); //除了哪些路径之外}
}
4.如果短时间内多次访问,会提示重定向次数过多,login.html页面无法打开。将浏览器cookie请求,再将浏览器设置为初始设置。
解释:
//将自定义拦截器进行注册 default void addInterceptors(InterceptorRegistry registry) {}
源码解析:
public interface HandlerInterceptor {
//在调用所有处理请求的方法之前被自动调用执行的方法default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}
//在ModelAndView对象返回之后被调用的方法default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}
//在整个请求所有关联的资源被执行完毕最后所执行的方法default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}
相关文章:
【基于SprintBoot+Mybatis+Mysql】电脑商城项目之用户登录
🧸安清h:个人主页 🎥个人专栏:【Spring篇】【计算机网络】【Mybatis篇】 🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。 目录 🎯1.登录-持久层 &…...
【Deep Seek本地化部署】模型实测:规划求解python代码
目录 前言 一、实测 1、整数规划问题 2、非线性规划问题 二、代码正确性验证 1、整数规划问题代码验证 2、非线性规划问题代码验证 三、结果正确性验证 1、整数规划问题结果正确性验证 2、非线性规划问题正确性验证 四、整数规划问题示例 后记 前言 模型ÿ…...
虚幻基础17:动画蓝图
能帮到你的话,就给个赞吧 😘 文章目录 animation blueprint图表(Graph): 编辑动画逻辑。变量(Variables): 管理动画参数。函数(Functions): 自定义…...
【游戏设计原理】98 - 时间膨胀
从上文中,我们可以得到以下几个启示: 游戏设计的核心目标是让玩家感到“时间飞逝” 游戏的成功与否,往往取决于玩家的沉浸感。如果玩家能够完全投入游戏并感受到时间飞逝,说明游戏设计在玩法、挑战、叙事等方面达到了吸引人的平衡…...
C语言基础系列【1】第一个C程序:Hello, World!
C语言的历史与特点 历史背景 C语言起源于20世纪70年代,最初是由美国贝尔实验室的Dennis Ritchie和Ken Thompson为了开发UNIX操作系统而设计的一种编程语言。在UNIX系统的开发过程中,他们发现原有的B语言(由Thompson设计)在功能和…...
【LLM】DeepSeek-R1-Distill-Qwen-7B部署和open webui
note DeepSeek-R1-Distill-Qwen-7B 的测试效果很惊艳,CoT 过程可圈可点,25 年应该值得探索更多端侧的硬件机会。 文章目录 note一、下载 Ollama二、下载 Docker三、下载模型四、部署 open webui 一、下载 Ollama 访问 Ollama 的官方网站 https://ollam…...
go-zero学习笔记(三)
利用goctl生成rpc服务 编写proto文件 // 声明 proto 使用的语法版本 syntax "proto3";// proto 包名 package demoRpc;// golang 包名(可选) option go_package "./demo";// 如需为 .proto 文件添加注释,请使用 C/C 样式的 // 和 /* ... */…...
C# 修改项目类型 应用程序程序改类库
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
普罗米修斯监控服务搭建位置全解析:权衡与抉择
在数字化时代,监控系统对于企业的稳定运营和业务发展至关重要。普罗米修斯作为一款备受青睐的开源监控和告警工具,其搭建位置的决策绝非小事,它紧密关联着监控系统的性能、可靠性与安全性,如同为整座大厦奠定基石。接下来…...
为什么“记住密码”适合持久化?
✅ 特性 1:应用重启后仍需生效 记住密码的本质是长期存储用户的登录凭证(如用户名、密码、JWT Token),即使用户关闭应用、重启设备,仍然可以自动登录。持久化存储方案: React Native 推荐使用 AsyncStorag…...
地址查询API接口:高效查询地址信息,提升数据处理效率
地址查询各省市区API接口 地址查询是我们日常生活中经常遇到的一个需求,无论是在物流配送、地图导航还是社交网络等应用中,都需要通过地址来获取地理位置信息。为了满足这个需求,我们可以使用地址查询API接口来高效查询地址信息,提…...
2021版小程序开发5——小程序项目开发实践(1)
2021版小程序开发5——小程序项目开发实践(1) 学习笔记 2025 使用uni-app开发一个电商项目; Hbuidler 首选uni-app官方推荐工具:https://www.dcloud.io/hbuilderx.htmlhttps://dev.dcloud.net.cn/pages/app/list 微信小程序 管理后台:htt…...
元音字母(模拟)
给定一个由大小写字母、空格和问号组成的字符串。 请你判断字符串中的最后一个字母是否是元音字母。 我们认为元音字母共有 66 个,分别为:AA、EE、II、OO、UU、YY(当然还有它们的小写)。 输入格式 一个由大小写字母、空格和问…...
如何处理 Typecho Joe 主题被抄袭或盗版的问题
在开源社区中,版权保护是一个非常重要的话题。如果你发现自己的主题(如 Joe 主题)被其他主题(如子比主题)抄袭或盗版,你可以采取以下措施来维护自己的权益。 一、确认侵权行为 在采取任何行动之前…...
将markdown文件和LaTex公式转为word
通义千问等大模型生成的回答多数是markdown类型的,需要将他们转为Word文件 一 pypandoc 介绍 1. 项目介绍 pypandoc 是一个用于 pandoc 的轻量级 Python 包装器。pandoc 是一个通用的文档转换工具,支持多种格式的文档转换,如 Markdown、HTM…...
自动化测试框架搭建-封装requests-优化
目的 1、实际的使用场景,无法避免的需要区分GET、POST、PUT、PATCH、DELETE等不同的方式请求,以及不同请求的传参方式 2、python中requests中,session.request方法,GET请求,只支持params传递参数 session.request(me…...
Smart contract -- 钱包合约
在区块链的世界里,钱包是存储和管理加密货币的基本工具。今天,我们将通过 Solidity 智能合约来创建一个简单的以太坊钱包。这个钱包将允许用户存入和取出以太坊主币(ETH),并且只有管理员(合约的创建者&…...
模拟实战-用CompletableFuture优化远程RPC调用
实战场景 这是广州某500-900人互联网厂的面试原题 手写并发优化解决思路 我们要调用对方的RPC接口,我们的RPC接口每调用一次对方都会阻塞50ms 但是我们的业务要批量调用RPC,例如我们要批量调用1k次,我们不可能在for循环里面写1k次远程调用…...
图 、图的存储
图的基本概念: 图g由顶点集v和边集e组成,记为g(v,e) 用|v|表示图g中顶点的个数,也称图g的阶,用|e|表示图g中边的条数 线性表可以是空表,树可以是空树,但图不可以是空&…...
快速提升网站收录:利用网站新闻发布功能
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/63.html 利用网站新闻发布功能快速提升网站收录是一个有效的策略。以下是一些具体的建议,帮助你更好地利用这一功能: 一、保持新闻更新频率 搜索引擎尤其重视网站的…...
信息学奥赛一本通 2112:【24CSPJ普及组】地图探险(explore) | 洛谷 P11228 [CSP-J 2024] 地图探险
【题目链接】 ybt 2112:【24CSPJ普及组】地图探险(explore) 洛谷 P11228 [CSP-J 2024] 地图探险 【题目考点】 1. 模拟 2. 二维数组 3. 方向数组 在一个矩阵中,当前位置为(sx, sy),将下一个位置与当前位置横纵坐…...
【数据结构】(4) 线性表 List
一、什么是线性表 线性表就是 n 个相同类型元素的有限序列,每一个元素只有一个前驱和后继(除了第一个和最后一个元素)。 数据结构中,常见的线性表有:顺序表、链表、栈、队列。 二、什么是 List List 是 Java 中的线性…...
YOLO11/ultralytics:环境搭建
前言 人工智能物体识别行业应该已经饱和了吧?或许现在并不是一个好的入行时候。 最近看到了各种各样相关的扩展应用,为了理解它,我不得不去尝试了解一下。 我选择了git里非常受欢迎的yolo系列,并尝试了最新版本YOLO11或者叫它ultr…...
Spring Boot 2 快速教程:WebFlux优缺点及性能分析(四)
WebFlux优缺点 【来源DeepSeek】 Spring WebFlux 是 Spring 框架提供的响应式编程模型,旨在支持非阻塞、异步和高并发的应用场景。其优缺点如下: 优点 高并发与低资源消耗 非阻塞 I/O:基于事件循环模型(如 Netty)&am…...
《OpenCV》——图像透视转换
图像透视转换简介 在 OpenCV 里,图像透视转换属于重要的几何变换,也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。 原理 实现步骤 选取对应点:要在源图像和目标图像上分别找出至少四个对应的点。这些对…...
20250202在Ubuntu22.04下使用Guvcview录像的时候降噪
20250202在Ubuntu22.04下使用Guvcview录像的时候降噪 2025/2/2 21:25 声卡:笔记本电脑的摄像头自带的【USB接口的】麦克风。没有外接3.5mm接口的耳机。 缘起:在安装Ubuntu18.04/20.04系统的笔记本电脑中直接使用Guvcview录像的时候底噪很大! …...
fflush的概念和使用案例
fflush() 是C语言标准库中用于控制输入/输出缓冲区的函数,其主要功能是强制刷新缓冲区,确保数据及时写入目标设备(如屏幕、文件)。以下是其概念和典型使用场景: 概念 功能: 刷新指定流的缓冲区。对于输出流…...
2024年度总结
首先,我是在2023年结束高中生涯进入大学的,难免会有固化的“高中生”思维,我等着老师的安排,看着课表上课,跟着时间吃饭,睡觉,偶尔会熬夜,但整体跟高中没差太多。我对社团没兴趣&…...
The Simulation技术浅析(四):随机数生成
随机数生成技术 是 The Simulation 中的核心组成部分,广泛应用于蒙特卡洛模拟、密码学、统计建模等领域。随机数生成技术主要分为 伪随机数生成器(PRNG,Pseudo-Random Number Generator) 和 真随机数生成器(TRNG,True Random Number Generator)。 1. 伪随机数生成器(PR…...
如何生成强密码:提高网络安全性的全面指南
引言 在数字化时代,密码的安全性至关重要。随着我们在社交媒体、电子邮件、在线银行等平台上储存越来越多的个人信息,强密码的使用变得更加关键。强密码能有效防止暴力破解、字典攻击等安全威胁。因此,在本文中,我们将深入探讨如…...
