当前位置: 首页 > news >正文

【基于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】电脑商城项目之用户登录

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【Spring篇】【计算机网络】【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;1.登录-持久层 &…...

测试方案和测试计划相同点和不同点

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

c++提取矩形区域图像的梯度并拟合直线

c提取旋转矩形区域的边缘最强梯度点&#xff0c;并拟合直线 #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 新增工具&#xff1a;搜索引擎Agent 文章目录 note一、搜索引擎AgentReference 一、搜索引擎Agent import os from dotenv import load_dotenv# 加载环境变量 load_dotenv() # 初始化变量 base_url None chat_model None api_key None# 使用with语句打开文件&#xf…...

携程Java开发面试题及参考答案 (200道-下)

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

GWO优化SVM回归预测matlab

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

QMK启用摇杆和鼠标按键功能

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

Unity实现按键设置功能代码

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

基于物联网技术的实时数据流可视化研究(论文+源码)

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

list容器(详解)

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

Elasticsearch基本使用详解

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

17.3.4 颜色矩阵

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

FPGA 时钟多路复用

时钟多路复用 您可以使用并行和级联 BUFGCTRL 的组合构建时钟多路复用器。布局器基于时钟缓存 site 位置可用性查找最佳布局。 如果可能&#xff0c;布局器将 BUFGCTRL 布局在相邻 site 位置中以利用专用级联路径。如无法实现&#xff0c;则布局器将尝试将 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模块&#xff08;CoT&#xff09;: 提出了CoT模块&#xff0c;能够有效利用输入键之间的上下文信息…...

linux库函数 gettimeofday() localtime的概念和使用案例

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

编程题-电话号码的字母组合(中等)

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

EasyExcel使用详解

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

基于“蘑菇书”的强化学习知识点(二):强化学习中基于策略(Policy-Based)和基于价值(Value-Based)方法的区别

强化学习中基于策略&#xff08;Policy-Based&#xff09;和基于价值&#xff08;Value-Based&#xff09;方法的区别 摘要强化学习中基于策略&#xff08;Policy-Based&#xff09;和基于价值&#xff08;Value-Based&#xff09;方法的区别1. 定义与核心思想(1) 基于策略的方…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...