【基于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.登录-持久层 &…...

测试方案和测试计划相同点和不同点
在软件测试领域,测试方案与测试计划皆为举足轻重的关键文档,尽管它们有着紧密的关联,但在目的与内容层面存在着显著的差异。相同点: 1.共同目标:测试方案和测试计划的核心目标高度一致,均致力于保障软件的…...

c++提取矩形区域图像的梯度并拟合直线
c提取旋转矩形区域的边缘最强梯度点,并拟合直线 #include <opencv2/opencv.hpp> #include <iostream> #include <vector>using namespace cv; using namespace std;int main() {// 加载图像Mat img imread("image.jpg", IMREAD_GRAYS…...

Unity Shader Graph 2D - 角色身体电流覆盖效果
在游戏中,通常会有游戏角色受到“电击”的效果,此时游戏角色身体上会覆盖有电流,该效果能表明游戏角色的当前状态,让玩家能够获得更直观更好的体验。 那么如何实现呢 首先创建一个ShaderGraph文件,命名为Current,再创建对应的材质球M_Current。 基础的资源显示 老规矩,…...

【LLM-agent】(task4)搜索引擎Agent
note 新增工具:搜索引擎Agent 文章目录 note一、搜索引擎AgentReference 一、搜索引擎Agent import os from dotenv import load_dotenv# 加载环境变量 load_dotenv() # 初始化变量 base_url None chat_model None api_key None# 使用with语句打开文件…...

携程Java开发面试题及参考答案 (200道-下)
insert 一行数据的时候加的是什么锁?为什么? 在 MySQL 中,当执行 INSERT 操作插入一行数据时,加锁的情况会因存储引擎和具体的事务隔离级别而有所不同。一般来说,在 InnoDB 存储引擎下,INSERT 操作加的是行级排他锁(Row Exclusive Lock),以下详细说明原因。 行级排他…...

GWO优化SVM回归预测matlab
灰狼优化算法(Grey Wolf Optimizer,简称 GWO),是由澳大利亚格里菲斯大学的 Mirjalii 等人于 2014 年提出的群智能优化算法。该算法的设计灵感源自灰狼群体的捕食行为,核心思想是对灰狼社会的结构与行为模式进行模仿。 …...

QMK启用摇杆和鼠标按键功能
虽然选择了触摸屏,我仍选择为机械键盘嵌入摇杆模块,这本质上是对"操作连续性"的执着。 值得深思的是,本次开发过程中借助DeepSeek的代码生成与逻辑推理,其展现的能力已然颠覆传统编程范式,需求描述可自动…...

Unity实现按键设置功能代码
一、前言 最近在学习unity2D,想做一个横版过关游戏,需要按键设置功能,让用户可以自定义方向键与攻击键等。 自己写了一个,总结如下。 二、界面效果图 这个是一个csv文件,准备第一列是中文按键说明,第二列…...

基于物联网技术的实时数据流可视化研究(论文+源码)
1系统方案设计 根据系统功能的设计要求,展开基于物联网技术的实时数据流可视化研究设计。如图2.1所示为系统总体设计框图,系统以STM32单片机做为主控制器,通过DHT11、MQ-2、光照传感器实现环境中温湿度、烟雾、光照强度数据的实时检测&#x…...

list容器(详解)
1. list的介绍及使用 1.1 list的介绍(双向循环链表) https://cplusplus.com/reference/list/list/?kwlist(list文档介绍) 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭…...

Elasticsearch基本使用详解
文章目录 Elasticsearch基本使用详解一、引言二、环境搭建1、安装 Elasticsearch2、安装 Kibana(可选) 三、索引操作1、创建索引2、查看索引3、删除索引 四、数据操作1、插入数据2、查询数据(1)简单查询(2)…...

17.3.4 颜色矩阵
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,类似于数组。 由…...

FPGA 时钟多路复用
时钟多路复用 您可以使用并行和级联 BUFGCTRL 的组合构建时钟多路复用器。布局器基于时钟缓存 site 位置可用性查找最佳布局。 如果可能,布局器将 BUFGCTRL 布局在相邻 site 位置中以利用专用级联路径。如无法实现,则布局器将尝试将 BUFGCTRL 从…...

