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

server/2024/10/20 17:06:53/

一、前言

 本案例中的源代码已上传到资源库,可自行下载,传送阵 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.ppmy.cn/server/133396.html

相关文章

iptables 命令详解

iptables 是 Linux 中用于设置、维护和检查 IP 数据包过滤规则的命令。它是一个强大的工具&#xff0c;广泛用于网络防火墙、安全性和网络地址转换 (NAT) 等。 以下是 iptables 命令的主要选项及其详细说明。 1. 基本语法 iptables [选项] [链名称] [规则匹配条件] [动作][选…

Flutter开发的树莓派应用如何优化性能?

哈喽&#xff0c;我是老刘 前段时间有朋友咨询我在树莓派上开发的Flutter程序如何优化性能的问题。 老刘写了6年多的Flutter代码&#xff0c;树莓派这种平台还真是头一次碰到。 不过我听他说完他们的场景&#xff0c;我就知道他们大概率是碰到性能问题了。 那么今天就来说说这…

十三、行为型(策略模式)

策略模式&#xff08;Strategy Pattern&#xff09; 概念 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;允许定义一系列算法&#xff0c;将每个算法封装在策略类中&#xff0c;并使它们可以互换使用。客户端可以根据需要动态选择不同的策…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-16 目录 文章目录 目录1. Leveraging Social Determinants of Health in Alzheimers Research Using LLM-Augmented Literature Mining and Knowledge Graphs2. Alignment Between the Decision-Making Logic of …

Qt | CMake(Qt5 VS Qt6)

点击上方"蓝字"关注我们 01、CMake >>> CMake是一个简化跨不同平台开发项目构建过程的工具。CMake自动生成生成系统,如Makefiles和Visual Studio项目文件。 CMake是一个自带的第三方工具证明文件。 CMake 备忘清单02、如何使用CMake3.1.0带Qt 5 >>&…

【Golang】踩坑记录:make()创建引用类型,初始值是不是nil!!

文章目录 起因二、得记住的知识点1. make()切片&#xff0c;初始化了吗&#xff1f;2. make()切片不同长度容量&#xff0c;append时的差别3. 切片是指向数组的指针吗&#xff1f;4. 切片扩容时&#xff0c;重新分配内存&#xff0c;原切片的数据怎么办&#xff1f; 三、咳咳&a…

blender 金币基站 建模 学习笔记

一、学习blender视频教程链接 案例3&#xff1a;金币基站_建模_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Bt4y1E7qn?vd_sourced0ea58f1127eed138a4ba5421c577eb1&p12&spm_id_from333.788.videopod.episodes 二、金币基站建模过程 &#xff08;1&#x…

Spring AI Java程序员的AI之Spring AI(三)RAG实战

Spring AI之RAG实战与原理分析 前言RAGDocumentDocumentReaderDocumentTransformerDocumentWriter VectorStoreSimpleVectorStoreRedisVectorStore元数据搜索组装提示词 前言 检索增强生成&#xff08;RAG&#xff09;是一种结合信息检索和生成模型的技术&#xff0c;用于将相…