From 2ceaa01e1b0b6a90b8a5d567c6fb8c518de585e8 Mon Sep 17 00:00:00 2001
From: yutao <2930275373@qq.com>
Date: Tue, 22 Apr 2025 19:36:26 +0800
Subject: [PATCH 1/4] 111
---
1.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 1.txt
diff --git a/1.txt b/1.txt
new file mode 100644
index 0000000..dc46e18
--- /dev/null
+++ b/1.txt
@@ -0,0 +1 @@
+654148951
\ No newline at end of file
--
2.34.1
From 9e2436cbc8357107d619f6cd0bc71e4df74591cc Mon Sep 17 00:00:00 2001
From: yutao <2930275373@qq.com>
Date: Mon, 28 Apr 2025 21:10:39 +0800
Subject: [PATCH 2/4] LYT
---
repo/controller/RepoController.java | 132 ++++++
repo/dto/RepoDTO.java | 67 +++
repo/dto/request/RepoReqDTO.java | 40 ++
repo/dto/response/RepoRespDTO.java | 45 ++
repo/entity/Repo.java | 62 +++
repo/mapper/RepoMapper.java | 31 ++
repo/service/RepoService.java | 38 ++
repo/service/impl/RepoServiceImpl.java | 53 +++
.../controller/SysConfigController.java | 92 +++++
sys/config/dto/SysConfigDTO.java | 61 +++
sys/config/entity/SysConfig.java | 53 +++
sys/config/mapper/SysConfigMapper.java | 25 ++
sys/config/service/SysConfigService.java | 34 ++
.../service/impl/SysConfigServiceImpl.java | 54 +++
.../controller/SysDepartController.java | 186 +++++++++
sys/depart/dto/SysDepartDTO.java | 73 ++++
sys/depart/dto/request/DepartSortReqDTO.java | 42 ++
sys/depart/dto/response/SysDepartTreeDTO.java | 41 ++
sys/depart/entity/SysDepart.java | 59 +++
sys/depart/mapper/SysDepartMapper.java | 28 ++
sys/depart/service/SysDepartService.java | 62 +++
.../service/impl/SysDepartServiceImpl.java | 368 +++++++++++++++++
sys/system/mapper/SysDictMapper.java | 40 ++
sys/system/service/SysDictService.java | 26 ++
.../service/impl/SysDictServiceImpl.java | 45 ++
sys/user/controller/SysRoleController.java | 106 +++++
sys/user/controller/SysUserController.java | 245 +++++++++++
sys/user/dto/SysRoleDTO.java | 45 ++
sys/user/dto/SysUserDTO.java | 108 +++++
sys/user/dto/SysUserRoleDTO.java | 55 +++
sys/user/dto/request/SysUserLoginReqDTO.java | 45 ++
sys/user/dto/request/SysUserSaveReqDTO.java | 83 ++++
sys/user/dto/request/SysUserTokenReqDTO.java | 38 ++
sys/user/dto/response/SysUserLoginDTO.java | 106 +++++
sys/user/entity/SysRole.java | 54 +++
sys/user/entity/SysUser.java | 103 +++++
sys/user/entity/SysUserRole.java | 53 +++
sys/user/mapper/SysRoleMapper.java | 32 ++
sys/user/mapper/SysUserMapper.java | 32 ++
sys/user/mapper/SysUserRoleMapper.java | 32 ++
sys/user/service/SysRoleService.java | 52 +++
sys/user/service/SysUserRoleService.java | 94 +++++
sys/user/service/SysUserService.java | 99 +++++
sys/user/service/impl/SysRoleServiceImpl.java | 62 +++
.../service/impl/SysUserRoleServiceImpl.java | 200 +++++++++
sys/user/service/impl/SysUserServiceImpl.java | 383 ++++++++++++++++++
46 files changed, 3784 insertions(+)
create mode 100644 repo/controller/RepoController.java
create mode 100644 repo/dto/RepoDTO.java
create mode 100644 repo/dto/request/RepoReqDTO.java
create mode 100644 repo/dto/response/RepoRespDTO.java
create mode 100644 repo/entity/Repo.java
create mode 100644 repo/mapper/RepoMapper.java
create mode 100644 repo/service/RepoService.java
create mode 100644 repo/service/impl/RepoServiceImpl.java
create mode 100644 sys/config/controller/SysConfigController.java
create mode 100644 sys/config/dto/SysConfigDTO.java
create mode 100644 sys/config/entity/SysConfig.java
create mode 100644 sys/config/mapper/SysConfigMapper.java
create mode 100644 sys/config/service/SysConfigService.java
create mode 100644 sys/config/service/impl/SysConfigServiceImpl.java
create mode 100644 sys/depart/controller/SysDepartController.java
create mode 100644 sys/depart/dto/SysDepartDTO.java
create mode 100644 sys/depart/dto/request/DepartSortReqDTO.java
create mode 100644 sys/depart/dto/response/SysDepartTreeDTO.java
create mode 100644 sys/depart/entity/SysDepart.java
create mode 100644 sys/depart/mapper/SysDepartMapper.java
create mode 100644 sys/depart/service/SysDepartService.java
create mode 100644 sys/depart/service/impl/SysDepartServiceImpl.java
create mode 100644 sys/system/mapper/SysDictMapper.java
create mode 100644 sys/system/service/SysDictService.java
create mode 100644 sys/system/service/impl/SysDictServiceImpl.java
create mode 100644 sys/user/controller/SysRoleController.java
create mode 100644 sys/user/controller/SysUserController.java
create mode 100644 sys/user/dto/SysRoleDTO.java
create mode 100644 sys/user/dto/SysUserDTO.java
create mode 100644 sys/user/dto/SysUserRoleDTO.java
create mode 100644 sys/user/dto/request/SysUserLoginReqDTO.java
create mode 100644 sys/user/dto/request/SysUserSaveReqDTO.java
create mode 100644 sys/user/dto/request/SysUserTokenReqDTO.java
create mode 100644 sys/user/dto/response/SysUserLoginDTO.java
create mode 100644 sys/user/entity/SysRole.java
create mode 100644 sys/user/entity/SysUser.java
create mode 100644 sys/user/entity/SysUserRole.java
create mode 100644 sys/user/mapper/SysRoleMapper.java
create mode 100644 sys/user/mapper/SysUserMapper.java
create mode 100644 sys/user/mapper/SysUserRoleMapper.java
create mode 100644 sys/user/service/SysRoleService.java
create mode 100644 sys/user/service/SysUserRoleService.java
create mode 100644 sys/user/service/SysUserService.java
create mode 100644 sys/user/service/impl/SysRoleServiceImpl.java
create mode 100644 sys/user/service/impl/SysUserRoleServiceImpl.java
create mode 100644 sys/user/service/impl/SysUserServiceImpl.java
diff --git a/repo/controller/RepoController.java b/repo/controller/RepoController.java
new file mode 100644
index 0000000..7d1c420
--- /dev/null
+++ b/repo/controller/RepoController.java
@@ -0,0 +1,132 @@
+package com.yf.exam.modules.repo.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yf.exam.core.api.ApiRest;
+import com.yf.exam.core.api.controller.BaseController;
+import com.yf.exam.core.api.dto.BaseIdReqDTO;
+import com.yf.exam.core.api.dto.BaseIdsReqDTO;
+import com.yf.exam.core.api.dto.PagingReqDTO;
+import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO;
+import com.yf.exam.modules.qu.service.QuRepoService;
+import com.yf.exam.modules.repo.dto.RepoDTO;
+import com.yf.exam.modules.repo.dto.request.RepoReqDTO;
+import com.yf.exam.modules.repo.dto.response.RepoRespDTO;
+import com.yf.exam.modules.repo.entity.Repo;
+import com.yf.exam.modules.repo.service.RepoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 题库控制器,处理与题库相关的 HTTP 请求
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:25
+ */
+@Api(tags={"题库"})
+@RestController
+@RequestMapping("/exam/api/repo")
+public class RepoController extends BaseController {
+
+ /**
+ * 注入题库服务,用于处理题库相关的业务逻辑
+ */
+ @Autowired
+ private RepoService baseService;
+
+ /**
+ * 注入题目与题库关联服务,用于处理题目与题库的批量操作
+ */
+ @Autowired
+ private QuRepoService quRepoService;
+
+ /**
+ * 添加或修改题库信息
+ * @param reqDTO 包含题库信息的请求数据传输对象
+ * @return 操作结果,封装在 ApiRest 对象中
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "添加或修改")
+ @RequestMapping(value = "/save", method = { RequestMethod.POST})
+ public ApiRest save(@RequestBody RepoDTO reqDTO) {
+ // 调用服务层方法保存或更新题库信息
+ baseService.save(reqDTO);
+ // 返回操作成功的响应
+ return super.success();
+ }
+
+ /**
+ * 批量删除题库
+ * @param reqDTO 包含要删除的题库 ID 列表的请求数据传输对象
+ * @return 操作结果,封装在 ApiRest 对象中
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "批量删除")
+ @RequestMapping(value = "/delete", method = { RequestMethod.POST})
+ public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) {
+ // 根据 ID 列表删除题库
+ baseService.removeByIds(reqDTO.getIds());
+ // 返回操作成功的响应
+ return super.success();
+ }
+
+ /**
+ * 查找单个题库的详情信息
+ * @param reqDTO 包含要查找的题库 ID 的请求数据传输对象
+ * @return 包含题库详情信息的操作结果,封装在 ApiRest 对象中
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "查找详情")
+ @RequestMapping(value = "/detail", method = { RequestMethod.POST})
+ public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) {
+ // 根据 ID 获取题库实体
+ Repo entity = baseService.getById(reqDTO.getId());
+ // 创建一个新的 DTO 对象
+ RepoDTO dto = new RepoDTO();
+ // 将实体对象的属性复制到 DTO 对象中
+ BeanUtils.copyProperties(entity, dto);
+ // 返回包含 DTO 对象的操作成功响应
+ return super.success(dto);
+ }
+
+ /**
+ * 分页查找题库信息
+ * @param reqDTO 包含分页和查询条件的请求数据传输对象
+ * @return 包含分页查询结果的操作结果,封装在 ApiRest 对象中
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "分页查找")
+ @RequestMapping(value = "/paging", method = { RequestMethod.POST})
+ public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) {
+
+ // 调用服务层方法进行分页查询并转换结果
+ IPage page = baseService.paging(reqDTO);
+
+ // 返回包含分页结果的操作成功响应
+ return super.success(page);
+ }
+
+ /**
+ * 批量操作,批量加入或从题库移除题目
+ * @param reqDTO 包含批量操作信息的请求数据传输对象
+ * @return 操作结果,封装在 ApiRest 对象中
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "批量操作", notes = "批量加入或从题库移除")
+ @RequestMapping(value = "/batch-action", method = { RequestMethod.POST})
+ public ApiRest batchAction(@RequestBody QuRepoBatchReqDTO reqDTO) {
+
+ // 调用服务层方法进行批量操作
+ quRepoService.batchAction(reqDTO);
+ // 返回操作成功的响应
+ return super.success();
+ }
+}
diff --git a/repo/dto/RepoDTO.java b/repo/dto/RepoDTO.java
new file mode 100644
index 0000000..c2063da
--- /dev/null
+++ b/repo/dto/RepoDTO.java
@@ -0,0 +1,67 @@
+package com.yf.exam.modules.repo.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *
+ * 题库请求类,用于在与题库相关的业务操作中传输数据,实现了 Serializable 接口,可进行序列化操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+@Data
+@ApiModel(value="题库", description="题库")
+public class RepoDTO implements Serializable {
+
+ // 序列化版本号,确保序列化和反序列化的兼容性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 题库的唯一标识 ID,在业务操作中用于唯一确定一个题库。
+ * 该属性为必填项。
+ */
+ @ApiModelProperty(value = "题库ID", required=true)
+ private String id;
+
+ /**
+ * 题库的编号,可用于对题库进行分类或标识。
+ * 该属性为必填项。
+ */
+ @ApiModelProperty(value = "题库编号", required=true)
+ private String code;
+
+ /**
+ * 题库的名称,用于直观地表示题库的主题或内容。
+ * 该属性为必填项。
+ */
+ @ApiModelProperty(value = "题库名称", required=true)
+ private String title;
+
+ /**
+ * 题库的备注信息,可用于记录关于题库的额外说明或注意事项。
+ * 该属性为必填项。
+ */
+ @ApiModelProperty(value = "题库备注", required=true)
+ private String remark;
+
+ /**
+ * 题库的创建时间,记录该题库创建的具体时间点。
+ * 该属性为必填项。
+ */
+ @ApiModelProperty(value = "创建时间", required=true)
+ private Date createTime;
+
+ /**
+ * 题库的更新时间,记录该题库最后一次被修改的具体时间点。
+ * 该属性为必填项。
+ */
+ @ApiModelProperty(value = "更新时间", required=true)
+ private Date updateTime;
+
+}
diff --git a/repo/dto/request/RepoReqDTO.java b/repo/dto/request/RepoReqDTO.java
new file mode 100644
index 0000000..89cef56
--- /dev/null
+++ b/repo/dto/request/RepoReqDTO.java
@@ -0,0 +1,40 @@
+package com.yf.exam.modules.repo.dto.request;
+
+import com.yf.exam.modules.repo.dto.RepoDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ *
+ * 题库请求类,用于在分页查询题库信息时传递请求参数,继承自 RepoDTO 类,可复用其属性。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+@Data
+@ApiModel(value="题库分页请求类", description="题库分页请求类")
+public class RepoReqDTO extends RepoDTO {
+
+ // 序列化版本号,确保序列化和反序列化的兼容性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 排除题库 ID 列表,在查询题库时,会排除这些 ID 对应的题库。
+ * 该参数为必填项。
+ */
+ @ApiModelProperty(value = "排除题库ID", required=true)
+ private List excludes;
+
+ /**
+ * 题库标题,用于筛选具有特定标题的题库。
+ * 此处注解中的描述与字段名不符,原注解描述为单选题数量,可能存在错误,应根据实际需求调整。
+ * 该参数为必填项。
+ */
+ @ApiModelProperty(value = "单选题数量", required=true)
+ private String title;
+
+}
diff --git a/repo/dto/response/RepoRespDTO.java b/repo/dto/response/RepoRespDTO.java
new file mode 100644
index 0000000..e871768
--- /dev/null
+++ b/repo/dto/response/RepoRespDTO.java
@@ -0,0 +1,45 @@
+package com.yf.exam.modules.repo.dto.response;
+
+import com.yf.exam.modules.repo.dto.RepoDTO;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ * 题库分页响应类,用于封装题库分页查询的响应数据。
+ * 该类继承自 RepoDTO,在其基础上扩展了不同题型数量的属性。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+@Data
+@ApiModel(value="题库分页响应类", description="题库分页响应类")
+public class RepoRespDTO extends RepoDTO {
+
+ // 序列化版本号,用于在序列化和反序列化过程中确保版本的兼容性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 多选题数量,代表该题库中多选题的总数。
+ * 该属性为必填项,在响应数据中必须包含。
+ */
+ @ApiModelProperty(value = "多选题数量", required=true)
+ private Integer multiCount;
+
+ /**
+ * 单选题数量,代表该题库中单选题的总数。
+ * 该属性为必填项,在响应数据中必须包含。
+ */
+ @ApiModelProperty(value = "单选题数量", required=true)
+ private Integer radioCount;
+
+ /**
+ * 判断题数量,代表该题库中判断题的总数。
+ * 该属性为必填项,在响应数据中必须包含。
+ */
+ @ApiModelProperty(value = "判断题数量", required=true)
+ private Integer judgeCount;
+
+}
diff --git a/repo/entity/Repo.java b/repo/entity/Repo.java
new file mode 100644
index 0000000..cb37a3c
--- /dev/null
+++ b/repo/entity/Repo.java
@@ -0,0 +1,62 @@
+package com.yf.exam.modules.repo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ *
+ * 题库实体类,对应数据库中的 `el_repo` 表,用于封装题库相关的数据。
+ * 继承自 MyBatis-Plus 的 Model 类,可使用其提供的 ActiveRecord 功能进行数据库操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+@Data
+// 表明该实体类对应数据库中的 el_repo 表
+@TableName("el_repo")
+public class Repo extends Model {
+
+ // 序列化版本号,确保序列化和反序列化的兼容性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 题库ID,作为表的主键,使用 MyBatis-Plus 的 ASSIGN_ID 策略自动分配 ID。
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private String id;
+
+ /**
+ * 题库编号,用于标识不同的题库。
+ */
+ private String code;
+
+ /**
+ * 题库名称,直观反映题库的主题或内容。
+ */
+ private String title;
+
+ /**
+ * 题库备注,可用于记录关于题库的额外说明信息。
+ */
+ private String remark;
+
+ /**
+ * 创建时间,记录题库创建的时间,对应数据库表中的 create_time 字段。
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 更新时间,记录题库最后一次更新的时间,对应数据库表中的 update_time 字段。
+ */
+ @TableField("update_time")
+ private Date updateTime;
+
+}
diff --git a/repo/mapper/RepoMapper.java b/repo/mapper/RepoMapper.java
new file mode 100644
index 0000000..f6d009e
--- /dev/null
+++ b/repo/mapper/RepoMapper.java
@@ -0,0 +1,31 @@
+package com.yf.exam.modules.repo.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yf.exam.modules.repo.dto.request.RepoReqDTO;
+import com.yf.exam.modules.repo.dto.response.RepoRespDTO;
+import com.yf.exam.modules.repo.entity.Repo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ *
+ * 题库Mapper接口,继承自 MyBatis-Plus 的 BaseMapper 接口,用于操作题库实体类与数据库的交互。
+ * BaseMapper 接口提供了基本的增删改查操作,该接口在此基础上扩展了分页查询功能。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+public interface RepoMapper extends BaseMapper {
+
+ /**
+ * 分页查询题库信息
+ *
+ * @param page 分页对象,包含分页的相关信息,如当前页码、每页记录数等,用于控制查询结果的分页展示。
+ * @param query 题库查询请求对象,包含查询条件,如排除题库ID、题库标题等,用于筛选符合条件的题库记录。
+ * @return 返回一个包含 RepoRespDTO 对象的分页数据,RepoRespDTO 是题库分页响应类,封装了题库的相关信息以及不同题型的数量。
+ */
+ IPage paging(Page page, @Param("query") RepoReqDTO query);
+
+}
diff --git a/repo/service/RepoService.java b/repo/service/RepoService.java
new file mode 100644
index 0000000..85dbed7
--- /dev/null
+++ b/repo/service/RepoService.java
@@ -0,0 +1,38 @@
+package com.yf.exam.modules.repo.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yf.exam.core.api.dto.PagingReqDTO;
+import com.yf.exam.modules.repo.dto.RepoDTO;
+import com.yf.exam.modules.repo.dto.request.RepoReqDTO;
+import com.yf.exam.modules.repo.dto.response.RepoRespDTO;
+import com.yf.exam.modules.repo.entity.Repo;
+
+/**
+ *
+ * 题库业务类,定义了与题库相关的业务操作接口。
+ * 该接口继承自 MyBatis-Plus 的 IService 接口,可使用其提供的基础 CRUD 操作方法。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+public interface RepoService extends IService {
+
+ /**
+ * 分页查询题库数据
+ *
+ * @param reqDTO 包含分页信息和查询条件的请求对象。
+ * PagingReqDTO 封装了分页参数,RepoReqDTO 封装了具体的查询条件,如排除题库 ID、题库标题等。
+ * @return 一个 IPage 对象,包含分页查询结果,结果元素为 RepoRespDTO 类型,该类型封装了题库的详细信息及题型数量。
+ */
+ IPage paging(PagingReqDTO reqDTO);
+
+ /**
+ * 保存或更新题库信息
+ *
+ * @param reqDTO 包含题库信息的数据传输对象,包含题库的 ID、编号、名称、备注等信息。
+ * 若 DTO 中的 ID 存在,则进行更新操作;若 ID 不存在,则进行新增操作。
+ */
+ void save(RepoDTO reqDTO);
+}
diff --git a/repo/service/impl/RepoServiceImpl.java b/repo/service/impl/RepoServiceImpl.java
new file mode 100644
index 0000000..454d167
--- /dev/null
+++ b/repo/service/impl/RepoServiceImpl.java
@@ -0,0 +1,53 @@
+package com.yf.exam.modules.repo.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yf.exam.core.api.dto.PagingReqDTO;
+import com.yf.exam.core.utils.BeanMapper;
+import com.yf.exam.modules.repo.dto.RepoDTO;
+import com.yf.exam.modules.repo.dto.request.RepoReqDTO;
+import com.yf.exam.modules.repo.dto.response.RepoRespDTO;
+import com.yf.exam.modules.repo.entity.Repo;
+import com.yf.exam.modules.repo.mapper.RepoMapper;
+import com.yf.exam.modules.repo.service.RepoService;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 题库服务实现类,实现了 RepoService 接口,继承自 MyBatis-Plus 的 ServiceImpl,
+ * 用于处理题库相关的业务逻辑,与数据库进行交互。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-05-25 13:23
+ */
+@Service
+public class RepoServiceImpl extends ServiceImpl implements RepoService {
+
+ /**
+ * 分页查询题库信息
+ *
+ * @param reqDTO 包含分页信息和查询参数的请求对象
+ * @return 包含分页结果的 IPage 对象,其中元素为 RepoRespDTO 类型
+ */
+ @Override
+ public IPage paging(PagingReqDTO reqDTO) {
+ // 调用 RepoMapper 的 paging 方法进行分页查询,传入分页对象和查询参数
+ return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams());
+ }
+
+ /**
+ * 保存或更新题库信息
+ *
+ * @param reqDTO 包含题库信息的请求数据传输对象
+ */
+ @Override
+ public void save(RepoDTO reqDTO) {
+
+ // 复制 DTO 对象的属性到实体对象
+ Repo entity = new Repo();
+ BeanMapper.copy(reqDTO, entity);
+ // 调用 MyBatis-Plus 的 saveOrUpdate 方法保存或更新实体对象
+ this.saveOrUpdate(entity);
+ }
+}
diff --git a/sys/config/controller/SysConfigController.java b/sys/config/controller/SysConfigController.java
new file mode 100644
index 0000000..fa9cfe4
--- /dev/null
+++ b/sys/config/controller/SysConfigController.java
@@ -0,0 +1,92 @@
+package com.yf.exam.modules.sys.config.controller;
+
+// 导入 API 响应结果类,用于封装接口返回数据
+import com.yf.exam.core.api.ApiRest;
+// 导入基础控制器类,提供一些通用的控制器方法
+import com.yf.exam.core.api.controller.BaseController;
+// 导入基础 ID 响应数据传输对象类
+import com.yf.exam.core.api.dto.BaseIdRespDTO;
+// 导入 Bean 映射工具类,用于对象属性的复制
+import com.yf.exam.core.utils.BeanMapper;
+// 导入图片校验工具类
+import com.yf.exam.modules.qu.utils.ImageCheckUtils;
+// 导入系统配置数据传输对象类
+import com.yf.exam.modules.sys.config.dto.SysConfigDTO;
+// 导入系统配置实体类
+import com.yf.exam.modules.sys.config.entity.SysConfig;
+// 导入系统配置服务接口
+import com.yf.exam.modules.sys.config.service.SysConfigService;
+// 导入 Swagger 注解,用于生成 API 文档,标记控制器的标签
+import io.swagger.annotations.Api;
+// 导入 Swagger 注解,用于生成 API 文档,标记接口的操作描述
+import io.swagger.annotations.ApiOperation;
+// 导入 Shiro 注解,用于权限控制,要求用户具有指定角色才能访问接口
+import org.apache.shiro.authz.annotation.RequiresRoles;
+// 导入 Spring 依赖注入注解
+import org.springframework.beans.factory.annotation.Autowired;
+// 导入 Spring 请求体注解,用于将请求体中的数据绑定到方法参数上
+import org.springframework.web.bind.annotation.RequestBody;
+// 导入 Spring 请求映射注解,用于映射请求路径
+import org.springframework.web.bind.annotation.RequestMapping;
+// 导入 Spring 请求方法注解,用于指定请求的 HTTP 方法
+import org.springframework.web.bind.annotation.RequestMethod;
+// 导入 Spring 控制器注解,标记该类为 RESTful 风格的控制器
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ *
+ * 通用配置控制器,处理与系统通用配置相关的接口请求
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-17 09:12
+ */
+@Api(tags={"通用配置"})
+@RestController
+@RequestMapping("/exam/api/sys/config")
+public class SysConfigController extends BaseController {
+
+ // 自动注入系统配置服务实例,用于调用系统配置相关的业务逻辑
+ @Autowired
+ private SysConfigService baseService;
+
+ // 自动注入图片校验工具实例,用于校验图片地址
+ @Autowired
+ private ImageCheckUtils imageCheckUtils;
+
+ /**
+ * 添加或修改系统配置信息
+ * @param reqDTO 系统配置数据传输对象,包含要添加或修改的配置信息
+ * @return 封装了操作结果和配置 ID 的 API 响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "添加或修改")
+ @RequestMapping(value = "/save", method = { RequestMethod.POST})
+ public ApiRest save(@RequestBody SysConfigDTO reqDTO) {
+
+ // 复制请求数据传输对象中的属性到系统配置实体对象中
+ SysConfig entity = new SysConfig();
+ BeanMapper.copy(reqDTO, entity);
+
+ // 调用图片校验工具类的方法,校验系统配置中的背景 LOGO 地址是否合法
+ imageCheckUtils.checkImage(entity.getBackLogo(), "系统LOGO地址错误!");
+
+ // 调用系统配置服务的方法,保存或更新系统配置信息
+ baseService.saveOrUpdate(entity);
+ // 调用父类的成功响应方法,返回包含配置 ID 的响应对象
+ return super.success(new BaseIdRespDTO(entity.getId()));
+ }
+
+ /**
+ * 查找系统配置详情
+ * @return 封装了系统配置详情数据传输对象的 API 响应对象
+ */
+ @ApiOperation(value = "查找详情")
+ @RequestMapping(value = "/detail", method = { RequestMethod.POST})
+ public ApiRest find() {
+ // 调用系统配置服务的方法,获取系统配置详情数据传输对象
+ SysConfigDTO dto = baseService.find();
+ // 调用父类的成功响应方法,返回包含系统配置详情的响应对象
+ return super.success(dto);
+ }
+}
diff --git a/sys/config/dto/SysConfigDTO.java b/sys/config/dto/SysConfigDTO.java
new file mode 100644
index 0000000..f85b824
--- /dev/null
+++ b/sys/config/dto/SysConfigDTO.java
@@ -0,0 +1,61 @@
+// 定义包名,表明该类所属的模块和功能目录
+package com.yf.exam.modules.sys.config.dto;
+
+// 导入 Swagger 注解,用于生成 API 文档,标记类或属性的描述信息
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法
+import lombok.Data;
+
+// 导入 Serializable 接口,表明该类的对象可以被序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 通用配置请求类,用于在不同层之间传输系统通用配置信息
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-17 09:12
+ */
+// 自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 为 Swagger 文档提供类的描述信息
+@ApiModel(value="通用配置", description="通用配置")
+public class SysConfigDTO implements Serializable {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 系统配置的唯一标识
+ * 该属性在请求和响应中是必需的
+ */
+ @ApiModelProperty(value = "ID", required=true)
+ private String id;
+
+ /**
+ * 系统的名称
+ */
+ @ApiModelProperty(value = "系统名称")
+ private String siteName;
+
+ /**
+ * 前端页面显示的 LOGO 地址
+ */
+ @ApiModelProperty(value = "前端LOGO")
+ private String frontLogo;
+
+ /**
+ * 后台管理页面显示的 LOGO 地址
+ */
+ @ApiModelProperty(value = "后台LOGO")
+ private String backLogo;
+
+ /**
+ * 系统的版权信息
+ */
+ @ApiModelProperty(value = "版权信息")
+ private String copyRight;
+
+}
diff --git a/sys/config/entity/SysConfig.java b/sys/config/entity/SysConfig.java
new file mode 100644
index 0000000..070ab06
--- /dev/null
+++ b/sys/config/entity/SysConfig.java
@@ -0,0 +1,53 @@
+package com.yf.exam.modules.sys.config.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+*
+* 通用配置实体类
+*
+*
+* @author 聪明笨狗
+* @since 2020-04-17 09:12
+*/
+@Data
+@TableName("sys_config")
+public class SysConfig extends Model {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * ID
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private String id;
+
+ /**
+ * 系统名称
+ */
+ @TableField("site_name")
+ private String siteName;
+
+ /**
+ * 前端LOGO
+ */
+ @TableField("front_logo")
+ private String frontLogo;
+
+ /**
+ * 后台LOGO
+ */
+ @TableField("back_logo")
+ private String backLogo;
+
+ /**
+ * 版权信息
+ */
+ @TableField("copy_right")
+ private String copyRight;
+}
diff --git a/sys/config/mapper/SysConfigMapper.java b/sys/config/mapper/SysConfigMapper.java
new file mode 100644
index 0000000..35eea21
--- /dev/null
+++ b/sys/config/mapper/SysConfigMapper.java
@@ -0,0 +1,25 @@
+/**
+ * 定义包名,表明该类所在的模块和目录结构,此包为系统配置模块的映射器包
+ */
+package com.yf.exam.modules.sys.config.mapper;
+
+/**
+ * 导入 MyBatis-Plus 框架的 BaseMapper 接口,用于提供基本的数据库操作方法
+ */
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+/**
+ * 导入系统配置实体类,该实体类对应数据库中的系统配置表
+ */
+import com.yf.exam.modules.sys.config.entity.SysConfig;
+
+/**
+ *
+ * 通用配置Mapper,用于与数据库中的系统配置表进行交互,继承自 BaseMapper 可使用其提供的基础 CRUD 操作
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-17 09:12
+ */
+public interface SysConfigMapper extends BaseMapper {
+ // 该接口目前未自定义额外的数据库操作方法,可根据需求在此添加
+}
diff --git a/sys/config/service/SysConfigService.java b/sys/config/service/SysConfigService.java
new file mode 100644
index 0000000..321b533
--- /dev/null
+++ b/sys/config/service/SysConfigService.java
@@ -0,0 +1,34 @@
+/**
+ * 定义包名,表明该类所属的模块和功能目录,这里是系统配置服务模块
+ */
+package com.yf.exam.modules.sys.config.service;
+
+/**
+ * 导入 MyBatis-Plus 框架的扩展服务接口,该接口提供了一些通用的服务层方法
+ */
+import com.baomidou.mybatisplus.extension.service.IService;
+/**
+ * 导入系统配置数据传输对象类,用于在不同层之间传输系统配置相关的数据
+ */
+import com.yf.exam.modules.sys.config.dto.SysConfigDTO;
+/**
+ * 导入系统配置实体类,对应数据库中的系统配置表
+ */
+import com.yf.exam.modules.sys.config.entity.SysConfig;
+
+/**
+ *
+ * 通用配置业务类,定义了与系统通用配置相关的业务方法,继承自 IService 接口可使用其提供的基础服务方法
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-17 09:12
+ */
+public interface SysConfigService extends IService {
+
+ /**
+ * 查找配置信息,从数据库或其他数据源中获取系统配置信息并封装成 SysConfigDTO 对象返回
+ * @return 系统配置数据传输对象,包含系统配置的相关信息
+ */
+ SysConfigDTO find();
+}
diff --git a/sys/config/service/impl/SysConfigServiceImpl.java b/sys/config/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 0000000..c02cf8e
--- /dev/null
+++ b/sys/config/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,54 @@
+// 定义当前类所在的包
+package com.yf.exam.modules.sys.config.service.impl;
+
+// 导入 MyBatis-Plus 框架的查询条件构造器类
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 框架的服务实现基类
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+// 导入自定义的 Bean 映射工具类,用于对象属性的复制
+import com.yf.exam.core.utils.BeanMapper;
+// 导入系统配置数据传输对象类
+import com.yf.exam.modules.sys.config.dto.SysConfigDTO;
+// 导入系统配置实体类
+import com.yf.exam.modules.sys.config.entity.SysConfig;
+// 导入系统配置映射器接口
+import com.yf.exam.modules.sys.config.mapper.SysConfigMapper;
+// 导入系统配置服务接口
+import com.yf.exam.modules.sys.config.service.SysConfigService;
+// 导入 Spring 框架的服务注解,将该类标记为服务层组件
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 语言设置 服务实现类,负责处理系统配置的具体业务逻辑
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-17 09:12
+ */
+// 将该类标记为 Spring 服务组件,使其可以被 Spring 容器管理
+@Service
+public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService {
+
+ /**
+ * 查找系统配置信息,返回第一个系统配置的 DTO 对象
+ *
+ * @return 系统配置数据传输对象
+ */
+ @Override
+ public SysConfigDTO find() {
+ // 创建一个查询条件构造器,用于构建对 SysConfig 实体的查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ // 在查询语句末尾添加 "LIMIT 1",表示只查询一条记录
+ wrapper.last(" LIMIT 1");
+
+ // 调用父类的 getOne 方法,根据查询条件获取一个 SysConfig 实体对象,false 表示不严格校验是否只返回一条记录
+ SysConfig entity = this.getOne(wrapper, false);
+ // 创建一个新的系统配置数据传输对象
+ SysConfigDTO dto = new SysConfigDTO();
+ // 使用 BeanMapper 工具类将 SysConfig 实体对象的属性复制到 SysConfigDTO 对象中
+ BeanMapper.copy(entity, dto);
+ // 返回填充好数据的系统配置数据传输对象
+ return dto;
+ }
+}
diff --git a/sys/depart/controller/SysDepartController.java b/sys/depart/controller/SysDepartController.java
new file mode 100644
index 0000000..fe7be06
--- /dev/null
+++ b/sys/depart/controller/SysDepartController.java
@@ -0,0 +1,186 @@
+// 定义当前类所在的包,表明该类属于系统部门控制器模块
+package com.yf.exam.modules.sys.depart.controller;
+
+// 导入 MyBatis-Plus 的查询条件构造器,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于处理分页查询结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入自定义的 API 统一响应类,用于封装接口返回数据
+import com.yf.exam.core.api.ApiRest;
+// 导入自定义的基础控制器类,提供一些通用的控制器方法
+import com.yf.exam.core.api.controller.BaseController;
+// 导入自定义的基础单个 ID 请求数据传输对象类
+import com.yf.exam.core.api.dto.BaseIdReqDTO;
+// 导入自定义的基础多个 ID 请求数据传输对象类
+import com.yf.exam.core.api.dto.BaseIdsReqDTO;
+// 导入自定义的分页请求数据传输对象类
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入自定义的 Bean 映射工具类,用于对象属性的复制
+import com.yf.exam.core.utils.BeanMapper;
+// 导入系统部门数据传输对象类,用于在不同层之间传输部门信息
+import com.yf.exam.modules.sys.depart.dto.SysDepartDTO;
+// 导入部门排序请求数据传输对象类,用于接收部门排序的请求信息
+import com.yf.exam.modules.sys.depart.dto.request.DepartSortReqDTO;
+// 导入系统部门树状数据传输对象类,用于返回部门的树状结构信息
+import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO;
+// 导入系统部门实体类,对应数据库中的部门表
+import com.yf.exam.modules.sys.depart.entity.SysDepart;
+// 导入系统部门服务接口,用于调用部门相关的业务逻辑
+import com.yf.exam.modules.sys.depart.service.SysDepartService;
+// 导入 Swagger 注解,用于生成 API 文档,标记控制器的标签
+import io.swagger.annotations.Api;
+// 导入 Swagger 注解,用于生成 API 文档,标记接口的操作描述
+import io.swagger.annotations.ApiOperation;
+// 导入 Shiro 注解,用于权限控制,要求用户具有指定角色才能访问接口
+import org.apache.shiro.authz.annotation.RequiresRoles;
+// 导入 Spring 框架的依赖注入注解,用于自动注入依赖的 Bean
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+// 导入 Spring 框架的请求体注解,用于将请求体中的数据绑定到方法参数上
+import org.springframework.web.bind.annotation.RequestBody;
+// 导入 Spring 框架的请求映射注解,用于映射请求路径
+import org.springframework.web.bind.annotation.RequestMapping;
+// 导入 Spring 框架的请求方法注解,用于指定请求的 HTTP 方法
+import org.springframework.web.bind.annotation.RequestMethod;
+// 导入 Spring 框架的控制器注解,标记该类为 RESTful 风格的控制器
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ *
+ * 部门信息控制器,处理与系统部门信息相关的接口请求
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-09-02 17:25
+ */
+// 为 Swagger 文档标记该控制器的标签为 "部门信息"
+@Api(tags={"部门信息"})
+// 标记该类为 RESTful 风格的控制器,返回数据直接作为 HTTP 响应体
+@RestController
+// 定义该控制器处理的请求路径前缀
+@RequestMapping("/exam/api/sys/depart")
+public class SysDepartController extends BaseController {
+
+ // 自动注入系统部门服务实例,用于调用部门相关的业务逻辑
+ @Autowired
+ private SysDepartService baseService;
+
+ /**
+ * 添加或修改部门信息
+ * @param reqDTO 部门信息数据传输对象,包含要添加或修改的部门信息
+ * @return 封装了操作结果的 API 统一响应对象
+ */
+ // 要求用户具有 "sa" 角色才能访问该接口
+ @RequiresRoles("sa")
+ // 为 Swagger 文档标记该接口的操作描述为 "添加或修改"
+ @ApiOperation(value = "添加或修改")
+ // 映射请求路径为 "/save",并指定请求方法为 POST
+ @RequestMapping(value = "/save", method = { RequestMethod.POST})
+ public ApiRest save(@RequestBody SysDepartDTO reqDTO) {
+ // 调用部门服务的保存方法,保存或更新部门信息
+ baseService.save(reqDTO);
+ // 调用父类的成功响应方法,返回操作成功的响应对象
+ return super.success();
+ }
+
+ /**
+ * 批量删除部门信息
+ * @param reqDTO 包含多个部门 ID 的请求数据传输对象,用于指定要删除的部门
+ * @return 封装了操作结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "批量删除")
+ @RequestMapping(value = "/delete", method = { RequestMethod.POST})
+ public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) {
+ // 根据传入的部门 ID 列表,调用部门服务的删除方法删除部门信息
+ baseService.removeByIds(reqDTO.getIds());
+ return super.success();
+ }
+
+ /**
+ * 查找部门详情信息
+ * @param reqDTO 包含单个部门 ID 的请求数据传输对象,用于指定要查找的部门
+ * @return 封装了部门详情信息的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "查找详情")
+ @RequestMapping(value = "/detail", method = { RequestMethod.POST})
+ public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) {
+ // 根据传入的部门 ID,调用部门服务的获取方法获取部门实体对象
+ SysDepart entity = baseService.getById(reqDTO.getId());
+ // 创建一个新的部门数据传输对象
+ SysDepartDTO dto = new SysDepartDTO();
+ // 将部门实体对象的属性复制到部门数据传输对象中
+ BeanUtils.copyProperties(entity, dto);
+ return super.success(dto);
+ }
+
+ /**
+ * 分页查找部门信息
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数
+ * @return 封装了分页查询结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "分页查找")
+ @RequestMapping(value = "/paging", method = { RequestMethod.POST})
+ public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) {
+
+ // 调用部门服务的分页查询方法,进行分页查询并将结果转换为树状数据传输对象
+ IPage page = baseService.paging(reqDTO);
+
+ return super.success(page);
+ }
+
+ /**
+ * 查找部门列表,每次最多返回 200 条数据
+ * @param reqDTO 部门信息数据传输对象,包含查询部门列表的条件
+ * @return 封装了部门列表信息的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "查找列表")
+ @RequestMapping(value = "/list", method = { RequestMethod.POST})
+ public ApiRest> list(@RequestBody SysDepartDTO reqDTO) {
+
+ // 创建一个 MyBatis-Plus 的查询条件构造器
+ QueryWrapper wrapper = new QueryWrapper<>();
+
+ // 调用部门服务的列表查询方法,根据查询条件获取部门实体列表
+ List list = baseService.list(wrapper);
+
+ // 使用 Bean 映射工具类将部门实体列表转换为部门数据传输对象列表
+ List dtoList = BeanMapper.mapList(list, SysDepartDTO.class);
+
+ return super.success(dtoList);
+ }
+
+
+ /**
+ * 获取部门树列表
+ * @return 封装了部门树列表信息的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "树列表")
+ @RequestMapping(value = "/tree", method = { RequestMethod.POST})
+ public ApiRest> tree() {
+ // 调用部门服务的查找树列表方法,获取部门树列表数据传输对象列表
+ List dtoList = baseService.findTree();
+ return super.success(dtoList);
+ }
+
+
+ /**
+ * 对部门进行分类排序
+ * @param reqDTO 部门排序请求数据传输对象,包含要排序的部门 ID 和排序值
+ * @return 封装了操作结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "分类排序")
+ @RequestMapping(value = "/sort", method = { RequestMethod.POST})
+ public ApiRest sort(@RequestBody DepartSortReqDTO reqDTO) {
+ // 调用部门服务的排序方法,根据传入的部门 ID 和排序值对部门进行排序
+ baseService.sort(reqDTO.getId(), reqDTO.getSort());
+ return super.success();
+ }
+}
diff --git a/sys/depart/dto/SysDepartDTO.java b/sys/depart/dto/SysDepartDTO.java
new file mode 100644
index 0000000..70d8efb
--- /dev/null
+++ b/sys/depart/dto/SysDepartDTO.java
@@ -0,0 +1,73 @@
+// 定义该类所在的包,表明其在项目模块中的位置
+package com.yf.exam.modules.sys.depart.dto;
+
+// 导入 Swagger 注解,用于在生成 API 文档时描述类的信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于在生成 API 文档时描述类属性的信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+// 导入 Serializable 接口,使该类的对象可以被序列化和反序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 部门信息数据传输类,用于在不同层之间传输部门相关信息,如在控制器与服务层、服务层与数据访问层之间传递数据。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-09-02 17:25
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用方法
+@Data
+// 使用 Swagger 的 ApiModel 注解,为 API 文档描述该类的信息
+@ApiModel(value="部门信息", description="部门信息")
+public class SysDepartDTO implements Serializable {
+
+ // 序列化版本号,确保序列化和反序列化时类的版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 部门的唯一标识 ID
+ * 在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "ID", required=true)
+ private String id;
+
+ /**
+ * 部门类型,1 表示公司,2 表示部门
+ * 在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "1公司2部门", required=true)
+ private Integer deptType;
+
+ /**
+ * 该部门所属的上级部门 ID
+ * 在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "所属上级", required=true)
+ private String parentId;
+
+ /**
+ * 部门的名称
+ * 在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "部门名称", required=true)
+ private String deptName;
+
+ /**
+ * 部门的编码
+ * 在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "部门编码", required=true)
+ private String deptCode;
+
+ /**
+ * 部门的排序值,用于对部门进行排序展示
+ * 在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "排序", required=true)
+ private Integer sort;
+
+}
diff --git a/sys/depart/dto/request/DepartSortReqDTO.java b/sys/depart/dto/request/DepartSortReqDTO.java
new file mode 100644
index 0000000..40fd441
--- /dev/null
+++ b/sys/depart/dto/request/DepartSortReqDTO.java
@@ -0,0 +1,42 @@
+// 声明该类所在的包,表明其在项目模块中的位置
+package com.yf.exam.modules.sys.depart.dto.request;
+
+// 导入 Swagger 注解,用于生成 API 文档,标记类的描述信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于生成 API 文档,标记类属性的描述信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法
+import lombok.Data;
+
+// 导入 Serializable 接口,表明该类的对象可以被序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 部门排序请求类,用于封装部门排序操作所需的请求参数
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-03-14 10:37
+ */
+// 自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 为 Swagger 文档提供类的描述信息
+@ApiModel(value="部门排序请求类", description="部门排序请求类")
+public class DepartSortReqDTO implements Serializable {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 分类 ID,标识要进行排序操作的部门
+ */
+ @ApiModelProperty(value = "分类ID")
+ private String id;
+
+ /**
+ * 排序方式,0 表示下降排序,1 表示上升排序
+ */
+ @ApiModelProperty(value = "排序,0下降,1上升")
+ private Integer sort;
+}
diff --git a/sys/depart/dto/response/SysDepartTreeDTO.java b/sys/depart/dto/response/SysDepartTreeDTO.java
new file mode 100644
index 0000000..bb7137b
--- /dev/null
+++ b/sys/depart/dto/response/SysDepartTreeDTO.java
@@ -0,0 +1,41 @@
+// 定义包名,表明该类所属的模块和功能目录
+package com.yf.exam.modules.sys.depart.dto.response;
+
+// 导入 SysDepartDTO 类,该类是当前类的父类,包含部门的基本信息
+import com.yf.exam.modules.sys.depart.dto.SysDepartDTO;
+// 导入 Swagger 注解,用于生成 API 文档,标记类的描述信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于生成 API 文档,标记类属性的描述信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法
+import lombok.Data;
+
+// 导入 List 接口,用于存储子部门列表
+import java.util.List;
+
+/**
+ *
+ * 部门树结构响应类,继承自 SysDepartDTO,用于返回部门的树状结构信息
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-09-02 17:25
+ */
+// 自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 为 Swagger 文档提供类的描述信息
+@ApiModel(value="部门树结构响应类", description="部门树结构响应类")
+public class SysDepartTreeDTO extends SysDepartDTO {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 子部门列表,存储当前部门的所有子部门信息
+ * 该属性在 API 文档中标记为必需项
+ */
+ @ApiModelProperty(value = "子列表", required=true)
+ private List children;
+
+
+}
diff --git a/sys/depart/entity/SysDepart.java b/sys/depart/entity/SysDepart.java
new file mode 100644
index 0000000..71ca156
--- /dev/null
+++ b/sys/depart/entity/SysDepart.java
@@ -0,0 +1,59 @@
+package com.yf.exam.modules.sys.depart.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+/**
+*
+* 部门信息实体类
+*
+*
+* @author 聪明笨狗
+* @since 2020-09-02 17:25
+*/
+@Data
+@TableName("sys_depart")
+public class SysDepart extends Model {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * ID
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private String id;
+
+ /**
+ * 1公司2部门
+ */
+ @TableField("dept_type")
+ private Integer deptType;
+
+ /**
+ * 所属上级
+ */
+ @TableField("parent_id")
+ private String parentId;
+
+ /**
+ * 部门名称
+ */
+ @TableField("dept_name")
+ private String deptName;
+
+ /**
+ * 部门编码
+ */
+ @TableField("dept_code")
+ private String deptCode;
+
+ /**
+ * 排序
+ */
+ private Integer sort;
+
+}
diff --git a/sys/depart/mapper/SysDepartMapper.java b/sys/depart/mapper/SysDepartMapper.java
new file mode 100644
index 0000000..221ab89
--- /dev/null
+++ b/sys/depart/mapper/SysDepartMapper.java
@@ -0,0 +1,28 @@
+package com.yf.exam.modules.sys.depart.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yf.exam.modules.sys.depart.dto.SysDepartDTO;
+import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO;
+import com.yf.exam.modules.sys.depart.entity.SysDepart;
+import org.apache.ibatis.annotations.Param;
+
+/**
+*
+* 部门信息Mapper
+*
+*
+* @author 聪明笨狗
+* @since 2020-09-02 17:25
+*/
+public interface SysDepartMapper extends BaseMapper {
+
+ /**
+ * 部门树分页
+ * @param page
+ * @param query
+ * @return
+ */
+ IPage paging(Page page, @Param("query") SysDepartDTO query);
+}
diff --git a/sys/depart/service/SysDepartService.java b/sys/depart/service/SysDepartService.java
new file mode 100644
index 0000000..1b70e83
--- /dev/null
+++ b/sys/depart/service/SysDepartService.java
@@ -0,0 +1,62 @@
+package com.yf.exam.modules.sys.depart.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yf.exam.core.api.dto.PagingReqDTO;
+import com.yf.exam.modules.sys.depart.dto.SysDepartDTO;
+import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO;
+import com.yf.exam.modules.sys.depart.entity.SysDepart;
+
+import java.util.List;
+
+/**
+*
+* 部门信息业务类
+*
+*
+* @author 聪明笨狗
+* @since 2020-09-02 17:25
+*/
+public interface SysDepartService extends IService {
+
+ /**
+ * 保存
+ * @param reqDTO
+ */
+ void save(SysDepartDTO reqDTO);
+
+ /**
+ * 分页查询数据
+ * @param reqDTO
+ * @return
+ */
+ IPage paging(PagingReqDTO reqDTO);
+
+ /**
+ * 查找部门树结构
+ * @return
+ */
+ List findTree();
+
+ /**
+ * 查找部门树
+ * @param ids
+ * @return
+ */
+ List findTree(List ids);
+
+ /**
+ * 排序
+ * @param id
+ * @param sort
+ */
+ void sort(String id, Integer sort);
+
+
+ /**
+ * 获取某个部门ID下的所有子部门ID
+ * @param id
+ * @return
+ */
+ List listAllSubIds( String id);
+}
diff --git a/sys/depart/service/impl/SysDepartServiceImpl.java b/sys/depart/service/impl/SysDepartServiceImpl.java
new file mode 100644
index 0000000..e0a610a
--- /dev/null
+++ b/sys/depart/service/impl/SysDepartServiceImpl.java
@@ -0,0 +1,368 @@
+package com.yf.exam.modules.sys.depart.service.impl;
+
+// 导入 MyBatis-Plus 的查询条件构造器,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于处理分页查询结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入 MyBatis-Plus 的分页类,用于创建分页对象
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+// 导入 MyBatis-Plus 的服务实现基类,提供通用的服务层方法
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+// 导入自定义的分页请求数据传输对象类,用于封装分页查询请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入自定义的 Bean 映射工具类,用于对象属性的复制
+import com.yf.exam.core.utils.BeanMapper;
+// 导入系统部门数据传输对象类,用于在不同层之间传输部门信息
+import com.yf.exam.modules.sys.depart.dto.SysDepartDTO;
+// 导入系统部门树状数据传输对象类,用于返回部门的树状结构信息
+import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO;
+// 导入系统部门实体类,对应数据库中的部门表
+import com.yf.exam.modules.sys.depart.entity.SysDepart;
+// 导入系统部门映射器接口,用于与数据库进行交互
+import com.yf.exam.modules.sys.depart.mapper.SysDepartMapper;
+// 导入系统部门服务接口,定义部门相关的业务方法
+import com.yf.exam.modules.sys.depart.service.SysDepartService;
+// 导入 Apache Commons Lang3 工具类,用于字符串操作
+import org.apache.commons.lang3.StringUtils;
+// 导入 Spring 工具类,用于集合操作
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * 部门信息业务实现类,实现了系统部门服务接口,处理部门相关的业务逻辑
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-09-02 17:25
+ */
+// 将该类标记为 Spring 服务组件,使其可以被 Spring 容器管理
+@Service
+public class SysDepartServiceImpl extends ServiceImpl implements SysDepartService {
+
+ /**
+ * 0标识为顶级分类,作为根部门的标记
+ */
+ private static final String ROOT_TAG = "0";
+
+ /**
+ * 保存或更新部门信息
+ * 如果传入的部门 ID 为空,则填充部门编码;否则,清空排序和部门编码信息
+ * @param reqDTO 部门信息数据传输对象,包含要保存或更新的部门信息
+ */
+ @Override
+ public void save(SysDepartDTO reqDTO) {
+ // 判断传入的部门 ID 是否为空
+ if(StringUtils.isBlank(reqDTO.getId())) {
+ // 若为空,则填充部门编码
+ this.fillCode(reqDTO);
+ } else {
+ // 若不为空,则清空排序和部门编码信息
+ reqDTO.setSort(null);
+ reqDTO.setDeptCode(null);
+ }
+
+ // 创建一个新的部门实体对象
+ SysDepart entity = new SysDepart();
+ // 使用 BeanMapper 工具类将部门数据传输对象的属性复制到部门实体对象中
+ BeanMapper.copy(reqDTO, entity);
+ // 调用 MyBatis-Plus 的保存或更新方法,保存或更新部门信息
+ this.saveOrUpdate(entity);
+ }
+
+ /**
+ * 分页查询部门信息,并将结果转换为树状结构
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数
+ * @return 分页的部门树状结构数据传输对象列表
+ */
+ @Override
+ public IPage paging(PagingReqDTO reqDTO) {
+ // 创建分页对象,传入当前页码和每页记录数
+ Page query = new Page(reqDTO.getCurrent(), reqDTO.getSize());
+ // 获取请求参数中的部门信息
+ SysDepartDTO params = reqDTO.getParams();
+ // 调用映射器的分页查询方法,将结果转换为部门树状结构数据传输对象列表
+ IPage pageData = baseMapper.paging(query, params);
+
+ return pageData;
+ }
+
+ /**
+ * 查找部门树状结构,调用重载方法,不传入部门 ID 列表
+ * @return 部门树状结构数据传输对象列表
+ */
+ @Override
+ public List findTree() {
+ return this.findTree(null);
+ }
+
+ /**
+ * 根据指定的部门 ID 列表查找部门树状结构
+ * @param ids 部门 ID 列表,若为空则查找所有部门的树状结构
+ * @return 部门树状结构数据传输对象列表
+ */
+ @Override
+ public List findTree(List ids) {
+ // 创建查询条件构造器
+ QueryWrapper wrapper = new QueryWrapper();
+ // 按部门排序字段升序排序
+ wrapper.lambda().orderByAsc(SysDepart::getSort);
+
+ // 判断传入的部门 ID 列表是否不为空
+ if(!CollectionUtils.isEmpty(ids)) {
+ // 存储所有相关部门 ID 的列表
+ List fullIds = new ArrayList<>();
+ // 遍历传入的部门 ID 列表
+ for(String id: ids) {
+ // 递归获取该部门及其所有父部门的 ID 并添加到 fullIds 列表中
+ this.cycleAllParent(fullIds, id);
+ }
+
+ // 判断 fullIds 列表是否不为空
+ if(!CollectionUtils.isEmpty(fullIds)) {
+ // 将查询条件限制为 fullIds 列表中的部门 ID
+ wrapper.lambda().in(SysDepart::getId, fullIds);
+ }
+ }
+
+ // 根据查询条件获取所有部门列表
+ List list = this.list(wrapper);
+ // 使用 BeanMapper 工具类将部门实体列表转换为部门树状结构数据传输对象列表
+ List dtoList = BeanMapper.mapList(list, SysDepartTreeDTO.class);
+
+ // 存储每个父部门 ID 对应的子部门列表的映射
+ Map> map = new HashMap<>(16);
+
+ // 遍历部门树状结构数据传输对象列表
+ for(SysDepartTreeDTO item: dtoList) {
+ // 判断映射中是否已存在该父部门 ID
+ if(map.containsKey(item.getParentId())) {
+ // 若存在,则将该部门添加到对应的子部门列表中
+ map.get(item.getParentId()).add(item);
+ continue;
+ }
+
+ // 若不存在,则创建一个新的子部门列表,并将该部门添加到列表中
+ List a = new ArrayList<>();
+ a.add(item);
+ // 将该父部门 ID 和对应的子部门列表添加到映射中
+ map.put(item.getParentId(), a);
+ }
+
+ // 获取根部门(父部门 ID 为 0)的子部门列表
+ List topList = map.get(ROOT_TAG);
+ // 判断根部门的子部门列表是否不为空
+ if(!CollectionUtils.isEmpty(topList)) {
+ // 遍历根部门的子部门列表
+ for(SysDepartTreeDTO item: topList) {
+ // 递归填充每个部门的子部门信息
+ this.fillChildren(map, item);
+ }
+ }
+
+ return topList;
+ }
+
+ /**
+ * 对部门进行排序操作,可实现部门的上升或下降排序
+ * @param id 要排序的部门 ID
+ * @param sort 排序方式,0 表示上升,1 表示下降
+ */
+ @Override
+ public void sort(String id, Integer sort) {
+ // 根据部门 ID 获取要排序的部门实体对象
+ SysDepart depart = this.getById(id);
+ // 用于交换排序的部门实体对象
+ SysDepart exchange = null;
+
+ // 创建查询条件构造器
+ QueryWrapper wrapper = new QueryWrapper<>();
+ // 限制查询条件为与要排序的部门同级(父部门相同)
+ wrapper.lambda()
+ .eq(SysDepart::getParentId, depart.getParentId());
+ // 限制查询结果只返回一条记录
+ wrapper.last("LIMIT 1");
+
+ // 判断排序方式是否为上升
+ if(sort == 0) {
+ // 限制查询条件为排序值小于要排序部门的排序值,并按排序值降序排序
+ wrapper.lambda()
+ .lt(SysDepart::getSort, depart.getSort())
+ .orderByDesc(SysDepart::getSort);
+ // 获取满足条件的部门实体对象
+ exchange = this.getOne(wrapper, false);
+ }
+
+ // 判断排序方式是否为下降
+ if(sort == 1) {
+ // 限制查询条件为排序值大于要排序部门的排序值,并按排序值升序排序
+ wrapper.lambda()
+ .gt(SysDepart::getSort, depart.getSort())
+ .orderByAsc(SysDepart::getSort);
+ // 获取满足条件的部门实体对象
+ exchange = this.getOne(wrapper, false);
+ }
+
+ // 判断是否找到可交换排序的部门实体对象
+ if(exchange != null) {
+ // 创建一个新的部门实体对象,用于更新要排序的部门的排序值
+ SysDepart a = new SysDepart();
+ a.setId(id);
+ a.setSort(exchange.getSort());
+ // 创建一个新的部门实体对象,用于更新可交换排序的部门的排序值
+ SysDepart b = new SysDepart();
+ b.setId(exchange.getId());
+ b.setSort(depart.getSort());
+ // 调用 MyBatis-Plus 的更新方法,更新两个部门的排序值
+ this.updateById(a);
+ this.updateById(b);
+ }
+ }
+
+ /**
+ * 填充部门编码,根据父部门信息和同级部门排序生成新的部门编码
+ * @param reqDTO 部门信息数据传输对象,用于填充部门编码
+ */
+ private void fillCode(SysDepartDTO reqDTO) {
+ // 部门编码的前缀
+ String code = "";
+
+ // 判断传入的父部门 ID 是否不为空且不为根部门 ID
+ if(StringUtils.isNotBlank(reqDTO.getParentId())
+ && !ROOT_TAG.equals(reqDTO.getParentId())) {
+ // 根据父部门 ID 获取父部门实体对象
+ SysDepart parent = this.getById(reqDTO.getParentId());
+ // 将父部门的编码作为前缀
+ code = parent.getDeptCode();
+ }
+
+ // 创建查询条件构造器
+ QueryWrapper wrapper = new QueryWrapper<>();
+ // 限制查询条件为与要填充编码的部门同级(父部门相同),并按排序值降序排序
+ wrapper.lambda()
+ .eq(SysDepart::getParentId, reqDTO.getParentId())
+ .orderByDesc(SysDepart::getSort);
+ // 限制查询结果只返回一条记录
+ wrapper.last("LIMIT 1");
+ // 获取满足条件的部门实体对象
+ SysDepart depart = this.getOne(wrapper, false);
+
+ // 判断是否找到同级部门实体对象
+ if(depart != null) {
+ // 生成新的部门编码,将同级部门的排序值加 1 并格式化后添加到前缀后面
+ code += this.formatCode(depart.getSort() + 1);
+ // 设置要填充编码的部门的排序值为同级部门的排序值加 1
+ reqDTO.setSort(depart.getSort() + 1);
+ } else {
+ // 若未找到同级部门实体对象,则生成新的部门编码,排序值为 1 并格式化后添加到前缀后面
+ code += this.formatCode(1);
+ // 设置要填充编码的部门的排序值为 1
+ reqDTO.setSort(1);
+ }
+
+ // 设置要填充编码的部门的部门编码
+ reqDTO.setDeptCode(code);
+ }
+
+ /**
+ * 格式化排序值,根据排序值生成对应的部门编码前缀
+ * @param sort 排序值
+ * @return 格式化后的部门编码前缀
+ */
+ private String formatCode(Integer sort) {
+ // 判断排序值是否小于 10
+ if(sort < 10) {
+ // 若小于 10,则在排序值前添加 "A0"
+ return "A0" + sort;
+ }
+ // 若不小于 10,则在排序值前添加 "A"
+ return "A" + sort;
+ }
+
+ /**
+ * 递归填充部门的子部门信息
+ * @param map 存储每个父部门 ID 对应的子部门列表的映射
+ * @param item 当前要填充子部门信息的部门树状结构数据传输对象
+ */
+ private void fillChildren(Map> map, SysDepartTreeDTO item) {
+ // 判断映射中是否存在该部门 ID 对应的子部门列表
+ if(map.containsKey(item.getId())) {
+ // 获取该部门 ID 对应的子部门列表
+ List children = map.get(item.getId());
+ // 判断子部门列表是否不为空
+ if(!CollectionUtils.isEmpty(children)) {
+ // 遍历子部门列表
+ for(SysDepartTreeDTO sub: children) {
+ // 递归填充每个子部门的子部门信息
+ this.fillChildren(map, sub);
+ }
+ }
+ // 设置该部门的子部门列表
+ item.setChildren(children);
+ }
+ }
+
+ /**
+ * 获取指定部门及其所有子部门的 ID 列表
+ * @param id 要获取子部门 ID 列表的部门 ID
+ * @return 包含指定部门及其所有子部门 ID 的列表
+ */
+ @Override
+ public List listAllSubIds( String id) {
+ // 存储指定部门及其所有子部门 ID 的列表
+ List ids = new ArrayList<>();
+ // 递归获取指定部门及其所有子部门的 ID 并添加到列表中
+ this.cycleAllSubs(ids, id);
+ return ids;
+ }
+
+ /**
+ * 递归获取指定部门及其所有子部门的 ID 并添加到列表中
+ * @param list 存储部门 ID 的列表
+ * @param id 当前要处理的部门 ID
+ */
+ private void cycleAllSubs(List list, String id) {
+ // 将当前部门 ID 添加到列表中
+ list.add(id);
+
+ // 创建查询条件构造器
+ QueryWrapper wrapper = new QueryWrapper<>();
+ // 限制查询条件为父部门 ID 等于当前部门 ID,并按排序值降序排序
+ wrapper.lambda()
+ .eq(SysDepart::getParentId, id)
+ .orderByDesc(SysDepart::getSort);
+ // 获取满足条件的子部门列表
+ List subList = this.list(wrapper);
+ // 判断子部门列表是否不为空
+ if(!CollectionUtils.isEmpty(subList)) {
+ // 遍历子部门列表
+ for(SysDepart item: subList) {
+ // 递归处理每个子部门
+ this.cycleAllSubs(list, item.getId());
+ }
+ }
+ }
+
+ /**
+ * 递归获取指定部门及其所有父部门的 ID 并添加到列表中
+ * @param list 存储部门 ID 的列表
+ * @param id 当前要处理的部门 ID
+ */
+ private void cycleAllParent(List list, String id) {
+ // 将当前部门 ID 添加到列表中
+ list.add(id);
+ // 根据部门 ID 获取部门实体对象
+ SysDepart depart = this.getById(id);
+
+ // 判断该部门的父部门 ID 是否不为空且不为根部门 ID
+ if(StringUtils.isNotBlank(depart.getParentId())
+ && !ROOT_TAG.equals(depart.getParentId())) {
+ // 递归处理该部门的父部门
+ this.cycleAllParent(list, depart.getParentId());
+ }
+ }
+}
diff --git a/sys/system/mapper/SysDictMapper.java b/sys/system/mapper/SysDictMapper.java
new file mode 100644
index 0000000..a5c92ab
--- /dev/null
+++ b/sys/system/mapper/SysDictMapper.java
@@ -0,0 +1,40 @@
+/**
+ * 定义包名,表明该类所属的模块和目录结构,这里是系统模块下的 mapper 包。
+ */
+package com.yf.exam.modules.sys.system.mapper;
+
+/**
+ * 导入 MyBatis 的 Mapper 注解,用于标识该接口是一个 MyBatis 的映射器接口。
+ */
+import org.apache.ibatis.annotations.Mapper;
+/**
+ * 导入 MyBatis 的 Param 注解,用于为方法参数指定名称,在 SQL 语句中可以使用该名称引用参数。
+ */
+import org.apache.ibatis.annotations.Param;
+
+/**
+ *
+ * 机主信息Mapper,用于与数据库中机主信息相关表进行交互,定义数据库操作方法。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-08-22 13:46
+ */
+// 标识该接口是 MyBatis 的映射器接口,Spring 会自动扫描并将其注册到 MyBatis 中。
+@Mapper
+public interface SysDictMapper {
+
+ /**
+ * 查找数据字典,根据传入的表名、文本、键和值在数据库中查找对应的字典数据。
+ *
+ * @param table 要查询的数据库表名
+ * @param text 用于查询的文本条件
+ * @param key 用于查询的键条件
+ * @param value 用于查询的值条件
+ * @return 返回查询到的字典数据,如果未找到则返回 null。
+ */
+ String findDict(@Param("table") String table,
+ @Param("text") String text,
+ @Param("key") String key,
+ @Param("value") String value);
+}
diff --git a/sys/system/service/SysDictService.java b/sys/system/service/SysDictService.java
new file mode 100644
index 0000000..ae6d0ce
--- /dev/null
+++ b/sys/system/service/SysDictService.java
@@ -0,0 +1,26 @@
+/**
+ * 定义包名,表明该类所属的模块和目录结构,此包下存放系统相关的服务类
+ */
+package com.yf.exam.modules.sys.system.service;
+
+/**
+ * 数据字典工具类
+ * 该接口定义了与数据字典查找相关的方法,可被不同的实现类实现以提供具体的查找逻辑。
+ * @author bool
+ */
+public interface SysDictService {
+
+ /**
+ * 查找数据字典
+ * 该方法用于根据传入的表名、文本、键和值,在对应的数据字典中查找匹配的结果。
+ * @param table 数据字典所在的表名,指定从哪个表中进行查找操作。
+ * @param text 查找时匹配的文本信息,可用于筛选符合条件的数据。
+ * @param key 数据字典中的键,用于定位特定的数据项。
+ * @param value 数据字典中的值,与键配合使用,进一步精确查找。
+ * @return 返回查找到的数据字典值,如果未找到则可能返回 null。
+ */
+ String findDict(String table,
+ String text,
+ String key,
+ String value);
+}
diff --git a/sys/system/service/impl/SysDictServiceImpl.java b/sys/system/service/impl/SysDictServiceImpl.java
new file mode 100644
index 0000000..d7771a4
--- /dev/null
+++ b/sys/system/service/impl/SysDictServiceImpl.java
@@ -0,0 +1,45 @@
+// 定义包名,指定该类所在的包路径
+package com.yf.exam.modules.sys.system.service.impl;
+
+// 导入系统字典映射器接口,用于与数据库进行交互
+import com.yf.exam.modules.sys.system.mapper.SysDictMapper;
+// 导入系统字典服务接口,定义了系统字典相关的业务方法
+import com.yf.exam.modules.sys.system.service.SysDictService;
+// 导入 Spring 框架的自动装配注解,用于依赖注入
+import org.springframework.beans.factory.annotation.Autowired;
+// 导入 Spring 框架的服务注解,将该类标记为服务层组件
+import org.springframework.stereotype.Service;
+
+/**
+ * SysDictServiceImpl 类实现了 SysDictService 接口,
+ * 负责处理系统字典相关的业务逻辑,通过调用 SysDictMapper 与数据库进行交互。
+ *
+ * @author bool
+ */
+// 将该类标记为 Spring 服务组件,使其可以被 Spring 容器管理
+@Service
+public class SysDictServiceImpl implements SysDictService {
+
+ /**
+ * 注入系统字典映射器实例,用于执行数据库操作。
+ * 通过 Spring 的自动装配机制,将 SysDictMapper 的实例注入到该类中。
+ */
+ @Autowired
+ private SysDictMapper sysDictMapper;
+
+ /**
+ * 根据传入的表名、文本、键和值,从数据库中查找对应的字典数据。
+ * 该方法调用了 SysDictMapper 的 findDict 方法来执行实际的数据库查询操作。
+ *
+ * @param table 要查询的数据库表名
+ * @param text 用于查询的文本条件
+ * @param key 用于查询的键条件
+ * @param value 用于查询的值条件
+ * @return 返回从数据库中查询到的字典数据,如果未找到则返回 null
+ */
+ @Override
+ public String findDict(String table, String text, String key, String value) {
+ // 调用 SysDictMapper 的 findDict 方法执行数据库查询
+ return sysDictMapper.findDict(table, text, key, value);
+ }
+}
diff --git a/sys/user/controller/SysRoleController.java b/sys/user/controller/SysRoleController.java
new file mode 100644
index 0000000..d2932af
--- /dev/null
+++ b/sys/user/controller/SysRoleController.java
@@ -0,0 +1,106 @@
+// 声明当前类所在的包,表明该类属于系统用户控制器模块
+package com.yf.exam.modules.sys.user.controller;
+
+// 导入 MyBatis-Plus 的查询条件构造器,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于处理分页查询结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入自定义的 API 统一响应类,用于封装接口返回数据
+import com.yf.exam.core.api.ApiRest;
+// 导入自定义的基础控制器类,提供一些通用的控制器方法
+import com.yf.exam.core.api.controller.BaseController;
+// 导入自定义的分页请求数据传输对象类,用于封装分页查询请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入自定义的 Bean 映射工具类,用于对象属性的复制
+import com.yf.exam.core.utils.BeanMapper;
+// 导入系统角色数据传输对象类,用于在不同层之间传输角色信息
+import com.yf.exam.modules.sys.user.dto.SysRoleDTO;
+// 导入系统角色实体类,对应数据库中的角色表
+import com.yf.exam.modules.sys.user.entity.SysRole;
+// 导入系统角色服务接口,用于调用角色相关的业务逻辑
+import com.yf.exam.modules.sys.user.service.SysRoleService;
+// 导入 Swagger 注解,用于生成 API 文档,标记控制器的标签
+import io.swagger.annotations.Api;
+// 导入 Swagger 注解,用于生成 API 文档,标记接口的操作描述
+import io.swagger.annotations.ApiOperation;
+// 导入 Shiro 注解,用于权限控制,要求用户具有指定角色才能访问接口
+import org.apache.shiro.authz.annotation.RequiresRoles;
+// 导入 Spring 框架的依赖注入注解,用于自动注入依赖的 Bean
+import org.springframework.beans.factory.annotation.Autowired;
+// 导入 Spring 框架的请求体注解,用于将请求体中的数据绑定到方法参数上
+import org.springframework.web.bind.annotation.RequestBody;
+// 导入 Spring 框架的请求映射注解,用于映射请求路径
+import org.springframework.web.bind.annotation.RequestMapping;
+// 导入 Spring 框架的请求方法注解,用于指定请求的 HTTP 方法
+import org.springframework.web.bind.annotation.RequestMethod;
+// 导入 Spring 框架的控制器注解,标记该类为 RESTful 风格的控制器
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ *
+ * 管理用户控制器,处理与系统角色相关的接口请求
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 为 Swagger 文档标记该控制器的标签为 "管理用户"
+@Api(tags = {"管理用户"})
+// 标记该类为 RESTful 风格的控制器,返回数据直接作为 HTTP 响应体
+@RestController
+// 定义该控制器处理的请求路径前缀
+@RequestMapping("/exam/api/sys/role")
+public class SysRoleController extends BaseController {
+
+ // 自动注入系统角色服务实例,用于调用角色相关的业务逻辑
+ @Autowired
+ private SysRoleService baseService;
+
+ /**
+ * 分页查找系统角色信息
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数
+ * @return 封装了分页查询结果的 API 统一响应对象
+ */
+ // 要求用户具有 "sa" 角色才能访问该接口
+ @RequiresRoles("sa")
+ // 为 Swagger 文档标记该接口的操作描述为 "分页查找"
+ @ApiOperation(value = "分页查找")
+ // 映射请求路径为 "/paging",并指定请求方法为 POST
+ @RequestMapping(value = "/paging", method = { RequestMethod.POST})
+ public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) {
+
+ // 调用角色服务的分页查询方法,进行分页查询并将结果转换为角色数据传输对象
+ IPage page = baseService.paging(reqDTO);
+ // 调用父类的成功响应方法,返回包含分页结果的响应对象
+ return super.success(page);
+ }
+
+ /**
+ * 查找系统角色列表,每次最多返回 200 条数据
+ *
+ * @return 封装了角色列表信息的 API 统一响应对象
+ */
+ // 要求用户具有 "sa" 角色才能访问该接口
+ @RequiresRoles("sa")
+ // 为 Swagger 文档标记该接口的操作描述为 "查找列表"
+ @ApiOperation(value = "查找列表")
+ // 映射请求路径为 "/list",并指定请求方法为 POST
+ @RequestMapping(value = "/list", method = { RequestMethod.POST})
+ public ApiRest> list() {
+
+ // 创建一个 MyBatis-Plus 的查询条件构造器,用于构建查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+
+ // 调用角色服务的列表查询方法,根据查询条件获取角色实体列表
+ List list = baseService.list(wrapper);
+
+ // 使用 Bean 映射工具类将角色实体列表转换为角色数据传输对象列表
+ List dtoList = BeanMapper.mapList(list, SysRoleDTO.class);
+
+ // 调用父类的成功响应方法,返回包含角色列表的响应对象
+ return super.success(dtoList);
+ }
+}
diff --git a/sys/user/controller/SysUserController.java b/sys/user/controller/SysUserController.java
new file mode 100644
index 0000000..7b989ad
--- /dev/null
+++ b/sys/user/controller/SysUserController.java
@@ -0,0 +1,245 @@
+// 声明当前类所在的包,该包属于系统用户控制器模块
+package com.yf.exam.modules.sys.user.controller;
+
+// 导入 MyBatis-Plus 的查询条件构造器,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于处理分页查询结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入自定义的 API 统一响应类,用于封装接口返回数据
+import com.yf.exam.core.api.ApiRest;
+// 导入自定义的基础控制器类,提供一些通用的控制器方法
+import com.yf.exam.core.api.controller.BaseController;
+// 导入自定义的基础多个 ID 请求数据传输对象类,用于批量操作时传递 ID 列表
+import com.yf.exam.core.api.dto.BaseIdsReqDTO;
+// 导入自定义的基础状态请求数据传输对象类,用于传递状态修改请求
+import com.yf.exam.core.api.dto.BaseStateReqDTO;
+// 导入自定义的分页请求数据传输对象类,用于分页查询时传递请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入系统用户数据传输对象类,用于在不同层之间传输用户信息
+import com.yf.exam.modules.sys.user.dto.SysUserDTO;
+// 导入系统用户登录请求数据传输对象类,用于用户登录时传递请求信息
+import com.yf.exam.modules.sys.user.dto.request.SysUserLoginReqDTO;
+// 导入系统用户保存请求数据传输对象类,用于保存或修改用户信息时传递请求信息
+import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO;
+// 导入系统用户登录响应数据传输对象类,用于用户登录成功后返回响应信息
+import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO;
+// 导入系统用户实体类,对应数据库中的用户表
+import com.yf.exam.modules.sys.user.entity.SysUser;
+// 导入系统用户服务接口,用于调用用户相关的业务逻辑
+import com.yf.exam.modules.sys.user.service.SysUserService;
+// 导入 Swagger 注解,用于生成 API 文档,标记控制器的标签
+import io.swagger.annotations.Api;
+// 导入 Swagger 注解,用于生成 API 文档,标记接口的操作描述
+import io.swagger.annotations.ApiOperation;
+// 导入 Shiro 注解,用于权限控制,要求用户具有指定角色才能访问接口
+import org.apache.shiro.authz.annotation.RequiresRoles;
+// 导入 Spring 框架的依赖注入注解,用于自动注入依赖的 Bean
+import org.springframework.beans.factory.annotation.Autowired;
+// 导入 Spring 框架的跨域请求注解,允许跨域访问该接口
+import org.springframework.web.bind.annotation.CrossOrigin;
+// 导入 Spring 框架的请求体注解,用于将请求体中的数据绑定到方法参数上
+import org.springframework.web.bind.annotation.RequestBody;
+// 导入 Spring 框架的请求映射注解,用于映射请求路径
+import org.springframework.web.bind.annotation.RequestMapping;
+// 导入 Spring 框架的请求方法注解,用于指定请求的 HTTP 方法
+import org.springframework.web.bind.annotation.RequestMethod;
+// 导入 Spring 框架的请求参数注解,用于获取请求参数
+import org.springframework.web.bind.annotation.RequestParam;
+// 导入 Spring 框架的控制器注解,标记该类为 RESTful 风格的控制器
+import org.springframework.web.bind.annotation.RestController;
+
+// 导入 HttpServletRequest 类,用于获取 HTTP 请求信息
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ *
+ * 管理用户控制器,处理与系统用户相关的各种请求,如登录、登出、修改资料等操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 为 Swagger 文档标记该控制器的标签为 "管理用户"
+@Api(tags = {"管理用户"})
+// 标记该类为 RESTful 风格的控制器,返回数据直接作为 HTTP 响应体
+@RestController
+// 定义该控制器处理的请求路径前缀
+@RequestMapping("/exam/api/sys/user")
+public class SysUserController extends BaseController {
+
+ // 自动注入系统用户服务实例,用于调用用户相关的业务逻辑
+ @Autowired
+ private SysUserService baseService;
+
+ /**
+ * 用户登录接口,接收用户登录请求信息,调用服务层方法进行登录验证,并返回登录结果。
+ *
+ * @param reqDTO 包含用户登录信息的请求数据传输对象
+ * @return 封装了用户登录响应信息的 API 统一响应对象
+ */
+ @CrossOrigin
+ @ApiOperation(value = "用户登录")
+ @RequestMapping(value = "/login", method = {RequestMethod.POST})
+ public ApiRest login(@RequestBody SysUserLoginReqDTO reqDTO) {
+ // 调用服务层的登录方法,传入用户名和密码,获取登录响应信息
+ SysUserLoginDTO respDTO = baseService.login(reqDTO.getUsername(), reqDTO.getPassword());
+ // 调用父类的成功响应方法,返回包含登录响应信息的响应对象
+ return super.success(respDTO);
+ }
+
+ /**
+ * 用户登出接口,接收 HTTP 请求,从请求头中获取 token,调用服务层方法进行登出操作,并返回操作结果。
+ *
+ * @param request HTTP 请求对象,用于获取请求头中的 token
+ * @return 封装了登出操作结果的 API 统一响应对象
+ */
+ @CrossOrigin
+ @ApiOperation(value = "用户登录")
+ @RequestMapping(value = "/logout", method = {RequestMethod.POST})
+ public ApiRest logout(HttpServletRequest request) {
+ // 从请求头中获取 token
+ String token = request.getHeader("token");
+ // 打印当前会话的 token 信息
+ System.out.println("+++++当前会话为:"+token);
+ // 调用服务层的登出方法,传入 token 进行登出操作
+ baseService.logout(token);
+ // 调用父类的成功响应方法,返回操作成功的响应对象
+ return super.success();
+ }
+
+ /**
+ * 获取会话信息接口,接收 token 参数,调用服务层方法根据 token 获取用户会话信息,并返回会话信息。
+ *
+ * @param token 用户的 token,用于验证用户身份并获取会话信息
+ * @return 封装了用户会话信息的 API 统一响应对象
+ */
+ @ApiOperation(value = "获取会话")
+ @RequestMapping(value = "/info", method = {RequestMethod.POST})
+ public ApiRest info(@RequestParam("token") String token) {
+ // 调用服务层的 token 方法,传入 token 获取用户会话信息
+ SysUserLoginDTO respDTO = baseService.token(token);
+ // 调用父类的成功响应方法,返回包含会话信息的响应对象
+ return success(respDTO);
+ }
+
+ /**
+ * 修改用户资料接口,接收用户资料修改请求信息,调用服务层方法进行用户资料修改,并返回操作结果。
+ *
+ * @param reqDTO 包含用户资料修改信息的请求数据传输对象
+ * @return 封装了用户资料修改操作结果的 API 统一响应对象
+ */
+ @ApiOperation(value = "修改用户资料")
+ @RequestMapping(value = "/update", method = {RequestMethod.POST})
+ public ApiRest update(@RequestBody SysUserDTO reqDTO) {
+ // 调用服务层的更新方法,传入用户资料修改信息进行用户资料修改
+ baseService.update(reqDTO);
+ // 调用父类的成功响应方法,返回操作成功的响应对象
+ return success();
+ }
+
+ /**
+ * 保存或修改系统用户接口,要求用户具有 "sa" 角色,接收用户保存或修改请求信息,调用服务层方法进行用户保存或修改操作,并返回操作结果。
+ *
+ * @param reqDTO 包含用户保存或修改信息的请求数据传输对象
+ * @return 封装了用户保存或修改操作结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "保存或修改")
+ @RequestMapping(value = "/save", method = {RequestMethod.POST})
+ public ApiRest save(@RequestBody SysUserSaveReqDTO reqDTO) {
+ // 调用服务层的保存方法,传入用户保存或修改信息进行用户保存或修改操作
+ baseService.save(reqDTO);
+ // 调用父类的成功响应方法,返回操作成功的响应对象
+ return success();
+ }
+
+ /**
+ * 批量删除用户接口,要求用户具有 "sa" 角色,接收包含多个用户 ID 的请求信息,调用服务层方法根据 ID 批量删除用户,并返回操作结果。
+ *
+ * @param reqDTO 包含多个用户 ID 的请求数据传输对象,用于指定要删除的用户
+ * @return 封装了批量删除用户操作结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "批量删除")
+ @RequestMapping(value = "/delete", method = { RequestMethod.POST})
+ public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) {
+ // 根据传入的用户 ID 列表,调用服务层的删除方法批量删除用户
+ baseService.removeByIds(reqDTO.getIds());
+ // 调用父类的成功响应方法,返回操作成功的响应对象
+ return super.success();
+ }
+
+ /**
+ * 分页查找用户接口,要求用户具有 "sa" 角色,接收分页请求信息,调用服务层方法进行分页查询,并返回分页查询结果。
+ *
+ * @param reqDTO 包含分页查询条件和参数的请求数据传输对象
+ * @return 封装了分页查询结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "分页查找")
+ @RequestMapping(value = "/paging", method = { RequestMethod.POST})
+ public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) {
+ // 调用服务层的分页查询方法,传入分页请求信息进行分页查询并转换结果
+ IPage page = baseService.paging(reqDTO);
+ // 调用父类的成功响应方法,返回包含分页查询结果的响应对象
+ return super.success(page);
+ }
+
+ /**
+ * 修改用户状态接口,要求用户具有 "sa" 角色,接收用户状态修改请求信息,构建查询条件,调用服务层方法修改用户状态,并返回操作结果。
+ *
+ * @param reqDTO 包含用户状态修改信息的请求数据传输对象
+ * @return 封装了用户状态修改操作结果的 API 统一响应对象
+ */
+ @RequiresRoles("sa")
+ @ApiOperation(value = "修改状态")
+ @RequestMapping(value = "/state", method = { RequestMethod.POST})
+ public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) {
+ // 创建 MyBatis-Plus 的查询条件构造器,用于构建查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ // 使用 Lambda 表达式构建查询条件,筛选出 ID 在请求 ID 列表中且用户名不为 "admin" 的用户
+ wrapper.lambda()
+ .in(SysUser::getId, reqDTO.getIds())
+ .ne(SysUser::getUserName, "admin");
+
+ // 创建一个新的用户实体对象,用于设置要修改的状态
+ SysUser record = new SysUser();
+ // 设置用户状态为请求中的状态
+ record.setState(reqDTO.getState());
+ // 调用服务层的更新方法,根据查询条件更新用户状态
+ baseService.update(record, wrapper);
+
+ // 调用父类的成功响应方法,返回操作成功的响应对象
+ return super.success();
+ }
+
+ /**
+ * 学员注册接口,接收学员注册请求信息,调用服务层方法进行学员注册,并返回注册结果。
+ *
+ * @param reqDTO 包含学员注册信息的请求数据传输对象
+ * @return 封装了学员注册响应信息的 API 统一响应对象
+ */
+ @ApiOperation(value = "学员注册")
+ @RequestMapping(value = "/reg", method = {RequestMethod.POST})
+ public ApiRest reg(@RequestBody SysUserDTO reqDTO) {
+ // 调用服务层的注册方法,传入学员注册信息进行学员注册,获取注册响应信息
+ SysUserLoginDTO respDTO = baseService.reg(reqDTO);
+ // 调用父类的成功响应方法,返回包含注册响应信息的响应对象
+ return success(respDTO);
+ }
+
+ /**
+ * 快速注册接口,接收用户信息,调用服务层方法进行快速注册,如果手机号存在则登录,不存在就注册,并返回操作结果。
+ *
+ * @param reqDTO 包含用户信息的请求数据传输对象
+ * @return 封装了快速注册响应信息的 API 统一响应对象
+ */
+ @ApiOperation(value = "快速注册")
+ @RequestMapping(value = "/quick-reg", method = {RequestMethod.POST})
+ public ApiRest quick(@RequestBody SysUserDTO reqDTO) {
+ // 调用服务层的快速注册方法,传入用户信息进行快速注册,获取注册或登录响应信息
+ SysUserLoginDTO respDTO = baseService.quickReg(reqDTO);
+ // 调用父类的成功响应方法,返回包含注册或登录响应信息的响应对象
+ return success(respDTO);
+ }
+}
diff --git a/sys/user/dto/SysRoleDTO.java b/sys/user/dto/SysRoleDTO.java
new file mode 100644
index 0000000..7cc31e4
--- /dev/null
+++ b/sys/user/dto/SysRoleDTO.java
@@ -0,0 +1,45 @@
+// 定义该类所在的包,表明其在项目模块中的位置
+package com.yf.exam.modules.sys.user.dto;
+
+// 导入 Swagger 注解,用于在生成 API 文档时描述类的信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于在生成 API 文档时描述类属性的信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+// 导入 Serializable 接口,使该类的对象可以被序列化和反序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 角色请求类,用于在不同层之间传输角色相关的数据,如在控制器与服务层、服务层与数据访问层之间传递数据。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用方法
+@Data
+// 使用 Swagger 的 ApiModel 注解,为 API 文档描述该类的信息
+@ApiModel(value="角色", description="角色")
+public class SysRoleDTO implements Serializable {
+
+ // 序列化版本号,确保序列化和反序列化时类的版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 角色的唯一标识 ID
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供
+ */
+ @ApiModelProperty(value = "角色ID", required=true)
+ private String id;
+
+ /**
+ * 角色的名称
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供
+ */
+ @ApiModelProperty(value = "角色名称", required=true)
+ private String roleName;
+
+}
diff --git a/sys/user/dto/SysUserDTO.java b/sys/user/dto/SysUserDTO.java
new file mode 100644
index 0000000..8fc9ad0
--- /dev/null
+++ b/sys/user/dto/SysUserDTO.java
@@ -0,0 +1,108 @@
+/**
+ * 定义包名,表明该类属于系统用户模块下的数据传输对象包
+ */
+package com.yf.exam.modules.sys.user.dto;
+
+// 导入 Swagger 注解,用于为 API 文档提供类的描述信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于为 API 文档提供类属性的描述信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+// 导入 Serializable 接口,使该类的对象可以被序列化
+import java.io.Serializable;
+// 导入 Date 类,用于表示日期和时间
+import java.util.Date;
+
+/**
+ *
+ * 管理用户请求类,用于在不同层之间传输管理用户的相关信息,如从控制器传递到服务层,或从服务层传递到数据访问层。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用的 getter、setter 等方法
+@Data
+// 使用 Swagger 的 ApiModel 注解,为 API 文档描述该类的信息
+@ApiModel(value="管理用户", description="管理用户")
+public class SysUserDTO implements Serializable {
+
+ /**
+ * 序列化版本号,确保序列化和反序列化时类的版本一致性。
+ * 当类的结构发生变化时,可能需要更新该版本号以避免反序列化错误。
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 管理用户的唯一标识 ID。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "ID", required=true)
+ private String id;
+
+ /**
+ * 管理用户的用户名,用于系统登录和身份识别。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "用户名", required=true)
+ private String userName;
+
+ /**
+ * 管理用户的真实姓名,用于更准确地识别用户身份和展示信息。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "真实姓名", required=true)
+ private String realName;
+
+ /**
+ * 管理用户的登录密码,用于系统登录验证。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "密码", required=true)
+ private String password;
+
+ /**
+ * 密码盐,用于增强密码的安全性,通常与密码一起进行哈希处理。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "密码盐", required=true)
+ private String salt;
+
+ /**
+ * 管理用户所属的角色列表,以字符串形式存储角色 ID,多个 ID 之间可能用特定分隔符分隔。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "角色列表", required=true)
+ private String roleIds;
+
+ /**
+ * 管理用户所属部门的 ID,用于关联部门信息。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "部门ID", required=true)
+ private String departId;
+
+ /**
+ * 管理用户记录的创建时间,使用 Date 类型表示。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "创建时间", required=true)
+ private Date createTime;
+
+ /**
+ * 管理用户记录的更新时间,使用 Date 类型表示。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "更新时间", required=true)
+ private Date updateTime;
+
+ /**
+ * 管理用户的状态,使用整数类型表示不同的状态值,具体状态含义需根据业务逻辑定义。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "状态", required=true)
+ private Integer state;
+
+}
diff --git a/sys/user/dto/SysUserRoleDTO.java b/sys/user/dto/SysUserRoleDTO.java
new file mode 100644
index 0000000..99dd349
--- /dev/null
+++ b/sys/user/dto/SysUserRoleDTO.java
@@ -0,0 +1,55 @@
+// 定义包名,指定该类所属的模块和目录结构
+package com.yf.exam.modules.sys.user.dto;
+
+// 导入 Swagger 注解,用于为 API 文档定义模型信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于为 API 文档定义模型属性信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+// 导入 Serializable 接口,使该类的对象可以被序列化和反序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 用户角色请求类,用于在不同层之间传输用户角色相关的数据,如在控制器与服务层之间传递数据。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用的 getter、setter 等方法
+@Data
+// 使用 Swagger 的 ApiModel 注解,为 API 文档定义该类的信息
+@ApiModel(value="用户角色", description="用户角色")
+public class SysUserRoleDTO implements Serializable {
+
+ /**
+ * 序列化版本号,确保序列化和反序列化时类的版本一致性。
+ * 当类的结构发生变化时,可能需要更新该版本号以避免反序列化错误。
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户角色的唯一标识 ID。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "ID", required=true)
+ private String id;
+
+ /**
+ * 关联的用户的唯一标识 ID。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "用户ID", required=true)
+ private String userId;
+
+ /**
+ * 关联的角色的唯一标识 ID。
+ * 在 API 文档中标记为必需项,表明在使用该数据传输对象时,该字段必须提供。
+ */
+ @ApiModelProperty(value = "角色ID", required=true)
+ private String roleId;
+
+}
diff --git a/sys/user/dto/request/SysUserLoginReqDTO.java b/sys/user/dto/request/SysUserLoginReqDTO.java
new file mode 100644
index 0000000..91e738a
--- /dev/null
+++ b/sys/user/dto/request/SysUserLoginReqDTO.java
@@ -0,0 +1,45 @@
+// 定义当前类所在的包,表明该类属于系统用户模块下的请求数据传输对象包
+package com.yf.exam.modules.sys.user.dto.request;
+
+// 导入 Swagger 注解,用于生成 API 文档,标记类的描述信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于生成 API 文档,标记类属性的描述信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法
+import lombok.Data;
+
+// 导入 Serializable 接口,表明该类的对象可以被序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 管理员登录请求类,用于封装管理员登录时所需的请求参数
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 为 Swagger 文档提供类的描述信息
+@ApiModel(value="管理员登录请求类", description="管理员登录请求类")
+public class SysUserLoginReqDTO implements Serializable {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 管理员登录使用的用户名
+ * 在 API 文档中标记为必需项,表明该参数在请求时必须提供
+ */
+ @ApiModelProperty(value = "用户名", required=true)
+ private String username;
+
+ /**
+ * 管理员登录使用的密码
+ * 在 API 文档中标记为必需项,表明该参数在请求时必须提供
+ */
+ @ApiModelProperty(value = "密码", required=true)
+ private String password;
+
+}
diff --git a/sys/user/dto/request/SysUserSaveReqDTO.java b/sys/user/dto/request/SysUserSaveReqDTO.java
new file mode 100644
index 0000000..5ce334c
--- /dev/null
+++ b/sys/user/dto/request/SysUserSaveReqDTO.java
@@ -0,0 +1,83 @@
+// 声明该类所在的包,明确其在项目模块中的位置
+package com.yf.exam.modules.sys.user.dto.request;
+
+// 导入 Swagger 注解,用于在生成 API 文档时描述类的信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于在生成 API 文档时描述类属性的信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+// 导入 Serializable 接口,使该类的对象可以进行序列化和反序列化操作
+import java.io.Serializable;
+// 导入 List 接口,用于存储角色 ID 列表
+import java.util.List;
+
+/**
+ *
+ * 管理员保存请求类,用于封装管理员信息保存操作所需的请求参数。
+ * 该类作为数据传输对象,在不同层之间传递管理员保存相关的数据。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用的 getter、setter 等方法
+@Data
+// 使用 Swagger 的 ApiModel 注解,为 API 文档描述该类的信息
+@ApiModel(value="管理员保存请求类", description="管理员保存请求类")
+public class SysUserSaveReqDTO implements Serializable {
+
+ // 序列化版本号,确保序列化和反序列化时类的版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 管理员的唯一标识 ID
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "ID", required=true)
+ private String id;
+
+ /**
+ * 管理员的用户名,用于系统登录和身份识别
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "用户名", required=true)
+ private String userName;
+
+ /**
+ * 管理员的头像链接,用于在系统中展示管理员的头像
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "头像", required=true)
+ private String avatar;
+
+ /**
+ * 管理员的真实姓名,用于在系统中进行更准确的身份识别和展示
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "真实姓名", required=true)
+ private String realName;
+
+ /**
+ * 管理员的登录密码,用于系统登录验证
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "密码", required=true)
+ private String password;
+
+ /**
+ * 管理员所属部门的 ID,用于关联管理员所在的部门信息
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "部门", required=true)
+ private String departId;
+
+ /**
+ * 管理员拥有的角色列表,存储角色的 ID 集合
+ * 在 API 文档中标记为必需项,表明保存操作时该字段必须提供
+ */
+ @ApiModelProperty(value = "角色列表", required=true)
+ private List roles;
+
+}
diff --git a/sys/user/dto/request/SysUserTokenReqDTO.java b/sys/user/dto/request/SysUserTokenReqDTO.java
new file mode 100644
index 0000000..e945041
--- /dev/null
+++ b/sys/user/dto/request/SysUserTokenReqDTO.java
@@ -0,0 +1,38 @@
+// 定义包名,表明该类所属的模块和功能目录
+package com.yf.exam.modules.sys.user.dto.request;
+
+// 导入 Swagger 注解,用于生成 API 文档,标记类的描述信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于生成 API 文档,标记类属性的描述信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法
+import lombok.Data;
+
+// 导入 Serializable 接口,使该类的对象可以被序列化和反序列化
+import java.io.Serializable;
+
+/**
+ *
+ * 会话检查请求类,用于封装会话检查所需的请求参数
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 为 Swagger 文档提供类的描述信息
+@ApiModel(value="会话检查请求类", description="会话检查请求类")
+public class SysUserTokenReqDTO implements Serializable {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用于会话检查的令牌
+ * 在 API 文档中标记为必需项,表明该参数在请求时必须提供
+ */
+ @ApiModelProperty(value = "用户名", required=true)
+ private String token;
+
+}
diff --git a/sys/user/dto/response/SysUserLoginDTO.java b/sys/user/dto/response/SysUserLoginDTO.java
new file mode 100644
index 0000000..244086d
--- /dev/null
+++ b/sys/user/dto/response/SysUserLoginDTO.java
@@ -0,0 +1,106 @@
+// 定义包名,表明该类属于系统用户模块下的响应数据传输对象包
+package com.yf.exam.modules.sys.user.dto.response;
+
+// 导入 Swagger 注解,用于生成 API 文档,标记类的描述信息
+import io.swagger.annotations.ApiModel;
+// 导入 Swagger 注解,用于生成 API 文档,标记类属性的描述信息
+import io.swagger.annotations.ApiModelProperty;
+// 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法
+import lombok.Data;
+
+// 导入 Serializable 接口,表明该类的对象可以被序列化
+import java.io.Serializable;
+// 导入 Date 类,用于表示日期和时间
+import java.util.Date;
+// 导入 List 接口,用于存储角色列表
+import java.util.List;
+
+/**
+ *
+ * 管理用户登录响应类,用于封装管理用户登录成功后返回的信息。
+ * 该类作为数据传输对象,在不同层之间传递登录响应数据。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 为 Swagger 文档提供类的描述信息
+@ApiModel(value="管理用户登录响应类", description="管理用户登录响应类")
+public class SysUserLoginDTO implements Serializable {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 管理用户的唯一标识 ID
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "ID", required=true)
+ private String id;
+
+ /**
+ * 管理用户的用户名
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "用户名", required=true)
+ private String userName;
+
+ /**
+ * 管理用户的真实姓名
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "真实姓名", required=true)
+ private String realName;
+
+ /**
+ * 管理用户的角色 ID 列表,以字符串形式存储
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "角色列表", required=true)
+ private String roleIds;
+
+ /**
+ * 管理用户所属部门的 ID
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "部门ID", required=true)
+ private String departId;
+
+ /**
+ * 管理用户记录的创建时间
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "创建时间", required=true)
+ private Date createTime;
+
+ /**
+ * 管理用户记录的更新时间
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "更新时间", required=true)
+ private Date updateTime;
+
+ /**
+ * 管理用户的状态,使用整数表示
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "状态", required=true)
+ private Integer state;
+
+ /**
+ * 管理用户的角色列表,以字符串列表形式存储
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "角色列表", required=true)
+ private List roles;
+
+ /**
+ * 管理用户登录后生成的令牌,用于后续的身份验证
+ * 在 API 文档中标记为必需项,表明该字段在响应数据中必须存在
+ */
+ @ApiModelProperty(value = "登录令牌", required=true)
+ private String token;
+
+}
diff --git a/sys/user/entity/SysRole.java b/sys/user/entity/SysRole.java
new file mode 100644
index 0000000..8386f64
--- /dev/null
+++ b/sys/user/entity/SysRole.java
@@ -0,0 +1,54 @@
+/**
+ * 定义包名,指定该类所属的模块和实体类所在的目录结构
+ */
+package com.yf.exam.modules.sys.user.entity;
+
+// 导入 MyBatis-Plus 提供的主键生成策略枚举类
+import com.baomidou.mybatisplus.annotation.IdType;
+// 导入 MyBatis-Plus 提供的表字段注解,用于指定数据库表字段名
+import com.baomidou.mybatisplus.annotation.TableField;
+// 导入 MyBatis-Plus 提供的表主键注解,用于指定数据库表的主键
+import com.baomidou.mybatisplus.annotation.TableId;
+// 导入 MyBatis-Plus 提供的表名注解,用于指定实体类对应的数据库表名
+import com.baomidou.mybatisplus.annotation.TableName;
+// 导入 MyBatis-Plus 提供的 ActiveRecord 模式基类,方便进行数据库操作
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+// 导入 Lombok 提供的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+/**
+ *
+ * 角色实体类,用于映射数据库中的 sys_role 表,封装角色相关的属性。
+ * 该类继承自 MyBatis-Plus 的 Model 类,可使用 ActiveRecord 模式进行数据库操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用的 getter、setter 等方法
+@Data
+// 指定该实体类对应的数据库表名为 sys_role
+@TableName("sys_role")
+public class SysRole extends Model {
+
+ /**
+ * 序列化版本号,用于在反序列化时验证版本一致性。
+ * 当实体类的结构发生变化时,可能需要更新该版本号以避免反序列化错误。
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 角色ID,对应数据库表中的 id 字段,作为表的主键。
+ * 使用 MyBatis-Plus 的 TableId 注解指定主键生成策略为 ASSIGN_ID,通常为分布式 ID 生成策略。
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private String id;
+
+ /**
+ * 角色名称,对应数据库表中的 role_name 字段。
+ * 使用 MyBatis-Plus 的 TableField 注解明确指定数据库表字段名。
+ */
+ @TableField("role_name")
+ private String roleName;
+
+}
diff --git a/sys/user/entity/SysUser.java b/sys/user/entity/SysUser.java
new file mode 100644
index 0000000..e6fc698
--- /dev/null
+++ b/sys/user/entity/SysUser.java
@@ -0,0 +1,103 @@
+// 声明当前类所在的包,明确该类属于系统用户实体类所在的包
+package com.yf.exam.modules.sys.user.entity;
+
+// 导入 MyBatis-Plus 注解,用于指定主键生成策略
+import com.baomidou.mybatisplus.annotation.IdType;
+// 导入 MyBatis-Plus 注解,用于指定数据库表字段名
+import com.baomidou.mybatisplus.annotation.TableField;
+// 导入 MyBatis-Plus 注解,用于指定数据库表的主键
+import com.baomidou.mybatisplus.annotation.TableId;
+// 导入 MyBatis-Plus 注解,用于指定实体类对应的数据库表名
+import com.baomidou.mybatisplus.annotation.TableName;
+// 导入 MyBatis-Plus 扩展的 ActiveRecord 模式基类
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+// 导入 Lombok 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+// 导入 Date 类,用于表示日期和时间
+import java.util.Date;
+
+/**
+ *
+ * 管理用户实体类,用于映射数据库中的 sys_user 表,封装管理用户的相关属性。
+ * 该类继承自 MyBatis-Plus 的 Model 类,可使用 ActiveRecord 模式进行数据库操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 @Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+@Data
+// 指定该实体类对应的数据库表名为 sys_user
+@TableName("sys_user")
+public class SysUser extends Model {
+
+ // 序列化版本号,用于在反序列化时验证版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户的唯一标识 ID
+ * 使用 MyBatis-Plus 的 @TableId 注解指定该字段为主键,
+ * value 属性指定数据库表中的字段名,type 属性指定主键生成策略为 ASSIGN_ID
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private String id;
+
+ /**
+ * 用户名,对应数据库表中的 user_name 字段
+ * 使用 MyBatis-Plus 的 @TableField 注解指定数据库表中的字段名
+ */
+ @TableField("user_name")
+ private String userName;
+
+ /**
+ * 真实姓名,对应数据库表中的 real_name 字段
+ * 使用 MyBatis-Plus 的 @TableField 注解指定数据库表中的字段名
+ */
+ @TableField("real_name")
+ private String realName;
+
+ /**
+ * 用户密码,未指定 @TableField 时,默认字段名与属性名相同
+ */
+ private String password;
+
+ /**
+ * 密码盐,用于增强密码的安全性,未指定 @TableField 时,默认字段名与属性名相同
+ */
+ private String salt;
+
+ /**
+ * 角色列表,以字符串形式存储角色 ID,对应数据库表中的 role_ids 字段
+ * 使用 MyBatis-Plus 的 @TableField 注解指定数据库表中的字段名
+ */
+ @TableField("role_ids")
+ private String roleIds;
+
+ /**
+ * 部门 ID,对应数据库表中的 depart_id 字段
+ * 使用 MyBatis-Plus 的 @TableField 注解指定数据库表中的字段名
+ */
+ @TableField("depart_id")
+ private String departId;
+
+ /**
+ * 用户记录的创建时间,对应数据库表中的 create_time 字段
+ * 使用 MyBatis-Plus 的 @TableField 注解指定数据库表中的字段名
+ */
+ @TableField("create_time")
+ private Date createTime;
+
+ /**
+ * 用户记录的更新时间,对应数据库表中的 update_time 字段
+ * 使用 MyBatis-Plus 的 @TableField 注解指定数据库表中的字段名
+ */
+ @TableField("update_time")
+ private Date updateTime;
+
+ /**
+ * 用户状态,未指定 @TableField 时,默认字段名与属性名相同
+ */
+ private Integer state;
+
+}
diff --git a/sys/user/entity/SysUserRole.java b/sys/user/entity/SysUserRole.java
new file mode 100644
index 0000000..fb33b77
--- /dev/null
+++ b/sys/user/entity/SysUserRole.java
@@ -0,0 +1,53 @@
+// 声明当前类所在的包,该包属于系统用户模块下的实体类包
+package com.yf.exam.modules.sys.user.entity;
+
+// 导入 MyBatis-Plus 提供的主键生成策略枚举类
+import com.baomidou.mybatisplus.annotation.IdType;
+// 导入 MyBatis-Plus 提供的表字段注解,用于指定数据库表字段名
+import com.baomidou.mybatisplus.annotation.TableField;
+// 导入 MyBatis-Plus 提供的表主键注解,用于指定数据库表的主键
+import com.baomidou.mybatisplus.annotation.TableId;
+// 导入 MyBatis-Plus 提供的表名注解,用于指定实体类对应的数据库表名
+import com.baomidou.mybatisplus.annotation.TableName;
+// 导入 MyBatis-Plus 提供的 ActiveRecord 模式基类,方便进行数据库操作
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+// 导入 Lombok 提供的 Data 注解,自动生成 getter、setter、equals、hashCode 和 toString 方法
+import lombok.Data;
+
+/**
+ *
+ * 用户角色实体类,用于映射数据库中的 sys_user_role 表,存储用户与角色的关联信息。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+// 使用 Lombok 的 Data 注解,自动生成常用的 getter、setter 等方法
+@Data
+// 指定该实体类对应的数据库表名为 sys_user_role
+@TableName("sys_user_role")
+public class SysUserRole extends Model {
+
+ // 序列化版本号,确保序列化和反序列化时类的版本一致性
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户角色关联记录的唯一标识 ID
+ * 使用 TableId 注解指定该字段为主键,采用 ASSIGN_ID 主键生成策略
+ */
+ @TableId(value = "id", type = IdType.ASSIGN_ID)
+ private String id;
+
+ /**
+ * 关联的用户 ID,对应数据库表中的 user_id 字段
+ */
+ @TableField("user_id")
+ private String userId;
+
+ /**
+ * 关联的角色 ID,对应数据库表中的 role_id 字段
+ */
+ @TableField("role_id")
+ private String roleId;
+
+}
diff --git a/sys/user/mapper/SysRoleMapper.java b/sys/user/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..af66098
--- /dev/null
+++ b/sys/user/mapper/SysRoleMapper.java
@@ -0,0 +1,32 @@
+/**
+ * 定义包名,表明该类属于系统用户模块下的映射器包。
+ * 包名的组织有助于代码的模块化管理和避免命名冲突。
+ */
+package com.yf.exam.modules.sys.user.mapper;
+
+/**
+ * 导入 MyBatis-Plus 核心的 BaseMapper 接口,
+ * 该接口提供了通用的数据库 CRUD 操作方法,
+ * 可以减少开发者编写重复的 SQL 映射代码。
+ */
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * 导入系统角色实体类,该类用于封装角色相关的属性,
+ * 作为 Mapper 接口操作的对象类型。
+ */
+import com.yf.exam.modules.sys.user.entity.SysRole;
+
+/**
+ *
+ * 角色Mapper接口,继承自 MyBatis-Plus 的 BaseMapper 接口。
+ * 该接口用于定义与系统角色相关的数据库操作方法,
+ * 借助 BaseMapper 提供的通用方法,可以直接进行角色数据的增删改查操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+public interface SysRoleMapper extends BaseMapper {
+ // 目前该接口仅继承 BaseMapper 的通用方法,未自定义额外的数据库操作方法
+}
diff --git a/sys/user/mapper/SysUserMapper.java b/sys/user/mapper/SysUserMapper.java
new file mode 100644
index 0000000..7c81b34
--- /dev/null
+++ b/sys/user/mapper/SysUserMapper.java
@@ -0,0 +1,32 @@
+/**
+ * 声明该接口所在的包,用于组织代码结构,避免命名冲突。
+ * 此包属于系统用户模块下的映射器包。
+ */
+package com.yf.exam.modules.sys.user.mapper;
+
+/**
+ * 导入 MyBatis-Plus 框架的核心接口 BaseMapper。
+ * BaseMapper 提供了一系列通用的数据库 CRUD 操作方法,
+ * 继承该接口可以减少重复编写基础数据库操作代码的工作量。
+ */
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * 导入系统用户实体类 SysUser。
+ * 该实体类用于封装系统用户的相关属性,
+ * 作为当前 Mapper 接口操作的对象类型。
+ */
+import com.yf.exam.modules.sys.user.entity.SysUser;
+
+/**
+ *
+ * 管理用户Mapper接口,用于与数据库中管理用户相关的数据表进行交互。
+ * 继承自 MyBatis-Plus 的 BaseMapper 接口,可直接使用其提供的通用数据库操作方法。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+public interface SysUserMapper extends BaseMapper {
+ // 目前该接口仅继承 BaseMapper 的通用方法,未自定义额外的数据库操作方法
+}
diff --git a/sys/user/mapper/SysUserRoleMapper.java b/sys/user/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..38f9ac9
--- /dev/null
+++ b/sys/user/mapper/SysUserRoleMapper.java
@@ -0,0 +1,32 @@
+/**
+ * 定义包名,表明该类所属的模块和功能目录,这里是系统用户模块下的 mapper 目录。
+ */
+package com.yf.exam.modules.sys.user.mapper;
+
+/**
+ * 导入 MyBatis-Plus 框架的 BaseMapper 接口,
+ * 该接口提供了通用的数据库 CRUD 操作方法,
+ * 继承它可以让我们快速实现对数据库表的基本操作。
+ */
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * 导入系统用户角色实体类,
+ * 该实体类用于封装用户角色的相关属性,
+ * 作为当前 Mapper 接口操作的对象类型。
+ */
+import com.yf.exam.modules.sys.user.entity.SysUserRole;
+
+/**
+ *
+ * 用户角色Mapper接口,继承自 MyBatis-Plus 的 BaseMapper 接口。
+ * 该接口用于与数据库中用户角色相关的数据表进行交互,
+ * 借助 BaseMapper 提供的通用方法,可以直接进行用户角色数据的增删改查操作。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+public interface SysUserRoleMapper extends BaseMapper {
+ // 目前该接口仅继承 BaseMapper 的通用方法,未自定义额外的数据库操作方法
+}
diff --git a/sys/user/service/SysRoleService.java b/sys/user/service/SysRoleService.java
new file mode 100644
index 0000000..4855f8f
--- /dev/null
+++ b/sys/user/service/SysRoleService.java
@@ -0,0 +1,52 @@
+/**
+ * 定义包名,表明该接口所属的模块和服务层目录结构。
+ * 此包路径用于组织系统用户模块下的服务接口类。
+ */
+package com.yf.exam.modules.sys.user.service;
+
+/**
+ * 导入 MyBatis-Plus 框架的分页元数据接口,
+ * 该接口用于表示分页查询的结果,包含总记录数、当前页码等信息。
+ */
+import com.baomidou.mybatisplus.core.metadata.IPage;
+/**
+ * 导入 MyBatis-Plus 框架的扩展服务接口,
+ * 该接口提供了通用的 CRUD 操作方法,可减少重复代码编写。
+ */
+import com.baomidou.mybatisplus.extension.service.IService;
+/**
+ * 导入系统角色数据传输对象类,
+ * 用于在不同层之间传输角色相关的数据,避免直接暴露实体类。
+ */
+import com.yf.exam.modules.sys.user.dto.SysRoleDTO;
+/**
+ * 导入系统角色实体类,
+ * 该类用于映射数据库中的角色表,封装角色的属性信息。
+ */
+import com.yf.exam.modules.sys.user.entity.SysRole;
+/**
+ * 导入自定义的分页请求数据传输对象类,
+ * 用于封装分页查询的请求参数,如当前页码、每页记录数等。
+ */
+import com.yf.exam.core.api.dto.PagingReqDTO;
+
+/**
+ *
+ * 角色业务类接口,定义了与系统角色相关的业务方法。
+ * 继承自 MyBatis-Plus 的 IService 接口,可使用其提供的通用服务方法。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+public interface SysRoleService extends IService {
+
+ /**
+ * 分页查询角色数据。
+ * 根据传入的分页请求参数,从数据库中查询角色数据并进行分页处理。
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数。
+ * @return 分页查询结果,包含符合条件的角色数据传输对象列表。
+ */
+ IPage paging(PagingReqDTO reqDTO);
+}
diff --git a/sys/user/service/SysUserRoleService.java b/sys/user/service/SysUserRoleService.java
new file mode 100644
index 0000000..774b663
--- /dev/null
+++ b/sys/user/service/SysUserRoleService.java
@@ -0,0 +1,94 @@
+/**
+ * 定义包名,明确该接口所属的模块和服务层目录,用于组织系统用户角色相关的服务类。
+ */
+package com.yf.exam.modules.sys.user.service;
+
+/**
+ * 导入 MyBatis-Plus 框架的分页元数据接口,用于表示分页查询结果,包含总记录数、当前页码等信息。
+ */
+import com.baomidou.mybatisplus.core.metadata.IPage;
+/**
+ * 导入 MyBatis-Plus 框架的扩展服务接口,提供通用的 CRUD 操作方法,减少重复代码编写。
+ */
+import com.baomidou.mybatisplus.extension.service.IService;
+/**
+ * 导入系统用户角色数据传输对象类,用于在不同层之间传输用户角色相关的数据,避免直接暴露实体类。
+ */
+import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO;
+/**
+ * 导入系统用户角色实体类,用于映射数据库中的用户角色表,封装用户角色的属性信息。
+ */
+import com.yf.exam.modules.sys.user.entity.SysUserRole;
+/**
+ * 导入自定义的分页请求数据传输对象类,用于封装分页查询的请求参数,如当前页码、每页记录数等。
+ */
+import com.yf.exam.core.api.dto.PagingReqDTO;
+
+import java.util.List;
+
+/**
+ *
+ * 用户角色业务类接口,定义了与系统用户角色相关的业务方法。
+ * 继承自 MyBatis-Plus 的 IService 接口,可使用其提供的通用服务方法。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+public interface SysUserRoleService extends IService {
+
+ /**
+ * 分页查询用户角色数据。
+ * 根据传入的分页请求参数,从数据库中查询用户角色数据并进行分页处理。
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数。
+ * @return 分页查询结果,包含符合条件的用户角色数据传输对象列表。
+ */
+ IPage paging(PagingReqDTO reqDTO);
+
+ /**
+ * 查找指定用户的角色列表。
+ * 根据用户 ID 从数据库中查询该用户关联的所有角色 ID。
+ *
+ * @param userId 用户的唯一标识。
+ * @return 该用户关联的角色 ID 列表。
+ */
+ List listRoles(String userId);
+
+ /**
+ * 保存指定用户的全部角色。
+ * 先删除该用户原有的所有角色关联,再添加新的角色关联。
+ *
+ * @param userId 用户的唯一标识。
+ * @param ids 要保存的角色 ID 列表。
+ * @return 保存操作完成后,返回保存的角色 ID 相关信息(具体格式由实现类定义)。
+ */
+ String saveRoles(String userId, List ids);
+
+ /**
+ * 判断指定用户是否为学生角色。
+ * 根据用户 ID 检查该用户是否关联了学生角色。
+ *
+ * @param userId 用户的唯一标识。
+ * @return 如果用户是学生角色返回 true,否则返回 false。
+ */
+ boolean isStudent(String userId);
+
+ /**
+ * 判断指定用户是否为老师角色。
+ * 根据用户 ID 检查该用户是否关联了老师角色。
+ *
+ * @param userId 用户的唯一标识。
+ * @return 如果用户是老师角色返回 true,否则返回 false。
+ */
+ boolean isTeacher(String userId);
+
+ /**
+ * 判断指定用户是否为管理员角色。
+ * 根据用户 ID 检查该用户是否关联了管理员角色。
+ *
+ * @param userId 用户的唯一标识。
+ * @return 如果用户是管理员角色返回 true,否则返回 false。
+ */
+ boolean isAdmin(String userId);
+}
diff --git a/sys/user/service/SysUserService.java b/sys/user/service/SysUserService.java
new file mode 100644
index 0000000..c35b999
--- /dev/null
+++ b/sys/user/service/SysUserService.java
@@ -0,0 +1,99 @@
+// 声明当前接口所在的包,明确该接口属于系统用户服务模块
+package com.yf.exam.modules.sys.user.service;
+
+// 导入 MyBatis-Plus 分页元数据接口,用于处理分页查询结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入 MyBatis-Plus 扩展服务接口,提供通用的 CRUD 操作方法
+import com.baomidou.mybatisplus.extension.service.IService;
+// 导入系统用户数据传输对象类,用于在不同层之间传输用户相关数据
+import com.yf.exam.modules.sys.user.dto.SysUserDTO;
+// 导入系统用户保存请求数据传输对象类,用于封装用户保存操作的请求参数
+import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO;
+// 导入系统用户登录响应数据传输对象类,用于封装用户登录操作的响应信息
+import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO;
+// 导入系统用户实体类,用于映射数据库中的用户表
+import com.yf.exam.modules.sys.user.entity.SysUser;
+// 导入自定义的分页请求数据传输对象类,用于封装分页查询的请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+
+/**
+ *
+ * 管理用户业务类接口,定义了系统用户相关的业务操作方法。
+ * 继承自 MyBatis-Plus 的 IService 接口,可使用其提供的通用服务方法。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+public interface SysUserService extends IService {
+
+ /**
+ * 分页查询系统用户数据。
+ * 根据传入的分页请求参数,从数据库中查询符合条件的用户数据并进行分页处理。
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的条件和参数
+ * @return 分页查询结果,包含系统用户数据传输对象列表
+ */
+ IPage paging(PagingReqDTO reqDTO);
+
+ /**
+ * 用户登录方法。
+ * 根据传入的用户名和密码,验证用户身份,若验证通过则返回登录信息。
+ *
+ * @param userName 用户名,用于标识用户身份
+ * @param password 用户密码,用于验证用户身份
+ * @return 系统用户登录响应数据传输对象,包含登录成功后的用户信息和令牌等
+ */
+ SysUserLoginDTO login(String userName, String password);
+
+ /**
+ * 根据令牌获取管理会话信息。
+ * 验证传入的令牌是否有效,若有效则返回对应的用户登录信息。
+ *
+ * @param token 用户登录后生成的令牌,用于验证用户身份和保持会话
+ * @return 系统用户登录响应数据传输对象,包含令牌对应的用户信息
+ */
+ SysUserLoginDTO token(String token);
+
+ /**
+ * 用户退出登录方法。
+ * 使传入的令牌失效,清除用户的登录会话信息。
+ *
+ * @param token 用户登录后生成的令牌,用于标识用户会话
+ */
+ void logout(String token);
+
+ /**
+ * 修改用户资料方法。
+ * 根据传入的用户数据传输对象,更新数据库中对应的用户信息。
+ *
+ * @param reqDTO 系统用户数据传输对象,包含要更新的用户信息
+ */
+ void update(SysUserDTO reqDTO);
+
+ /**
+ * 保存添加系统用户方法。
+ * 根据传入的用户保存请求数据传输对象,将新用户信息保存到数据库中。
+ *
+ * @param reqDTO 系统用户保存请求数据传输对象,包含要添加的用户信息
+ */
+ void save(SysUserSaveReqDTO reqDTO);
+
+ /**
+ * 用户注册方法。
+ * 根据传入的用户数据传输对象,在数据库中创建新的用户记录,并返回注册后的登录信息。
+ *
+ * @param reqDTO 系统用户数据传输对象,包含要注册的用户信息
+ * @return 系统用户登录响应数据传输对象,包含注册成功后的用户信息和令牌等
+ */
+ SysUserLoginDTO reg(SysUserDTO reqDTO);
+
+ /**
+ * 快速注册方法。
+ * 根据传入的用户数据传输对象,快速创建新的用户记录,并返回注册后的登录信息。
+ *
+ * @param reqDTO 系统用户数据传输对象,包含要快速注册的用户信息
+ * @return 系统用户登录响应数据传输对象,包含快速注册成功后的用户信息和令牌等
+ */
+ SysUserLoginDTO quickReg(SysUserDTO reqDTO);
+}
diff --git a/sys/user/service/impl/SysRoleServiceImpl.java b/sys/user/service/impl/SysRoleServiceImpl.java
new file mode 100644
index 0000000..845939f
--- /dev/null
+++ b/sys/user/service/impl/SysRoleServiceImpl.java
@@ -0,0 +1,62 @@
+// 声明该类所在的包,明确其在项目中的模块和层级位置
+package com.yf.exam.modules.sys.user.service.impl;
+
+// 导入阿里巴巴的 FastJSON 库,用于 JSON 数据的序列化和反序列化
+import com.alibaba.fastjson.JSON;
+// 导入 FastJSON 的 TypeReference 类,用于处理泛型类型的 JSON 反序列化
+import com.alibaba.fastjson.TypeReference;
+// 导入 MyBatis-Plus 的查询条件构造器类,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于表示分页查询的结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入 MyBatis-Plus 的分页实现类,用于创建分页对象
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+// 导入 MyBatis-Plus 的服务实现基类,提供了通用的服务层方法实现
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+// 导入系统角色数据传输对象类,用于在不同层之间传输角色相关的数据
+import com.yf.exam.modules.sys.user.dto.SysRoleDTO;
+// 导入系统角色实体类,用于映射数据库中的角色表
+import com.yf.exam.modules.sys.user.entity.SysRole;
+// 导入系统角色数据访问接口,用于与数据库进行角色数据的交互
+import com.yf.exam.modules.sys.user.mapper.SysRoleMapper;
+// 导入系统角色服务接口,定义了角色相关的业务方法
+import com.yf.exam.modules.sys.user.service.SysRoleService;
+// 导入分页请求数据传输对象类,用于封装分页查询的请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入 Spring 的服务注解,将该类标记为一个服务组件,由 Spring 容器进行管理
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 系统角色 服务实现类,实现了系统角色相关的业务逻辑。
+ * 继承自 MyBatis-Plus 的 ServiceImpl 类,使用 SysRoleMapper 操作 SysRole 实体。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+@Service
+public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService {
+
+ /**
+ * 分页查询系统角色信息。
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的当前页码、每页记录数等信息
+ * @return 分页查询结果,包含系统角色数据传输对象列表
+ */
+ @Override
+ public IPage paging(PagingReqDTO reqDTO) {
+
+ // 创建分页对象,根据请求中的当前页码和每页记录数初始化
+ IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
+
+ // 创建查询条件构造器,用于构建数据库查询条件,当前未添加具体查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+
+ // 调用父类的 page 方法进行分页查询,获取包含 SysRole 实体的分页结果
+ IPage page = this.page(query, wrapper);
+ // 将包含 SysRole 实体的分页结果转换为 JSON 字符串,再反序列化为包含 SysRoleDTO 的分页结果
+ IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){});
+ return pageData;
+ }
+}
diff --git a/sys/user/service/impl/SysUserRoleServiceImpl.java b/sys/user/service/impl/SysUserRoleServiceImpl.java
new file mode 100644
index 0000000..dc67c40
--- /dev/null
+++ b/sys/user/service/impl/SysUserRoleServiceImpl.java
@@ -0,0 +1,200 @@
+package com.yf.exam.modules.sys.user.service.impl;
+
+// 导入阿里巴巴的 FastJSON 库,用于 JSON 数据的序列化和反序列化
+import com.alibaba.fastjson.JSON;
+// 导入 FastJSON 的 TypeReference 类,用于处理泛型类型的 JSON 反序列化
+import com.alibaba.fastjson.TypeReference;
+// 导入 MyBatis-Plus 的查询条件构造器类,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于表示分页查询的结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入 MyBatis-Plus 的分页实现类,用于创建分页对象
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+// 导入 MyBatis-Plus 的服务实现基类,提供了通用的服务层方法实现
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+// 导入系统用户角色数据传输对象类,用于在不同层之间传输用户角色相关的数据
+import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO;
+// 导入系统用户角色实体类,用于映射数据库中的用户角色表
+import com.yf.exam.modules.sys.user.entity.SysUserRole;
+// 导入系统用户角色数据访问接口,用于与数据库进行用户角色数据的交互
+import com.yf.exam.modules.sys.user.mapper.SysUserRoleMapper;
+// 导入系统用户角色服务接口,定义了用户角色相关的业务方法
+import com.yf.exam.modules.sys.user.service.SysUserRoleService;
+// 导入分页请求数据传输对象类,用于封装分页查询的请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入 Spring 的服务注解,将该类标记为一个服务组件,由 Spring 容器进行管理
+import org.springframework.stereotype.Service;
+// 导入 Spring 的集合工具类,用于判断集合是否为空
+import org.springframework.util.CollectionUtils;
+// 导入 Spring 的字符串工具类,用于判断字符串是否为空
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * 用户角色 服务实现类,实现了用户角色相关的业务逻辑。
+ * 继承自 MyBatis-Plus 的 ServiceImpl 类,使用 SysUserRoleMapper 操作 SysUserRole 实体。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+@Service
+public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService {
+
+ /**
+ * 分页查询用户角色信息。
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页查询的当前页码、每页记录数等信息
+ * @return 分页查询结果,包含用户角色数据传输对象列表
+ */
+ @Override
+ public IPage paging(PagingReqDTO reqDTO) {
+
+ // 创建分页对象,根据请求中的当前页码和每页记录数初始化
+ IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
+
+ // 创建查询条件构造器,用于构建数据库查询条件,当前未添加具体查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+
+ // 调用父类的 page 方法进行分页查询,获取包含 SysUserRole 实体的分页结果
+ IPage page = this.page(query, wrapper);
+ // 将包含 SysUserRole 实体的分页结果转换为 JSON 字符串,再反序列化为包含 SysUserRoleDTO 的分页结果
+ IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){});
+ return pageData;
+ }
+
+ /**
+ * 根据用户 ID 查询用户的角色列表。
+ *
+ * @param userId 用户的唯一标识
+ * @return 用户的角色 ID 列表
+ */
+ @Override
+ public List listRoles(String userId) {
+
+ // 创建查询条件构造器,添加用户 ID 作为查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUserRole::getUserId, userId);
+
+ // 调用父类的 list 方法进行查询,获取符合条件的用户角色实体列表
+ List list = this.list(wrapper);
+ // 初始化一个空的角色 ID 列表
+ List roles = new ArrayList<>();
+ // 判断查询结果列表是否不为空
+ if(!CollectionUtils.isEmpty(list)){
+ // 遍历用户角色实体列表,将每个实体的角色 ID 添加到角色 ID 列表中
+ for(SysUserRole item: list){
+ roles.add(item.getRoleId());
+ }
+ }
+
+ return roles;
+ }
+
+ /**
+ * 保存用户的角色信息,先删除用户原有的所有角色,再添加新的角色。
+ *
+ * @param userId 用户的唯一标识
+ * @param ids 新的角色 ID 列表
+ * @return 保存的角色 ID 以逗号连接的字符串
+ */
+ @Override
+ public String saveRoles(String userId, List ids) {
+
+ // 创建查询条件构造器,添加用户 ID 作为查询条件,用于删除用户原有的所有角色
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUserRole::getUserId, userId);
+ // 调用父类的 remove 方法删除符合条件的用户角色记录
+ this.remove(wrapper);
+
+ // 判断新的角色 ID 列表是否不为空
+ if(!CollectionUtils.isEmpty(ids)){
+
+ // 初始化一个空的用户角色实体列表
+ List list = new ArrayList<>();
+ // 用于存储以逗号连接的角色 ID 字符串
+ String roleIds = null;
+
+ // 遍历新的角色 ID 列表
+ for(String item: ids){
+ // 创建一个新的用户角色实体对象
+ SysUserRole role = new SysUserRole();
+ // 设置角色 ID
+ role.setRoleId(item);
+ // 设置用户 ID
+ role.setUserId(userId);
+ // 将用户角色实体对象添加到列表中
+ list.add(role);
+ // 判断 roleIds 是否为空
+ if(StringUtils.isEmpty(roleIds)){
+ // 若为空,则直接赋值为当前角色 ID
+ roleIds = item;
+ }else{
+ // 若不为空,则将当前角色 ID 追加到 roleIds 后面,用逗号分隔
+ roleIds+=","+item;
+ }
+ }
+
+ // 调用父类的 saveBatch 方法批量保存用户角色实体列表
+ this.saveBatch(list);
+ return roleIds;
+ }
+
+ return "";
+ }
+
+ /**
+ * 判断用户是否具有学生角色。
+ *
+ * @param userId 用户的唯一标识
+ * @return 若用户具有学生角色返回 true,否则返回 false
+ */
+ @Override
+ public boolean isStudent(String userId) {
+
+ // 创建查询条件构造器,添加用户 ID 和角色 ID(student)作为查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUserRole::getUserId, userId)
+ .eq(SysUserRole::getRoleId, "student");
+
+ // 调用父类的 count 方法统计符合条件的记录数,若大于 0 则表示用户具有学生角色
+ return this.count(wrapper) > 0;
+ }
+
+ /**
+ * 判断用户是否具有教师角色。
+ *
+ * @param userId 用户的唯一标识
+ * @return 若用户具有教师角色返回 true,否则返回 false
+ */
+ @Override
+ public boolean isTeacher(String userId) {
+ // 创建查询条件构造器,添加用户 ID 和角色 ID(teacher)作为查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUserRole::getUserId, userId)
+ .eq(SysUserRole::getRoleId, "teacher");
+
+ // 调用父类的 count 方法统计符合条件的记录数,若大于 0 则表示用户具有教师角色
+ return this.count(wrapper) > 0;
+ }
+
+ /**
+ * 判断用户是否具有管理员角色。
+ *
+ * @param userId 用户的唯一标识
+ * @return 若用户具有管理员角色返回 true,否则返回 false
+ */
+ @Override
+ public boolean isAdmin(String userId) {
+ // 创建查询条件构造器,添加用户 ID 和角色 ID(sa)作为查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUserRole::getUserId, userId)
+ .eq(SysUserRole::getRoleId, "sa");
+
+ // 调用父类的 count 方法统计符合条件的记录数,若大于 0 则表示用户具有管理员角色
+ return this.count(wrapper) > 0;
+ }
+}
diff --git a/sys/user/service/impl/SysUserServiceImpl.java b/sys/user/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..6aa7169
--- /dev/null
+++ b/sys/user/service/impl/SysUserServiceImpl.java
@@ -0,0 +1,383 @@
+// 声明该类所在的包,表明它属于系统用户服务实现模块
+package com.yf.exam.modules.sys.user.service.impl;
+
+// 导入阿里巴巴 FastJSON 库,用于 JSON 数据的序列化和反序列化
+import com.alibaba.fastjson.JSON;
+// 导入 FastJSON 的 TypeReference 类,用于处理泛型类型的 JSON 反序列化
+import com.alibaba.fastjson.TypeReference;
+// 导入 MyBatis-Plus 的查询条件构造器,用于构建数据库查询条件
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+// 导入 MyBatis-Plus 的分页元数据接口,用于表示分页查询结果
+import com.baomidou.mybatisplus.core.metadata.IPage;
+// 导入 MyBatis-Plus 的 ID 生成工具类,用于生成分布式 ID
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+// 导入 MyBatis-Plus 的分页实现类,用于创建分页对象
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+// 导入 MyBatis-Plus 的服务实现基类,提供通用的服务层方法实现
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+// 导入自定义的 API 错误类,用于封装 API 错误信息
+import com.yf.exam.core.api.ApiError;
+// 导入自定义的分页请求数据传输对象类,用于封装分页查询请求参数
+import com.yf.exam.core.api.dto.PagingReqDTO;
+// 导入自定义的通用状态枚举类,定义通用的状态常量
+import com.yf.exam.core.enums.CommonState;
+// 导入自定义的服务异常类,用于抛出服务层异常
+import com.yf.exam.core.exception.ServiceException;
+// 导入自定义的 Bean 映射工具类,用于对象属性的复制
+import com.yf.exam.core.utils.BeanMapper;
+// 导入自定义的密码处理工具类,用于密码的加密和验证
+import com.yf.exam.core.utils.passwd.PassHandler;
+// 导入自定义的密码信息类,用于封装密码和盐值
+import com.yf.exam.core.utils.passwd.PassInfo;
+// 导入自定义的 JWT 工具类,用于生成和验证 JWT 令牌
+import com.yf.exam.ability.shiro.jwt.JwtUtils;
+// 导入自定义的系统用户数据传输对象类,用于在不同层之间传输用户数据
+import com.yf.exam.modules.sys.user.dto.SysUserDTO;
+// 导入自定义的系统用户保存请求数据传输对象类,用于封装用户保存请求参数
+import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO;
+// 导入自定义的系统用户登录响应数据传输对象类,用于封装用户登录响应信息
+import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO;
+// 导入自定义的系统用户实体类,用于映射数据库中的用户表
+import com.yf.exam.modules.sys.user.entity.SysUser;
+// 导入自定义的系统用户数据访问接口,用于与数据库进行用户数据交互
+import com.yf.exam.modules.sys.user.mapper.SysUserMapper;
+// 导入自定义的系统用户角色服务接口,用于处理用户角色相关业务
+import com.yf.exam.modules.sys.user.service.SysUserRoleService;
+// 导入自定义的系统用户服务接口,定义用户相关的业务方法
+import com.yf.exam.modules.sys.user.service.SysUserService;
+// 导入自定义的用户工具类,提供用户相关的工具方法
+import com.yf.exam.modules.user.UserUtils;
+// 导入 Apache Commons Lang3 的字符串工具类,提供字符串操作方法
+import org.apache.commons.lang3.StringUtils;
+// 导入 Apache Shiro 的安全工具类,用于进行身份验证和授权操作
+import org.apache.shiro.SecurityUtils;
+// 导入 Spring 的自动装配注解,用于自动注入依赖的 Bean
+import org.springframework.beans.factory.annotation.Autowired;
+// 导入 Spring 的服务注解,将该类标记为服务组件,由 Spring 容器管理
+import org.springframework.stereotype.Service;
+// 导入 Spring 的事务管理注解,用于声明事务方法
+import org.springframework.transaction.annotation.Transactional;
+// 导入 Spring 的集合工具类,用于判断集合是否为空
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * 系统用户 服务实现类,实现了系统用户相关的业务逻辑。
+ * 继承自 MyBatis-Plus 的 ServiceImpl 类,使用 SysUserMapper 操作 SysUser 实体。
+ *
+ *
+ * @author 聪明笨狗
+ * @since 2020-04-13 16:57
+ */
+@Service
+public class SysUserServiceImpl extends ServiceImpl implements SysUserService {
+
+ // 自动注入系统用户角色服务类的实例,用于处理用户角色相关业务
+ @Autowired
+ private SysUserRoleService sysUserRoleService;
+
+ /**
+ * 分页查询系统用户信息。
+ *
+ * @param reqDTO 分页请求数据传输对象,包含分页信息和查询参数
+ * @return 分页查询结果,包含系统用户数据传输对象列表
+ */
+ @Override
+ public IPage paging(PagingReqDTO reqDTO) {
+
+ // 创建分页对象,指定当前页码和每页记录数
+ IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
+
+ // 创建查询条件构造器,用于构建数据库查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+
+ // 获取查询参数
+ SysUserDTO params = reqDTO.getParams();
+
+ // 如果查询参数不为空
+ if(params!=null){
+ // 如果用户名不为空,添加用户名模糊查询条件
+ if(!StringUtils.isBlank(params.getUserName())){
+ wrapper.lambda().like(SysUser::getUserName, params.getUserName());
+ }
+
+ // 如果真实姓名不为空,添加真实姓名模糊查询条件
+ if(!StringUtils.isBlank(params.getRealName())){
+ wrapper.lambda().like(SysUser::getRealName, params.getRealName());
+ }
+ }
+
+ // 执行分页查询,获取包含系统用户实体的分页结果
+ IPage page = this.page(query, wrapper);
+ // 将包含系统用户实体的分页结果转换为包含系统用户数据传输对象的分页结果
+ IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){});
+ return pageData;
+ }
+
+ /**
+ * 用户登录方法。
+ *
+ * @param userName 用户名
+ * @param password 密码
+ * @return 系统用户登录响应数据传输对象,包含登录成功后的用户信息和令牌
+ * @throws ServiceException 若用户名不存在、用户被禁用或密码错误,抛出服务异常
+ */
+ @Override
+ public SysUserLoginDTO login(String userName, String password) {
+
+ // 创建查询条件构造器,添加用户名等于查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUser::getUserName, userName);
+
+ // 根据查询条件获取一个用户实体
+ SysUser user = this.getOne(wrapper, false);
+ // 如果用户不存在,抛出用户名或密码错误异常
+ if(user == null){
+ throw new ServiceException(ApiError.ERROR_90010002);
+ }
+
+ // 如果用户状态为异常(被禁用),抛出用户被禁用异常
+ if(user.getState().equals(CommonState.ABNORMAL)){
+ throw new ServiceException(ApiError.ERROR_90010005);
+ }
+
+ // 验证密码是否正确
+ boolean check = PassHandler.checkPass(password,user.getSalt(), user.getPassword());
+ // 如果密码不正确,抛出用户名或密码错误异常
+ if(!check){
+ throw new ServiceException(ApiError.ERROR_90010002);
+ }
+
+ // 为用户设置令牌并返回登录响应信息
+ return this.setToken(user);
+ }
+
+ /**
+ * 根据令牌验证用户信息并返回登录响应信息。
+ *
+ * @param token 令牌
+ * @return 系统用户登录响应数据传输对象,包含验证通过后的用户信息和令牌
+ * @throws ServiceException 若令牌验证失败、用户不存在或用户被禁用,抛出服务异常
+ */
+ @Override
+ public SysUserLoginDTO token(String token) {
+
+ // 从令牌中获取用户名
+ String username = JwtUtils.getUsername(token);
+
+ // 验证令牌是否有效
+ boolean check = JwtUtils.verify(token, username);
+
+ // 如果令牌验证失败,抛出用户名或密码错误异常
+ if(!check){
+ throw new ServiceException(ApiError.ERROR_90010002);
+ }
+
+ // 创建查询条件构造器,添加用户名等于查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUser::getUserName, username);
+
+ // 根据查询条件获取一个用户实体
+ SysUser user = this.getOne(wrapper, false);
+ // 如果用户不存在,抛出用户不存在异常
+ if(user == null){
+ throw new ServiceException(ApiError.ERROR_10010002);
+ }
+
+ // 如果用户状态为异常(被禁用),抛出用户被禁用异常
+ if(user.getState().equals(CommonState.ABNORMAL)){
+ throw new ServiceException(ApiError.ERROR_90010005);
+ }
+
+ // 为用户设置令牌并返回登录响应信息
+ return this.setToken(user);
+ }
+
+ /**
+ * 用户退出登录方法。
+ *
+ * @param token 令牌
+ */
+ @Override
+ public void logout(String token) {
+
+ // 仅退出当前会话
+ SecurityUtils.getSubject().logout();
+ }
+
+ /**
+ * 更新用户信息,主要处理密码更新。
+ *
+ * @param reqDTO 系统用户数据传输对象,包含要更新的用户信息
+ */
+ @Override
+ public void update(SysUserDTO reqDTO) {
+
+ // 获取用户输入的新密码
+ String pass = reqDTO.getPassword();
+ // 如果新密码不为空
+ if(!StringUtils.isBlank(pass)){
+ // 生成新的密码信息,包含加密后的密码和盐值
+ PassInfo passInfo = PassHandler.buildPassword(pass);
+ // 根据当前用户 ID 获取用户实体
+ SysUser user = this.getById(UserUtils.getUserId());
+ // 更新用户密码
+ user.setPassword(passInfo.getPassword());
+ // 更新用户密码盐值
+ user.setSalt(passInfo.getSalt());
+ // 更新用户信息到数据库
+ this.updateById(user);
+ }
+ }
+
+ /**
+ * 保存或更新用户信息,同时处理用户角色信息。
+ *
+ * @param reqDTO 系统用户保存请求数据传输对象,包含要保存的用户信息和角色列表
+ * @throws ServiceException 若角色列表为空,抛出服务异常
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void save(SysUserSaveReqDTO reqDTO) {
+
+ // 获取用户的角色列表
+ List roles = reqDTO.getRoles();
+
+ // 如果角色列表为空,抛出角色不能为空异常
+ if(CollectionUtils.isEmpty(roles)){
+ throw new ServiceException(ApiError.ERROR_90010003);
+ }
+
+ // 创建系统用户实体对象
+ SysUser user = new SysUser();
+ // 将请求数据传输对象的属性复制到用户实体对象中
+ BeanMapper.copy(reqDTO, user);
+
+ // 如果用户 ID 为空,说明是新增用户,生成新的用户 ID
+ if(StringUtils.isBlank(user.getId())){
+ user.setId(IdWorker.getIdStr());
+ }
+
+ // 如果请求中包含密码,更新用户密码信息
+ if(!StringUtils.isBlank(reqDTO.getPassword())){
+ // 生成新的密码信息,包含加密后的密码和盐值
+ PassInfo pass = PassHandler.buildPassword(reqDTO.getPassword());
+ // 更新用户密码
+ user.setPassword(pass.getPassword());
+ // 更新用户密码盐值
+ user.setSalt(pass.getSalt());
+ }
+
+ // 保存用户角色信息,并返回角色 ID 字符串
+ String roleIds = sysUserRoleService.saveRoles(user.getId(), roles);
+ // 设置用户的角色 ID 字符串
+ user.setRoleIds(roleIds);
+ // 保存或更新用户信息到数据库
+ this.saveOrUpdate(user);
+ }
+
+ /**
+ * 用户注册方法。
+ *
+ * @param reqDTO 系统用户数据传输对象,包含要注册的用户信息
+ * @return 系统用户登录响应数据传输对象,包含注册成功后的用户信息和令牌
+ * @throws ServiceException 若用户名已存在,抛出服务异常
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public SysUserLoginDTO reg(SysUserDTO reqDTO) {
+
+ // 创建查询条件构造器,添加用户名等于查询条件
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUser::getUserName, reqDTO.getUserName());
+
+ // 统计符合条件的用户数量
+ int count = this.count(wrapper);
+
+ // 如果用户数量大于 0,说明用户名已存在,抛出用户名已存在异常
+ if(count > 0){
+ throw new ServiceException(1, "用户名已存在,换一个吧!");
+ }
+
+ // 创建系统用户实体对象
+ SysUser user = new SysUser();
+ // 生成新的用户 ID
+ user.setId(IdWorker.getIdStr());
+ // 设置用户名
+ user.setUserName(reqDTO.getUserName());
+ // 设置真实姓名
+ user.setRealName(reqDTO.getRealName());
+ // 生成新的密码信息,包含加密后的密码和盐值
+ PassInfo passInfo = PassHandler.buildPassword(reqDTO.getPassword());
+ // 设置用户密码
+ user.setPassword(passInfo.getPassword());
+ // 设置用户密码盐值
+ user.setSalt(passInfo.getSalt());
+
+ // 创建角色列表,默认添加学生角色
+ List roles = new ArrayList<>();
+ roles.add("student");
+ // 保存用户角色信息,并返回角色 ID 字符串
+ String roleIds = sysUserRoleService.saveRoles(user.getId(), roles);
+ // 设置用户的角色 ID 字符串
+ user.setRoleIds(roleIds);
+ // 保存用户信息到数据库
+ this.save(user);
+
+ // 为用户设置令牌并返回登录响应信息
+ return this.setToken(user);
+ }
+
+ /**
+ * 快速注册方法,如果用户已存在则直接返回登录信息,否则进行注册。
+ *
+ * @param reqDTO 系统用户数据传输对象,包含要注册的用户信息
+ * @return 系统用户登录响应数据传输对象,包含注册或登录成功后的用户信息和令牌
+ */
+ @Override
+ public SysUserLoginDTO quickReg(SysUserDTO reqDTO) {
+
+ // 创建查询条件构造器,添加用户名等于查询条件,并限制查询结果为 1 条
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.lambda().eq(SysUser::getUserName, reqDTO.getUserName());
+ wrapper.last(" LIMIT 1 ");
+ // 根据查询条件获取一个用户实体
+ SysUser user = this.getOne(wrapper);
+ // 如果用户存在,为用户设置令牌并返回登录响应信息
+ if(user!=null){
+ return this.setToken(user);
+ }
+
+ // 如果用户不存在,进行注册操作
+ return this.reg(reqDTO);
+ }
+
+ /**
+ * 为用户设置令牌并返回登录响应信息。
+ *
+ * @param user 系统用户实体对象
+ * @return 系统用户登录响应数据传输对象,包含用户信息和令牌
+ */
+ private SysUserLoginDTO setToken(SysUser user){
+
+ // 创建系统用户登录响应数据传输对象
+ SysUserLoginDTO respDTO = new SysUserLoginDTO();
+ // 将用户实体对象的属性复制到登录响应数据传输对象中
+ BeanMapper.copy(user, respDTO);
+
+ // 生成 JWT 令牌
+ String token = JwtUtils.sign(user.getUserName());
+ // 设置登录响应数据传输对象的令牌
+ respDTO.setToken(token);
+
+ // 获取用户的角色列表
+ List roles = sysUserRoleService.listRoles(user.getId());
+ // 设置登录响应数据传输对象的角色列表
+ respDTO.setRoles(roles);
+
+ return respDTO;
+ }
+}
--
2.34.1
From b6971277385318c4bfd1ee06d6ff99b1f1b68d01 Mon Sep 17 00:00:00 2001
From: yutao <2930275373@qq.com>
Date: Mon, 28 Apr 2025 21:34:32 +0800
Subject: [PATCH 3/4] LYT
---
.../java/com/yf/exam/ability/Constant.java | 15 -
.../yf/exam/ability/job/enums/JobGroup.java | 14 -
.../yf/exam/ability/job/enums/JobPrefix.java | 14 -
.../exam/ability/job/service/JobService.java | 52 --
.../job/service/impl/JobServiceImpl.java | 153 ------
.../ability/shiro/CNFilterFactoryBean.java | 38 --
.../com/yf/exam/ability/shiro/ShiroRealm.java | 129 -----
.../yf/exam/ability/shiro/aop/JwtFilter.java | 68 ---
.../yf/exam/ability/shiro/jwt/JwtToken.java | 45 --
.../yf/exam/ability/shiro/jwt/JwtUtils.java | 95 ----
.../ability/upload/config/UploadConfig.java | 34 --
.../upload/controller/UploadController.java | 58 ---
.../exam/ability/upload/dto/UploadReqDTO.java | 25 -
.../ability/upload/dto/UploadRespDTO.java | 27 -
.../ability/upload/service/UploadService.java | 32 --
.../service/impl/UploadServiceImpl.java | 140 -----
.../exam/ability/upload/utils/FileUtils.java | 159 ------
.../exam/ability/upload/utils/MediaUtils.java | 43 --
.../java/com/yf/exam/aspect/DictAspect.java | 315 ------------
.../exam/aspect/mybatis/QueryInterceptor.java | 129 -----
.../aspect/mybatis/UpdateInterceptor.java | 92 ----
.../com/yf/exam/aspect/utils/InjectUtils.java | 110 ----
.../java/com/yf/exam/config/CorsConfig.java | 50 --
.../com/yf/exam/config/MultipartConfig.java | 28 -
.../com/yf/exam/config/MybatisConfig.java | 37 --
.../com/yf/exam/config/ScheduledConfig.java | 93 ----
.../java/com/yf/exam/config/ShiroConfig.java | 153 ------
.../com/yf/exam/config/SwaggerConfig.java | 72 ---
.../java/com/yf/exam/core/annon/Dict.java | 32 --
.../java/com/yf/exam/core/api/ApiError.java | 118 -----
.../java/com/yf/exam/core/api/ApiRest.java | 64 ---
.../core/api/controller/BaseController.java | 160 ------
.../com/yf/exam/core/api/dto/BaseDTO.java | 15 -
.../yf/exam/core/api/dto/BaseIdReqDTO.java | 32 --
.../yf/exam/core/api/dto/BaseIdRespDTO.java | 28 -
.../yf/exam/core/api/dto/BaseIdsReqDTO.java | 34 --
.../yf/exam/core/api/dto/BaseStateReqDTO.java | 34 --
.../yf/exam/core/api/dto/PagingReqDTO.java | 61 ---
.../yf/exam/core/api/dto/PagingRespDTO.java | 28 -
.../yf/exam/core/api/utils/JsonConverter.java | 47 --
.../com/yf/exam/core/enums/CommonState.java | 19 -
.../java/com/yf/exam/core/enums/OpenType.java | 18 -
.../exam/core/exception/ServiceException.java | 51 --
.../exception/ServiceExceptionHandler.java | 46 --
.../com/yf/exam/core/utils/BeanMapper.java | 59 ---
.../com/yf/exam/core/utils/CronUtils.java | 31 --
.../com/yf/exam/core/utils/DateUtils.java | 103 ----
.../java/com/yf/exam/core/utils/IpUtils.java | 65 ---
.../com/yf/exam/core/utils/Reflections.java | 324 ------------
.../com/yf/exam/core/utils/SpringUtils.java | 53 --
.../com/yf/exam/core/utils/StringUtils.java | 42 --
.../yf/exam/core/utils/excel/ExportExcel.java | 402 ---------------
.../yf/exam/core/utils/excel/ImportExcel.java | 303 -----------
.../utils/excel/annotation/ExcelField.java | 59 ---
.../core/utils/excel/fieldtype/ListType.java | 62 ---
.../com/yf/exam/core/utils/file/Md5Util.java | 33 --
.../exam/core/utils/passwd/PassHandler.java | 57 ---
.../yf/exam/core/utils/passwd/PassInfo.java | 70 ---
.../exam/controller/ExamController.java | 151 ------
.../com/yf/exam/modules/exam/dto/ExamDTO.java | 101 ----
.../exam/modules/exam/dto/ExamDepartDTO.java | 33 --
.../yf/exam/modules/exam/dto/ExamRepoDTO.java | 51 --
.../modules/exam/dto/ext/ExamRepoExtDTO.java | 32 --
.../exam/dto/request/ExamSaveReqDTO.java | 32 --
.../exam/dto/response/ExamOnlineRespDTO.java | 22 -
.../exam/dto/response/ExamReviewRespDTO.java | 31 --
.../com/yf/exam/modules/exam/entity/Exam.java | 100 ----
.../exam/modules/exam/entity/ExamDepart.java | 42 --
.../yf/exam/modules/exam/entity/ExamRepo.java | 78 ---
.../modules/exam/mapper/ExamDepartMapper.java | 15 -
.../exam/modules/exam/mapper/ExamMapper.java | 45 --
.../modules/exam/mapper/ExamRepoMapper.java | 26 -
.../exam/service/ExamDepartService.java | 32 --
.../modules/exam/service/ExamRepoService.java | 40 --
.../modules/exam/service/ExamService.java | 63 ---
.../service/impl/ExamDepartServiceImpl.java | 66 ---
.../service/impl/ExamRepoServiceImpl.java | 67 ---
.../exam/service/impl/ExamServiceImpl.java | 194 -------
.../paper/controller/PaperController.java | 159 ------
.../yf/exam/modules/paper/dto/PaperDTO.java | 148 ------
.../modules/paper/dto/PaperQuAnswerDTO.java | 79 ---
.../yf/exam/modules/paper/dto/PaperQuDTO.java | 93 ----
.../paper/dto/ext/PaperQuAnswerExtDTO.java | 35 --
.../paper/dto/ext/PaperQuDetailDTO.java | 43 --
.../paper/dto/request/PaperAnswerDTO.java | 30 --
.../paper/dto/request/PaperCreateReqDTO.java | 31 --
.../paper/dto/request/PaperListReqDTO.java | 56 --
.../paper/dto/request/PaperQuQueryDTO.java | 30 --
.../paper/dto/response/ExamDetailRespDTO.java | 57 ---
.../paper/dto/response/ExamResultRespDTO.java | 25 -
.../paper/dto/response/PaperListRespDTO.java | 30 --
.../yf/exam/modules/paper/entity/Paper.java | 125 -----
.../yf/exam/modules/paper/entity/PaperQu.java | 80 ---
.../modules/paper/entity/PaperQuAnswer.java | 68 ---
.../exam/modules/paper/enums/ExamState.java | 33 --
.../exam/modules/paper/enums/PaperState.java | 33 --
.../exam/modules/paper/job/BreakExamJob.java | 57 ---
.../modules/paper/mapper/PaperMapper.java | 39 --
.../paper/mapper/PaperQuAnswerMapper.java | 27 -
.../modules/paper/mapper/PaperQuMapper.java | 42 --
.../paper/service/PaperQuAnswerService.java | 44 --
.../modules/paper/service/PaperQuService.java | 70 ---
.../modules/paper/service/PaperService.java | 83 ---
.../impl/PaperQuAnswerServiceImpl.java | 61 ---
.../service/impl/PaperQuServiceImpl.java | 94 ----
.../paper/service/impl/PaperServiceImpl.java | 477 ------------------
user/UserUtils.java | 75 +++
user/book/controller/UserBookController.java | 79 +++
user/book/dto/UserBookDTO.java | 79 +++
user/book/entity/UserBook.java | 80 +++
user/book/mapper/UserBookMapper.java | 18 +
user/book/service/UserBookService.java | 41 ++
.../service/impl/UserBookServiceImpl.java | 192 +++++++
user/exam/controller/UserExamController.java | 65 +++
user/exam/dto/UserExamDTO.java | 84 +++
user/exam/dto/request/UserExamReqDTO.java | 42 ++
user/exam/dto/response/UserExamRespDTO.java | 36 ++
user/exam/entity/UserExam.java | 85 ++++
user/exam/mapper/UserExamMapper.java | 37 ++
user/exam/service/UserExamService.java | 50 ++
.../service/impl/UserExamServiceImpl.java | 116 +++++
121 files changed, 1079 insertions(+), 8040 deletions(-)
delete mode 100644 src/main/java/com/yf/exam/ability/Constant.java
delete mode 100644 src/main/java/com/yf/exam/ability/job/enums/JobGroup.java
delete mode 100644 src/main/java/com/yf/exam/ability/job/enums/JobPrefix.java
delete mode 100644 src/main/java/com/yf/exam/ability/job/service/JobService.java
delete mode 100644 src/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java
delete mode 100644 src/main/java/com/yf/exam/ability/shiro/ShiroRealm.java
delete mode 100644 src/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java
delete mode 100644 src/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java
delete mode 100644 src/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/config/UploadConfig.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/controller/UploadController.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/service/UploadService.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/utils/FileUtils.java
delete mode 100644 src/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java
delete mode 100644 src/main/java/com/yf/exam/aspect/DictAspect.java
delete mode 100644 src/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java
delete mode 100644 src/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java
delete mode 100644 src/main/java/com/yf/exam/aspect/utils/InjectUtils.java
delete mode 100644 src/main/java/com/yf/exam/config/CorsConfig.java
delete mode 100644 src/main/java/com/yf/exam/config/MultipartConfig.java
delete mode 100644 src/main/java/com/yf/exam/config/MybatisConfig.java
delete mode 100644 src/main/java/com/yf/exam/config/ScheduledConfig.java
delete mode 100644 src/main/java/com/yf/exam/config/ShiroConfig.java
delete mode 100644 src/main/java/com/yf/exam/config/SwaggerConfig.java
delete mode 100644 src/main/java/com/yf/exam/core/annon/Dict.java
delete mode 100644 src/main/java/com/yf/exam/core/api/ApiError.java
delete mode 100644 src/main/java/com/yf/exam/core/api/ApiRest.java
delete mode 100644 src/main/java/com/yf/exam/core/api/controller/BaseController.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/BaseDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/BaseIdReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/BaseIdRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/BaseIdsReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/BaseStateReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/PagingReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/dto/PagingRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/core/api/utils/JsonConverter.java
delete mode 100644 src/main/java/com/yf/exam/core/enums/CommonState.java
delete mode 100644 src/main/java/com/yf/exam/core/enums/OpenType.java
delete mode 100644 src/main/java/com/yf/exam/core/exception/ServiceException.java
delete mode 100644 src/main/java/com/yf/exam/core/exception/ServiceExceptionHandler.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/BeanMapper.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/CronUtils.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/DateUtils.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/IpUtils.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/Reflections.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/SpringUtils.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/StringUtils.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/excel/ExportExcel.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/excel/ImportExcel.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/excel/annotation/ExcelField.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/excel/fieldtype/ListType.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/file/Md5Util.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/passwd/PassHandler.java
delete mode 100644 src/main/java/com/yf/exam/core/utils/passwd/PassInfo.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/controller/ExamController.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/entity/Exam.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/service/ExamService.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/controller/PaperController.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/entity/Paper.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/entity/PaperQu.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/enums/ExamState.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/enums/PaperState.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/service/PaperQuService.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/service/PaperService.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java
delete mode 100644 src/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java
create mode 100644 user/UserUtils.java
create mode 100644 user/book/controller/UserBookController.java
create mode 100644 user/book/dto/UserBookDTO.java
create mode 100644 user/book/entity/UserBook.java
create mode 100644 user/book/mapper/UserBookMapper.java
create mode 100644 user/book/service/UserBookService.java
create mode 100644 user/book/service/impl/UserBookServiceImpl.java
create mode 100644 user/exam/controller/UserExamController.java
create mode 100644 user/exam/dto/UserExamDTO.java
create mode 100644 user/exam/dto/request/UserExamReqDTO.java
create mode 100644 user/exam/dto/response/UserExamRespDTO.java
create mode 100644 user/exam/entity/UserExam.java
create mode 100644 user/exam/mapper/UserExamMapper.java
create mode 100644 user/exam/service/UserExamService.java
create mode 100644 user/exam/service/impl/UserExamServiceImpl.java
diff --git a/src/main/java/com/yf/exam/ability/Constant.java b/src/main/java/com/yf/exam/ability/Constant.java
deleted file mode 100644
index 91b40a7..0000000
--- a/src/main/java/com/yf/exam/ability/Constant.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.yf.exam.ability;
-
-
- //通用常量类
- //该类定义了应用程序中使用的通用常量。
- // @author bool
-
-public class Constant {
-
-
- //文件上传路径
- //该常量定义了文件上传时的默认路径前缀。
-
- public static final String FILE_PREFIX = "/upload/file/";
-}
diff --git a/src/main/java/com/yf/exam/ability/job/enums/JobGroup.java b/src/main/java/com/yf/exam/ability/job/enums/JobGroup.java
deleted file mode 100644
index 9b5f078..0000000
--- a/src/main/java/com/yf/exam/ability/job/enums/JobGroup.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.yf.exam.ability.job.enums;
-
-/**
- * 任务分组
- * @author van
- */
-public interface JobGroup {
-
- //定义了一个常量字符串,表示系统任务。
- //这个常量可以用于标识在系统中执行的任务组,通常用于任务调度和管理。
-
- String SYSTEM = "system";
-}
-
diff --git a/src/main/java/com/yf/exam/ability/job/enums/JobPrefix.java b/src/main/java/com/yf/exam/ability/job/enums/JobPrefix.java
deleted file mode 100644
index 404a996..0000000
--- a/src/main/java/com/yf/exam/ability/job/enums/JobPrefix.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.yf.exam.ability.job.enums;
-
-/**
- * 任务前缀
- * @author bool
- */
-public interface JobPrefix {
-
- //定义了一个常量字符串,表示强制交卷的操作前缀。
- //这个常量可以用于标识在系统中强制交卷的任务或操作,通常用于考试系统中的任务管理。
-
- String BREAK_EXAM = "break_exam_";
-}
-
diff --git a/src/main/java/com/yf/exam/ability/job/service/JobService.java b/src/main/java/com/yf/exam/ability/job/service/JobService.java
deleted file mode 100644
index c48c118..0000000
--- a/src/main/java/com/yf/exam/ability/job/service/JobService.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.yf.exam.ability.job.service;
-
-
- //任务业务类,用于动态处理任务信息
- //@author bool
- //@date 2020/11/29 下午2:17
-
-public interface JobService {
-
-
-
- //任务数据
-
- String TASK_DATA = "taskData";
-
-
- //添加定时任务
- //@param jobClass
- //@param jobName
- //@param cron
- //@param data
-
- void addCronJob(Class jobClass, String jobName, String cron, String data);
-
-
- //添加立即执行的任务
- //@param jobClass
- //@param jobName
- //@param data
-
- void addCronJob(Class jobClass, String jobName, String data);
-
-
- //暂停任务
- //@param jobName
- //@param jobGroup
-
- void pauseJob(String jobName, String jobGroup);
-
-
- //恢复任务
- //@param triggerName
- //@param triggerGroup
-
- void resumeJob(String triggerName, String triggerGroup);
-
- //删除job
- //@param jobName
- //@param jobGroup
-
- void deleteJob(String jobName, String jobGroup);
-}
diff --git a/src/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java b/src/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java
deleted file mode 100644
index d8152e2..0000000
--- a/src/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.yf.exam.ability.job.service.impl;
-
-import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.core.toolkit.IdWorker;
-import com.yf.exam.ability.job.enums.JobGroup;
-import com.yf.exam.ability.job.service.JobService;
-import lombok.extern.log4j.Log4j2;
-import org.quartz.*;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.quartz.SchedulerFactoryBean;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-
-/**
- * Quartz定时任务服务实现类
- * @author bool
- */
-@Log4j2
-@Service
-public class JobServiceImpl implements JobService {
-
-
- //Quartz调度器,用于管理定时任务
-
- private Scheduler scheduler;
-
-
- //构造函数,注入SchedulerFactoryBean并初始化scheduler
- //@param schedulerFactoryBean Spring的SchedulerFactoryBean实例
-
- public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) {
- scheduler = schedulerFactoryBean.getScheduler();
- }
-
-
- //添加一个新的定时任务
- //@param jobClass 定时任务的类
- //@param jobName 定时任务的名称
- //@param cron 定时任务的cron表达式
- //@param data 传递给任务的数据
-
- @Override
- public void addCronJob(Class jobClass, String jobName, String cron, String data) {
- String jobGroup = JobGroup.SYSTEM;
- // 如果jobName为空,则自动生成一个唯一名称
- if(StringUtils.isEmpty(jobName)){
- jobName = jobClass.getSimpleName().toUpperCase() + "_"+IdWorker.getIdStr();
- }
- try {
- JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
- JobDetail jobDetail = scheduler.getJobDetail(jobKey);
- // 如果任务已经存在,则删除旧任务
- if (jobDetail != null) {
- log.info("++++++++++任务:{} 已存在", jobName);
- this.deleteJob(jobName, jobGroup);
- }
- log.info("++++++++++构建任务:{},{},{},{},{} ", jobClass.toString(), jobName, jobGroup, cron, data);
- // 构建新的JobDetail实例
- jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();
- // 使用JobDataMap传递数据给任务
- jobDetail.getJobDataMap().put(TASK_DATA, data);
- // 构建Trigger实例
- Trigger trigger = null;
- // 如果cron表达式不为空,则使用cron表达式构建Trigger
- if(!StringUtils.isEmpty(cron)){
- log.info("+++++表达式执行:"+ JSON.toJSONString(jobDetail));
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
- trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build();
- } else {
- // 如果cron表达式为空,则立即执行任务
- log.info("+++++立即执行:"+ JSON.toJSONString(jobDetail));
- trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).startNow().build();
- }
- // 将JobDetail和Trigger添加到调度器中
- scheduler.scheduleJob(jobDetail, trigger);
- } catch (Exception e) {
- // 打印异常堆栈信息
- e.printStackTrace();
- }
- }
-
-
- //添加一个新的立即执行的定时任务
- //@param jobClass 定时任务的类
- //@param jobName 定时任务的名称
- //@param data 传递给任务的数据
-
- @Override
- public void addCronJob(Class jobClass, String jobName, String data) {
- // 调用addCronJob方法,设置cron为null以立即执行任务
- this.addCronJob(jobClass, jobName, null, data);
- }
-
-
- //暂停指定的定时任务
- //@param jobName 定时任务的名称
- //@param jobGroup 定时任务的组名
-
- @Override
- public void pauseJob(String jobName, String jobGroup) {
- try {
- // 创建TriggerKey以标识要暂停的任务
- TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
- // 使用调度器暂停任务触发器
- scheduler.pauseTrigger(triggerKey);
- // 记录日志,表示任务已成功暂停
- log.info("++++++++++暂停任务:{}", jobName);
- } catch (SchedulerException e) {
- // 打印调度异常堆栈信息
- e.printStackTrace();
- }
- }
-
-
- //恢复指定的暂停定时任务
- //@param jobName 定时任务的名称
- //@param jobGroup 定时任务的组名
-
- @Override
- public void resumeJob(String jobName, String jobGroup) {
- try {
- // 创建TriggerKey以标识要恢复的任务
- TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
- // 使用调度器恢复任务触发器
- scheduler.resumeTrigger(triggerKey);
- // 记录日志,表示任务已成功恢复
- log.info("++++++++++重启任务:{}", jobName);
- } catch (SchedulerException e) {
- // 打印调度异常堆栈信息
- e.printStackTrace();
- }
- }
-
-
- //删除指定的定时任务
- //@param jobName 定时任务的名称
- //@param jobGroup 定时任务的组名
-
- @Override
- public void deleteJob(String jobName, String jobGroup) {
- try {
- // 创建JobKey以标识要删除的任务
- JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
- // 使用调度器删除任务
- scheduler.deleteJob(jobKey);
- // 记录日志,表示任务已成功删除
- log.info("++++++++++删除任务:{}", jobKey);
- } catch (SchedulerException e) {
- // 打印调度异常堆栈信息
- e.printStackTrace();
- }
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java b/src/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java
deleted file mode 100644
index 0c9b7a3..0000000
--- a/src/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.yf.exam.ability.shiro;
-
-import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
-import org.apache.shiro.web.filter.InvalidRequestFilter;
-import org.apache.shiro.web.filter.mgt.DefaultFilter;
-import org.apache.shiro.web.filter.mgt.FilterChainManager;
-import javax.servlet.Filter;
-import java.util.Map;
-
-
- //自定义过滤器工厂类,用于处理包含中文字符的URL问题
- //当URL中包含中文字符时,Shiro默认会返回400错误,这是因为InvalidRequestFilter会阻止非ASCII字符的请求。
- //该自定义过滤器重写了createFilterChainManager方法,修改了InvalidRequestFilter的配置,允许非ASCII字符的请求。
- //例如:https://youdomain.com/upload/file/云帆考试系统用户手册.pdf
- //@author van
-
-public class CNFilterFactoryBean extends ShiroFilterFactoryBean {
-
- //重写createFilterChainManager方法,以允许包含中文字符的URL请求
- //@return 自定义的FilterChainManager
-
- @Override
- protected FilterChainManager createFilterChainManager() {
- // 调用父类方法创建FilterChainManager
- FilterChainManager manager = super.createFilterChainManager();
- // 获取所有过滤器
- Map filterMap = manager.getFilters();
- // 获取InvalidRequestFilter
- Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name());
- // 检查invalidRequestFilter是否为InvalidRequestFilter实例
- if (invalidRequestFilter instanceof InvalidRequestFilter) {
- // 设置InvalidRequestFilter允许非ASCII字符的请求
- ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false);
- }
- // 返回自定义的FilterChainManager
- return manager;
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/shiro/ShiroRealm.java b/src/main/java/com/yf/exam/ability/shiro/ShiroRealm.java
deleted file mode 100644
index df91d62..0000000
--- a/src/main/java/com/yf/exam/ability/shiro/ShiroRealm.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package com.yf.exam.ability.shiro;
-
-
-import com.yf.exam.ability.shiro.jwt.JwtToken;
-import com.yf.exam.ability.shiro.jwt.JwtUtils;
-import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO;
-import com.yf.exam.modules.sys.user.service.SysUserRoleService;
-import com.yf.exam.modules.sys.user.service.SysUserService;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.shiro.authc.AuthenticationException;
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.authz.SimpleAuthorizationInfo;
-import org.apache.shiro.realm.AuthorizingRealm;
-import org.apache.shiro.subject.PrincipalCollection;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Component;
-import java.util.HashSet;
-import java.util.List;
-
-
- //用户登录鉴权和获取用户授权
- //@author bool
-
-@Component
-@Slf4j
-public class ShiroRealm extends AuthorizingRealm {
- @Autowired
- @Lazy
- private SysUserService sysUserService; // 注入用户服务,用于处理用户信息相关操作
-
- @Autowired
- @Lazy
- private SysUserRoleService sysUserRoleService; // 注入用户角色服务,用于处理用户角色相关操作
-
-
- //判断该Realm是否支持指定的AuthenticationToken。
- //仅支持JwtToken类型的token。
-
- //@param token 需要验证的AuthenticationToken对象。
- //@return 如果支持该token类型则返回true,否则返回false。
-
- @Override
- public boolean supports(AuthenticationToken token) {
- return token instanceof JwtToken;
- }
-
-
- //获取指定用户主体的授权信息。
- //该方法从用户主体中获取用户ID,然后查询与该用户关联的角色信息,并返回授权信息。
-
- //@param principals 用户主体集合,包含了用户的权限信息。
- //@return 包含用户角色信息的AuthorizationInfo对象。
-
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- String userId = null;
- if (principals != null) {
- SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal();
- userId = user.getId();
- }
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- // 查找用户角色
- List roles = sysUserRoleService.listRoles(userId);
- info.setRoles(new HashSet<>(roles));
- log.info("++++++++++校验详细权限完成");
- return info;
- }
-
-
- //校验用户的账号密码是否正确。
- //该方法通过获取token并调用checkToken方法验证token的有效性,然后返回认证信息。
-
- //@param auth 包含用户认证信息的AuthenticationToken对象。
- //@return 包含认证信息的AuthenticationInfo对象。
- //@throws AuthenticationException 如果认证失败则抛出此异常。
-
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
- String token = (String) auth.getCredentials();
- if (token == null) {
- throw new AuthenticationException("token为空!");
- }
- // 校验token有效性
- SysUserLoginDTO user = this.checkToken(token);
- return new SimpleAuthenticationInfo(user, token, getName());
- }
-
-
- //校验Token的有效性。
- //该方法从token中提取用户名,并验证token是否有效。如果无效则抛出异常。
-
- //@param token 需要验证的token字符串。
- //@return 包含用户信息的SysUserLoginDTO对象。
- //@throws AuthenticationException 如果token无效或已过期则抛出此异常。
-
- public SysUserLoginDTO checkToken(String token) throws AuthenticationException {
- // 查询用户信息
- log.debug("++++++++++校验用户token: " + token);
- // 从token中获取用户名
- String username = JwtUtils.getUsername(token);
- log.debug("++++++++++用户名: " + username);
- if (username == null) {
- throw new AuthenticationException("无效的token");
- }
- // 查找登录用户对象
- SysUserLoginDTO user = sysUserService.token(token);
- // 校验token是否失效
- if (!JwtUtils.verify(token, username)) {
- throw new AuthenticationException("登陆失效,请重试登陆!");
- }
- return user;
- }
-
-
- //清除指定用户主体的权限认证缓存。
- //该方法调用父类的clearCache方法来实现缓存清除功能。
-
- //@param principals 用户主体集合,包含了用户的权限信息。
-
- @Override
- public void clearCache(PrincipalCollection principals) {
- super.clearCache(principals);
- }
-}
-
diff --git a/src/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java b/src/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java
deleted file mode 100644
index ba02f75..0000000
--- a/src/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.yf.exam.ability.shiro.aop;
-
-import com.yf.exam.ability.shiro.jwt.JwtToken;
-import com.yf.exam.aspect.utils.InjectUtils;
-import com.yf.exam.modules.Constant;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-
- //鉴权登录拦截器,用于处理JWT(JSON Web Token)认证
- //@author bool
-
-@Slf4j
-public class JwtFilter extends BasicHttpAuthenticationFilter {
-
-
- //检查用户是否被允许访问资源
- //@param request 包含用户请求信息的ServletRequest对象
- //@param response 包含用户响应信息的ServletResponse对象
- // @param mappedValue 在Shiro配置中映射的值,通常用于权限检查
- //@return 如果用户成功登录并被允许访问资源,则返回true;否则返回false
-
- @Override
- protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
- try {
- // 调用executeLogin方法执行登录认证
- executeLogin(request, response);
- // 如果登录成功,返回true表示用户被允许访问
- return true;
- } catch (Exception e) {
- // 如果发生异常,调用InjectUtils.restError方法写出统一错误信息
- InjectUtils.restError((HttpServletResponse) response);
- // 返回false表示用户未被允许访问
- return false;
- }
- }
-
-
- //执行JWT登录认证
- //@param request 包含用户请求信息的ServletRequest对象
- //@param response 包含用户响应信息的ServletResponse对象
- // @return 如果登录成功,则返回true;否则抛出异常
- //@throws Exception 如果登录过程中发生异常
-
- @Override
- protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
- HttpServletRequest httpServletRequest = (HttpServletRequest) request;
- // 从请求头中获取JWT token
- String token = httpServletRequest.getHeader(Constant.TOKEN);
- // 创建JwtToken对象
- JwtToken jwtToken = new JwtToken(token);
- try {
- // 提交给realm进行登录认证,如果认证失败会抛出异常
- getSubject(request, response).login(jwtToken);
- // 如果没有抛出异常则代表登录成功,返回true
- return true;
- } catch (Exception e) {
- // 如果发生异常,记录日志
- log.error("JWT登录认证失败: ", e);
- // 抛出异常以便在调用处捕获并处理
- throw e;
- }
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java b/src/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java
deleted file mode 100644
index 969b715..0000000
--- a/src/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.yf.exam.ability.shiro.jwt;
-
-import lombok.Data;
-import org.apache.shiro.authc.AuthenticationToken;
-
-/**
- * JWT(JSON Web Token)认证令牌,用于Shiro认证过程
- * @author bool
- */
-@Data
-public class JwtToken implements AuthenticationToken {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * JWT的字符token,用于认证用户身份
- */
- private String token;
-
- /**
- * 构造函数,初始化JWT token
- * @param token JWT的字符token
- */
- public JwtToken(String token) {
- this.token = token;
- }
-
- /**
- * 获取认证主体,这里返回JWT token
- * @return JWT token
- */
- @Override
- public Object getPrincipal() {
- return token;
- }
-
- /**
- * 获取认证凭证,这里返回JWT token
- * @return JWT token
- */
- @Override
- public Object getCredentials() {
- return token;
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java b/src/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java
deleted file mode 100644
index 1ca221f..0000000
--- a/src/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.yf.exam.ability.shiro.jwt;
-
-import com.auth0.jwt.JWT;
-import com.auth0.jwt.JWTVerifier;
-import com.auth0.jwt.algorithms.Algorithm;
-import com.auth0.jwt.exceptions.JWTDecodeException;
-import com.auth0.jwt.interfaces.DecodedJWT;
-import com.yf.exam.core.utils.file.Md5Util;
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * JWT工具类,用于处理JWT(JSON Web Token)的生成、验证和解析
- * @author bool
- */
-public class JwtUtils {
- /**
- * 有效期24小时(以毫秒为单位)
- */
- private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000;
-
- /**
- * 校验JWT token是否正确
- * @param token JWT token字符串
- * @param username 用户名
- * @return 如果token有效且用户名匹配,则返回true;否则返回false
- */
- public static boolean verify(String token, String username) {
- try {
- // 根据用户名生成HMAC256算法的密钥
- Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username));
- // 创建JWT验证器,并指定需要验证的用户名声明
- JWTVerifier verifier = JWT.require(algorithm)
- .withClaim("username", username)
- .build();
- // 验证token
- verifier.verify(token);
- return true;
- } catch (Exception exception) {
- return false;
- }
- }
-
- /**
- * 从JWT token中解密并获取用户名
- * @param token JWT token字符串
- * @return 如果解析成功,则返回用户名;否则返回null
- */
- public static String getUsername(String token) {
- try {
- // 解码JWT token
- DecodedJWT jwt = JWT.decode(token);
- // 获取用户名声明
- return jwt.getClaim("username").asString();
- } catch (JWTDecodeException e) {
- return null;
- }
- }
-
- /**
- * 生成JWT token字符串
- * @param username 用户名
- * @return 生成的JWT token字符串
- */
- public static String sign(String username) {
- // 计算token的过期时间
- Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
- // 根据用户名生成HMAC256算法的密钥
- Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username));
- // 创建JWT并附带用户名信息及过期时间
- return JWT.create()
- .withClaim("username", username)
- .withExpiresAt(date)
- .sign(algorithm);
- }
-
- /**
- * 根据用户名生成一个新的密钥,用于增强JWT的安全性
- * @param userName 用户名
- * @return 生成的密钥
- */
- private static String encryptSecret(String userName) {
- // 获取当前时间
- Calendar cl = Calendar.getInstance();
- cl.setTimeInMillis(System.currentTimeMillis());
- // 创建一个简单的加密串,包含用户名和当前月份
- StringBuffer sb = new StringBuffer(userName)
- .append("&")
- .append(cl.get(Calendar.MONTH));
- // 对加密串进行MD5哈希
- String secret = Md5Util.md5(sb.toString());
- // 再次对用户名和上一步的MD5哈希结果进行MD5哈希,生成最终的密钥
- return Md5Util.md5(userName + "&" + secret);
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/config/UploadConfig.java b/src/main/java/com/yf/exam/ability/upload/config/UploadConfig.java
deleted file mode 100644
index 00c8207..0000000
--- a/src/main/java/com/yf/exam/ability/upload/config/UploadConfig.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.yf.exam.ability.upload.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-
- //文件上传配置类,用于定义文件上传的相关配置属性。
- //这些属性可以通过application.properties或application.yml文件进行配置。
-
- //@author van
-
-@Data
-@Configuration
-@ConfigurationProperties(prefix = "conf.upload")
-public class UploadConfig {
-
- //文件上传的访问路径,用户可以通过该路径访问上传的文件。
- //例如:http://example.com/upload/
-
- private String url;
-
-
- //文件上传的物理目录路径,指定文件在服务器上的存储位置。
- //例如:/var/www/upload/
-
- private String dir;
-
-
- //允许上传的文件后缀名数组,定义了哪些类型的文件可以被上传。
- //例如:{"jpg", "png", "pdf"}
-
- private String[] allowExtensions;
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/controller/UploadController.java b/src/main/java/com/yf/exam/ability/upload/controller/UploadController.java
deleted file mode 100644
index a54e6fa..0000000
--- a/src/main/java/com/yf/exam/ability/upload/controller/UploadController.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.yf.exam.ability.upload.controller;
-
-import com.yf.exam.ability.Constant;
-import com.yf.exam.ability.upload.dto.UploadReqDTO;
-import com.yf.exam.ability.upload.dto.UploadRespDTO;
-import com.yf.exam.ability.upload.service.UploadService;
-import com.yf.exam.core.api.ApiRest;
-import com.yf.exam.core.api.controller.BaseController;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RestController;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-
- //本地文件上传下载请求类
- //该类提供文件上传和下载的功能,继承自BaseController。
- //@author bool
-
-@Log4j2
-@Api(tags = {"文件上传"})
-@RestController
-public class UploadController extends BaseController {
-
- @Autowired
- private UploadService uploadService;
-
-
- //文件上传
- //该方法处理文件上传请求,参数通过表单方式提交。
- //@param reqDTO 包含上传文件信息的请求DTO
- //@return 包含上传文件结果的响应DTO
-
- @PostMapping("/common/api/file/upload")
- @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON")
- public ApiRest upload(@ModelAttribute UploadReqDTO reqDTO) {
- // 上传并返回URL
- UploadRespDTO respDTO = uploadService.upload(reqDTO);
- return super.success(respDTO);
- }
-
-
- //独立文件下载
- //该方法处理文件下载请求。
- //@param request HTTP请求对象
- //@param response HTTP响应对象
-
- @GetMapping(Constant.FILE_PREFIX + "**")
- @ApiOperation(value = "文件下载", notes = "文件下载")
- public void download(HttpServletRequest request, HttpServletResponse response) {
- uploadService.download(request, response);
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java b/src/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java
deleted file mode 100644
index 1879fcb..0000000
--- a/src/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.yf.exam.ability.upload.dto;
-
-import com.yf.exam.core.api.dto.BaseDTO;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import org.springframework.web.multipart.MultipartFile;
-
-
- //文件上传请求类。
- //该类用于封装文件上传请求的参数,继承自BaseDTO。
-
- // @author bool
- // @date 2019-12-26 17:54
-
-@Data
-@ApiModel(value = "文件上传参数", description = "包含上传文件信息的请求参数")
-public class UploadReqDTO extends BaseDTO {
-
- //上传文件的内容。
- //该字段是必填项,包含了用户需要上传的文件。
- //@ApiModelProperty(value = "上传文件内容", required = true)
-
- private MultipartFile file;
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java b/src/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java
deleted file mode 100644
index 6aa5903..0000000
--- a/src/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.yf.exam.ability.upload.dto;
-
-import com.yf.exam.core.api.dto.BaseDTO;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-
- //文件上传响应类。
- //该类用于封装文件上传后的响应信息,继承自BaseDTO。
-
- // @author bool
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-@ApiModel(value = "文件上传响应", description = "包含上传文件后的URL地址的响应信息")
-public class UploadRespDTO extends BaseDTO {
-
- //上传后的完整的URL地址。
- //该字段是必填项,包含了上传文件后可以访问的URL。
- //@ApiModelProperty(value = "上传后的完整的URL地址", required = true)
-
- private String url;
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/service/UploadService.java b/src/main/java/com/yf/exam/ability/upload/service/UploadService.java
deleted file mode 100644
index 3a89174..0000000
--- a/src/main/java/com/yf/exam/ability/upload/service/UploadService.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.yf.exam.ability.upload.service;
-
-import com.yf.exam.ability.upload.dto.UploadReqDTO;
-import com.yf.exam.ability.upload.dto.UploadRespDTO;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-
- //阿里云OSS业务类
- //该接口定义了文件上传和下载的功能,具体实现由其实现类提供。
- //@author bool
- //@date 2019-07-12 16:45
-
-public interface UploadService {
-
-
- //处理文件上传请求
- //@param reqDTO 文件上传请求对象,包含上传的文件信息
- //@return 文件上传响应对象,包含上传文件后的URL地址
-
- UploadRespDTO upload(UploadReqDTO reqDTO);
-
-
- //处理文件下载请求
- //@param request HTTP请求对象,包含下载文件的URI信息
- //@param response HTTP响应对象,用于返回下载的文件内容
- //@throws RuntimeException 如果下载过程中发生错误
-
- void download(HttpServletRequest request, HttpServletResponse response);
-
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java b/src/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java
deleted file mode 100644
index 6a750ef..0000000
--- a/src/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package com.yf.exam.ability.upload.service.impl;
-
-import com.yf.exam.ability.Constant;
-import com.yf.exam.ability.upload.config.UploadConfig;
-import com.yf.exam.ability.upload.dto.UploadReqDTO;
-import com.yf.exam.ability.upload.dto.UploadRespDTO;
-import com.yf.exam.ability.upload.service.UploadService;
-import com.yf.exam.ability.upload.utils.FileUtils;
-import com.yf.exam.core.exception.ServiceException;
-import lombok.extern.log4j.Log4j2;
-import org.apache.commons.io.FilenameUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.util.FileCopyUtils;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-
- //文件上传业务类。
- //该类实现了文件上传和下载的功能,继承自UploadService接口。
-
- //@author bool
- //@date 2019-07-30 21:02
-
-@Log4j2
-@Service
-public class UploadServiceImpl implements UploadService {
-
- @Autowired
- private UploadConfig conf;
-
-
- //处理文件上传请求。
-
- // @param reqDTO 文件上传请求对象,包含上传的文件信息。
- //@return 文件上传响应对象,包含上传文件后的URL地址。
- //@throws ServiceException 如果文件类型不允许上传或上传过程中发生IO异常。
-
- @Override
- public UploadRespDTO upload(UploadReqDTO reqDTO) {
- // 获取上传文件的内容
- MultipartFile file = reqDTO.getFile();
- // 验证文件后缀是否在允许的范围内
- boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions());
- if (!allow) {
- throw new ServiceException("文件类型不允许上传!");
- }
- // 获取上传文件夹的路径
- String fileDir = conf.getDir();
- // 构造真实物理地址
- String fullPath;
- try {
- // 处理文件路径
- String filePath = FileUtils.processPath(file);
- // 构造文件保存地址
- fullPath = fileDir + filePath;
- // 创建文件夹(如果不存在)
- FileUtils.checkDir(fullPath);
- // 上传文件到指定路径
- FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath));
- // 生成并返回上传结果
- return this.generateResult(filePath);
- } catch (IOException e) {
- e.printStackTrace();
- throw new ServiceException("文件上传失败:" + e.getMessage());
- }
- }
-
-
- //处理文件下载请求。
-
- //@param request HTTP请求对象,包含请求的URI。
- //@param response HTTP响应对象,用于返回文件内容。
- //@throws RuntimeException 如果URL解码过程中发生UnsupportedEncodingException。
-
- @Override
- public void download(HttpServletRequest request, HttpServletResponse response) {
- // 获取真实的文件路径
- String filePath = this.getRealPath(request.getRequestURI());
- // 处理中文文件名解码问题
- try {
- filePath = URLDecoder.decode(filePath, "utf-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- // 输出完整路径到控制台(调试使用)
- System.out.println("++++完整路径为:" + filePath);
- try {
- // 将文件内容写入HTTP响应
- FileUtils.writeRange(request, response, filePath);
- } catch (IOException e) {
- // 如果文件不存在,设置HTTP响应状态为404
- response.setStatus(404);
- // 记录错误日志
- log.error("预览文件失败:" + e.getMessage());
- }
- }
-
-
- //构造文件上传响应结果。
-
- //@param fileName 上传文件的路径。
- //@return 文件上传响应对象,包含上传文件后的完整URL地址。
-
- private UploadRespDTO generateResult(String fileName) {
- // 获取加速域名
- String domain = conf.getUrl();
- // 构造并返回文件上传响应对象
- return new UploadRespDTO(domain + fileName);
- }
-
-
- //获取真实物理文件地址。
- //@param uri 请求的URI,包含文件的相对路径。
- //@return 真实物理文件的完整路径。
-
- public String getRealPath(String uri) {
- // 定义正则表达式,匹配文件路径
- String regx = Constant.FILE_PREFIX + "(.*)";
- // 查找匹配的文件路径
- Pattern pattern = Pattern.compile(regx);
- Matcher m = pattern.matcher(uri);
- if (m.find()) {
- // 获取匹配的文件路径部分
- String str = m.group(1);
- // 构造真实物理文件的完整路径
- return conf.getDir() + str;
- }
- // 如果未找到匹配路径,返回null
- return null;
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/utils/FileUtils.java b/src/main/java/com/yf/exam/ability/upload/utils/FileUtils.java
deleted file mode 100644
index dd92e55..0000000
--- a/src/main/java/com/yf/exam/ability/upload/utils/FileUtils.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package com.yf.exam.ability.upload.utils;
-
-import com.baomidou.mybatisplus.core.toolkit.IdWorker;
-import com.yf.exam.core.utils.DateUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.springframework.web.multipart.MultipartFile;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.Date;
-
-
- //文件工具类
- //该类提供了文件上传、下载和处理的相关工具方法。
- //@author bool
-
-public class FileUtils {
-
-
- //后缀分割符号
-
- private static final String SUFFIX_SPLIT = ".";
-
-
- //持以断点的方式输出文件,提供文件在线预览和视频在线播放
- //@param request HTTP请求对象,包含请求头信息如Range
- //@param response HTTP响应对象,用于返回文件内容
- //@param filePath 文件的物理路径
- //@throws IOException 如果文件读取或写入过程中发生IO异常
-
- public static void writeRange(HttpServletRequest request,
- HttpServletResponse response, String filePath) throws IOException {
- // 读取文件
- File file = new File(filePath);
- // 只读模式
- RandomAccessFile randomFile = new RandomAccessFile(file, "r");
- long contentLength = randomFile.length();
- String range = request.getHeader("Range");
- int start = 0, end = 0;
-
- if (range != null && range.startsWith("bytes=")) {
- String[] values = range.split("=")[1].split("-");
- start = Integer.parseInt(values[0]);
- if (values.length > 1) {
- end = Integer.parseInt(values[1]);
- }
- }
-
- int requestSize;
- if (end != 0 && end > start) {
- requestSize = end - start + 1;
- } else {
- requestSize = Integer.MAX_VALUE;
- }
-
- byte[] buffer = new byte[128];
- response.setContentType(MediaUtils.getContentType(filePath));
- response.setHeader("Accept-Ranges", "bytes");
- response.setHeader("ETag", file.getName());
- response.setHeader("Last-Modified", new Date().toString());
-
- // 第一次请求只返回content length来让客户端请求多次实际数据
- if (range == null) {
- response.setHeader("Content-length", contentLength + "");
- } else {
- // 以后的多次以断点续传的方式来返回视频数据
- response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
- long requestStart = 0, requestEnd = 0;
- String[] ranges = range.split("=");
- if (ranges.length > 1) {
- String[] rangeData = ranges[1].split("-");
- requestStart = Integer.parseInt(rangeData[0]);
- if (rangeData.length > 1) {
- requestEnd = Integer.parseInt(rangeData[1]);
- }
- }
-
- long length;
- if (requestEnd > 0) {
- length = requestEnd - requestStart + 1;
- response.setHeader("Content-length", "" + length);
- response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
- } else {
- length = contentLength - requestStart;
- response.setHeader("Content-length", "" + length);
- response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength);
- }
- }
-
- ServletOutputStream out = response.getOutputStream();
- int needSize = requestSize;
- randomFile.seek(start);
-
- while (needSize > 0) {
- int len = randomFile.read(buffer);
- if (needSize < buffer.length) {
- out.write(buffer, 0, needSize);
- } else {
- out.write(buffer, 0, len);
- if (len < buffer.length) {
- break;
- }
- }
- needSize -= len;
- }
-
- randomFile.close();
- out.close();
- }
-
-
- //重命名文件
- //@param fileName 原始文件名
- //@return 重命名后的文件名
-
- public static String renameFile(String fileName) {
- // 没有后缀名不处理
- if (!fileName.contains(SUFFIX_SPLIT)) {
- return fileName;
- }
- // 文件后缀
- String extension = FilenameUtils.getExtension(fileName);
- // 以系统时间命名
- return IdWorker.getIdStr() + "." + extension;
- }
-
- //处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg
- //注意:前面没有斜杠
- //@param file 文件对象
- //@return 处理后的文件路径
-
- public static String processPath(MultipartFile file) {
- // 获取原始文件名
- String fileName = file.getOriginalFilename();
- // 需要重命名
- fileName = renameFile(fileName);
- // 获得上传的文件夹
- String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/");
- return new StringBuffer(dir).append(fileName).toString();
- }
-
-
- //检查文件夹是否存在,不存在则创建
- //@param fileName 文件路径,包含文件夹信息
-
- public static void checkDir(String fileName) {
- int index = fileName.lastIndexOf("/");
- if (index == -1) {
- return;
- }
- File file = new File(fileName.substring(0, index));
- if (!file.exists()) {
- file.mkdirs();
- }
- }
-}
diff --git a/src/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java b/src/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java
deleted file mode 100644
index e1ff58f..0000000
--- a/src/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.yf.exam.ability.upload.utils;
-
-import org.apache.commons.lang3.StringUtils;
-import java.util.HashMap;
-import java.util.Map;
-
-
- //媒体工具类,用于判断文件的媒体类型
- //该类包含一个媒体类型映射表,并提供获取文件内容类型的方法。
- //@author bool
- //@date 2019-11-14 16:21
-
-public class MediaUtils {
-
-
- //媒体类型映射表
- //该映射表存储了文件后缀与对应的MIME类型。
-
- public static final Map MEDIA_MAP = new HashMap() {
- {
- // PDF文件
- put(".pdf", "application/pdf");
- // MP4视频文件
- put(".mp4", "video/mp4");
- }
- };
-
-
- //获取文件的MIME类型
- //@param filePath 文件路径
- //@return 文件的MIME类型,如果文件路径无效或无法识别,则返回 "application/octet-stream"
-
- public static String getContentType(String filePath) {
- if (!StringUtils.isBlank(filePath) && filePath.indexOf(".") != -1) {
- // 后缀转换成小写
- String suffix = filePath.substring(filePath.lastIndexOf(".")).toLowerCase();
- if (MEDIA_MAP.containsKey(suffix)) {
- return MEDIA_MAP.get(suffix);
- }
- }
- return "application/octet-stream";
- }
-}
diff --git a/src/main/java/com/yf/exam/aspect/DictAspect.java b/src/main/java/com/yf/exam/aspect/DictAspect.java
deleted file mode 100644
index cc191e7..0000000
--- a/src/main/java/com/yf/exam/aspect/DictAspect.java
+++ /dev/null
@@ -1,315 +0,0 @@
-package com.yf.exam.aspect;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.yf.exam.core.annon.Dict;
-import com.yf.exam.core.api.ApiRest;
-import com.yf.exam.core.utils.Reflections;
-import com.yf.exam.modules.sys.system.service.SysDictService;
-import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-
- //数据字典AOP类,处理数据字典值
-
- //@author bool
-
-@Aspect
-@Component
-@Slf4j
-public class DictAspect {
-
- @Autowired
- private SysDictService sysDictService;
-
-
-// 切入Controller执行
-// @param pjp
-// @return
-// @throws Throwable
-//
- @Around("execution(public * com.yf.exam..*.*Controller.*(..))")
- public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
- return this.translate(pjp);
- }
-
-// *
-// * 进行翻译并返回,调用前必须实现:BaseDictService
-// *
-// * @param pjp
-// * @return
-// * @throws Throwable
- public Object translate(ProceedingJoinPoint pjp) throws Throwable {
- // 处理字典
- return this.parseAllDictText(pjp.proceed());
- }
-
-// *
-// * 转换全部数据字典
-// *
-// * @param result
-//
- private Object parseAllDictText(Object result) {
-
- // 非ApiRest类型不处理
- if (result instanceof ApiRest) {
- parseFullDictText(result);
- }
-
- return result;
- }
-
-
-// *
-// * 转换所有类型的数据字典、包含子列表
-// *
-// * @param result
- private void parseFullDictText(Object result) {
-
- try {
-
- Object rest = ((ApiRest) result).getData();
-
- // 不处理普通数据类型
- if (rest == null || this.isBaseType(rest.getClass())) {
- return;
- }
-
- // 分页的
- if (rest instanceof IPage) {
- List