SpringBoot项目--电脑商城【用户登录】

1. 用户登录功能

先分析一下思路:当用户输入用户名和密码将数据提交给后台数据库进行查询,如果存在对应的用户名和密码则表示登录成功,登录成功之后跳转到系统的主页就是index.html页面,跳转在前端使用jQuery来完成

2.持久层[Mapper]

规划需要执行的SQL语句


依据用户提交的用户名来做select查询

select * from t_user where username=? and password=?这种不太好,这种相当于在查询用户名时直接判断了用户和密码是否一致了,如果持久层把判断做了那业务层就没事干了,所以这里我们只查询用户名,判断用户名和密码是否一致交给业务层做

select * from t_user where username=?

分析完以后发现这个功能模块已经被开发完成(UserMapper接口的findByUsername方法),所以就可以省略当前的开发步骤,但是这个分析过程不能省略

3.业务层[Service]

1 规划异常

  • 用户名对应的密码错误,即密码匹配的异常,起名PasswordNotMatchException,这个是运行时异常
/*** 密码验证失败*/
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);}
}
  • 用户名没有被找到的异常,起名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);}
}

2 设计接口和抽象方法及实现

1.在IUserService接口中编写抽象方法login(String username,String password)login(User user)也是可以的

细说一个事:登录成功某一个网站后,右上角会展示头像,昵称甚至电话号码等等,这些信息依赖于登陆成功后的信息,也就意味着一旦登录成功后在页面中切换到任意一个子页面写右上角都会展示这些信息.本质上就是查询出来这些信息,然后展示在右上角,但是这里实现查询不太现实:js中虽然打开一个html页面就自动发送一个请求,但这样就需要把这个查询的代码写在每一个html页面,显然不现实

这种情况下我们可以将当前登录成功的用户数据以当前用户对象的形式进行返回,然后进行状态管理:将数据保存在cookie或者session中,可以避免重复度很高的数据多次频繁操作数据库进行获取(这里我们用session存放用户名和用户id,用cookie存放用户头像,其中用户id是为因为有的页面展示依赖于id,用户头像也可以放在session中,而这里放在cookie是为了回顾一下cookie)

    /*** 用户登录功能* @param username 用户名* @param password 用户密码* @return 当前匹配的用户数据,如果没有则返回null*/User login(String username,String password);

2.在抽象类UserServiceImpl中实现该抽象方法

    /*** 用户登录** @param username* @param password* @return*/@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表示标记为删除if(result.getIsDelete()==1){throw new UserNotFoundException("用户数据不存在");}//将当前用户的数据返回,返回的数据是为了辅助其他页面做数据展示User user = new User();user.setUid(result.getUid());user.setUsername(result.getUsername());user.setAvatar(result.getAvatar());return user;}

3 单元测试

