Spring Boot:Web应用开发之登录与退出的实现

Spring Boot

  • 前言
  • 实现登录功能
    • 配置拦截器
  • 实现退出功能

在这里插入图片描述

前言

登录与退出功能作为 Web 应用中的基础且重要的组成部分,直接关系到用户的安全和隐私保护。通过实现登录与退出功能,可以对用户的身份进行验证和授权,确保只有合法的用户才能访问特定的资源或执行特定的操作。同时,退出功能也为用户提供了便捷的方式来结束当前会话,保护其个人信息不被他人冒用。在完成 Spring Boot 前五章的学习后,下面简单介绍使用 Spring Boot 实现登录与退出的功能。

实现登录功能

案例中选用 Spring Boot 3.0.2 作为整合、Thymeleaf 作为视图、Spring Data JPA 作为持久层

简单示例:
首先,创建新项目 SpringBootWebDemo ,勾选 Web 、MySQLThymeleafJPA 的启动器
在这里插入图片描述

然后,在 application.properties 全局配置文件中配置数据库连接信息

#数据库连接信息
spring.datasource.username=root
spring.datasource.password=0123
spring.datasource.url=jdbc:mysql://localhost:3306/springbootwebdemo
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# SpringBoot 内部使用 SpringData , SpringData 的 JPA 是使用 Hibernate 实现的
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

接着,创建 Entity 包并在包内创建两个实体类 User 和 Address

package cn.edu.SpringBootWebDemo.Entity;import jakarta.persistence.*;import java.util.Date;@Entity
@Table(name = "user")
public class User {private int id;private String username;private String password;private Date regDate; // 注册日期private Address address; // 地址@Id@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Column(name = "reg_date") // 指定字段名public Date getRegDate() {return regDate;}public void setRegDate(Date regDate) {this.regDate = regDate;}@ManyToOne // 假设:每一个用户对应一个地址,一个地址可以对应多个用户@JoinColumn(name = "address_id") // 一般在多的这边建立外键public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", regDate=" + regDate +", address=" + address +'}';}
}
package cn.edu.SpringBootWebDemo.Entity;import jakarta.persistence.*;@Entity
@Table(name = "address")
public class Address {private int id;private String addressInfo; // 地址详情@Id@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增public int getId() {return id;}public void setId(int id) {this.id = id;}@Column(name = "address_info") // 指定字段名public String getAddressInfo() {return addressInfo;}public void setAddressInfo(String addressInfo) {this.addressInfo = addressInfo;}@Overridepublic String toString() {return "Address{" +"id=" + id +", addressInfo='" + addressInfo + '\'' +'}';}
}

随之,创建 Dao 包并在包内创建一个 UserDao 接口,继承 JpaRepository<实体类,主键类型> ,并且声明一个默认接口中没有提供,需要根据用户名查询账号的方法

