基于springboot+thymeleaf+springsecurity搭建一套web小案例

一、前言

 本案例中的源代码已上传到资源库,可自行下载,传送阵 https://download.csdn.net/download/qq_36260963/89906196

    Spring Boot是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。学习框架就是学习配置

​ 简单来说,它提供了一堆依赖打包Starter,并已经按照使用习惯解决了依赖问题—习惯大于约定。Spring Boot默认使用tomcat作为服务器,使用logback提供日志记录。无需多言,直接进入节奏.

   Thymeleaf是一个流行的现代服务器端Java模板引擎,它专门设计用于Web和独立环境中的应用程序。它允许开发者以清晰和直观的方式将服务器端的数据与HTML、XML、JavaScript、CSS以及纯文本等模板文件结合起来。Thymeleaf的最大特点之一是它的“自然模板”技术,这意味着开发者可以编写标准的HTML代码,并通过Thymeleaf特有的属性和表达式(如th:text、th:if等)来动态插入或修改内容,而无需改变HTML的结构或引入特定的模板语法。

  Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

二、效果演示

密码错误

登录成功

三、后端代码

四、springsecurity 相关

主要是springsecurity config 配置相关,包含开启表单登录,url地址拦截与放行,退出登录;以及自定义userdetailservice 接口,实现自己的登录逻辑

 4.1 springsecurity  核心配置

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final Logger logger = LoggerFactory.getLogger(this.getClass());@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().mvcMatchers("/user/**","/","/login","/register").permitAll() //允许访问.anyRequest().authenticated() // 其他都需要认证.and().formLogin() // 开启表单登录.loginProcessingUrl("/doLogin").usernameParameter("username").passwordParameter("passwd").loginPage("/login").successForwardUrl("/employee/lists")// 成功后跳转的url.failureUrl("/login").and().logout().logoutSuccessUrl("/login")//退出登录后跳转的页面.and().csrf().disable(); // 关闭csrf 防护}}

4.2 用户登录相关

@Service
public class UserServiceImpl implements UserService, UserDetailsService {@Autowired(required = false)private UserMapper userMapper;private final Logger logger = LoggerFactory.getLogger(this.getClass());@Overridepublic User login(String username, String password) throws IllegalAccessException {User queryUsr = userMapper.findByUserName(username);if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {throw new IllegalAccessException("用户名和密码不能为空");}if (ObjectUtils.isEmpty(queryUsr)) {throw new IllegalAccessException("用户不存在");}String encPwd = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));logger.info("原密码:{},加密后的密码为:{}",password,encPwd);// 密码对比DigestUtilsif (!encPwd.equals(queryUsr.getPassword())) {throw new IllegalAccessException("密码错误!");}return queryUsr;}@Overridepublic void addUser(User user) throws IllegalAccessException{if (!StringUtils.hasLength(user.getUsername()) || !StringUtils.hasLength(user.getPassword())) {throw new IllegalAccessException("用户名和密码不能为空");}//查看用户名是否重复User queryUser = userMapper.findByUserName(user.getUsername());if (!ObjectUtils.isEmpty(queryUser)) {throw new IllegalAccessException("用户【"+user.getUsername()+"】已存在,请更换用户名!");}String password = user.getPassword();String encPwd = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));user.setPassword(encPwd);//添加userMapper.save(user);logger.info("添加用户成功!");}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {if (!StringUtils.hasLength(username) ) {throw new UsernameNotFoundException("用户名不能为空");}User queryUsr = userMapper.findByUserName(username);if (ObjectUtils.isEmpty(queryUsr)) {throw new UsernameNotFoundException("用户不存在");}LoginSessionUser sessionUser = new LoginSessionUser(queryUsr);return sessionUser;}
}

4.3 userdetail 实体类

