【基于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 {}
}

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

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

相关文章

VSCode设置内容字体大小

1、打开VSCode软件&#xff0c;点击左下角的“图标”&#xff0c;选择“Setting”。 在命令面板中的Font Size处选择适合自己的字体大小。 2、对比Font Size值为14与20下的字体大小。

企业商业秘密百问百答之三十八【商务保密协议签订】

《企业商业秘密百问百答》是由天禾律所陈军律师团队精心编撰的成果&#xff0c;汇集了该团队律师在处理商业秘密相关的刑事和民事案件中的丰富经验。近年来&#xff0c;这份资料已通过线上和线下的方式向全国近千家企业进行了广泛宣讲&#xff0c;并获得了积极的社会反响。 其…

C++11中的bind

官方文档对于bind接口的概述解释&#xff1a;Bind function arguments 在C11中&#xff0c;std::bind 是一个非常有用的工具&#xff0c;用于将函数、成员函数或函数对象与特定的参数绑定在一起&#xff0c;生成一个新的可调用对象。std::bind 可以用于部分应用函数参数、改变…

Qt网络相关

“ 所有生而孤独的人&#xff0c;葆有的天真 ” 为了⽀持跨平台, QT对⽹络编程的 API 也进⾏了重新封装。本章会上手一套基于QT的网络通信编写。 UDP Socket 在使用Qt进行网络编程前&#xff0c;需要在Qt项目中的.pro文件里添加对应的网络模块( network ). QT core gui net…

会计学基础

【拯救者】会计学基础速成&#xff08;期末 复试 升本均可用&#xff09; ©无忌教育 重点: 适用课本: 会计基础 会计基础是指会计工作的基本原则和方法&#xff0c;它努力为会计核算提供一个共同的基础&#xff0c;以便各种组织在会计核算上得到一致的结果。会计基础主要…

我们信仰AI?从神明到人工智能——信任的进化

信任的进化&#xff1a; 信任是我们最宝贵的资产。而现在&#xff0c;它正像黑色星期五促销的廉价平板电视一样&#xff0c;被一点点拆解。在过去&#xff0c;世界很简单&#xff1a;人们相信晚间新闻、那些满是灰尘书籍的教授&#xff0c;或者手持病历、眉头紧锁的医生。而如…

《DeepSeek R1:7b 写一个python程序调用摄像头获取视频并显示》

C:\Users\Administrator>ollama run deepseek-r1:7b hello Hello! How can I assist you today? &#x1f60a; 写一个python程序调用摄像头获取视频并显示 好&#xff0c;我需要帮用户写一个Python程序&#xff0c;它能够使用摄像头获取视频&#xff0c;并在屏幕上显示出…

Linux网络 | 进入数据链路层,学习相关协议与概念

前言&#xff1a;本节内容进入博主讲解的网络层级中的最后一层&#xff1a;数据链路层。 首先博主还是会线代友友们认识一下数据链路层的报文。 然后会带大家重新理解一些概念&#xff0c;比如局域网交换机等等。然后就是ARP协议。 讲完这些&#xff0c; 本节任务就算结束。 那…

Python 科学计算

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

18.[前端开发]Day18-王者荣耀项目实战(一)

01-06 项目实战 1 代码规范 2 CSS编写顺序 3 组件化开发思想 组件化开发思路 项目整体思路 – 各个击破 07_(掌握)王者荣耀-top-整体布局完成 完整代码 01_page_top1.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8…

Java 大视界 -- Java 大数据在智能医疗影像诊断中的应用(72)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也期待你毫无保留地分享独特见解,愿我们于此携手成长,共赴新程!💖 一、…

知识管理平台在提升组织智慧与执行力方面的关键作用探讨

内容概要 知识管理平台是现代组织在日益激烈的竞争环境中提升自身智慧和执行力的重要工具。其基本概念在于通过系统化的方式收集、整理和共享知识资源&#xff0c;确保组织内部的信息流畅和决策信息的及时性。这不仅强化了团队成员之间的沟通与协作&#xff0c;还促进了对复杂…

STM32F103ZET6完整技术点(持续更新~)

①STM32②F③103④Z⑤E⑥T⑦6简介&#xff1a; ①基于ARM核心的32位微控制器&#xff0c;②通用类型&#xff0c;③增强型&#xff0c;④引脚数目144个 ⑤闪存存储器容量&#xff1a;512K字节&#xff0c;⑥封装:LQFP&#xff0c;⑦温度范围&#xff1a;工业级温度范围&#xf…

交叉验证、精确率、召回率

1. 交叉验证 交叉验证是在机器学习建立模型和验证模型参数时常用的办法。交叉验证&#xff0c;顾名思义&#xff0c;就是重复的使用数据&#xff0c;把得到的样本数据进行切分&#xff0c;组合为不同的训练集和测试集&#xff0c;用训练集来训练模型&#xff0c;用测试集来评估…

sql表的增删改、替换

一、增加 1、向原表的字段中插入多条记录的方法 # mysql中常用的三种插入数据的语句: # insert into表示插入数据&#xff0c;数据库会检查主键&#xff0c;如果出现重复会报错&#xff1b; # replace into表示插入替换数据&#xff0c;需求表中有PrimaryKey&#xff0c; # 或…

执行策略更改

执行策略三种模式&#xff1a; Restricted&#xff1a;不允许运行任何脚本&#xff08;这是默认设置&#xff09;。RemoteSigned&#xff1a;允许本地脚本运行&#xff0c;但从互联网下载的脚本需要有效的签名才能运行。Unrestricted&#xff1a;允许所有脚本运行&#xff0c;…

如何创建折叠式Title

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverGrid组件相关的内容&#xff0c;本章回中将介绍SliverAppBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverAppBar和普通的AppBar类似&#xff0c;它们的…

[Proteus仿真]基于51单片机的智能温控系统

[Proteus仿真]基于51单片机的智能温控系统 基于51单片机的智能温控系统&#xff1a;DS18B20精准测温LCD1602双屏显示三键设置上下限声光报警&#xff0c;支持温度校准、抗干扰设计、阈值记忆。 一.仿真原理图 ​​ 二.模块介绍 温度采集模块&#xff08;DS18B20&#xff0…

RAG 与历史信息相结合

初始化模型 # Step 4. 初始化模型, 该行初始化与 智谱 的 GLM - 4 模型进行连接&#xff0c;将其设置为处理和生成响应。 chat ChatZhipuAI(model"glm-4",temperature0.8, ) 此提示告诉模型接收聊天历史记录和用户的最新问题&#xff0c;然后重新表述问题&#x…

【Redis】安装配置Redis超详细教程 / Linux版

Linux安装配置Redis超详细教程 安装redis依赖安装redis启动redis停止redisredis.conf常见配置设置redis为后台启动修改redis监听地址设置工作目录修改密码监听的端口号数据库数量设置redis最大内存设置日志文件设置redis开机自动启动 学习视频&#xff1a;黑马程序员Redis入门到…