Spring Boot实践八--用户管理系统(上)

一,技术介绍

技术选型功能说明
springboot是一种基于 Spring 框架的快速开发应用程序的框架,它的主要作用是简化 Spring 应用程序的配置和开发,同时提供一系列开箱即用的功能和组件,如内置服务器、数据访问、安全、监控等,使开发者可以更加高效地构建和部署应用程序
Maven快速的引入jar包进行开发,自动构建部署
tomcatweb服务器,快速部署发布web 服务。Tomcat是一个开源的Java Servlet容器,它可以运行Java Servlet和JavaServer Pages(JSP)应用程序。作为一个Web服务器,它可以处理HTTP请求和响应,并将它们传递给Java Servlet和JSP应用程序进行处理。
ThymeleafThymeleaf是一种Java模板引擎,它可以将HTML、XML、JavaScript等文件转换为可执行的模板。在开发Web应用程序时,通常会使用Tomcat作为Web服务器,而Thymeleaf可以作为模板引擎来生成动态的Web页面。因此,Thymeleaf和Tomcat可以一起使用来构建动态Web应用程序。
junit单元测试框架
mybatis将Java对象与关系数据库进行映射,实现数据的持久化操作。mybatis的mapper文件是储存sql语句的一个xml文件,他替代了JDBC在类中写多条语句的问题,简化了步骤。
redis用作缓存。它的读写速度非常快,每秒可以处理超过10万次读写操作。高并发访问数据时直接走内存,和直接查询数据库相比,redis的高效性、快速性优势明显
mysql关系型数据库

Spring、Spring Boot和Spring Cloud的关系

在这里插入图片描述

Spring是一个开源的Java框架,它提供了IoC(控制反转)和AOP(面向切面编程)两个核心特性:

  • IoC(控制反转)是指将对象的创建、依赖关系的管理和对象的生命周期交给Spring容器来管理,而不是由程序员手动管理。Spring容器会根据配置文件或注解来创建对象,并将对象之间的依赖关系注入到对象中。这样可以降低代码的耦合度,提高代码的可维护性和可测试性。
  • AOP(面向切面编程)是一种编程思想,它将程序中的横切关注点(如日志、事务、安全等)从业务逻辑中分离出来,形成一个独立的模块,称为切面。Spring AOP通过动态代理技术,在运行时将切面织入到目标对象的方法中,从而实现对目标对象的增强。这样可以提高代码的复用性和可维护性,同时也可以降低代码的耦合度。

我们可以这样理解:正是由于 IoC (控制反转,把创建好的对象给Spring进行管理)和 AOP(面向切面编程,不修改源代码的情况下进行功能增加) 这两个强大的功能才有了强大的轻量级开源JavaEE框架 Spring;Spring 生态不断地发展才有了 Spring Boot;Spring Boot 开发、部署的简化,使得 Spring Cloud 微服务治理方案彻底落地。

Spring Boot 在 Spring Cloud 中起到了承上启下的作用:

  • Springboot 将原有的 xml 配置,简化为 java 注解
  • 使用 IDE 可以很方便的搭建一个 springboot 项目,选择对应的 maven 依赖,简化Spring应用的初始搭建以及开发过程
  • springboot 有内置的 tomcat 服务器,可以 jar 形式启动一个服务,可以快速部署发布 web 服务
  • springboot 使用 starter 依赖自动完成 bean 配置,解决 bean 之间的冲突,并引入相关的 jar 包

Mybatis和Redis缓存的区别

Mybatis和Redis缓存的区别在于:

  • Mybatis缓存是基于内存的,而Redis缓存是基于磁盘的。即Mybatis缓存是在应用程序内部实现的,而Redis缓存是在外部服务器上实现的,这意味着Redis缓存可以在多个应用程序之间共享,而Mybatis缓存只能在单个应用程序实例中使用。
  • Mybatis缓存是局部缓存,只能缓存查询结果,而Redis缓存可以缓存任何类型的数据,包括对象、列表、哈希表等。
  • Mybatis缓存是默认开启的,但需要手动配置,而Redis缓存需要安装和配置Redis服务器。
  • Mybatis缓存是基于时间和空间的限制,而Redis缓存可以设置过期时间和最大内存使用量。

二,项目介绍

本项目是一个基于SpringBoot的用户权限管理系统,主要实现用户的注册、登录、角色管理、权限管理等功能。

数据库设计

