From a351191b4ce599dfb240b9a32b13d5a07538eaa7 Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Fri, 25 Apr 2025 23:49:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=87=E4=BB=B6=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/config/WebSecurityConfig.java | 2 +- .../controller/system/DeptController.java | 6 +- .../controller/system/FilesController.java | 9 -- .../controller/system/PowerController.java | 2 +- .../controller/system/RoleController.java | 29 +++- .../system/RolePowerController.java | 2 +- .../controller/system/UserController.java | 7 +- .../cn/bunny/domain/i18n/excel/RoleExcel.java | 46 +++++++ .../services/mapper/system/RoleMapper.java | 2 +- .../services/excel/RoleExcelListener.java | 62 +++++++++ .../configuration/impl/I18nServiceImpl.java | 7 +- .../services/service/system/DeptService.java | 2 +- .../services/service/system/RoleService.java | 20 ++- .../services/service/system/UserService.java | 7 - .../service/system/impl/DeptServiceImpl.java | 2 +- .../service/system/impl/FilesServiceImpl.java | 2 +- .../service/system/impl/RoleServiceImpl.java | 75 ++++++++++- .../system/impl/RouterServiceImpl.java | 4 +- .../service/system/impl/UserServiceImpl.java | 21 +-- .../bunny/services/utils/system/FileUtil.java | 36 ----- .../bunny/services/utils/system/RoleUtil.java | 8 +- .../services/utils/system/RouterUtil.java | 127 +++++++++--------- common/common-config/pom.xml | 4 + .../config/ThreadLocalCleanupInterceptor.java | 17 +++ .../cn/bunny/services/config/WebConfig.java | 14 +- .../cn/bunny/services/utils/FileUtil.java | 68 ++++++++++ .../bunny/domain/constant/UserConstant.java | 3 - 27 files changed, 419 insertions(+), 165 deletions(-) create mode 100644 auth-system/domain/src/main/java/cn/bunny/domain/i18n/excel/RoleExcel.java create mode 100644 auth-system/services/src/main/java/cn/bunny/services/excel/RoleExcelListener.java delete mode 100644 auth-system/services/src/main/java/cn/bunny/services/utils/system/FileUtil.java create mode 100644 common/common-config/src/main/java/cn/bunny/services/config/ThreadLocalCleanupInterceptor.java create mode 100644 common/common-config/src/main/java/cn/bunny/services/utils/FileUtil.java diff --git a/auth-admin/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java b/auth-admin/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java index e7e7a91..10f8fe3 100644 --- a/auth-admin/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java +++ b/auth-admin/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java @@ -24,7 +24,7 @@ public class WebSecurityConfig { "/media.ico", "/favicon.ico", "/webjars/**", "/v3/api-docs/**", "/swagger-ui/**", "/*/*/login", "/*/*/noAuth/**", "/*/noAuth/**", "/noAuth/**", - "/*/i18n/getI18n", + "/*/i18n/getI18n" }; @Resource diff --git a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/DeptController.java b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/DeptController.java index 1804753..07b4818 100644 --- a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/DeptController.java +++ b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/DeptController.java @@ -49,9 +49,9 @@ public class DeptController { } @Operation(summary = "获取所有部门", description = "获取所有部门") - @GetMapping("noManage/getAllDeptList") - public Result> getAllDeptList() { - List voList = deptService.getAllDeptList(); + @GetMapping("noManage/allDeptList") + public Result> allDeptList() { + List voList = deptService.allDeptList(); return Result.success(voList); } diff --git a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/FilesController.java b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/FilesController.java index f4c08ee..20e3094 100644 --- a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/FilesController.java +++ b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/FilesController.java @@ -82,15 +82,6 @@ public class FilesController { return filesService.downloadFilesByFilepath(filepath); } - // // 无法做权限校验 - // @Operation(summary = "根据文件名访问resource下图片文件", description = "根据文件名访问resource下文件") - // @GetMapping("noAuth/getResourceImagesByFilename/{filename}") - // public ResponseEntity getResourceImagesByFilename(@PathVariable String filename) { - // Resource file = new ClassPathResource("static/images/" + filename); - // if (!file.exists()) throw new BunnyException(ResultCodeEnum.FILE_NOT_EXIST); - // return ResponseEntity.ok().body(file); - // } - @Operation(summary = "更新系统文件", description = "更新系统文件") @PutMapping("updateFiles") public Result updateFiles(@Valid FilesUpdateDto dto) { diff --git a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/PowerController.java b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/PowerController.java index 0b23e8b..57b33d0 100644 --- a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/PowerController.java +++ b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/PowerController.java @@ -28,7 +28,7 @@ import java.util.List; * @author Bunny * @since 2024-10-03 16:00:52 */ -@Tag(name = "权限", description = "权限相关接口") +@Tag(name = "系统权限", description = "权限相关接口") @RestController @RequestMapping("api/power") public class PowerController { diff --git a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RoleController.java b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RoleController.java index c8866c9..3f63b7c 100644 --- a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RoleController.java +++ b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RoleController.java @@ -1,13 +1,14 @@ package cn.bunny.services.controller.system; -import cn.bunny.domain.system.entity.Role; import cn.bunny.domain.system.dto.role.RoleAddDto; import cn.bunny.domain.system.dto.role.RoleDto; import cn.bunny.domain.system.dto.role.RoleUpdateDto; +import cn.bunny.domain.system.entity.Role; import cn.bunny.domain.system.vo.RoleVo; import cn.bunny.domain.vo.result.PageResult; import cn.bunny.domain.vo.result.Result; import cn.bunny.domain.vo.result.ResultCodeEnum; +import cn.bunny.services.exception.AuthCustomerException; import cn.bunny.services.service.system.RoleService; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; @@ -15,7 +16,9 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -27,7 +30,7 @@ import java.util.List; * @author Bunny * @since 2024-10-03 14:26:24 */ -@Tag(name = "角色", description = "角色相关接口") +@Tag(name = "系统角色", description = "角色相关接口") @RestController @RequestMapping("api/role") public class RoleController { @@ -49,12 +52,28 @@ public class RoleController { } @Operation(summary = "获取所有角色", description = "获取所有角色") - @GetMapping("noManage/getAllRoles") - public Result> getAllRoles() { - List roleVoList = roleService.getAllRoles(); + @GetMapping("noManage/allRoles") + public Result> allRoles() { + List roleVoList = roleService.allRoles(); return Result.success(roleVoList); } + @Operation(summary = "导出角色列表", description = "使用Excel导出导出角色列表") + @GetMapping("exportByExcel") + public ResponseEntity exportByExcel() { + return roleService.exportByExcel(); + } + + @Operation(summary = "更新角色列表", description = "使用Excel更新角色列表") + @PutMapping("update/roleByFile") + public Result updateRoleByFile(MultipartFile file) { + if (file == null) { + throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY); + } + roleService.updateRoleByFile(file); + return Result.success(); + } + @Operation(summary = "添加角色", description = "添加角色") @PostMapping("addRole") public Result addRole(@Valid @RequestBody RoleAddDto dto) { diff --git a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RolePowerController.java b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RolePowerController.java index 98c53b2..a6eeac4 100644 --- a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RolePowerController.java +++ b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/RolePowerController.java @@ -19,7 +19,7 @@ import java.util.List; * @author Bunny * @since 2024-09-26 */ -@Tag(name = "角色和权限", description = "角色和权限相关接口") +@Tag(name = "系统角色和权限", description = "角色和权限相关接口") @RestController @RequestMapping("api/rolePower") public class RolePowerController { diff --git a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/UserController.java b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/UserController.java index 7d3e472..04529a7 100644 --- a/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/UserController.java +++ b/auth-system/controllers/src/main/java/cn/bunny/services/controller/system/UserController.java @@ -10,6 +10,7 @@ import cn.bunny.domain.vo.LoginVo; import cn.bunny.domain.vo.result.PageResult; import cn.bunny.domain.vo.result.Result; import cn.bunny.domain.vo.result.ResultCodeEnum; +import cn.bunny.services.context.BaseContext; import cn.bunny.services.service.system.UserService; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; @@ -44,9 +45,9 @@ public class UserController { } @Operation(summary = "获取本地登录用户信息", description = "获取用户信息从Redis中获取") - @GetMapping("noManage/getUserinfo") - public Result getUserinfo() { - LoginVo vo = userService.getUserinfo(); + @GetMapping("noManage/userinfo") + public Result userinfo() { + LoginVo vo = BaseContext.getLoginVo(); return Result.success(vo); } diff --git a/auth-system/domain/src/main/java/cn/bunny/domain/i18n/excel/RoleExcel.java b/auth-system/domain/src/main/java/cn/bunny/domain/i18n/excel/RoleExcel.java new file mode 100644 index 0000000..66edea3 --- /dev/null +++ b/auth-system/domain/src/main/java/cn/bunny/domain/i18n/excel/RoleExcel.java @@ -0,0 +1,46 @@ +package cn.bunny.domain.i18n.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.*; +import com.alibaba.excel.enums.BooleanEnum; +import com.alibaba.excel.enums.poi.FillPatternTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +// fontHeightInPoints:字体大小,颜色:color 【绿色】 +@HeadFontStyle(fontHeightInPoints = 30, color = 14, bold = BooleanEnum.TRUE) +// fillForegroundColor 将背景填充为【白色】 +@HeadStyle(fillForegroundColor = 9, fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND) +@HeadRowHeight(30) +public class RoleExcel { + + @Schema(name = "id", title = "唯一标识") + @ExcelProperty({"修改时不要修改id列,如需更新不填写此列", "id/唯一标识(添加不填写)"}) + @ColumnWidth(66) + // 字体颜色红色 + @ContentFontStyle(fontHeightInPoints = 14, color = 10, bold = BooleanEnum.TRUE) + private String id; + + @Schema(name = "roleCode", title = "角色代码") + @ExcelProperty({"修改时不要修改id列,如需更新不填写此列", "roleCode/角色代码"}) + // 列宽 + @ColumnWidth(66) + // fontHeightInPoints:字体大小,颜色:color 【绿色】 + @ContentFontStyle(fontHeightInPoints = 14, color = 17, bold = BooleanEnum.TRUE) + private String roleCode; + + @Schema(name = "description", title = "描述") + @ExcelProperty({"修改时不要修改id列,如需更新不填写此列", "description/描述"}) + @ColumnWidth(66) + // fontHeightInPoints:字体大小,颜色:color 【天蓝色】 + @ContentFontStyle(fontHeightInPoints = 14, color = 40, bold = BooleanEnum.TRUE) + private String description; + +} diff --git a/auth-system/mappers/src/main/java/cn/bunny/services/mapper/system/RoleMapper.java b/auth-system/mappers/src/main/java/cn/bunny/services/mapper/system/RoleMapper.java index c574a37..8590580 100644 --- a/auth-system/mappers/src/main/java/cn/bunny/services/mapper/system/RoleMapper.java +++ b/auth-system/mappers/src/main/java/cn/bunny/services/mapper/system/RoleMapper.java @@ -1,7 +1,7 @@ package cn.bunny.services.mapper.system; -import cn.bunny.domain.system.entity.Role; import cn.bunny.domain.system.dto.role.RoleDto; +import cn.bunny.domain.system.entity.Role; import cn.bunny.domain.system.vo.RoleVo; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; diff --git a/auth-system/services/src/main/java/cn/bunny/services/excel/RoleExcelListener.java b/auth-system/services/src/main/java/cn/bunny/services/excel/RoleExcelListener.java new file mode 100644 index 0000000..ded0f36 --- /dev/null +++ b/auth-system/services/src/main/java/cn/bunny/services/excel/RoleExcelListener.java @@ -0,0 +1,62 @@ +package cn.bunny.services.excel; + +import cn.bunny.domain.i18n.excel.RoleExcel; +import cn.bunny.domain.system.entity.Role; +import cn.bunny.domain.vo.result.ResultCodeEnum; +import cn.bunny.services.exception.AuthCustomerException; +import cn.bunny.services.service.system.RoleService; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.util.ListUtils; +import com.alibaba.excel.util.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; + +import java.util.List; + +@Slf4j +public class RoleExcelListener implements ReadListener { + + private static final int BATCH_COUNT = 100; + private final RoleService roleService; + private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); + + public RoleExcelListener(RoleService roleService) { + this.roleService = roleService; + } + + @Override + public void invoke(RoleExcel roleExcel, AnalysisContext analysisContext) { + cachedDataList.add(roleExcel); + // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM + if (cachedDataList.size() >= BATCH_COUNT) { + saveData(); + // 存储完成清理 list + cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + saveData(); + } + + private void saveData() { + List roleList = cachedDataList.stream().map(item -> { + Role role = new Role(); + BeanUtils.copyProperties(item, role); + + // id 不为空设置 + String id = item.getId(); + if (!StringUtils.isEmpty(id)) { + role.setId(Long.valueOf(id)); + } + return role; + }).toList(); + + if (roleList.isEmpty()) { + throw new AuthCustomerException(ResultCodeEnum.DATA_TOO_LARGE); + } + roleService.saveOrUpdateBatch(roleList, BATCH_COUNT); + } +} \ No newline at end of file diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java b/auth-system/services/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java index 718a317..21a7c07 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/configuration/impl/I18nServiceImpl.java @@ -17,6 +17,7 @@ import cn.bunny.services.exception.AuthCustomerException; import cn.bunny.services.mapper.configuration.I18nMapper; import cn.bunny.services.mapper.configuration.I18nTypeMapper; import cn.bunny.services.service.configuration.I18nService; +import cn.bunny.services.utils.FileUtil; import cn.bunny.services.utils.i8n.I18nUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.fastjson2.JSON; @@ -178,11 +179,7 @@ public class I18nServiceImpl extends ServiceImpl implements I1 } // 设置响应头 - HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Disposition", "attachment; filename=" + "i18n.zip"); - headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); - headers.add("Pragma", "no-cache"); - headers.add("Expires", "0"); + HttpHeaders headers = FileUtil.buildHttpHeadersByBinary("i18n-configuration.zip"); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return new ResponseEntity<>(byteArrayInputStream.readAllBytes(), headers, HttpStatus.OK); diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/DeptService.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/DeptService.java index e9ad30d..4cae74f 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/DeptService.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/DeptService.java @@ -55,5 +55,5 @@ public interface DeptService extends IService { * * @return 所有部门列表 */ - List getAllDeptList(); + List allDeptList(); } diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/RoleService.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/RoleService.java index 423b8c8..111a8f9 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/RoleService.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/RoleService.java @@ -1,14 +1,16 @@ package cn.bunny.services.service.system; -import cn.bunny.domain.system.entity.Role; import cn.bunny.domain.system.dto.role.RoleAddDto; import cn.bunny.domain.system.dto.role.RoleDto; import cn.bunny.domain.system.dto.role.RoleUpdateDto; +import cn.bunny.domain.system.entity.Role; import cn.bunny.domain.system.vo.RoleVo; import cn.bunny.domain.vo.result.PageResult; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -55,5 +57,19 @@ public interface RoleService extends IService { * * @return 所有角色列表 */ - List getAllRoles(); + List allRoles(); + + /** + * 使用Excel导出导出角色列表 + * + * @return Excel + */ + ResponseEntity exportByExcel(); + + /** + * 使用Excel更新角色列表 + * + * @param file Excel文件 + */ + void updateRoleByFile(MultipartFile file); } diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/UserService.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/UserService.java index 9b43f5f..0b0b5b4 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/UserService.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/UserService.java @@ -126,13 +126,6 @@ public interface UserService extends IService { */ void updateUserStatusByAdmin(AdminUserUpdateUserStatusDto dto); - /** - * * 获取本地登录用户信息 - * - * @return 用户信息 - */ - LoginVo getUserinfo(); - /** * * 更新本地用户信息 * diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/DeptServiceImpl.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/DeptServiceImpl.java index 8d547f0..38b7a75 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/DeptServiceImpl.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/DeptServiceImpl.java @@ -65,7 +65,7 @@ public class DeptServiceImpl extends ServiceImpl implements De */ @Override @Cacheable(cacheNames = "dept", key = "'allDept'", cacheManager = "cacheManagerWithMouth") - public List getAllDeptList() { + public List allDeptList() { return list().stream().map(dept -> { DeptVo deptVo = new DeptVo(); BeanUtils.copyProperties(dept, deptVo); diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/FilesServiceImpl.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/FilesServiceImpl.java index 25a35e8..c866632 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/FilesServiceImpl.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/FilesServiceImpl.java @@ -14,9 +14,9 @@ import cn.bunny.services.context.BaseContext; import cn.bunny.services.exception.AuthCustomerException; import cn.bunny.services.mapper.system.FilesMapper; import cn.bunny.services.service.system.FilesService; +import cn.bunny.services.utils.FileUtil; import cn.bunny.services.utils.minio.MinioProperties; import cn.bunny.services.utils.minio.MinioUtil; -import cn.bunny.services.utils.system.FileUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RoleServiceImpl.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RoleServiceImpl.java index 68298c7..34decb6 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RoleServiceImpl.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RoleServiceImpl.java @@ -1,5 +1,6 @@ package cn.bunny.services.service.system.impl; +import cn.bunny.domain.i18n.excel.RoleExcel; import cn.bunny.domain.system.dto.role.RoleAddDto; import cn.bunny.domain.system.dto.role.RoleDto; import cn.bunny.domain.system.dto.role.RoleUpdateDto; @@ -8,13 +9,16 @@ import cn.bunny.domain.system.entity.UserRole; import cn.bunny.domain.system.vo.RoleVo; import cn.bunny.domain.vo.result.PageResult; import cn.bunny.domain.vo.result.ResultCodeEnum; +import cn.bunny.services.excel.RoleExcelListener; import cn.bunny.services.exception.AuthCustomerException; import cn.bunny.services.mapper.system.RoleMapper; import cn.bunny.services.mapper.system.RolePermissionMapper; import cn.bunny.services.mapper.system.RouterRoleMapper; import cn.bunny.services.mapper.system.UserRoleMapper; import cn.bunny.services.service.system.RoleService; +import cn.bunny.services.utils.FileUtil; import cn.bunny.services.utils.system.RoleUtil; +import com.alibaba.excel.EasyExcel; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -24,9 +28,19 @@ import jakarta.validation.Valid; import org.springframework.beans.BeanUtils; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** *

@@ -77,7 +91,7 @@ public class RoleServiceImpl extends ServiceImpl implements Ro */ @Override @Cacheable(cacheNames = "role", key = "'allRole'", cacheManager = "cacheManagerWithMouth") - public List getAllRoles() { + public List allRoles() { return list().stream().map(role -> { RoleVo roleVo = new RoleVo(); BeanUtils.copyProperties(role, roleVo); @@ -85,6 +99,65 @@ public class RoleServiceImpl extends ServiceImpl implements Ro }).toList(); } + /** + * 使用Excel导出导出角色列表 + * + * @return Excel + */ + @Override + public ResponseEntity exportByExcel() { + String filename = FileUtil.buildFilenameBefore("role-"); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) { + + List list = list().stream().map(role -> { + RoleExcel roleExcel = new RoleExcel(); + BeanUtils.copyProperties(role, roleExcel); + + roleExcel.setId(role.getId().toString()); + return roleExcel; + }).toList(); + + // 创建临时ByteArrayOutputStream + ByteArrayOutputStream excelOutputStream = new ByteArrayOutputStream(); + + ZipEntry zipEntry = new ZipEntry(filename + ".xlsx"); + zipOutputStream.putNextEntry(zipEntry); + + // 先写入到临时流 + EasyExcel.write(excelOutputStream, RoleExcel.class).sheet("role").doWrite(list); + zipOutputStream.write(excelOutputStream.toByteArray()); + zipOutputStream.closeEntry(); + + } catch (IOException e) { + throw new RuntimeException(e); + } + + // 设置响应头 + HttpHeaders headers = FileUtil.buildHttpHeadersByBinary(filename + ".zip"); + + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + return new ResponseEntity<>(byteArrayInputStream.readAllBytes(), headers, HttpStatus.OK); + } + + /** + * 使用Excel更新角色列表 + * + * @param file Excel文件 + */ + @Override + @CacheEvict(cacheNames = "role", key = "'allRole'", beforeInvocation = true) + public void updateRoleByFile(MultipartFile file) { + InputStream fileInputStream; + try { + fileInputStream = file.getInputStream(); + EasyExcel.read(fileInputStream, RoleExcel.class, new RoleExcelListener(this)).sheet().doRead(); + } catch (IOException e) { + throw new AuthCustomerException(ResultCodeEnum.UPLOAD_ERROR); + } + } + /** * 添加角色 * diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RouterServiceImpl.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RouterServiceImpl.java index d9ebc8a..4de60d1 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RouterServiceImpl.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/RouterServiceImpl.java @@ -65,7 +65,7 @@ public class RouterServiceImpl extends ServiceImpl impleme // 当前的所有的路由列表 List routerList = list(); - + // 查询路由角色列表 Map> routerRoleList = routerRoleMapper.selectRouterRoleList().stream() .collect(Collectors.groupingBy(ViewRouterRole::getRouterId, Collectors.toList())); @@ -74,7 +74,7 @@ public class RouterServiceImpl extends ServiceImpl impleme Map> rolePermissionList = rolePermissionMapper.viewRolePowerWithAll().stream() .collect(Collectors.groupingBy(ViewRolePermission::getRoleId, Collectors.toList())); - // 整理web用户所能看到的路由列表 + // 整理web用户所能看到的路由列表,并检查当前用户是否是admin List webUserRouterVoList = routerUtil.getWebUserRouterVos(routerList, routerRoleList, rolePermissionList); // 添加 admin 管理路由权限 diff --git a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java index 42c727d..29422b8 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java +++ b/auth-system/services/src/main/java/cn/bunny/services/service/system/impl/UserServiceImpl.java @@ -334,11 +334,12 @@ public class UserServiceImpl extends ServiceImpl implemen @Override public List queryUser(String keyword) { if (!StringUtils.hasText(keyword)) { - return list(Page.of(1, 20), Wrappers.lambdaQuery().eq(AdminUser::getStatus, false)).stream().map(adminUser -> { - SearchUserinfoVo adminUserVo = new SearchUserinfoVo(); - BeanUtils.copyProperties(adminUser, adminUserVo); - return adminUserVo; - }).toList(); + return list(Page.of(1, 20), Wrappers.lambdaQuery().eq(AdminUser::getStatus, false)).stream() + .map(adminUser -> { + SearchUserinfoVo adminUserVo = new SearchUserinfoVo(); + BeanUtils.copyProperties(adminUser, adminUserVo); + return adminUserVo; + }).toList(); } List list = baseMapper.queryUser(keyword); @@ -371,16 +372,6 @@ public class UserServiceImpl extends ServiceImpl implemen } } - /** - * * 获取本地登录用户信息 - * - * @return 用户信息 - */ - @Override - public LoginVo getUserinfo() { - return BaseContext.getLoginVo(); - } - /** * * 更新本地用户信息 * diff --git a/auth-system/services/src/main/java/cn/bunny/services/utils/system/FileUtil.java b/auth-system/services/src/main/java/cn/bunny/services/utils/system/FileUtil.java deleted file mode 100644 index 7d0964a..0000000 --- a/auth-system/services/src/main/java/cn/bunny/services/utils/system/FileUtil.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.bunny.services.utils.system; - - -/* - * 文件工具类 - * 格式化字节大小 - */ -public class FileUtil { - /** - * 获取文件大小字符串 - * - * @param fileSize 文件大小 - * @return 格式化后文件大小 - */ - public static String getSize(Long fileSize) { - double fileSizeInKB = fileSize / 1024.00; - double fileSizeInMB = fileSizeInKB / 1024; - double fileSizeInGB = fileSizeInMB / 1024; - - String size; - if (fileSizeInGB >= 1) { - fileSizeInGB = Double.parseDouble(String.format("%.2f", fileSizeInGB)); - size = fileSizeInGB + "GB"; - } else if (fileSizeInMB >= 1) { - fileSizeInMB = Double.parseDouble(String.format("%.2f", fileSizeInMB)); - size = fileSizeInMB + "MB"; - } else if (fileSizeInKB >= 1) { - fileSizeInKB = Double.parseDouble(String.format("%.2f", fileSizeInKB)); - size = fileSizeInKB + "KB"; - } else { - size = fileSize + "B"; - } - - return size; - } -} diff --git a/auth-system/services/src/main/java/cn/bunny/services/utils/system/RoleUtil.java b/auth-system/services/src/main/java/cn/bunny/services/utils/system/RoleUtil.java index 6c78d53..8028c12 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/utils/system/RoleUtil.java +++ b/auth-system/services/src/main/java/cn/bunny/services/utils/system/RoleUtil.java @@ -6,7 +6,7 @@ import cn.bunny.domain.system.entity.AdminUser; import cn.bunny.services.context.BaseContext; import cn.bunny.services.mapper.system.UserMapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import org.springframework.beans.factory.annotation.Autowired; +import jakarta.annotation.Resource; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; @@ -15,13 +15,13 @@ import java.util.List; @Component public class RoleUtil { - @Autowired + @Resource private RedisTemplate redisTemplate; - @Autowired + @Resource private UserMapper userMapper; - @Autowired + @Resource private UserUtil userUtil; /** diff --git a/auth-system/services/src/main/java/cn/bunny/services/utils/system/RouterUtil.java b/auth-system/services/src/main/java/cn/bunny/services/utils/system/RouterUtil.java index ffbc19e..56915a0 100644 --- a/auth-system/services/src/main/java/cn/bunny/services/utils/system/RouterUtil.java +++ b/auth-system/services/src/main/java/cn/bunny/services/utils/system/RouterUtil.java @@ -6,24 +6,21 @@ import cn.bunny.domain.system.entity.RouterRole; import cn.bunny.domain.system.views.ViewRolePermission; import cn.bunny.domain.system.views.ViewRouterRole; import cn.bunny.domain.system.vo.router.WebUserRouterVo; +import cn.bunny.services.context.BaseContext; import cn.bunny.services.service.system.RouterRoleService; import com.alibaba.fastjson2.JSON; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static cn.bunny.domain.constant.UserConstant.allAuths; +import java.util.*; +@Slf4j @Component public class RouterUtil { - @Resource private RouterRoleService routerRoleService; @@ -75,72 +72,78 @@ public class RouterUtil { */ @NotNull public List getWebUserRouterVos(List routerList, Map> routerRoleList, Map> rolePermissionList) { + // 检查当前是否是 admin 用户 + List roles = BaseContext.getLoginVo().getRoles(); + List allAuths = !RoleUtil.checkAdmin(roles) ? new ArrayList<>() : List.of("*:*:*", "*:*", "*", "admin"); + // 查询路由所有数据,整理前端需要的路和、角色、权限 return routerList.stream().map(view -> { - // 前端需要的格式路由 - WebUserRouterVo webUserRouterVo = new WebUserRouterVo(); + // 前端需要的格式路由 + WebUserRouterVo webUserRouterVo = new WebUserRouterVo(); - // 复制数据库中信息到新路由中 - BeanUtils.copyProperties(view, webUserRouterVo); + // 复制数据库中信息到新路由中 + BeanUtils.copyProperties(view, webUserRouterVo); - // 整理前端需要格式的路由 meta - String meta = view.getMeta(); - RouterMeta routerMeta; + // 整理前端需要格式的路由 meta + String meta = view.getMeta(); + RouterMeta routerMeta; - // 如果么meta存在,将其转成 RouterMeta 而不是 JSON/字符串 - if (StringUtils.hasText(meta)) { - routerMeta = JSON.parseObject(meta, RouterMeta.class); - webUserRouterVo.setMeta(routerMeta); - } else { - // 不存在时不能为 null 将路由名称设置为title - routerMeta = new RouterMeta(); - routerMeta.setTitle(view.getRouteName()); - webUserRouterVo.setMeta(routerMeta); - } + // 如果么meta存在,将其转成 RouterMeta 而不是 JSON/字符串 + if (StringUtils.hasText(meta)) { + routerMeta = JSON.parseObject(meta, RouterMeta.class); + webUserRouterVo.setMeta(routerMeta); + } else { + // 不存在时不能为 null 将路由名称设置为title + routerMeta = new RouterMeta(); + routerMeta.setTitle(view.getRouteName()); + webUserRouterVo.setMeta(routerMeta); + } - // 路由路由和橘色 设置角色信息,防止为空报错,最后添加 roles - List roleCodeList = new ArrayList<>(allAuths); - if (!routerRoleList.isEmpty()) { - // 找到当前路由下的角色信息 - List list = routerRoleList.getOrDefault(view.getId(), Collections.emptyList()).stream() - .map(ViewRouterRole::getRoleCode).toList(); + // 路由路由和橘色 设置角色信息,防止为空报错,最后添加 roles + List roleCodeList = new ArrayList<>(allAuths); + if (!routerRoleList.isEmpty()) { + // 找到当前路由下的角色信息 + List list = routerRoleList.getOrDefault(view.getId(), Collections.emptyList()).stream() + .map(ViewRouterRole::getRoleCode).toList(); - // 将角色码添加到角色列表 - roleCodeList.addAll(list); - } - webUserRouterVo.getMeta().setRoles(roleCodeList); + // 将角色码添加到角色列表 + roleCodeList.addAll(list); + } + webUserRouterVo.getMeta().setRoles(roleCodeList); - // 角色和权限 设置权限信息,最后添加权限信息 auth/permission - List permissionList = new ArrayList<>(allAuths); - if (!rolePermissionList.isEmpty()) { - // 找到当前路由下所有的角色id,之后根据 角色和权限查找 角色对应的权限 - List roleIds = routerRoleList.getOrDefault(view.getId(), Collections.emptyList()).stream() - .map(ViewRouterRole::getRoleId).toList(); + // 角色和权限 设置权限信息,最后添加权限信息 auth/permission + List permissionList = new ArrayList<>(allAuths); + if (!rolePermissionList.isEmpty()) { + // 找到当前路由下所有的角色id,之后根据 角色和权限查找 角色对应的权限 + List roleIds = routerRoleList.getOrDefault(view.getId(), Collections.emptyList()).stream() + .map(ViewRouterRole::getRoleId).toList(); - // 根据角色id找到所有权限 - List list = roleIds.stream() - .map(roleId -> { - List viewRolePermissions = rolePermissionList.get(roleId); + // 根据角色id找到所有权限 + List list = roleIds.stream() + .map(roleId -> { + List viewRolePermissions = rolePermissionList.get(roleId); - // 根据角色id查找权限,且角色和权限存在 - if (roleId != null && viewRolePermissions != null && !viewRolePermissions.isEmpty()) { - return viewRolePermissions.stream().map(ViewRolePermission::getPowerCode).toList(); - } + // 根据角色id查找权限,且角色和权限存在 + if (roleId != null && viewRolePermissions != null && !viewRolePermissions.isEmpty()) { + return viewRolePermissions.stream().map(ViewRolePermission::getPowerCode).toList(); + } - // 未找到返回 空字符串 - return List.of(""); - }) - // 将二维数组转成一维数组 - .flatMap(List::stream) - // 过滤掉为空的字符串 - .filter(StringUtils::hasText) - .distinct() - .toList(); - permissionList.addAll(list); - } - webUserRouterVo.getMeta().setAuths(permissionList); + // 未找到返回 空字符串 + return List.of(""); + }) + // 将二维数组转成一维数组 + .flatMap(List::stream) + // 过滤掉为空的字符串 + .filter(StringUtils::hasText) + .distinct() + .toList(); + permissionList.addAll(list); + } + webUserRouterVo.getMeta().setAuths(permissionList); - return webUserRouterVo; - }).toList(); + return webUserRouterVo; + }) + .sorted(Comparator.comparing(routerVo -> routerVo.getMeta().getRank())) + .toList(); } } diff --git a/common/common-config/pom.xml b/common/common-config/pom.xml index 2f98534..e259ef6 100644 --- a/common/common-config/pom.xml +++ b/common/common-config/pom.xml @@ -24,6 +24,10 @@ 0.0.1-SNAPSHOT + + cn.hutool + hutool-all + org.springframework.boot spring-boot-starter-web diff --git a/common/common-config/src/main/java/cn/bunny/services/config/ThreadLocalCleanupInterceptor.java b/common/common-config/src/main/java/cn/bunny/services/config/ThreadLocalCleanupInterceptor.java new file mode 100644 index 0000000..24d233a --- /dev/null +++ b/common/common-config/src/main/java/cn/bunny/services/config/ThreadLocalCleanupInterceptor.java @@ -0,0 +1,17 @@ +package cn.bunny.services.config; + +import cn.bunny.services.context.BaseContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +public class ThreadLocalCleanupInterceptor implements HandlerInterceptor { + + /* 请求完成后清理 */ + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + BaseContext.removeUser(); + } +} \ No newline at end of file diff --git a/common/common-config/src/main/java/cn/bunny/services/config/WebConfig.java b/common/common-config/src/main/java/cn/bunny/services/config/WebConfig.java index fcb2d91..a307b62 100644 --- a/common/common-config/src/main/java/cn/bunny/services/config/WebConfig.java +++ b/common/common-config/src/main/java/cn/bunny/services/config/WebConfig.java @@ -1,11 +1,23 @@ package cn.bunny.services.config; +import jakarta.annotation.Resource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class WebConfig { +public class WebConfig implements WebMvcConfigurer { + + @Resource + private ThreadLocalCleanupInterceptor interceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(interceptor); + } + @Bean public RestTemplate restTemplate() { return new RestTemplate(); diff --git a/common/common-config/src/main/java/cn/bunny/services/utils/FileUtil.java b/common/common-config/src/main/java/cn/bunny/services/utils/FileUtil.java new file mode 100644 index 0000000..03dcf80 --- /dev/null +++ b/common/common-config/src/main/java/cn/bunny/services/utils/FileUtil.java @@ -0,0 +1,68 @@ +package cn.bunny.services.utils; + +import cn.hutool.crypto.digest.MD5; +import org.springframework.http.HttpHeaders; + +/* + * 文件工具类 + * 格式化字节大小 + */ +public class FileUtil { + /** + * 获取文件大小字符串 + * + * @param fileSize 文件大小 + * @return 格式化后文件大小 + */ + public static String getSize(Long fileSize) { + double fileSizeInKB = fileSize / 1024.00; + double fileSizeInMB = fileSizeInKB / 1024; + double fileSizeInGB = fileSizeInMB / 1024; + + String size; + if (fileSizeInGB >= 1) { + fileSizeInGB = Double.parseDouble(String.format("%.2f", fileSizeInGB)); + size = fileSizeInGB + "GB"; + } else if (fileSizeInMB >= 1) { + fileSizeInMB = Double.parseDouble(String.format("%.2f", fileSizeInMB)); + size = fileSizeInMB + "MB"; + } else if (fileSizeInKB >= 1) { + fileSizeInKB = Double.parseDouble(String.format("%.2f", fileSizeInKB)); + size = fileSizeInKB + "KB"; + } else { + size = fileSize + "B"; + } + + return size; + } + + /** + * 构建二进制文件响应头 + * + * @param filename 文件名 + * @return HttpHeaders + */ + public static HttpHeaders buildHttpHeadersByBinary(String filename) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Disposition", "attachment; filename=" + filename); + headers.add("Cache-Control", "no-cache, no-store, must-revalidate"); + headers.add("Pragma", "no-cache"); + headers.add("Expires", "0"); + + return headers; + } + + /* 文件名在前面 */ + public static String buildFilenameBefore(String filename) { + long currentTimeMillis = System.currentTimeMillis(); + String digestHex = MD5.create().digestHex(currentTimeMillis + ""); + return filename + digestHex; + } + + /* 文件名在后面 */ + public static String buildFilenameAfter(String filename) { + long currentTimeMillis = System.currentTimeMillis(); + String digestHex = MD5.create().digestHex(currentTimeMillis + ""); + return digestHex + filename; + } +} diff --git a/common/domain-common/src/main/java/cn/bunny/domain/constant/UserConstant.java b/common/domain-common/src/main/java/cn/bunny/domain/constant/UserConstant.java index f0b2ef7..96046d0 100644 --- a/common/domain-common/src/main/java/cn/bunny/domain/constant/UserConstant.java +++ b/common/domain-common/src/main/java/cn/bunny/domain/constant/UserConstant.java @@ -2,11 +2,8 @@ package cn.bunny.domain.constant; import lombok.Data; -import java.util.List; - @Data public class UserConstant { public static final String USER_AVATAR = "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132"; public static final String PERSON_DESCRIPTION = "这个人很懒没有介绍..."; - public static final List allAuths = List.of("*::*::*", "*::*", "*"); }