在业务层的测试类UserServiceTests中添加测试方法:

    @Testpublic void login() {//因为login方法可能抛出异常,所以应该捕获异常,但是测试时没必要写那么严谨User user = userService.login("test02", "12");System.out.println(user);}

4. 控制层[Controller]

1处理异常

业务层抛出的异常需要在统一异常处理类中进行统一的捕获和处理,如果该异常类型已经在统一异常类中曾经处理过则不需要重复添加

/*** 控制层的基类*/
public class BaseController {/*** 操作成功的状态码*/public static final int OK = 200;//请求处理方法,这个方法的返回值就是需要传递给前端的数据//ServiceException.class:表示抛出这个异常才会调用这个方法//自动将异常对象传递给此方法的参数列表上//当项目中产生异常,被统一拦截到此方法中,这个方法此时就充当是请求处理方法,方法的返回值直接给到前端@ExceptionHandler(ServiceException.class)//统一处理抛出的异常public JsonResult<Void> handleException(Throwable e){JsonResult<Void> result = new JsonResult<>(e);if(e instanceof UsernameDuplicatedException){result.setState(4000);result.setMessage("用户名已经被占用");} else if(e instanceof UserNotFoundException){result.setState(5001);result.setMessage("用户数据不存在异常");}else if(e instanceof PasswordNotMatchException){result.setState(5002);result.setMessage("用户名的密码错误异常");}else if(e instanceof InsertException){result.setState(5000);result.setMessage("注册时产生未知的异常");}return result;}
}

2 设计请求

  • 请求路径:/users/login
  • 请求参数:String username,String password
  • 请求类型:POST
  • 响应结果:JsonResult<User>

3 处理请求

在UserController类中编写处理请求的方法.编写完成后启动主服务验证一下

    @RequestMapping("login")public JsonResult<User> login(String username,String password) {User data = userService.login(username, password);return new JsonResult<User>(OK,data);}

4 注意点

注意,控制层方法的参数是用来接收前端数据的,接收数据方式有两种:

    /*** 1.接收数据方式:请求处理方法的参数列表设置为pojo类型来接收前端的数据* SpringBoot会将前端url地址中的参数名和pojo类的属性名进行比较,如果这两个名称相同,* 则将值注入到pojo类中对于的属性上* @param user* @return*/@PostMapping("/reg")//@RequestBody//表示此方法的响应结果以json格式进行数据的1响应给前端public JsonResult<Void> reg(User user) {userService.reg(user);return new JsonResult<>(OK);}/*** 2.接收数据方式:请求处理的参数列表设置为非pojo类型* SpringBoot会直接将请求的参数名和方法的参数名直接进行比较,如果名称* 相同则自动完成值的依赖注入* @param username* @param password* @return*/@PostMapping("/login")public JsonResult<User> login(String username,String password,HttpSession session){User user = userService.login(username, password);//向session对象中完成数据的绑定(session全局的)session.setAttribute("uid", user.getUid());session.setAttribute("username",user.getUsername());//获取session中绑定的数据System.out.println(getuidFromSession(session));System.out.println(getUsernameFromSession(session));return new JsonResult<>(OK,user);}

5. 前端页面

        <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("登录成功")//跳转到系统主页index.html//index和login在同一个目录结构下,所以可以用相对路// 径index.html来确定跳转的页面,index.html和./ind// ex.html完全一样,因为./就是表示当前目录// 结构,也可以用../web/index.htmllocation.href = "index.html";} else {alert("登录失败")}},error: function (xhr) {//xhr.message可以获取未知异常的信息alert("登录时产生未知的异常!"+xhr.message);}});});</script>

6.用session存储和获取用户数据

6.1 封装位置

  • 在用户登录成功后要保存下来用户的id,username,avatar,并且需要在任何类中都可以访问存储下来的数据,也就是说存储在一个全局对象中,会话session可以实现
  • 把首次登录所获取的用户数据转移到session对象即可
  • 获取session对象的属性值用session.getAttribute(“key”),因为session对象的属性值在很多页面都要被访问,这时用session对象调用方法获取数据就显得太麻烦了,解决办法是将获取session中数据的这种行为进行封装
  • 考虑一下封装在哪里呢?放在一个干净的工具类里肯定可以,但就这个项目目录结构而言,只有可能在控制层使用session,而控制层里的类又继承BaseController,所以可以封装到BaseController里面

综上所述,该功能的实现需要两步:

1.在父类中封装两个方法:获取uid和获取username对应的两个方法(用户头像暂不考虑,将来封装到cookie中来使用)

    /*** 获取session对象中的uid* @param session session对象* @return 当前登录的用户uid的值*/public final Integer getUidFromSession(HttpSession session) {//getAttribute返回的是Object对象,需要转换为字符串再转换为包装类return Integer.valueOf(session.getAttribute("uid").toString());}public final String getUsernameFromSession(HttpSession session) {return session.getAttribute("username").toString();}

2.把首次登录所获取的用户数据转移到session对象:

服务器本身自动创建有session对象,已经是一个全局的session对象,所以我们需要想办法获取session对象:如果直接将HttpSession类型的对象作为请求处理方法的参数,这时springboot会自动将全局的session对象注入到请求处理方法的session形参上:

将登录模块的设计请求中的请求参数:String username,String password加上HttpSession session

将登录模块的处理请求中login方法加上参数HttpSession 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);}

7.拦截器


拦截器的作用是将所有的请求统一拦截到拦截器中,可以在拦截器中定义过滤的规则,如果不满足系统设置的过滤规则,该项目统一的处理是重新去打开login.html页面(重定向和转发都可以,推荐使用重定向)
拦截器在springboot中本质是依靠springMVC完成的.springMVC提供了一个HandlerInterceptor接口用于表示定义一个拦截器
1.所以想要使用拦截器就要定义一个类并使其实现HandlerInterceptor接口,在store下建包interceptor,包下建类LoginInterceptor并编写代码:

1.创建拦截器

