基于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. 基于像素的差异比较 可以逐像素比较…

基于MATLAB车牌识别系统设计

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

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

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

Linux安装Anaconda和Pytorch

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

[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…

1.2电子商务安全内涵

目录 1 电子商务安全的层次 2 计算机网络安全 3电子商务安全的特点 只有在你生命美丽的时候&#xff0c;世界才是美丽的。 —— 顾城 《顾城哲思录》 1 电子商务安全的层次 安全:主体没有危险的客观状态 电子商务安全是一个广泛的概念&#xff0c;它涉及到电子商务的各个方…

现今 CSS3 最强二维布局系统 Grid 网格布局

深入学习 CSS3 目前最强大的布局系统 Grid 网格布局 Grid 网格布局的基本认识 Grid 网格布局: Grid 布局是一个基于网格的二位布局系统&#xff0c;是目前 CSS 最强的布局系统&#xff0c;它可以同时对列和行进行处理&#xff08;它将网页划分成一个个网格&#xff0c;可以任…

PHP函数$_FILES详解

PHP函数$_FILES详解 在PHP中上传一个文件建一个表单要比ASP中灵活得多。具体的看代码。 <form enctype"multipart/form-data" action"upload.php" method"post"> <input type"hidden" name"MAX_FILE_SIZE" value…

嵌入式入门学习——8基于Protues仿真Arduino+SSD1306液晶显示数字时钟

0 系列文章入口 嵌入式入门学习——0快速入门&#xff0c;Let‘s Do It&#xff01; SSD1306 1 Protues查找SSD1306器件并放置在画布&#xff0c;画好电气连接&#xff08;这里VCC和GND画反了&#xff0c;后面仿真出错我才看见&#xff0c;要是现实硬件估计就烧毁了&#xf…

【时时三省】(C语言基础)函数介绍strncat

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 strncat 打印结果是hello wor 跟strcat不同的是他后面可以加一个参数 这个参数就是它可以根据后面的数字 来追加多少个字符 这个如果后面的参数改成10的话 就是打印hello world 不会跟strn…

Appium环境搭建、Appium连接真机

文章目录 一、安装Android SDK二、安装Appium-desktop三、安装Appium Inspector 一、安装Android SDK 首先需要安装jdk&#xff0c;这里就不演示安装jdk的过程了 SDK下载地址&#xff1a;Android SDK 下载 1、点击 Android SDK 下载 -> SKD Tools 2、选择对应的版本进行下…

诊断知识:NRC78(Response Pending)的回复时刻

文章目录 前言NRC78的使用场景客户需求解读Autosar Dcm中的定义工具链中的配置总结 前言 在项目开发过程中&#xff0c;客户变更需求&#xff0c;是关于NRC78的回复时间点的&#xff0c;该需求在Autosar Dem中也有对应的参数&#xff0c;DcmTimStrP2ServerAdjust&#xff08;针…