Spring Boot 实战:从0到1搭建简单管理后台
本文专为Spring Boot新手量身打造,全程剔除所有导包代码,聚焦核心实操步骤,用详实的文字描述补充每一步的细节的逻辑,让新手不仅能复制代码运行,还能理解每一步的意义,快速搭建出可落地、可扩展的简单管理后台。教程兼顾简洁性和实用性,不冗余、不堆砌,重点补充操作说明、逻辑讲解和避坑细节,确保即使是刚接触Spring Boot的开发者,也能跟着一步步完成搭建,最终实现完整的用户管理、角色菜单管理等核心功能。
本教程的核心优势的是“无导包、重实操、强落地”,所有代码均剔除package和import语句,直接复制即可使用,同时补充足够的文字描述,理清项目搭建的逻辑的脉络,避免新手走弯路,真正实现“从0到1”的完整落地。
一、核心目标与技术栈
1.1 核心需求(明确搭建方向)
本次搭建的简单管理后台,聚焦企业级后台的基础核心功能,无需复杂的权限细化和前端页面,重点实现后端核心接口,满足日常管理场景的基础需求,具体核心需求如下:
-
用户管理模块:实现用户的新增、删除、修改、分页查询,搭配Excel导入导出功能,方便批量操作用户数据;同时集成Redis缓存,提升查询效率,避免重复查询数据库;密码采用加密存储,保障数据安全。
-
角色/菜单管理模块:实现角色和菜单的基础CRUD操作,通过多对多关联表实现角色与用户、角色与菜单的关联,为后续权限控制打下基础,逻辑清晰且符合企业级开发规范。
-
辅助功能模块:集成全局异常处理,统一接口响应格式,避免接口报错时返回杂乱信息,提升项目健壮性;添加定时任务,用于清理系统操作日志,减少数据库冗余;集成异步任务,演示邮件通知等异步场景,丰富项目功能。
1.2 技术栈选型(新手友好,稳定适配)
技术栈选型遵循“稳定、简洁、新手易上手”的原则,避免使用复杂且难上手的框架,所有技术均为企业级开发常用版本,适配性强,无需额外配置复杂环境,具体选型如下:
核心框架:Spring Boot 2.7.x(稳定版,兼容性强,新手易上手,避免使用最新版导致的依赖兼容问题)
数据访问:MyBatis-Plus 3.5.x(简化MyBatis操作,自带CRUD方法,无需手动编写基础SQL,提升开发效率)
数据库:MySQL 8.0(主流关系型数据库,稳定性高,适配大部分企业级场景,操作简单易上手)
缓存技术:Redis 6.x(轻量级缓存,用于缓存热点数据,减少数据库压力,提升接口响应速度)
工具类:Lombok(简化实体类编写,无需手动生成get/set方法,减少代码冗余)、EasyExcel 3.3.2(简单易用的Excel导入导出工具,适配各类Excel格式,避免复杂的POI操作)
其他:Spring Web(实现HTTP接口开发)、Spring Cache(整合Redis缓存)、Spring异步/定时注解(实现异步任务和定时任务)
避坑提示:技术栈版本需严格对应,Spring Boot 2.7.x需搭配MyBatis-Plus 3.5.x,避免版本不兼容导致项目启动失败;Redis需提前安装并启动,确保本地Redis服务正常运行,否则缓存功能无法生效;MySQL建议使用8.0版本,低版本可能存在语法兼容问题。
二、数据库设计(极简适配,直接执行)
数据库设计是后台项目的基础,本次设计遵循“简洁、实用、可扩展”的原则,设计5张核心数据表,覆盖用户、角色、菜单、关联关系和操作日志,所有表结构均经过简化,去除冗余字段,适配本次后台项目的核心需求,同时保证符合企业级开发规范,SQL语句可直接复制到MySQL中执行,无需修改。
设计思路:采用“用户-角色-菜单”的权限模型,通过多对多关联表实现三者之间的关联,确保权限逻辑清晰;用户表存储核心用户信息,密码加密存储;日志表用于存储用户操作记录,配合定时任务实现自动清理,减少数据库冗余。
CREATE DATABASE IF NOT EXISTS management_db CHARACTER SET utf8mb4;
USE management_db;
-- 用户表:存储用户核心信息,密码加密存储,状态控制启用/禁用
CREATE TABLE `sys_user` (
`id` bigint(20) AUTO_INCREMENT,
`username` varchar(50) NOT NULL UNIQUE,
`password` varchar(100) NOT NULL,
`status` tinyint(1) DEFAULT 1,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
-- 角色表:存储角色信息,用于关联用户和菜单
CREATE TABLE `sys_role` (`id` bigint(20) AUTO_INCREMENT, `role_name` varchar(50) NOT NULL UNIQUE, PRIMARY KEY (`id`)) ENGINE=InnoDB;
-- 菜单表:存储菜单信息,用于权限控制的基础
CREATE TABLE `sys_menu` (`id` bigint(20) AUTO_INCREMENT, `menu_name` varchar(50) NOT NULL, `parent_id` bigint(20) DEFAULT 0, PRIMARY KEY (`id`)) ENGINE=InnoDB;
-- 用户-角色关联表:实现用户与角色的多对多关联,避免重复关联
CREATE TABLE `sys_user_role` (
`id` bigint(20) AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`role_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_role` (`user_id`,`role_id`)
) ENGINE=InnoDB;
-- 角色-菜单关联表:实现角色与菜单的多对多关联,控制菜单访问权限
CREATE TABLE `sys_role_menu` (
`id` bigint(20) AUTO_INCREMENT,
`role_id` bigint(20) NOT NULL,
`menu_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_role_menu` (`role_id`,`menu_id`)
) ENGINE=InnoDB;
-- 操作日志表:存储用户操作记录,用于定时清理演示
CREATE TABLE `sys_log` (
`id` bigint(20) AUTO_INCREMENT,
`operation` varchar(100) NOT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
实操提示:执行SQL前,务必确保MySQL服务正常启动;如果本地MySQL密码不是123456,后续配置文件中需对应修改;执行完成后,可通过Navicat、DBeaver等工具查看表结构,确认所有表创建成功后再继续后续操作;若执行过程中报错,检查MySQL版本是否为8.0,以及SQL语句是否完整复制。
三、项目初始化(3步搭建骨架,新手可直接跟着做)
项目初始化是搭建后台项目的基础,这一步的核心是搭建项目骨架、配置核心依赖和参数,确保后续功能能够正常开发和运行。本部分步骤清晰,每一步都补充详细的文字描述,明确操作目的和注意事项,新手无需具备复杂的开发经验,跟着步骤操作即可完成,避免走弯路。
3.1 新建Spring Boot项目(两种方式,任选其一)
为了适配不同新手的操作习惯,提供两种新建项目的方式,两种方式最终效果一致,可根据自己的实际情况选择,重点是配置正确的项目信息和依赖,确保项目骨架搭建成功。
方式1:通过Spring Initializr(在线创建,推荐新手,无需配置本地环境)
操作步骤详细说明:首先访问Spring Initializr官方网站(https://start.spring.io/),进入在线创建页面,该页面是Spring官方提供的项目快速创建工具,无需安装额外软件,操作简单。进入页面后,配置项目基本信息,Group可自定义(如com.example),Artifact为项目名称(建议命名为management-background,便于识别),Type选择Maven(新手友好,依赖管理更简单),Java版本选择8(主流版本,兼容性强),Spring Boot版本选择2.7.17(稳定版,避免使用最新版导致依赖兼容问题)。
配置完成后,勾选核心依赖,直接在搜索框中搜索对应的依赖并勾选,无需手动添加,勾选的依赖包括:Spring Web(用于开发HTTP接口)、MyBatis-Plus(简化数据库操作)、MySQL Driver(连接MySQL数据库)、Spring Data Redis(整合Redis缓存)、Spring Cache(启用缓存功能)、Lombok(简化实体类编写)。所有依赖勾选完成后,点击“Generate”按钮下载项目压缩包,解压后导入IDEA(或Eclipse),等待Maven依赖加载完成,加载时间根据网络情况而定,耐心等待即可,加载完成后无报错,说明项目骨架搭建成功。
方式2:IDEA本地创建(适合已安装IDEA的新手)
操作步骤:打开IDEA,点击“New Project”,在弹出的窗口中选择“Spring Initializr”,点击“Next”,后续的项目基本信息配置、依赖勾选,与方式1完全一致,配置完成后,选择项目保存路径,点击“Finish”,等待Maven依赖加载完成即可。
注意事项:依赖加载过程中,若出现依赖下载失败,可刷新Maven缓存(IDEA中点击右上角刷新按钮);若刷新后仍失败,检查网络连接,或更换Maven镜像源,确保依赖能够正常下载;Java版本建议选择8,避免使用更高版本导致部分依赖不兼容。
3.2 补充Maven依赖(完善功能,复制粘贴即可)
Spring Initializr勾选的依赖仅能满足基础功能需求,为了实现Excel导入导出、密码加密、文件操作等核心功能,需要补充部分依赖。打开项目的pom.xml文件,在标签内添加以下依赖,添加后点击IDEA右上角“刷新”按钮,加载新增依赖,无需修改任何内容,直接复制粘贴即可。
补充说明:新增的依赖各有作用,EasyExcel用于实现Excel导入导出功能,无需编写复杂的POI代码;Spring Security Crypto用于密码加密,保障用户密码安全;Commons-IO用于文件操作,适配Excel导入时的文件处理;Commons-Pool2用于Redis连接池配置,提升Redis缓存的性能和稳定性,所有依赖版本均经过适配,无需修改版本号,避免兼容性问题。
<!-- EasyExcel 导入导出依赖(核心) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
<!-- 密码加密依赖(Spring Security Crypto) -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
<!-- 文件操作依赖(Commons-IO,适配Excel导入) -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- Redis连接池依赖(提升Redis性能) -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
3.3 核心配置(application.yml,关键一步)
配置文件是项目运行的核心,用于连接数据库、Redis,配置MyBatis-Plus、缓存、服务器等参数,直接决定项目能否正常启动和运行。操作步骤:删除项目默认的application.properties文件,新建application.yml文件(右键resources → New → File,文件名输入application.yml),复制以下配置内容,根据自己的本地环境修改对应参数,配置说明清晰,便于新手理解和修改。
配置说明:数据库配置部分,需修改password为自己的MySQL密码,url中的management_db是之前创建的数据库名称,无需修改;Redis配置部分,若本地Redis设置了密码,填写对应的密码,无密码则留空;MyBatis-Plus配置部分,mapper-locations指定Mapper XML文件的路径,type-aliases-package指定实体类包路径,需与自己的项目包名一致;服务器配置部分,端口8080若被占用,可修改为8081等未被占用的端口,context-path为项目访问前缀,后续访问接口需加上该前缀。
spring:
# 数据库配置(核心,修改为自己的MySQL密码)
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/management_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root # 数据库用户名(默认root)
password: 123456 # 替换为自己的MySQL密码(重要)
# Redis配置(缓存用,默认本地Redis,无需修改)
redis:
host: localhost # Redis地址(本地为localhost)
port: 6379 # Redis端口(默认6379)
password: # 若Redis设置了密码,填写密码,无密码则留空
database: 0 # Redis数据库索引(默认0)
lettuce: # Redis连接池配置(提升性能)
pool:
max-active: 16 # 最大连接数
max-idle: 8 # 最大空闲连接数
min-idle: 4 # 最小空闲连接数
max-wait: 1000 # 最大等待时间(毫秒)
# 缓存配置(启用Redis缓存,替代默认本地缓存)
cache:
type: redis # 缓存类型:Redis
redis:
time-to-live: 3600000 # 缓存默认过期时间(1小时,单位:毫秒)
cache-null-values: false # 不缓存null值,避免缓存穿透
key-prefix: management:cache: # 缓存key前缀,避免与其他Redis数据冲突
use-key-prefix: true # 启用key前缀
# 定时任务与异步任务配置(无需修改)
task:
scheduling: # 定时任务线程池
pool:
size: 5 # 线程池大小
thread-name-prefix: scheduled-task- # 线程名称前缀
execution: # 异步任务线程池
pool:
core-size: 5 # 核心线程数
max-size: 10 # 最大线程数
queue-capacity: 20 # 队列容量
# MyBatis-Plus 配置(简化数据库操作,无需修改)
mybatis-plus:
mapper-locations: classpath:mybatis/mapper/**/*.xml # Mapper XML文件路径
type-aliases-package: com.example.management.entity # 实体类包路径(对应自己的包名)
configuration:
map-underscore-to-camel-case: true # 开启下划线转驼峰(如user_name → userName)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL语句,便于调试
# 服务器配置(无需修改,端口被占用可调整)
server:
port: 8080 # 项目端口(默认8080)
servlet:
context-path: /management # 项目访问路径前缀(访问接口时需加上)
3.4 项目目录结构(规范简洁,便于维护)
为了让项目结构清晰,便于后续开发和维护,按照“分层架构”设计目录,明确区分各模块的功能,新手可直接按照以下目录结构创建包和文件,包名需与配置文件中“type-aliases-package”一致(如com.example.management),避免出现路径错误。
目录结构说明:config包用于存放自定义配置类(如Redis缓存序列化配置);entity包用于存放实体类,对应数据库中的数据表;dto包用于存放数据传输对象(如Excel导入导出DTO);mapper包用于存放MyBatis-Plus Mapper接口,实现数据库操作;service包用于存放业务逻辑,分为接口和实现类;controller包用于开发接口,对外提供访问入口;listener包用于存放Excel导入监听器;util包用于存放通用工具类;exception包用于存放全局异常处理相关类。
com.example.management
├── ManagementApplication.java # 项目启动类(开启缓存、异步、定时任务)
├── config/ # 配置类包(自定义配置)
├── entity/ # 实体类包(对应数据库表)
├── dto/ # 数据传输对象包(Excel导入导出、接口参数)
├── mapper/ # MyBatis-Plus Mapper接口包
├── service/ # Service层包(核心业务逻辑)
│ └── impl/ # Service实现类包
├── controller/ # Controller层包(接口开发)
├── listener/ # EasyExcel监听器包(Excel导入用)
├── util/ # 工具类包(通用工具,复用性强)
└── exception/ # 全局异常处理包
3.5 启动类配置(开启核心功能,关键一步)
项目启动类是项目的入口,需要添加相关注解,开启缓存、异步任务、定时任务等核心功能,同时扫描Mapper接口,确保数据库操作能够正常生效。无需编写复杂代码,添加对应的注解即可,具体代码如下,直接复制到启动类中,确保类名与项目包名对应。
@SpringBootApplication
@MapperScan("com.example.management.mapper") // 扫描Mapper接口,确保数据库操作生效
@EnableCaching // 开启缓存功能(Redis缓存)
@EnableAsync // 开启异步任务(如异步邮件通知)
@EnableScheduling // 开启定时任务(如日志清理)
public class ManagementApplication {
public static void main(String[] args) {
SpringApplication.run(ManagementApplication.class, args);
// 启动成功提示,便于确认项目启动状态
System.out.println("======================================");
System.out.println(" 简单管理后台项目启动成功!");
System.out.println(" 访问地址:http://localhost:8080/management");
System.out.println("======================================");
}
}
注意事项:@MapperScan注解的路径必须与自己的Mapper接口包路径一致,否则MyBatis-Plus无法扫描到Mapper接口,会报“找不到Mapper”错误;三个注解(@EnableCaching、@EnableAsync、@EnableScheduling)必须添加,否则对应功能无法生效;启动类名称可自定义,但需与main方法中的类名一致。
四、核心功能实现(极简无导包,完整可落地)
本部分是项目的核心,按照“基础工具类→用户管理模块”的顺序实现,所有代码均剔除导包语句,直接复制即可使用,同时补充详细的文字描述,说明每段代码的功能、逻辑和实操注意事项,让新手不仅能复制代码,还能理解代码的作用,便于后续修改和扩展。核心功能围绕用户管理展开,串联Excel导入导出、Redis缓存、密码加密等知识点,实现完整的用户管理流程。
4.1 基础工具类(简化但完整,复用性强)
基础工具类是项目的通用组件,无需重复编写代码,重点实现密码加密和全局异常处理,密码加密用于保障用户密码安全,全局异常处理用于统一接口响应格式,提升项目健壮性,避免接口报错时返回杂乱的错误信息,便于前端对接。
4.1.1 密码加密工具类(PasswordUtil.java)
用户密码不能明文存储,本工具类使用BCrypt加密算法,该算法安全可靠,不可逆,能够有效保障用户密码安全,实现密码加密和密码校验两个核心方法,加密方法用于用户新增、密码修改时将明文密码转换为密文,校验方法用于用户登录时对比明文密码与数据库中的密文密码是否一致。
// 密码加密工具类:使用BCrypt加密,安全可靠,不可逆
@Component
public class PasswordUtil {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
/**
* 密码加密:将明文密码加密为密文,存储到数据库
* @param rawPassword 明文密码(用户输入的密码)
* @return 加密后的密文密码
*/
public String encodePassword(String rawPassword) {
return encoder.encode(rawPassword);
}
/**
* 密码校验:对比明文密码与加密后的密文是否一致(登录时使用)
* @param rawPassword 明文密码(用户登录输入)
* @param encodedPassword 数据库中存储的密文密码
* @return true:密码一致,false:密码不一致
*/
public boolean matchesPassword(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
4.1.2 全局异常处理(GlobalExceptionHandler.java)
全局异常处理器用于统一处理项目中所有未捕获的异常,包括系统异常、参数错误异常等,同时定义统一的接口响应格式,让接口返回的信息更规范,便于前端对接。无论接口出现何种异常,都能返回统一格式的响应,避免出现页面报错、返回杂乱错误信息的情况,提升项目的用户体验和健壮性。
// 全局异常处理器:统一处理所有接口异常,统一响应格式
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 统一接口响应格式(泛型,支持所有数据类型)
* 包含状态码、提示信息、响应数据,规范接口返回格式
*/
@Data
public static class Result<T> {
private Integer code; // 状态码(200:成功,400:参数错误,500:系统错误)
private String message; // 提示信息
private T data; // 响应数据(成功时返回,失败时为null)
// 成功响应(带数据)
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("操作成功");
result.setData(data);
return result;
}
// 成功响应(不带数据)
public static <T> Result<T> success() {
return success(null);
}
// 失败响应(自定义状态码和提示信息)
public static <T> Result<T> fail(Integer code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
result.setData(null);
return result;
}
}
/**
* 处理所有未捕获的异常(系统异常)
* 当项目中出现未捕获的异常时,统一返回500状态码和错误信息
*/
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
// 打印异常信息,便于开发调试(生产环境可注释,或输出到日志文件)
e.printStackTrace();
return Result.fail(500, "系统异常:" + e.getMessage());
}
/**
* 处理参数错误异常(如非法参数、参数为空)
* 专门捕获参数相关的异常,返回400状态码,提示参数错误
*/
@ExceptionHandler(IllegalArgumentException.class)
public Result<Void> handleIllegalArgumentException(IllegalArgumentException e) {
return Result.fail(400, e.getMessage());
}
}
4.2 用户管理模块实现(核心模块,完整可运行)
用户管理是管理后台的核心模块,集成了用户增删改查、分页查询、Excel导入导出、Redis缓存等核心功能,所有代码均剔除导包语句,直接复制即可使用,同时补充详细的功能说明和实操提示,确保新手能够顺利实现。
4.2.1 实体类与DTO(SysUser.java、ExcelUserDTO.java)
实体类对应数据库中的sys_user表,字段与数据库表字段一一对应,使用Lombok的@Data注解,简化代码编写,无需手动生成get/set方法;ExcelUserDTO用于Excel导入导出,字段与Excel表格字段对应,实现批量导入导出用户数据的功能,同时添加数据校验,确保导入的数据合法。
// 实体类(SysUser.java):对应sys_user表,存储用户核心信息
@Data
@TableName("sys_user") // 关联数据库表名
public class SysUser {
@TableId(type = IdType.AUTO) // 主键自增,对应数据库id字段
private Long id;
private String username; // 用户名(唯一,用于登录)
private String password; // 加密后的密码,存储到数据库
private String realName; // 真实姓名(可选,可根据需求添加)
private Integer status; // 状态(1启用,0禁用)
}
// Excel导入导出DTO(ExcelUserDTO.java):与Excel表格字段对应
@Data
public class ExcelUserDTO {
@ExcelIgnore // Excel导入导出时忽略该字段(自增主键,无需导入)
private Long id;
@ExcelProperty(value = "用户名", index = 0) // Excel第1列,列名“用户名”
private String username;
@ExcelProperty(value = "密码", index = 1) // Excel第2列,列名“密码”
private String password;
@ExcelProperty(value = "真实姓名", index = 2) // Excel第3列,列名“真实姓名”
private String realName;
@ExcelIgnore // 状态默认启用,无需导入导出
private Integer status = 1;
}
4.2.2 Mapper与Service层(数据库操作与业务逻辑)
Mapper接口继承MyBatis-Plus的BaseMapper,自带增删改查、分页等基础方法,无需手动编写SQL;Service层实现核心业务逻辑,包括分页查询(集成Redis缓存)、Excel导入导出、用户状态更新等功能,串联密码加密、缓存等知识点,确保业务逻辑清晰、可复用。
// Mapper(SysUserMapper.java):数据库操作接口,无需编写SQL
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {}
// Service接口(SysUserService.java):定义业务方法
public interface SysUserService extends IService<SysUser> {
// 分页查询用户(带Redis缓存)
List<SysUser> getUserList(Integer pageNum, Integer pageSize);
// Excel批量导入用户
void importUser(MultipartFile file);
// Excel导出用户
void exportUser(HttpServletResponse response);
// 启用/禁用用户
boolean updateUserStatus(Long userId, Integer status);
}
// Service实现类(SysUserServiceImpl.java):核心业务逻辑实现
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
@Autowired private PasswordUtil passwordUtil;
/**
* 分页查询用户:查询前先检查缓存,有缓存直接返回,无缓存查询数据库并存入缓存
* @Cacheable:缓存注解,指定缓存名称和缓存key,避免缓存冲突
*/
@Override
@Cacheable(value = "user", key = "'list:pageNum:'+#pageNum+':pageSize:'+#pageSize")
public List<SysUser> getUserList(Integer pageNum, Integer pageSize) {
// 分页查询(MyBatis-Plus自带分页方法,无需编写SQL)
Page<SysUser> page = new Page<>(pageNum, pageSize);
IPage<SysUser> userIPage = baseMapper.selectPage(page, null);
return userIPage.getRecords(); // 返回分页数据列表
}
/**
* Excel批量导入用户:批量插入数据,导入后清空缓存,避免缓存脏数据
* @CacheEvict:清空用户相关缓存,确保缓存与数据库数据一致
* @Transactional:事务注解,导入失败回滚,避免数据异常
*/
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = "user", allEntries = true)
public void importUser(MultipartFile file) throws IOException {
// 读取Excel文件,通过监听器处理每一行数据
EasyExcel.read(file.getInputStream(), ExcelUserDTO.class, new ExcelUserImportListener(this, passwordUtil))
.sheet() // 读取第一个sheet
.headRowNumber(1) // 第1行为表头,从第2行开始读取数据
.doRead(); // 开始读取并处理数据
}
/**
* Excel导出用户:查询所有用户数据,导出为Excel文件,便于批量查看
*/
@Override
public void exportUser(HttpServletResponse response) throws IOException {
// 1. 查询所有用户数据(实际项目可添加筛选条件)
List<SysUser> userList = baseMapper.selectList(null);
// 2. 将实体类转换为DTO(适配Excel导出字段)
List<ExcelUserDTO> dtoList = userList.stream().map(user -> {
ExcelUserDTO dto = new ExcelUserDTO();
BeanUtils.copyProperties(user, dto); // 复制属性(实体类→DTO)
return dto;
}).collect(Collectors.toList());
// 3. 配置响应头,避免Excel下载乱码
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("用户数据_" + System.currentTimeMillis(), "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// 4. 导出Excel文件
EasyExcel.write(response.getOutputStream(), ExcelUserDTO.class)
.sheet("用户列表") // sheet名称
.doWrite(dtoList); // 写入数据
}
/**
* 启用/禁用用户:更新用户状态,更新后清空缓存
*/
@Override
@CacheEvict(value = "user", allEntries = true)
public boolean updateUserStatus(Long userId, Integer status) {
// 校验状态参数,避免非法状态
if (status != 0 && status != 1) {
throw new IllegalArgumentException("状态参数错误,只能是0(禁用)或1(启用)");
}
// 更新用户状态
SysUser user = new SysUser();
user.setId(userId);
user.setStatus(status);
return updateById(user);
}
}
4.2.3 Controller层(接口开发,对外提供访问)
Controller层是接口的入口,对外提供用户管理相关的HTTP接口,包括分页查询、新增、修改、删除、Excel导入导出、状态更新等接口,接口路径规范,统一响应格式,便于前端对接,所有接口均有清晰的说明,明确请求方式、请求参数和访问路径。
// 用户管理接口:对外提供访问入口,统一响应格式
@RestController
@RequestMapping("/user") // 接口路径前缀,访问接口时需加上
public class SysUserController {
@Autowired private SysUserService sysUserService;
@Autowired private PasswordUtil passwordUtil;
/**
* 分页查询用户
* 访问路径:http://localhost:8080/management/user/list?pageNum=1&pageSize=10
* @param pageNum 页码(默认1)
* @param pageSize 每页条数(默认10)
*/
@GetMapping("/list")
public Result<List<SysUser>> getUserList(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
List<SysUser> userList = sysUserService.getUserList(pageNum, pageSize);
return Result.success(userList);
}
/**
* 新增用户
* 访问路径:http://localhost:8080/management/user/add(POST请求)
* 请求参数:JSON格式,如{"username":"test","password":"123456","realName":"测试用户"}
*/
@PostMapping("/add")
public Result<Void> addUser(@RequestBody SysUser user) {
// 校验用户名和密码不为空
if (user.getUsername() == null || user.getUsername().isEmpty()) {
return Result.fail(400, "用户名不能为空");
}
if (user.getPassword() == null || user.getPassword().isEmpty()) {
return Result.fail(400, "密码不能为空");
}
// 密码加密,避免明文存储
user.setPassword(passwordUtil.encodePassword(user.getPassword()));
// 保存用户
boolean success = sysUserService.save(user);
return success ? Result.success() : Result.fail(400, "新增用户失败");
}
/**
* Excel批量导入用户
* 访问路径:http://localhost:8080/management/user/import(POST请求)
* 请求参数:multipart/form-data格式,上传Excel文件
*/
@PostMapping("/import")
public Result<Void> importUser(@RequestParam("file") MultipartFile file) {
try {
sysUserService.importUser(file);
return Result.success();
} catch (Exception e) {
return Result.fail(400, "Excel导入失败:" + e.getMessage());
}
}
/**
* Excel导出用户
* 访问路径:http://localhost:8080/management/user/export(GET请求)
* 直接访问即可下载Excel文件
*/
@GetMapping("/export")
public void exportUser(HttpServletResponse response) {
try {
sysUserService.exportUser(response);
} catch (Exception e) {
// 捕获异常,返回错误信息
Result.fail(400, "Excel导出失败:" + e.getMessage());
}
}
/**
* 启用/禁用用户
* 访问路径:http://localhost:8080/management/user/status/1/0(PUT请求)
* @param userId 用户ID
* @param status 状态(0禁用,1启用)
*/
@PutMapping("/status/{userId}/{status}")
public Result<Void> updateUserStatus(@PathVariable Long userId, @PathVariable Integer status) {
boolean success = sysUserService.updateUserStatus(userId, status);
return success ? Result.success() : Result.fail(400, "更新用户状态失败");
}
/**
* 单条删除用户
* 访问路径:http://localhost:8080/management/user/1(DELETE请求,1为用户ID)
*/
@DeleteMapping("/{userId}")
public Result<Void> deleteUser(@PathVariable Long userId) {
boolean success = sysUserService.removeById(userId);
return success ? Result.success() : Result.fail(400, "删除用户失败");
}
}
4.2.4 Excel导入监听器(ExcelUserImportListener.java)
Excel导入时,需要通过监听器处理每一行数据,实现数据校验、密码加密、批量插入等功能,确保导入的数据合法、准确,避免出现数据异常,监听器代码直接复制即可使用,无需修改。
// Excel导入监听器:处理Excel每一行数据,实现批量导入
@Slf4j
@Getter
public class ExcelUserImportListener extends AnalysisEventListener<ExcelUserDTO> {
private static final int BATCH_SIZE = 100; // 批量插入批次大小,提升导入效率
private List<ExcelUserDTO> userList = new ArrayList<>(); // 临时存储导入数据
private final SysUserService userService; // 用户Service,用于插入数据
private final PasswordUtil passwordUtil; // 密码加密工具类
private int importCount = 0; // 导入成功条数
// 构造方法,注入Service和密码工具类
public ExcelUserImportListener(SysUserService userService, PasswordUtil passwordUtil) {
this.userService = userService;
this.passwordUtil = passwordUtil;
}
/**
* 每读取一行Excel数据,执行一次该方法
*/
@Override
public void invoke(ExcelUserDTO data, AnalysisContext context) {
// 数据校验(简单校验,可根据需求扩展)
if (data.getUsername() == null || data.getUsername().isEmpty()) {
throw new RuntimeException("第" + (context.readRowHolder().getRowIndex() + 1) + "行:用户名不能为空");
}
if (data.getPassword() == null || data.getPassword().isEmpty()) {
throw new RuntimeException("第" + (context.readRowHolder().getRowIndex() + 1) + "行:密码不能为空");
}
// 密码加密,将Excel中的明文密码转换为密文
data.setPassword(passwordUtil.encodePassword(data.getPassword()));
// 将数据加入临时列表
userList.add(data);
// 达到批次大小,批量插入数据,避免内存溢出
if (userList.size() >= BATCH_SIZE) {
batchInsert();
userList.clear(); // 清空临时列表
}
}
/**
* Excel读取完成后,执行一次该方法,处理剩余数据
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
if (!userList.isEmpty()) {
batchInsert(); // 处理剩余不足批次的数据
userList.clear();
}
log.info("Excel用户导入完成,共导入{}条数据", importCount);
}
/**
* 批量插入数据:将DTO转换为实体类,批量保存到数据库
*/
private void batchInsert() {
// DTO转换为实体类
List<SysUser> sysUsers = userList.stream().map(dto -> {
SysUser user = new SysUser();
BeanUtils.copyProperties(dto, user);
return user;
}).toList();
// 批量插入(MyBatis-Plus自带批量保存方法,提升效率)
userService.saveBatch(sysUsers);
// 更新导入成功条数
importCount += sysUsers.size();
}
}
实操提示:1. 所有代码均无导包,直接复制到对应类中即可使用,确保类名与文件名一致;2. 运行项目前,确保MySQL和Redis服务正常启动,配置文件中的数据库密码已修改为自己的;3. 测试接口时,可使用Postman工具,按照Controller层的接口路径和请求方式测试,确保接口正常返回数据;4. 角色、菜单模块的实现逻辑与用户模块一致,可参考用户模块仿写,核心是实体类、Mapper、Service、Controller的层层对应。
1257



被折叠的 条评论
为什么被折叠?