表设计作用
用户表用户表(user)用于存储系统中的用户信息,包括用户ID、用户名、密码、邮箱、手机号等字段。
角色表角色表(role)用于存储系统中的角色信息,包括角色ID、角色名称、角色描述等字段
权限表权限表(permission)用于存储系统中的权限信息,包括权限ID、权限名称、权限描述等字段。
用户角色关联表用户角色关联表(user_role)用于存储系统中用户与角色之间的关系,包括用户ID、角色ID等字段。
角色权限关联表角色权限关联表(role_permission)用于存储系统中角色与权限之间的关系,包括角色ID、权限ID等字段。

功能模块

用户注册:提供用户注册功能。
用户登录:提供用户登录功能。
角色管理:提供角色的增删改查功能。
权限管理:提供权限的增删改查功能。
用户角色管理:提供用户与角色的关联管理功能。
角色权限管理:提供角色与权限的关联管理功能。

代码结构

SpringBootRedis 工程项目结构如下:

  bean - 实体层

  controller - Controller 层:http响应接口

  dao - 数据操作层 (Data Access Object):访问数据库的接口

  service - 业务逻辑层:服务接口及实现

	job - 任务管理

	task - 具体任务处理

  Application - 启动类

  resources 资源文件夹

    application.properties - 应用配置文件,应用启动会自动读取配置

    mabatis文件夹

      Mapper.xml - mybatis 关系映射 xml 文件

    templates文件夹
           xxx.html  页面Thymeleaf模板

三,项目实现

1,配置依赖

pom.xml依赖

demospringboot\pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.15-SNAPSHOT</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demospringboot</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demospringboot</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-commons</artifactId>
		</dependency>
		<!-- 添加mybatis依赖 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.1</version>
		</dependency>

		<!-- 添加redis依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
		</dependency>

		<!-- 添加mysql依赖 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.30</version>
			<scope>runtime</scope>
			<!-- MySQL5.x时,请使用5.x的连接器(cmd执行mysql -V确定)
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.45</version>
			-->
		</dependency>

		<!-- 添加thymeleaf依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- 添加swagger依赖 -->
		<dependency>
			<groupId>com.spring4all</groupId>
			<artifactId>swagger-spring-boot-starter</artifactId>
			<version>1.9.0.RELEASE</version>
		</dependency>
		
		<!-- 添加junit依赖 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.20</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<releases>
				<enabled>false</enabled>
			</releases>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<releases>
				<enabled>false</enabled>
			</releases>
		</pluginRepository>
	</pluginRepositories>

</project>

application.properties配置

demospringboot\src\main\resources\application.properties:

# mysql 指定使用的数据库
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# mysql5: spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 执行初始化sql
spring.datasource.initialize=true
spring.datasource.schema=classpath:schema.sql

# redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms

# 默认线程池
spring.task.execution.pool.core-size=2
spring.task.execution.pool.max-size=5
spring.task.execution.pool.queue-capacity=10
spring.task.execution.pool.keep-alive=60
spring.task.execution.pool.allow-core-thread-timeout=true
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
spring.task.execution.thread-name-prefix=task-