/**定义一个拦截器*/
public class LoginInterceptor implements HandlerInterceptor {/***检测全局session对象中是否有uid数据,如果有则放行,如果没有重定向到登录页面* @param request 请求对象* @param response 响应对象* @param handler 处理器(把url和Controller映射到一块)* @return 返回值为true放行当前请求,反之拦截当前请求* @throws Exception*/@Override//在DispatcherServlet调用所有处理请求的方法前被自动调用执行的方法//springboot会自动把请求对象给到request,响应对象给到response,适配器给到handlerpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//通过HttpServletRequest对象来获取session对象Object obj = request.getSession().getAttribute("uid");if (obj == null) { //说明用户没有登录过系统,则重定向到login.html页面//不能用相对路径,因为这里是要告诉前端访问的新页面是在哪个目录下的新//页面,但前面的localhost:8080可以省略,因为在同一个项目下response.sendRedirect("/web/login.html");//结束后续的调用return false;}//放行这个请求return true;}//在ModelAndView对象返回给DispatcherServlet之后被自动调用的方法
//    @Override
//    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//    }//在整个请求所有关联的资源被执行完毕后所执行的方法
//    @Override
//    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//    }
}

2.注册过滤器

注册过滤器的技术:借助WebMvcConfigure接口将用户定义的拦截器进行注册.所以想要注册过滤器需要定义一个类使其实现WebMvcConfigure接口并在其内部添加黑名单(在用户登录的状态下才可以访问的页面资源)和白名单(哪些资源可以在不登录的情况下访问:①register.html②login.html③index.html④/users/reg⑤/users/login⑥静态资源):

WebMvcConfigure是配置信息,建议在store包下建config包,再定义类LoginInterceptorConfigure

/**拦截器的注册*/
@Configuration //自动加载当前的类并进行拦截器的注册,如果没有@Configuration就相当于没有写类LoginInterceptorConfigure
public class LoginInterceptorConfigure implements WebMvcConfigurer {@Override//配置拦截器public void addInterceptors(InterceptorRegistry registry) {//1.创建自定义的拦截器对象HandlerInterceptor interceptor =  new LoginInterceptor();//2.配置白名单并存放在一个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表// 示有哪些是白名单,且参数是列表registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns(patterns);}
}

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

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

相关文章

Android-Broadcast动态注册

广播的动作分别为&#xff1a;注册、发送、接收。 1. 定义接收器 public class MyReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {} } 2. 注册广播 final MyReceiver[] receivers {null};Button registerBroad fi…

【用unity实现100个游戏之7】从零开始制作一个仿杀戮尖塔卡牌回合制游戏

文章目录 前言素材资源开始一、UI框架二、挂载脚本三、事件监听&#xff0c;用于绑定按钮事件四、声音管理器五、excel转txt文本六、游戏配置七、用户信息表八、战斗管理器九、 敌人管理器十、玩家血量、能量、防御值、卡牌数十一、敌人血量 行动显示逻辑十二、UI提示效果实现十…

最新基于MATLAB 2023a的机器学习、深度学习教程

详情点击链接&#xff1a;最新基于MATLAB 2023a的机器学习、深度学习教程 前沿 MATLAB 2023版的深度学习工具箱&#xff0c;提供了完整的工具链&#xff0c;能够在一个集成的环境中进行深度学习的建模、训练和部署。与Python相比&#xff0c;MATLAB的语法简洁、易于上手&#…

vue 获取当前日期所属月的第一天和最后一天的日期

学习目标&#xff1a; 学习目标 - [ ] vue 获取当前日期所属月的第一天和最后一天的日期 学习内容&#xff1a; 学习内容如下所示&#xff1a; 1. 使用 JavaScript 的 Date 对象来获取当前日期所属月的第一天和最后一天的日期 // 获取当前日期 const today new Date();//…

第四篇 DirectShow 采集调用结构关系

第一篇: DirectShow视频采集_会头痛的可达鸭的博客-CSDN博客 一、GraphBuilder 1、IFilterGraph2、IGraphBuilder、ICaptureGraphBuiler2 (1)、CLSID IFilterGraph CLSID_FilterGraphIFilterGraph2 CLSID_CaptureGraphBuilderIGraphBuilder CL…

零碎的C++

构造函数和析构函数 构造函数不能是虚函数&#xff0c;而析构函数可以是虚函数。原因如下&#xff1a; 构造函数不能是虚函数&#xff0c;因为在执行构造函数时&#xff0c;对象还没有完全创建&#xff0c;还没有分配内存空间&#xff0c;也没有初始化虚函数表指针。如果构造…

Jetsonnano B01 笔记1:基础理解—网络配置—远程连接

今日开始学习 Jetsonnano B01&#xff0c;这是一台小电脑&#xff0c;可以用来&#xff1a; 运行现代 AI 负载&#xff0c;并行运行多个神经网络&#xff0c;以及同时处理来自多个高清传感器的数据&#xff0c;可广泛应用与图像分类、对象检测、图像分割、语音处 理等领域。它…