package cn.edu.SpringBootWebDemo.Dao;import cn.edu.SpringBootWebDemo.Entity.User;
import org.springframework.data.jpa.repository.JpaRepository;public interface UserDao extends JpaRepository<User,Integer> {// 默认接口中没有提供根据用户名查询账号的方法public User getByUsername(String username);}

再创建 Service 包并在包内创建一个 UserService 接口,并创建该接口的实现类 UserServiceImpl

package cn.edu.SpringBootWebDemo.Service;import cn.edu.SpringBootWebDemo.Entity.User;public interface UserService {public User login(User user);
}
package cn.edu.SpringBootWebDemo.Service;import cn.edu.SpringBootWebDemo.Dao.UserDao;
import cn.edu.SpringBootWebDemo.Entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service("userService")
public class UserServiceImpl implements UserService{@Autowiredprivate UserDao userDao;@Overridepublic User login(User user) {// 根据用户名查询有没有对应的账号User user1 = userDao.getByUsername(user.getUsername());// 判断是否为空或密码错误,登录失败返回 nullif (user1 == null) return null;if(!user1.getPassword().equals(user.getPassword())) return null;// 返回 User 对象,登录成功return user1;}
}

其次,创建 Controller 包并在包内创建一个 UserController 类

package cn.edu.SpringBootWebDemo.Controller;import cn.edu.SpringBootWebDemo.Entity.User;
import cn.edu.SpringBootWebDemo.Service.UserService;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;@Controller
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/Login.html")public String login(HttpSession httpSession){// 成功登录后不能再返回登录页面,而是跳转到主页boolean flag = httpSession.getAttribute("loginUser")==null?true:false;if (flag){return "Login";}else {return "redirect:/Main.html";}}@GetMapping("/Main.html")public String main(){return "Main";}// 判断登录@PostMapping("/Login.html")public String login(User user, HttpSession httpSession, Model model){// 控制层——接受页面的账号和密码。调用服务层的 login 方法,判断登录是否成功。// 成功将返回的 user 对象保存到 session 的域空间;反之返回一个错误提示。User user1 = userService.login(user);if(user1 != null) {// 将返回的 user 对象保存到 session 的域空间,页面跳转到主页中httpSession.setAttribute("loginUser",user1);return "redirect:/Main.html";}else {// 登录失败,返回错误提示model.addAttribute("loginError","用户名或密码错误!");return "Login";}}
}

最后,在 resources/templates 目录下创建两个页面 Login.html 和 Main.html ,再启动 Spring Boot ,打开浏览器输入 http://localhost:8080/Login.html 并按下回车键进行进行测试(启动 Spring Boot 后,数据表会自动生成,但需自行插入一条信息进行测试)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>LoginDemo</title>
</head>
<body><!--  loginError 不为空才显示错误提示  --><div style="color: red;" th:text="${loginError}" th:if="${not #strings.isEmpty(loginError)}"></div><form th:action="@{/Login.html}" method="post">账号:<input type="text" name="username" placeholder="请输入账号"> <br>密码:<input type="password" name="password" placeholder="请输入密码"> <br><input style="margin-left: 54px;" type="submit" value="登录"></form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>MainDemp</title>
</head>
<body>登录成功!!!主页
</body>
</html>

结果如图:
1.登录页面
在这里插入图片描述

2.输入账号密码,进行登录
在这里插入图片描述

3.登录成功,进入主页
在这里插入图片描述

4.错误提示
在这里插入图片描述

配置拦截器

通常为了确保用户在访问需要认证的资源之前已经登录,需要在登录功能中配置拦截器。

简单示例:
首先,创建 Web 包并在包内创建一个 LoginFilter 类来自定义拦截器

package cn.edu.SpringBootWebDemo.Web;import cn.edu.SpringBootWebDemo.Entity.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;public class LoginFilter implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HttpSession httpSession = request.getSession();// 从 session 的域空间获取 user 对象User user = (User) httpSession.getAttribute("loginUser");if(user != null){// 已登录,放行return true;}else {// 没有登录,不能访问主页面,出现提示信息request.setAttribute("loginError","请登录后再访问!");request.getRequestDispatcher("/Login.html").forward(request,response);return false;}}
}

然后,创建 Configuration 包并在包内创建一个配置类 LoginFilterConfiguration ,将拦截器存放在配置类中,才能注册到 Spring Boot 环境里

package cn.edu.SpringBootWebDemo.Configuration;import cn.edu.SpringBootWebDemo.Web.LoginFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class LoginFilterConfiguration implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册自定义的拦截器,拦截所有请求,排除登录页面registry.addInterceptor(new LoginFilter()).addPathPatterns("/**").excludePathPatterns("/Login.html");// 在 Spring MVC 中,还需要排除静态资源( *.css 、*.js 、*.jpg 等)拦截// 在 Spring Boot 中,已设置排除,不需再添加}
}

最后,启动 Spring Boot ,打开浏览器输入 http://localhost:8080/Main.html 并按下回车键进行进行测试
结果如图:
在这里插入图片描述

实现退出功能

在成功登录后,通常用户被重定向到主页,而不是返回登录页面。同时,提供一个退出功能让用户能够主动注销并清除会话信息,也是必要的安全措施。