# mybatis 指定mapper xml映射文件
mybatis.mapper-locations=classpath:mybatis/*.xml
# 打印mybatis的执行sql
# mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# swagger
swagger.title=spring-boot-starter-swagger
swagger.description=Starter for swagger 2.x
swagger.version=1.4.0.RELEASE
swagger.license=Apache License, Version 2.0
swagger.licenseUrl=https://www.apache.org/licenses/LICENSE-2.0.html
swagger.termsOfServiceUrl=https://github.com/xxx/spring-boot-starter-swagger
swagger.contact.name=didi
swagger.contact.url=http://blog.xxx.com
swagger.contact.email=xxx.com
swagger.base-package=com.example.demospringboot
swagger.base-path=/**

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

2,数据库初始化

在前面的application.properties的sql配置中,我们指定了会自动创建mydatabase,并且指定了初始化sql文件:

spring.datasource.initialize=true
spring.datasource.schema=classpath:schema.sql

对应的demospringboot\src\main\resources\schema.sql主要用来初始化设计的5张表,sql语句如下:


-- 测试表初始化

-- 测试表初始化
drop database if exists mydatabase;
create database if not exists mydatabase character set utf8;
use mydatabase;
drop table if exists user;
drop table if exists role;
drop table if exists permission;
drop table if exists user_role;
drop table if exists role_permission;
drop table if exists jobs;

-- 用户表
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `username` varchar(32) NOT NULL COMMENT '用户名',
  `password` varchar(64) NOT NULL COMMENT '密码',
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';

-- 角色表
CREATE TABLE `role` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  `name` varchar(32) NOT NULL COMMENT '角色名称',
  `description` varchar(128) DEFAULT NULL COMMENT '角色描述',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';

-- 权限表
CREATE TABLE `permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
  `name` varchar(32) NOT NULL COMMENT '权限名称',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';

-- 用户角色关联表
CREATE TABLE `user_role` (
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `role_id` int(11) NOT NULL COMMENT '角色ID',
  PRIMARY KEY (`user_id`,`role_id`),
  KEY `role_id` (`role_id`),
  CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表';

-- 角色权限关联表
CREATE TABLE `role_permission` (
  `role_id` int(11) NOT NULL COMMENT '角色ID',
  `permission_id` int(11) NOT NULL COMMENT '权限ID',
  PRIMARY KEY (`role_id`,`permission_id`),
  KEY `permission_id` (`permission_id`),
  CONSTRAINT `role_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `role_permission_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限关联表';

-- 初始化测试数据
INSERT INTO user VALUES(1,'Jacky','123456');
INSERT INTO user VALUES(2,'Mike','123456');
INSERT INTO user VALUES(3,'Tom','123456');
INSERT INTO user VALUES(4,'Lily','123456');

INSERT INTO role VALUES(1,'admin', 'system administrator');
INSERT INTO role VALUES(2,'user', 'ordinary users');

-- 一个管理员,其他普通用户
INSERT INTO user_role VALUES(1,1);
INSERT INTO user_role VALUES(2,2);
INSERT INTO user_role VALUES(3,2);
INSERT INTO user_role VALUES(4,2);

INSERT INTO permission VALUES(1, 'create');
INSERT INTO permission VALUES(2, 'read');
INSERT INTO permission VALUES(3, 'update');
INSERT INTO permission VALUES(4, 'delete');

-- 管理员有增删改查权限,普通用户只有读权限
INSERT INTO role_permission VALUES(1,1);
INSERT INTO role_permission VALUES(1,2);
INSERT INTO role_permission VALUES(1,3);
INSERT INTO role_permission VALUES(1,4);
INSERT INTO role_permission VALUES(2,2);

--任务表
CREATE TABLE `jobs` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务ID',
  `sendMail` int(11) NOT NULL  COMMENT '发送邮件任务',
  `analysisLog` int(11) NOT NULL  COMMENT '分析日志任务',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

INSERT INTO jobs VALUES(1,0,1);

这里我们额外创建了一张任务表,sendMail为1表示需要创建任务向用户发邮件, analysisLog为1表示每晚定时分析日志。

然后主类实现CommandLineRunner run接口,执行initDatabase进行初始化:

进行如下调用:

package com.example.demospringboot;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.scheduling.annotation.EnableAsync;

import org.springframework.cache.annotation.EnableCaching;

import com.example.demospringboot.workmanager.WorkManager;
import com.example.demospringboot.workmanager.AsyncWorkManager;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import com.spring4all.swagger.EnableSwagger2Doc;

@EnableCaching
@EnableAsync
@EnableSwagger2Doc
@SpringBootApplication
// 需要指定扫描的类,并在配置文件指定mybatis.mapper-locations为对应的xml路径
@MapperScan(value = {"com.example.demospringboot.dao"})
public class DemospringbootApplication implements CommandLineRunner {
	@Autowired
	private DataSource dataSource;

	public static void main(String[] args) {
		SpringApplication.run(DemospringbootApplication.class, args);
	}

	@Override
	public void run(String... strings) throws SQLException {
		initDatabase();
	}

	private void initDatabase() throws SQLException {
		System.out.println("======== 自动初始化数据库开始 ========");
		Resource initData = new ClassPathResource("schema.sql");
		Connection connection = null;
		try {
			connection = dataSource.getConnection();
			ScriptUtils.executeSqlScript(connection, initData);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			if (connection != null) {
				connection.close();
			}
		}
		System.out.println("======== 自动初始化数据库结束 ========");
	}
}

如上,我们通过DataSource.getConnection()总是从datasource或连接池返回一个新的连接,并通过ScriptUtils.executeSqlScript执行了我们的sql脚本。需要注意如果开发者没有手工释放这连接(显式调用 Connection.close() 方法),则这个连接将永久被占用(处于 active 状态),造成连接泄漏!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值