【python爬虫】15.Scrapy框架实战(热门职位爬取)

文章目录 前言明确目标分析过程企业排行榜的公司信息公司详情页面的招聘信息 代码实现创建项目定义item 创建和编写爬虫文件存储文件修改设置 代码实操总结 前言 上一关&#xff0c;我们学习了Scrapy框架&#xff0c;知道了Scrapy爬虫公司的结构和工作原理。 在Scrapy爬虫公司…

配置本地maven

安装maven安装包 修改环境变量 vim ~/.bash_profile export JMETER_HOME/Users/yyyyjinying/apache-jmeter-5.4.1 export GOROOT/usr/local/go export GOPATH/Users/yyyyjinying/demo-file/git/backend/go export GROOVY_HOME/Users/yyyyjinying/sortware/groovy-4.0.14 exp…

手写Mybatis:第10章-使用策略模式,调用参数处理器

文章目录 一、目标&#xff1a;参数处理器二、设计&#xff1a;参数处理器三、实现&#xff1a;参数处理器3.1 工程结构3.2 参数处理器关系图3.3 入参数校准3.4 参数策略处理器3.4.1 JDBC枚举类型修改3.4.2 类型处理器接口3.4.3 模板模式&#xff1a;类型处理器抽象基类3.4.4 类…

linux 进程隔离Namespace 学习

一、linux namespace 介绍 1.1、概念 Linux Namespace是Linux内核提供的一种机制&#xff0c;它用于隔离不同进程的资源视图&#xff0c;使得每个进程都拥有独立的资源空间&#xff0c;从而实现进程之间的隔离和资源管理。 Linux Namespace的设计目标是为了解决多个进程之间…

微服务设计和高并发实践

文章目录 1、微服务的设计原则1.1、服务拆分方法1.2、微服务的设计原则1.3、微服务架构 2、高并发系统的一些优化经验2.1、提高性能2.1.1、数据库优化2.1.2、使用缓存2.1.3、服务调用优化2.1.4、动静分离2.1.5、数据库读写分离 2.2、服务高可用2.2.1、限流和服务降级2.2.2、隔离…

C语言插入排序

前言&#xff1a; 本文主要讲解插入排序中的直接插入排序和希尔排序。 1、直接插入排序&#xff1a; 1.1基本思想 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是把待排序的数值按照大小顺序逐个插入到一个已经排好序的有序序列中&#xff0c;直到将所有记录…

Spring Cloud--从零开始搭建微服务基础环境【四】

&#x1f600;前言 本篇博文是关于Spring Cloud–从零开始搭建微服务基础环境【四】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;…

QT day5

服务器&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//给服务器指针实例化对象server new QTcpServer(this); }Widget::~Widget() {delete ui…

Java“牵手”京东商品评论数据接口方法,京东商品评论接口,京东商品评价接口,行业数据监测,京东API实现批量商品评论内容数据抓取示例

京东平台商品评论数据接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片、评论内容、评论日期、评论图片、追评内容等详细信息 。 获取商品评论接口API是一种用于获取…

el-select 加多选框使用

解决方法&#xff1a; el-select 添加属性 multiple&#xff0c; <el-form-item label"订单来源&#xff1a;"><el-selectv-model"tableFrom.userType"clearablemultipleplaceholder"请选择"class"selWidth"><el-opt…

LeetCode-53-最大子数组和-贪心算法

贪心算法理论基础&#xff1a; 局部最优推全局最优 贪心无套路~ 没有什么规律~ 重点&#xff1a;每个阶段的局部最优是什么&#xff1f; 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#…

Python AttributeError: module ‘distutils‘ has no attribute ‘version‘

1, 问题 在安装或运行使用 PyTorch 的 Python 代码时&#xff0c;您可能会看到一个错误: AttributeError: module distutils has no attribute version本文将帮助您理解发生此错误的原因以及如何解决此错误。 2&#xff0c;为什么 AttributeError: module ‘distutils’ has…

开发工具——IDE安装 / IDEA子module依赖导入失败编译提示xx找不到符号 / IDEA在Git提交时卡顿

近期换了工作电脑&#xff0c;公司的IT团队不够给力&#xff0c;不能复制电脑系统&#xff0c;所以又到了需要重装IDE配置开发环境的时候了&#xff1b;在安装和导入Java编译器IDEA的时候遇到一些"棘手"问题&#xff0c;这里整理下解决方法以备不时之需&#xff1b; …