简单示例:
首先,在 Main.html 中重新编写

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>MainDemo</title>
</head>
<body>登录成功!!!<br><h3>主页</h3> <br><a th:href="@{/logout.html}">退出</a>
</body>
</html>

然后,在 UserController 类上添加一个退出的方法

// 退出
@GetMapping("/logout.html")
public String logout(HttpSession httpSession){// 通过 invalidate 方法清空 httpSession 里的内容httpSession.invalidate();return "redirect:/Login.html";
}

最后,启动 Spring Boot ,打开浏览器输入 http://localhost:8080/Login.html 并按下回车键进行进行测试
结果如图:
成功登录后,点击退出便返回登录页面
在这里插入图片描述

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

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

相关文章

Qwen1.5大语言模型微调实践

在人工智能领域&#xff0c;大语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff09;的兴起和广泛应用&#xff0c;为自然语言处理&#xff08;NLP&#xff09;带来了前所未有的变革。Qwen1.5大语言模型作为其中的佼佼者&#xff0c;不仅拥有强大的语言生成和理…

vue3【详解】选项式 API 实现逻辑复用

抽离逻辑代码到一个函数函数命名约定为 useXxxx格式 ( React Hooks 也是 )在 setup 中引用 useXxx 函数 演示代码&#xff1a;实时获取鼠标的坐标 逻辑封装 useMousePosition.js // 导入 ref, onMounted, onUnmounted import { ref, onMounted, onUnmounted } from "vue…

锐捷云桌面的安装

按下 <DEL> 键进入 BIOS setup 界面&#xff08;初始密码为 admin &#xff09;。 输入密码之后就进入 BIOS 的 Main 界面 设置服务器 BMC IP 地址。 a 云服务器启动后&#xff0c;在 BIOS 的主页面&#xff0c;把光标移到 [Server Mgmt] 项。 b 选择 [BMC Network C…

游戏前摇后摇Q闪E闪QE闪QA等操作

备注&#xff1a;未经博主允许禁止转载 个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_w…

基于Springboot的社区防疫物资申报系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的社区防疫物资申报系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

Quartz + SpringBoot 实现分布式定时任务

文章目录 前言一、分布式定时任务解决方案二、Quartz是什么&#xff1f;1.quartz简介2.quartz的优缺点 二、Quartz分布式部署总结 前言 因为应用升级&#xff0c;由之前的单节点微服务应用升级为集群微服务应用&#xff0c;所以之前的定时任务Spring Scheduled不再适用了&…

SV-704LW 无线WIFI网络音柱

SV-704LW 无线WIFI网络音柱(工业级) 一、描述 SV-704LW是深圳锐科达电子有限公司的一款壁挂式WIFI无线网络音柱&#xff0c;通过WIFI无线接入到WIFI覆盖的网络中&#xff0c;可将网络音源通过自带的功放和喇叭输出播放&#xff0c;其采用防水设计&#xff0c;功率可以从30W到6…

如何利用FLUENT计算流体力学方法解决大气与环境领域流动问题

ANSYS FLUENT是目前全球领先的商用CFD 软件&#xff0c;市场占有率达70%左右&#xff0c;是工程师和研究者不可多得的有力工具。由于采用了多种求解方法和多重网格加速收敛技术&#xff0c;因而FLUENT能达到最佳的收敛速度和求解精度。灵活的非结构化网格和基于解的自适应网格技…

从OWASP API Security TOP 10谈API安全

1.前言 应用程序编程接口&#xff08;API&#xff09;是当今应用驱动世界创新的一个基本元素。从银行、零售、运输到物联网、 自动驾驶汽车、智慧城市&#xff0c;API 是现代移动、SaaS 和 web 应用程序的重要组成部分&#xff0c;可以在面向客 户、面向合作伙伴和内部的应用程…

计算机组成原理 — 控制单元的功能

控制单元的功能 控制单元的功能微操作命令分析取指周期间址周期执行周期中断周期 控制单元的功能控制单元的外特性输入信号输出信号 控制信号举例不采用CPU内部总线的方式取指周期间址周期执行周期 采用CPU内部总线的方式取指周期间址周期执行周期 多级时序系统机器周期时钟周期…