public class LoginSessionUser implements UserDetails {private User user;public LoginSessionUser(User user) {this.user = user;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return Arrays.asList(new SimpleGrantedAuthority("ROLE_amin"));}@Overridepublic String getPassword() {return "{MD5}"+user.getPassword();}@Overridepublic String getUsername() {return user.getUsername();}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

五、spring mvc 配置

用来配置静态资源拦截,常规url 以及viername配置

5.1 mvc 核心配置

@Configuration
public class MvcConfig implements WebMvcConfigurer {@Value("${photo.file.dir}")private String dir;@Overridepublic void addViewControllers(ViewControllerRegistry registry) {//viewController 请求路径    viewName: 跳转视图registry.addViewController("/").setViewName("redirect:/login");registry.addViewController("/login").setViewName("login");registry.addViewController("/register").setViewName("regist");registry.addViewController("/addEmp").setViewName("addEmp");}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");registry.addResourceHandler("/**").addResourceLocations("classpath:/static/**").addResourceLocations("file:"+dir);}}

六、yml 配置相关

1、数据库相关配置

2、日志配置

3、静态文件配置

4、模版解析器 thymeleaf 配置

server:port: 8082spring:## 数据库配置datasource:driver-class-name: com.mysql.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceusername: rootpassword: 123456url: jdbc:mysql://localhost:3306/springboot_ems_db?characterEncoding=UTF-8web:#静态文件配置resources:static-locations: classpath:/static/,file:${photo.file.dir}mvc:static-path-pattern: /static/**# thymeleaf 模版配置thymeleaf:cache: falsesuffix: .htmlprefix: classpath:/templates/mode: html# mybatis 配置
mybatis:mapper-locations: classpath:/mapper/mysql/*.xmltype-aliases-package: com.fashion.entity# 日志配置
logging:level:com.fashion: debugphoto:file:dir: j:\java\project\springboot-study\springboot-ems-security\images\

七、前端相关页面

这里只是展示部分thymeleaf 的部分,因为过多页面,需要可自行下载zip文件包

7.1 登录页面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en" xmlns:th="http://www.thymeleaf.org"><head><title>login</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" /></head><body><div id="wrap"><div id="top_content"><div id="header"><div id="rightheader"><p><span th:text="${#dates.format(#dates.createNow(), 'yyyy-MM-dd HH:mm:ss')}"/><br /></p></div><div id="topheader"><h1 id="title"><a th:href="@{/login }">main</a></h1></div><div id="navigation"></div></div><div id="content"><p id="whereami"></p><h1>欢迎进入,请登录!<!--<span th:text="${session.SPRING_SECURITY_LAST_EXCEPTION }" style="color: red;"/><span th:text="${session.errMsg }" style="color: deeppink;"/>--><span th:if="${session.SPRING_SECURITY_LAST_EXCEPTION != null}" th:text="${session.SPRING_SECURITY_LAST_EXCEPTION.message }" style="color: deeppink;"/></h1><form th:action="@{/doLogin }" method="post"><table cellpadding="0" cellspacing="0" border="0"class="form_table"><tr><td valign="middle" align="right">用户名:</td><td valign="middle" align="left"><input type="text" class="inputgri" name="username" /></td></tr><tr><td valign="middle" align="right">密码:</td><td valign="middle" align="left"><input type="password" class="inputgri" name="passwd" /></td></tr></table><p><input type="submit" class="button" value="点我登录 &raquo;" />&nbsp;&nbsp;<a th:href="@{/register}">还没有账号,立即注册</a></p></form></div></div><div id="footer"><div id="footer_bg">ABC@126.com</div></div></div></body>
</html>

7.2 登录成页面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extrasspringsecurity5"><head><title>emplist</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" /></head><body><div id="wrap"><div id="top_content"> <div id="header"><div id="rightheader"><p><span th:text="${#dates.format(#dates.createNow(), 'yyyy-MM-dd HH:mm:ss')}"/><br /><span sec:authorize="isAuthenticated()"><a th:href="@{/logout }">安全退出</a></span></p></div><div id="topheader"><h1 id="title"><a th:href="@{/employee/lists }">main</a></h1></div><div id="navigation"></div></div><div id="content"><p id="whereami"></p><h1>欢迎<span sec:authorize="isAuthenticated()"><span sec:authentication="principal.username"></span></span></h1><table class="table"><tr class="table_header"><td>编号</td><td>姓名</td><td>头像</td><td>工资</td><td>生日</td><td>操作</td></tr><tr  th:each="emp,status:${employeeList }" th:class="${status.odd ? 'row1' : 'row2'}"><td><span th:text="${emp.id }"/></td><td><span th:text="${emp.name }"/></td><td><img th:src="@{/ }+${emp.photo}" width="60"></td><td><span th:text="${emp.salary }"/></td><td><span th:text="${#dates.format(emp.birthday,'yyyy年MM月hh日')}"/></td><td><a  href="javascript:;" th:onclick="'delFn('+${emp.id}+');'">删除</a>&nbsp;<a href="javascript:;" th:onclick="'updFn('+${emp.id }+');'">更新</a></td></tr></tr></table><script type="text/javascript">function delFn(id) {if (confirm("你真的要删除员工id为:"+id+"的记录吗?")) {location.href = '[[@{/employee/delEmployee?id= }]]'+id;}}function updFn(id) {location.href = '[[@{/employee/getDetail?id= }]]'+id;}</script><p><!--<input type="button" class="button" value="添加" onclick="location='addEmp.html'"/>--><input type="button" class="button" value="添加" onclick="addEmp()"/><script type="text/javascript">function addEmp() {location.href = '[[@{/addEmp}]]'}</script></p></div></div><div id="footer"><div id="footer_bg">ABC@126.com</div></div></div></body>
</html>

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

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

相关文章

git clone 鉴权失败

git clone 鉴权失败问题 1. 问题描述2. 解决方法 1. 问题描述 使用git clone自己的代码报如下错误&#xff1a; 正克隆到 xxx... Username for https://github.com: Password for https://xxxgithub.com: remote: Support for password authentication was removed on Augu…

RAG流程的实现与改进

一、 RAG流程图 数据入库&#xff1a;读取本地数据并切成小块&#xff0c;并把这些小块经过编码embedding后&#xff0c;存储在一个向量数据库中&#xff08;下图1——6步&#xff09;&#xff1b;相关性检索&#xff1a;用户提出问题&#xff0c;问题经过编码&#xff0c;再在…

Vue项目中实现拖拽上传附件:原生JS与Element UI组件方法对比

在现代化的Web应用中&#xff0c;文件上传是一个基本功能。随着技术的发展&#xff0c;拖拽上传已经成为提升用户体验的一个重要特性。在Vue项目中&#xff0c;我们可以通过原生JavaScript或使用Element UI组件来实现这一功能。下面我们将分别介绍这两种方法&#xff0c;并对比…

吴恩达深度学习笔记(6)

正交化 为了提高算法准确率&#xff0c;我们想到的方法 收集更多的训练数据增强样本多样性使用梯度下降将算法使算法训练时间更长换一种优化算法更复杂或者更简单的神经网络利用dropout 或者L2正则化改变网络框架更换激活函数改变隐藏单元个数 为了使有监督机制的学习系统良…

vue使用jquery的ajax,页面跳转

一、引入jquery依赖 打开终端更新npm npm install -g npm 更新完后引入输入npm install jquery 加载完后 在最外层的package.json文件中加入以下代码 配置好后导入jquery 设置变量用于接收服务器传输的数据 定义ajax申请数据 服务器的Controller层传输数据 &#xff08;…

【VUE小型网站开发】初始环境搭建

1. 初始化VUE项目 1.1 创建vue项目 1.2 删除多余的界面 根据自己情况删除红框内的文件 清理app页面代码 1.3 引入vue-router 1.3.1 下载vue-router npm install vue-router1.3.2 配置vue-router 在 main.js 或 main.ts 中引入 vue-router import ./assets/main.css im…

Android 图片相识度比较(pHash)

概述 在 Android 中&#xff0c;要比对两张 Bitmap 图片的相似度&#xff0c;常见的方法有基于像素差异、直方图比较、或者使用一些更高级的算法如 SSIM&#xff08;结构相似性&#xff09;和感知哈希&#xff08;pHash&#xff09;。 1. 基于像素的差异比较 可以逐像素比较…

【SQL】写SQL查询时,常用到的日期函数

我们在做SQL的查询&#xff0c;日期函数是我们经常会用得到的函数&#xff0c;可以方便调用用于处理日期和时间数据。 以下是一些常见的日期函数及其用法示例&#xff1a; 1. 直接报出日期和时间 CURRENT_DATE&#xff1a;返回当前日期。NOW()&#xff1a;返回当前日期和时间…

【tensorrt install 】

无需点击download的下载界面&#xff0c;直接可选TensorRT Download | NVIDIA Developer 下载的是 tar type &#xff08;推荐&#xff09;&#xff1a;- TensorRT 10.5 GA for Linux x86_64 and CUDA 12.0 to 12.6 TAR Package 下载的是deb type&#xff1a; TensorRT 10.5 GA…

基于MATLAB车牌识别系统设计

MATLAB车牌识别系统设计 实践目的 车牌是一辆汽车独一无二的信息&#xff0c;因此&#xff0c;对车辆牌照的识别技术可以作为 辨识一辆车最为有效的方法。随着ITS(智能交通系统)的高速发展&#xff0c;对车牌识别技术的研究也随之发展。从根本上讲&#xff0c;牌照识别应用了…

中缀表达式转后缀表达式(逆波兰表达式)及如何计算后缀表达式

目录 中缀、后缀表达式简介 中缀转后缀的规则 模拟中缀转后缀 中缀转后缀代码 后缀表达式求值 后缀表达式求值代码 Leetcode相关题目 中缀、后缀表达式简介 首先说说什么是中缀表达式&#xff0c;中缀表达式中&#xff0c;操作符是以中缀形式处于操作数的中间。例如&…

ImportError: DLL load failed while importing _rust: 找不到指定的模块。

ImportError: DLL load failed while importing _rust: 找不到指定的模块。 安装qwen-agent 过程需要安装 cryptography 报错 &#xff1a; 177 WARNING: Failed to collect submodules for ‘cryptography.hazmat.backends.openssl’ because importing ‘cryptography.hazm…

【openwrt-21.02】T750 openwrt 概率出现nat46_ipv4_input+0x90/0x4b4问题分析及解决方案

Openwrt版本 NAME="OpenWrt" VERSION="21.02-SNAPSHOT" ID="openwrt" ID_LIKE="lede openwrt" PRETTY_NAME="OpenWrt 21.02-SNAPSHOT" VERSION_ID="21.02-snapshot" HOME_URL="https://openwrt.org/" …

Linux安装Anaconda和Pytorch

又到了一年一度换环境、换服务器不断折腾的时节了&#xff0c;一通折腾后&#xff0c;重新启动遂做记录。 1. Linux安装Anaconda 1.1 离线安装模式 进入官网https://www.anaconda.com/download/success&#xff0c;如图所示&#xff1a; 选择版本进行下载即可。 1.2 在线w…

基于IP的真实地址生成器

ip-geoaddress-generator 是一个基于 Web 的在线应用程序&#xff0c;能够根据 IP 地址生成真实的随机地址信息。通过多个 API 获取位置数据和随机用户信息&#xff0c;该工具为用户提供了完整的虚拟身份。它由 Next.js 和 Radix UI 构建&#xff0c;具备自动检测当前 IP 地址和…

[Linux网络编程]03-TCP协议

一.TCP协议数据通信的过程 TCP数据报如下&#xff0c;数据报中的标志位双端通信的关键。 三次握手: 1.客户端向服务端发送SYN标志位&#xff0c;请求建立连接&#xff0c;同时发送空包 2.服务端向客户端回发ACK标志位(即确认标志位&#xff0c;任何一端发送数据后都需要另一端…

【VUE】【IOS】【APP】IOS Music APP播放器开发

前言 周末闲来无事&#xff0c;学习了下移动端的一些知识。了解到移动端的一些实现方式&#xff0c;先从最简单的开始。本人没有IOS swift 和Android的开发经验。抱着学习态度从简单的入手&#xff0c;经过了解&#xff0c;本人之前自己用vue的写着玩了几个小项目。看到可以用…

《使用Gin框架构建分布式应用》阅读笔记:p101-p107

《用Gin框架构建分布式应用》学习第7天&#xff0c;p101-p107总结&#xff0c;总计7页。 一、技术总结 1.StatusBadRequest vs StatusInternalServerError 写代码的时候有一个问题&#xff0c;什么时候使用 StatusBadRequest(400错误)&#xff0c;什么时候使用 StatusIntern…

c语言中的%运算和/运算

在C语言中&#xff0c;%运算和/运算分别表示取模运算和除法运算。以下是它们的详细解释和用法&#xff1a; 1. % 运算&#xff08;取模运算&#xff09; 取模运算用于计算两个整数相除后的余数。语法如下&#xff1a; result a % b; a 是被除数。b 是除数。result 是 a 除…

了解CSS Typed OM

CSS Typed OM&#xff08;CSS Typed Object Model&#xff09;是一项前沿的技术&#xff0c;旨在改变我们编写和操作CSS的方式。以下是对CSS Typed OM的详细解析&#xff1a; 一、CSS Typed OM概述 CSS Typed OM是一个包含类型和方法的CSS对象模型&#xff0c;它暴露了作为Ja…