机器学习10
自定义数据集 使用scikit-learn中svm的包实现svm分类 代码 import numpy as np import matplotlib.pyplot as pltclass1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4, 1.1]])class2_points np.array([[3.2, 3.2],[3.7, 2.9],…...

【Block总结】CoT,上下文Transformer注意力|即插即用
一. 论文信息 标题: Contextual Transformer Networks for Visual Recognition论文链接: arXivGitHub链接: https://github.com/JDAI-CV/CoTNet 二. 创新点 上下文Transformer模块(CoT): 提出了CoT模块,能够有效利用输入键之间的上下文信息…...

linux库函数 gettimeofday() localtime的概念和使用案例
在Linux系统中,gettimeofday() 和 localtime() 是两个常用的时间处理函数,分别用于获取高精度时间戳和将时间戳转换为本地时间。以下是它们的概念和使用案例的详细说明: 1. gettimeofday() 函数 概念 功能:获取当前时间…...

编程题-电话号码的字母组合(中等)
题目: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 解法一(哈希表动态添加)&#x…...

EasyExcel使用详解
文章目录 EasyExcel使用详解一、引言二、环境准备与基础配置1、添加依赖2、定义实体类 三、Excel 读取详解1、基础读取2、自定义监听器3、多 Sheet 处理 四、Excel 写入详解1、基础写入2、动态列与复杂表头3、样式与模板填充 五、总结 EasyExcel使用详解 一、引言 EasyExcel 是…...

基于“蘑菇书”的强化学习知识点(二):强化学习中基于策略(Policy-Based)和基于价值(Value-Based)方法的区别
强化学习中基于策略(Policy-Based)和基于价值(Value-Based)方法的区别 摘要强化学习中基于策略(Policy-Based)和基于价值(Value-Based)方法的区别1. 定义与核心思想(1) 基于策略的方…...

民法学学习笔记(个人向) Part.2
民法学学习笔记(个人向) Part.2 民法始终在解决两个生活中的核心问题: 私法自治;交易安全; 3. 自然人 3.4 个体工商户、农村承包经营户 都是特殊的个体经济单位; 3.4.1 个体工商户 是指在法律的允许范围内,依法经…...

物业管理系统源码驱动社区管理革新提升用户满意度与服务效率
内容概要 在当今社会,物业管理正面临着前所未有的挑战,尤其是在社区管理方面。人们对社区安全、环境卫生、设施维护等日常生活需求愈发重视,物业公司必须提升服务质量,以满足居民日益增长的期望。而物业管理系统源码的出现&#…...

租房管理系统助力数字化转型提升租赁服务质量与用户体验
内容概要 随着信息技术的快速发展,租房管理系统正逐渐成为租赁行业数字化转型的核心工具。通过全面集成资产管理、租赁管理和物业管理等功能,这种系统力求为用户提供高效便捷的服务体验。无论是工业园、产业园还是写字楼、公寓,租房管理系统…...

Ollama教程:轻松上手本地大语言模型部署
Ollama教程:轻松上手本地大语言模型部署 在大语言模型(LLM)飞速发展的今天,越来越多的开发者希望能够在本地部署和使用这些模型,以便更好地控制数据隐私和计算资源。Ollama作为一个开源工具,旨在简化大语言…...

Baklib推动数字化内容管理解决方案助力企业数字化转型
内容概要 在当今信息爆炸的时代,数字化内容管理成为企业提升效率和竞争力的关键。企业在面对大量数据时,如何高效地存储、分类与检索信息,直接关系到其经营的成败。数字化内容管理不仅限于简单的文档存储,更是整合了文档、图像、…...

DeepSeek-R1 论文. Reinforcement Learning 通过强化学习激励大型语言模型的推理能力
论文链接: [2501.12948] DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 实在太长,自行扔到 Model 里,去翻译去提问吧。 工作原理: 主要技术,就是训练出一些专有用途小模型&…...

DOM 操作入门:HTML 元素操作与页面事件处理
DOM 操作入门:HTML 元素操作与页面事件处理 DOM 操作入门:HTML 元素操作与页面事件处理什么是 DOM?1. 如何操作 HTML 元素?1.1 使用 `document.getElementById()` 获取单个元素1.2 使用 `document.querySelector()` 和 `document.querySelectorAll()` 获取多个元素1.3 创建…...

使用 HTTP::Server::Simple 实现轻量级 HTTP 服务器
在Perl中,HTTP::Server::Simple 模块提供了一种轻量级的方式来实现HTTP服务器。该模块简单易用,适合快速开发和测试HTTP服务。本文将详细介绍如何使用 HTTP::Server::Simple 模块创建和配置一个轻量级HTTP服务器。 安装 HTTP::Server::Simple 首先&…...

C++滑动窗口技术深度解析:核心原理、高效实现与高阶应用实践
目录 一、滑动窗口的核心原理 二、滑动窗口的两种类型 1. 固定大小的窗口 2. 可变大小的窗口 三、实现细节与关键点 1. 窗口的初始化 2. 窗口的移动策略 3. 结果的更新时机 四、经典问题与代码示例 示例 1:和 ≥ target 的最短子数组(可变窗口…...

基于构件的软件开发方法
摘要: 本人在2023年1月参与广东某公司委托我司开发的“虚拟电厂”项目,主要负责整体架构设计和中间件的选型,该项目为新型电力存储、电力调度、能源交易提供一整套的软件系统,包括设备接入、负载预测、邀约竞价、用户设备调控等功能。本项目以“虚拟电厂”项目为例,讨论基…...