反激电源——TL431及光耦反馈电路计算(不涉及环路补偿)

一、TL431及光耦反馈电路 TL431以及光耦电路是反激的副边反馈类型电路中的常见应用。 其反馈工作原理为&#xff1a;当副边的输出电压升高时&#xff0c;TL431的REF点采样电压也会升高&#xff0c;使得TL431的导通量增加&#xff0c;同时光耦内部的发光二极管流过的电流也增大&…

线段树汇总

线段树是一种二叉搜索树&#xff0c;与区间树相似&#xff0c;它将一个区间划分成一些单元区间&#xff0c;每个单元区间对应线段树中的一个叶结点。 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数&#xff0c;时间复杂度为O(logN)。而未优化的空间复杂度为2N&a…

SpringCloud系列(4)--SpringCloud微服务工程构建

前言&#xff1a;在上节我们新建了一个SpringCloud父工程&#xff0c;这一节主要是构建微服务工程&#xff0c;通过实现订单模块和支付模块来熟悉微服务的概念和构建过程。 1、在父工程下新建模块 2、选择模块的项目类型为Maven并选择模块要使用的JDK版本 3、填写子模块的名称&…

企业网盘搭建——LNMP

php包链接&#xff1a;https://pan.baidu.com/s/1RElYTQx320pN6452N_7t1Q?pwdp8gs 提取码&#xff1a;p8gs 网盘源码包链接&#xff1a;https://pan.baidu.com/s/1BaYqwruka1P6h5wBBrLiBw?pwdwrzo 提取码&#xff1a;wrzo 目录 一.手动部署 二.自动部署 一.手动部署 …

SQL表连接详解:JOIN与逗号(,)的使用及其性能影响

省流版 在这个详细的解释中&#xff0c;我们将深入探讨SQL中表连接的概念&#xff0c;特别是JOIN和逗号&#xff08;,&#xff09;在连接表时的不同用法及其对查询性能的影响。通过实际示例和背后的逻辑分析&#xff0c;我们将揭示在不同场景下选择哪种连接方式更为合适。 1.…

BioTech - 使用 Amber 工具 松弛(Relaxation) 蛋白质三维结构 (Python)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/137889532 Amber 工具在蛋白质 松弛(Relaxation) 过程中起着重要的作用。在分子动力学模拟中,蛋白质松弛是指模拟过程中蛋白质结构达到一个较为稳定的状态。这个过程通…

社交媒体数据恢复:推特、Twitter

推特&#xff08;Twitter&#xff09;数据恢复&#xff1a;如何找回丢失的内容 随着社交媒体的普及&#xff0c;越来越多的人开始使用推特&#xff08;Twitter&#xff09;来分享生活点滴、发表观点和获取信息。然而&#xff0c;有时候我们会不小心删除了重要的推文&#xff0…

根据 Excel 列生成 SQL

公司有个历史数据刷数据的需求, 开发功能有点浪费, 手工刷数据有点慢, 所以研究了下 excel 直接生成 SQL, 挺好用, 记录一下; 例如这是我们的数据, 要求把创建时间和完成时间刷进数据库中, 工单编号唯一 Excel 公式如下: "UPDATE service_order SET create…

工业控制(ICS)---MMS

MMS 工控领域的TCP协议&#xff0c;有时wireshark会将response包解析为tcp协议&#xff0c;影响做题&#xff0c;如果筛选mms时出现连续request包&#xff0c;考虑wireshark解析错误&#xff0c;将筛选条件删除手动看一下 initiate&#xff08;可以理解为握手&#xff09; i…

DRF 序列化类serializer单表

【五】序列化类serializer单表 【1】主要功能 快速序列化 将数据库模型类对象转换成响应数据&#xff0c;以便前端进行展示或使用。这些响应数据通常是以Json&#xff08;或者xml、yaml&#xff09;的格式进行传输的。 反序列化之前数据校验 序列化器还可以对接收到的数据进行…