From af3b1605512ade2a3bf818e602359df77494acb4 Mon Sep 17 00:00:00 2001 From: "aoli.qu" <408346101@qq.com> Date: Wed, 11 Oct 2023 11:37:24 +0800 Subject: [PATCH] init --- pom.xml | 173 ++++ src/main/java/com/org/WelfareApplication.java | 15 + .../org/oss/controller/SysOssController.java | 181 ++++ .../org/oss/controller/commonController.java | 28 + src/main/java/com/org/oss/entity/SysOss.java | 33 + .../java/com/org/oss/mapper/SysOssMapper.java | 22 + .../com/org/oss/service/SysOssService.java | 288 ++++++ .../org/system/annotation/CheckVerify.java | 13 + .../java/com/org/system/annotation/Excel.java | 142 +++ .../com/org/system/annotation/Excels.java | 18 + .../java/com/org/system/annotation/Log.java | 26 + .../com/org/system/aspectj/LogAspect.java | 198 ++++ .../org/system/config/async/AsyncFactory.java | 76 ++ .../org/system/config/async/AsyncManager.java | 54 + .../java/com/org/system/config/config.java | 10 + .../org/system/config/redis/RedisCache.java | 204 ++++ .../AuthenticationEntryPointImpl.java | 28 + .../JwtAuthenticationTokenFilter.java | 39 + .../security/LogoutSuccessHandlerImpl.java | 51 + .../config/security/Md5PasswordEncoder.java | 67 ++ .../config/security/SecurityConfig.java | 124 +++ .../config/thread/ThreadPoolConfig.java | 56 + .../org/system/config/validation/Insert.java | 7 + .../org/system/config/validation/Update.java | 7 + .../com/org/system/config/xss/EscapeUtil.java | 118 +++ .../org/system/config/xss/FilterConfig.java | 53 + .../com/org/system/config/xss/HttpHelper.java | 39 + .../system/config/xss/RepeatableFilter.java | 38 + .../config/xss/RepeatedlyRequestWrapper.java | 57 + .../com/org/system/config/xss/XssFilter.java | 73 ++ .../xss/XssHttpServletRequestWrapper.java | 86 ++ .../org/system/controller/BaseController.java | 87 ++ .../SysDataDictionaryController.java | 87 ++ .../SysDataDictionaryItemController.java | 137 +++ .../system/controller/SysLoginController.java | 72 ++ .../system/controller/SysMenuController.java | 85 ++ .../controller/SysOperLogController.java | 42 + .../system/controller/SysRoleController.java | 105 ++ .../controller/SysRoleMenuController.java | 69 ++ .../system/controller/SysUserController.java | 117 +++ .../controller/SysUserRoleController.java | 82 ++ .../com/org/system/entity/BaseEntity.java | 44 + .../java/com/org/system/entity/LoginBody.java | 15 + .../java/com/org/system/entity/LoginUser.java | 119 +++ .../org/system/entity/SysDataDictionary.java | 27 + .../system/entity/SysDataDictionaryItem.java | 43 + .../java/com/org/system/entity/SysMenu.java | 67 ++ .../com/org/system/entity/SysOperLog.java | 69 ++ .../java/com/org/system/entity/SysRole.java | 53 + .../com/org/system/entity/SysRoleMenu.java | 27 + .../java/com/org/system/entity/SysUser.java | 88 ++ .../com/org/system/entity/SysUserRole.java | 23 + .../com/org/system/entity/vo/PersonVo.java | 48 + .../com/org/system/enums/BusinessStatus.java | 10 + .../com/org/system/enums/BusinessType.java | 40 + .../com/org/system/enums/MenuTypeEnum.java | 34 + .../com/org/system/enums/OperatorType.java | 14 + .../java/com/org/system/enums/SmsType.java | 31 + .../com/org/system/enums/YesOrNoState.java | 15 + .../mapper/SysDataDictionaryItemMapper.java | 39 + .../mapper/SysDataDictionaryMapper.java | 10 + .../com/org/system/mapper/SysMenuMapper.java | 15 + .../org/system/mapper/SysOperLogMapper.java | 11 + .../com/org/system/mapper/SysOrgMapper.java | 12 + .../com/org/system/mapper/SysRoleMapper.java | 12 + .../org/system/mapper/SysRoleMenuMapper.java | 31 + .../com/org/system/mapper/SysUserMapper.java | 18 + .../org/system/mapper/SysUserRoleMapper.java | 32 + .../system/params/SysRoleGrantMenuParam.java | 26 + .../system/params/SysUserGrantRoleParam.java | 26 + .../org/system/pojo/LoginMenuTreeNode.java | 88 ++ .../org/system/service/CustomUserService.java | 50 + .../org/system/service/PermissionService.java | 153 +++ .../service/SysDataDictionaryItemService.java | 243 +++++ .../service/SysDataDictionaryService.java | 153 +++ .../org/system/service/SysLoginService.java | 165 +++ .../org/system/service/SysMenuService.java | 339 ++++++ .../org/system/service/SysOperLogService.java | 23 + .../system/service/SysRoleMenuService.java | 64 ++ .../org/system/service/SysRoleService.java | 178 ++++ .../system/service/SysUserRoleService.java | 157 +++ .../org/system/service/SysUserService.java | 234 +++++ .../com/org/system/service/TokenService.java | 190 ++++ .../ueditor/controller/UeditorContorller.java | 46 + .../com/org/ueditor/domain/UeditorConfig.java | 29 + .../org/ueditor/domain/UeditorConfigJson.java | 140 +++ src/main/java/com/org/utils/AjaxResult.java | 119 +++ src/main/java/com/org/utils/Constants.java | 140 +++ .../java/com/org/utils/HttpServletUtil.java | 82 ++ src/main/java/com/org/utils/ImagePicUtil.java | 113 ++ src/main/java/com/org/utils/MessageUtil.java | 19 + src/main/java/com/org/utils/SecurityUtil.java | 53 + src/main/java/com/org/utils/SpringUtil.java | 111 ++ src/main/java/com/org/utils/SqlUtil.java | 32 + src/main/java/com/org/utils/StringUtils.java | 370 +++++++ src/main/java/com/org/utils/Threads.java | 71 ++ .../java/com/org/utils/core/IdParams.java | 19 + .../java/com/org/utils/core/PageParams.java | 29 + .../org/utils/exception/BaseException.java | 80 ++ .../org/utils/exception/CustomException.java | 39 + .../exception/GlobalExceptionHandler.java | 88 ++ .../org/utils/exception/UserException.java | 11 + .../UserPasswordNotMatchException.java | 12 + .../java/com/org/utils/page/PageDomain.java | 28 + .../com/org/utils/page/TableDataInfo.java | 47 + .../java/com/org/utils/page/TableSupport.java | 34 + .../java/com/org/utils/poi/ExcelUtil.java | 977 ++++++++++++++++++ .../com/org/utils/reflect/ReflectUtils.java | 402 +++++++ .../com/org/utils/spring/SpringUtils.java | 144 +++ .../java/com/org/utils/upload/CommonUtil.java | 98 ++ .../com/org/utils/upload/FileTypeUtils.java | 39 + .../java/com/org/utils/upload/FileUtils.java | 248 +++++ .../com/org/utils/upload/MimeTypeUtils.java | 48 + .../java/com/org/utils/upload/UpLoadUtil.java | 305 ++++++ .../controller/BcHonorShowController.java | 83 ++ .../com/org/web/honor/domain/BcHonorShow.java | 44 + .../web/honor/mapper/BcHonorShowMapper.java | 26 + .../web/honor/service/BcHonorShowService.java | 61 ++ .../BcHospitalRecordController.java | 117 +++ .../web/hospital/domain/BcHospitalRecord.java | 94 ++ .../mapper/BcHospitalRecordMapper.java | 73 ++ .../service/BcHospitalRecordService.java | 155 +++ .../controller/BcPersonServiceController.java | 82 ++ .../controller/BcPersonSupportController.java | 82 ++ .../org/web/person/domain/BcPersonFamily.java | 51 + .../web/person/domain/BcPersonService.java | 109 ++ .../web/person/domain/BcPersonSupport.java | 210 ++++ .../org/web/person/enums/PersonTypeEnums.java | 25 + .../person/mapper/BcPersonFamilyMapper.java | 41 + .../person/mapper/BcPersonServiceMapper.java | 34 + .../person/mapper/BcPersonSupportMapper.java | 36 + .../person/service/BcPersonFamilyService.java | 74 ++ .../service/BcPersonServiceService.java | 162 +++ .../service/BcPersonSupportService.java | 162 +++ .../web/room/controller/BcRoomController.java | 125 +++ .../java/com/org/web/room/domain/BcRoom.java | 51 + .../com/org/web/room/domain/BcRoomBed.java | 32 + .../org/web/room/mapper/BcRoomBedMapper.java | 46 + .../com/org/web/room/mapper/BcRoomMapper.java | 30 + .../web/room/service/BcRoomBedService.java | 70 ++ .../org/web/room/service/BcRoomService.java | 107 ++ .../java/com/org/web/utils/Dictionary.java | 32 + src/main/resources/application.yml | 97 ++ .../resources/message/messages.properties | 37 + .../resources/static/题目导入模板.xls | Bin 0 -> 6656 bytes welfare-api.iml | 2 + 146 files changed, 12566 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/com/org/WelfareApplication.java create mode 100644 src/main/java/com/org/oss/controller/SysOssController.java create mode 100644 src/main/java/com/org/oss/controller/commonController.java create mode 100644 src/main/java/com/org/oss/entity/SysOss.java create mode 100644 src/main/java/com/org/oss/mapper/SysOssMapper.java create mode 100644 src/main/java/com/org/oss/service/SysOssService.java create mode 100644 src/main/java/com/org/system/annotation/CheckVerify.java create mode 100644 src/main/java/com/org/system/annotation/Excel.java create mode 100644 src/main/java/com/org/system/annotation/Excels.java create mode 100644 src/main/java/com/org/system/annotation/Log.java create mode 100644 src/main/java/com/org/system/aspectj/LogAspect.java create mode 100644 src/main/java/com/org/system/config/async/AsyncFactory.java create mode 100644 src/main/java/com/org/system/config/async/AsyncManager.java create mode 100644 src/main/java/com/org/system/config/config.java create mode 100644 src/main/java/com/org/system/config/redis/RedisCache.java create mode 100644 src/main/java/com/org/system/config/security/AuthenticationEntryPointImpl.java create mode 100644 src/main/java/com/org/system/config/security/JwtAuthenticationTokenFilter.java create mode 100644 src/main/java/com/org/system/config/security/LogoutSuccessHandlerImpl.java create mode 100644 src/main/java/com/org/system/config/security/Md5PasswordEncoder.java create mode 100644 src/main/java/com/org/system/config/security/SecurityConfig.java create mode 100644 src/main/java/com/org/system/config/thread/ThreadPoolConfig.java create mode 100644 src/main/java/com/org/system/config/validation/Insert.java create mode 100644 src/main/java/com/org/system/config/validation/Update.java create mode 100644 src/main/java/com/org/system/config/xss/EscapeUtil.java create mode 100644 src/main/java/com/org/system/config/xss/FilterConfig.java create mode 100644 src/main/java/com/org/system/config/xss/HttpHelper.java create mode 100644 src/main/java/com/org/system/config/xss/RepeatableFilter.java create mode 100644 src/main/java/com/org/system/config/xss/RepeatedlyRequestWrapper.java create mode 100644 src/main/java/com/org/system/config/xss/XssFilter.java create mode 100644 src/main/java/com/org/system/config/xss/XssHttpServletRequestWrapper.java create mode 100644 src/main/java/com/org/system/controller/BaseController.java create mode 100644 src/main/java/com/org/system/controller/SysDataDictionaryController.java create mode 100644 src/main/java/com/org/system/controller/SysDataDictionaryItemController.java create mode 100644 src/main/java/com/org/system/controller/SysLoginController.java create mode 100644 src/main/java/com/org/system/controller/SysMenuController.java create mode 100644 src/main/java/com/org/system/controller/SysOperLogController.java create mode 100644 src/main/java/com/org/system/controller/SysRoleController.java create mode 100644 src/main/java/com/org/system/controller/SysRoleMenuController.java create mode 100644 src/main/java/com/org/system/controller/SysUserController.java create mode 100644 src/main/java/com/org/system/controller/SysUserRoleController.java create mode 100644 src/main/java/com/org/system/entity/BaseEntity.java create mode 100644 src/main/java/com/org/system/entity/LoginBody.java create mode 100644 src/main/java/com/org/system/entity/LoginUser.java create mode 100644 src/main/java/com/org/system/entity/SysDataDictionary.java create mode 100644 src/main/java/com/org/system/entity/SysDataDictionaryItem.java create mode 100644 src/main/java/com/org/system/entity/SysMenu.java create mode 100644 src/main/java/com/org/system/entity/SysOperLog.java create mode 100644 src/main/java/com/org/system/entity/SysRole.java create mode 100644 src/main/java/com/org/system/entity/SysRoleMenu.java create mode 100644 src/main/java/com/org/system/entity/SysUser.java create mode 100644 src/main/java/com/org/system/entity/SysUserRole.java create mode 100644 src/main/java/com/org/system/entity/vo/PersonVo.java create mode 100644 src/main/java/com/org/system/enums/BusinessStatus.java create mode 100644 src/main/java/com/org/system/enums/BusinessType.java create mode 100644 src/main/java/com/org/system/enums/MenuTypeEnum.java create mode 100644 src/main/java/com/org/system/enums/OperatorType.java create mode 100644 src/main/java/com/org/system/enums/SmsType.java create mode 100644 src/main/java/com/org/system/enums/YesOrNoState.java create mode 100644 src/main/java/com/org/system/mapper/SysDataDictionaryItemMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysDataDictionaryMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysMenuMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysOperLogMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysOrgMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysRoleMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysRoleMenuMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysUserMapper.java create mode 100644 src/main/java/com/org/system/mapper/SysUserRoleMapper.java create mode 100644 src/main/java/com/org/system/params/SysRoleGrantMenuParam.java create mode 100644 src/main/java/com/org/system/params/SysUserGrantRoleParam.java create mode 100644 src/main/java/com/org/system/pojo/LoginMenuTreeNode.java create mode 100644 src/main/java/com/org/system/service/CustomUserService.java create mode 100644 src/main/java/com/org/system/service/PermissionService.java create mode 100644 src/main/java/com/org/system/service/SysDataDictionaryItemService.java create mode 100644 src/main/java/com/org/system/service/SysDataDictionaryService.java create mode 100644 src/main/java/com/org/system/service/SysLoginService.java create mode 100644 src/main/java/com/org/system/service/SysMenuService.java create mode 100644 src/main/java/com/org/system/service/SysOperLogService.java create mode 100644 src/main/java/com/org/system/service/SysRoleMenuService.java create mode 100644 src/main/java/com/org/system/service/SysRoleService.java create mode 100644 src/main/java/com/org/system/service/SysUserRoleService.java create mode 100644 src/main/java/com/org/system/service/SysUserService.java create mode 100644 src/main/java/com/org/system/service/TokenService.java create mode 100644 src/main/java/com/org/ueditor/controller/UeditorContorller.java create mode 100644 src/main/java/com/org/ueditor/domain/UeditorConfig.java create mode 100644 src/main/java/com/org/ueditor/domain/UeditorConfigJson.java create mode 100644 src/main/java/com/org/utils/AjaxResult.java create mode 100644 src/main/java/com/org/utils/Constants.java create mode 100644 src/main/java/com/org/utils/HttpServletUtil.java create mode 100644 src/main/java/com/org/utils/ImagePicUtil.java create mode 100644 src/main/java/com/org/utils/MessageUtil.java create mode 100644 src/main/java/com/org/utils/SecurityUtil.java create mode 100644 src/main/java/com/org/utils/SpringUtil.java create mode 100644 src/main/java/com/org/utils/SqlUtil.java create mode 100644 src/main/java/com/org/utils/StringUtils.java create mode 100644 src/main/java/com/org/utils/Threads.java create mode 100644 src/main/java/com/org/utils/core/IdParams.java create mode 100644 src/main/java/com/org/utils/core/PageParams.java create mode 100644 src/main/java/com/org/utils/exception/BaseException.java create mode 100644 src/main/java/com/org/utils/exception/CustomException.java create mode 100644 src/main/java/com/org/utils/exception/GlobalExceptionHandler.java create mode 100644 src/main/java/com/org/utils/exception/UserException.java create mode 100644 src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java create mode 100644 src/main/java/com/org/utils/page/PageDomain.java create mode 100644 src/main/java/com/org/utils/page/TableDataInfo.java create mode 100644 src/main/java/com/org/utils/page/TableSupport.java create mode 100644 src/main/java/com/org/utils/poi/ExcelUtil.java create mode 100644 src/main/java/com/org/utils/reflect/ReflectUtils.java create mode 100644 src/main/java/com/org/utils/spring/SpringUtils.java create mode 100644 src/main/java/com/org/utils/upload/CommonUtil.java create mode 100644 src/main/java/com/org/utils/upload/FileTypeUtils.java create mode 100644 src/main/java/com/org/utils/upload/FileUtils.java create mode 100644 src/main/java/com/org/utils/upload/MimeTypeUtils.java create mode 100644 src/main/java/com/org/utils/upload/UpLoadUtil.java create mode 100644 src/main/java/com/org/web/honor/controller/BcHonorShowController.java create mode 100644 src/main/java/com/org/web/honor/domain/BcHonorShow.java create mode 100644 src/main/java/com/org/web/honor/mapper/BcHonorShowMapper.java create mode 100644 src/main/java/com/org/web/honor/service/BcHonorShowService.java create mode 100644 src/main/java/com/org/web/hospital/controller/BcHospitalRecordController.java create mode 100644 src/main/java/com/org/web/hospital/domain/BcHospitalRecord.java create mode 100644 src/main/java/com/org/web/hospital/mapper/BcHospitalRecordMapper.java create mode 100644 src/main/java/com/org/web/hospital/service/BcHospitalRecordService.java create mode 100644 src/main/java/com/org/web/person/controller/BcPersonServiceController.java create mode 100644 src/main/java/com/org/web/person/controller/BcPersonSupportController.java create mode 100644 src/main/java/com/org/web/person/domain/BcPersonFamily.java create mode 100644 src/main/java/com/org/web/person/domain/BcPersonService.java create mode 100644 src/main/java/com/org/web/person/domain/BcPersonSupport.java create mode 100644 src/main/java/com/org/web/person/enums/PersonTypeEnums.java create mode 100644 src/main/java/com/org/web/person/mapper/BcPersonFamilyMapper.java create mode 100644 src/main/java/com/org/web/person/mapper/BcPersonServiceMapper.java create mode 100644 src/main/java/com/org/web/person/mapper/BcPersonSupportMapper.java create mode 100644 src/main/java/com/org/web/person/service/BcPersonFamilyService.java create mode 100644 src/main/java/com/org/web/person/service/BcPersonServiceService.java create mode 100644 src/main/java/com/org/web/person/service/BcPersonSupportService.java create mode 100644 src/main/java/com/org/web/room/controller/BcRoomController.java create mode 100644 src/main/java/com/org/web/room/domain/BcRoom.java create mode 100644 src/main/java/com/org/web/room/domain/BcRoomBed.java create mode 100644 src/main/java/com/org/web/room/mapper/BcRoomBedMapper.java create mode 100644 src/main/java/com/org/web/room/mapper/BcRoomMapper.java create mode 100644 src/main/java/com/org/web/room/service/BcRoomBedService.java create mode 100644 src/main/java/com/org/web/room/service/BcRoomService.java create mode 100644 src/main/java/com/org/web/utils/Dictionary.java create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/message/messages.properties create mode 100644 src/main/resources/static/题目导入模板.xls create mode 100644 welfare-api.iml diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e1e1496 --- /dev/null +++ b/pom.xml @@ -0,0 +1,173 @@ + + + 4.0.0 + + com.dc + welfare-api + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.3.4.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework + spring-test + 5.3.23 + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + + + + org.springframework.boot + spring-boot-starter-security + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.3.0 + + + org.mybatis + mybatis + + + org.mybatis + mybatis-spring + + + + + + + com.baomidou + mybatis-plus-boot-starter + 3.3.2 + + + + + mysql + mysql-connector-java + runtime + + + + + com.alibaba + fastjson + 1.2.74 + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + cn.hutool + hutool-all + 5.0.5 + + + javax.servlet + javax.servlet-api + 3.1.0 + + provided + + + + + org.projectlombok + lombok + + + + + commons-io + commons-io + 2.5 + + + org.apache.commons + commons-lang3 + 3.10 + + + + + org.apache.poi + poi-ooxml + 3.17 + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/src/main/java/com/org/WelfareApplication.java b/src/main/java/com/org/WelfareApplication.java new file mode 100644 index 0000000..63b96d0 --- /dev/null +++ b/src/main/java/com/org/WelfareApplication.java @@ -0,0 +1,15 @@ +package com.org; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableScheduling +@SpringBootApplication +public class WelfareApplication { + + public static void main(String[] args) { + SpringApplication.run(WelfareApplication.class, args); + } + +} diff --git a/src/main/java/com/org/oss/controller/SysOssController.java b/src/main/java/com/org/oss/controller/SysOssController.java new file mode 100644 index 0000000..f07dada --- /dev/null +++ b/src/main/java/com/org/oss/controller/SysOssController.java @@ -0,0 +1,181 @@ +package com.org.oss.controller; + +import cn.hutool.core.util.IdUtil; +import com.org.oss.entity.SysOss; +import com.org.oss.service.SysOssService; +import com.org.system.annotation.Log; +import com.org.system.controller.BaseController; +import com.org.system.enums.BusinessType; +import com.org.utils.AjaxResult; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import com.org.utils.page.TableDataInfo; +import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.codec.binary.Base64; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("sys/oss") +public class SysOssController extends BaseController { + + @Autowired + private SysOssService sysOssService; + + /** + * 分页查询 + * + * @return RestResponse + */ + @GetMapping("/list") + @PreAuthorize("@ss.hasPermi('sys:oss:list')") + @Log(title = "系统文件分页查询", businessType = BusinessType.SELECT) + public TableDataInfo getList(SysOss sysOss) { + log.info("SysOssController - getList sysOss:{}", sysOss); + + startPage(); + List list = sysOssService.queryList(sysOss); + + return getDataTable(list); + } + + /** + * 上传文件 + * + * @param file file + * @return RestResponse + */ + @RequestMapping("/upload") + @PreAuthorize("@ss.hasPermi('sys:oss:edit')") + @Log(title = "系统文件上传", businessType = BusinessType.INSERT) + public Object upload(@RequestParam(value = "file", required = false) MultipartFile file, + @RequestParam(value = "sourceId", required = false) String sourceId, + @RequestParam(value = "fileType", required = false) String fileType) throws IOException { + if (null == file || file.isEmpty()) throw new CustomException("上传文件不能为空"); + + return sysOssService.upload(file, sourceId, fileType); + } + + + /** + * 上传图片-指定图片大小 + * + * @param file file + * @return RestResponse + */ + @RequestMapping("/uploadImg") + @PreAuthorize("@ss.hasPermi('sys:oss:edit')") + @Log(title = "系统文件上传", businessType = BusinessType.INSERT) + public Object uploadImg(@RequestParam(value = "file", required = false) MultipartFile file, + @RequestParam(value = "sourceId", required = false) String sourceId, + @RequestParam(value = "fileType", required = false) String fileType, + @RequestParam(value = "fileSize", required = false) Long fileSize) throws IOException { + if (null == file || file.isEmpty()) throw new CustomException("上传文件不能为空"); + + if (null == fileSize) return sysOssService.upload(file, sourceId, fileType); + return sysOssService.uploadImg(file, sourceId, fileType, fileSize); + } + + /** + * 文件上传-图片Base64 + * + * @param base64 + * @return + * @throws IOException + */ + @PostMapping("/upload/base64") + @PreAuthorize("@ss.hasPermi('sys:oss:edit')") + @Log(title = "系统文件上传-图片Base64", businessType = BusinessType.INSERT) + public Object uploadBase64(@RequestBody String base64) throws IOException { + if(StringUtils.isEmpty(base64)) throw new CustomException("上传文件Base64不能为空"); + + base64 = base64.substring(base64.indexOf(",")+1); + byte[] data = Base64.decodeBase64(base64); + + String fileName = String.format("%s.%s", IdUtil.simpleUUID(), "png") ; + MultipartFile file = new MockMultipartFile(fileName, fileName, "application/x-png", data); + + return sysOssService.upload(file, "", ""); + } + + /** + * 删除文件上传记录 + * + * @param ids ids + * @return RestResponse + */ + @PostMapping("/delete") + @PreAuthorize("@ss.hasPermi('sys:oss:edit')") + @Log(title = "系统文件删除", businessType = BusinessType.DELETE) + public AjaxResult delete(@RequestBody Integer[] ids) { + log.info("SysOssController - delete ids:{}", ids); + + sysOssService.delete(ids); + + return AjaxResult.success(); + } + + /** + * 根据文件全路径数组删除上传文件 + * + * @param urls + * @return + */ + @PostMapping("/deleteByUrl") + @PreAuthorize("@ss.hasPermi('sys:oss:edit')") + @Log(title = "系统文件删除", businessType = BusinessType.DELETE) + public AjaxResult deleteByUrl(@RequestBody String[] urls) { + log.info("SysOssController - deleteByUrl urls:{}", urls); + + sysOssService.deleteByUrl(urls); + + return AjaxResult.success(); + } + + /** + * 获取文件 + * + * @param dateDir + * @param fileName + */ + @GetMapping(value = "/show/{dateDir}/{fileName}") + public void show(@PathVariable("dateDir") String dateDir, @PathVariable("fileName") String fileName) { + log.info("SysOssController - show dateDir:{}", dateDir); + log.info("SysOssController - show fileName:{}", fileName); + + sysOssService.show(dateDir, fileName); + } + + /** + * 根据文件ID获取文件 + * @param id + */ + @GetMapping(value = "/show") + public void show(@RequestParam String id) { + log.info("SysOssController - show id:{}", id); + + sysOssService.show(id); + } + + /** + * COS工作流回调 + * @param callbackStr + * @return + + @PostMapping("/cos/callback") + public String cosCallback(@RequestBody String callbackStr){ + log.info("SysOssController - cosCallback callbackStr:{}", callbackStr); + + sysOssService.cosCallback(callbackStr); + + return "ok"; + } + */ +} diff --git a/src/main/java/com/org/oss/controller/commonController.java b/src/main/java/com/org/oss/controller/commonController.java new file mode 100644 index 0000000..cbbff31 --- /dev/null +++ b/src/main/java/com/org/oss/controller/commonController.java @@ -0,0 +1,28 @@ +package com.org.oss.controller; + +import com.org.system.controller.BaseController; +import com.org.utils.upload.CommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("common") +public class commonController extends BaseController { + + /** + * 通用下载接口 + * + * @param fileName + */ + @GetMapping("/download") + public void fileDownload(String fileName){ + log.info("commonController - fileDownload fileName:{}", fileName); + + CommonUtil.download(fileName, true); + } + + +} diff --git a/src/main/java/com/org/oss/entity/SysOss.java b/src/main/java/com/org/oss/entity/SysOss.java new file mode 100644 index 0000000..ba3cfaa --- /dev/null +++ b/src/main/java/com/org/oss/entity/SysOss.java @@ -0,0 +1,33 @@ +package com.org.oss.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.org.system.entity.BaseEntity; +import lombok.Data; + +@Data +public class SysOss extends BaseEntity { + + /** 附件ID **/ + @TableId(type = IdType.AUTO) + private String id; + + /** 来源ID **/ + private String sourceId; + + /** 附件名称 **/ + private String fileName; + + /** 附件新名称 **/ + private String newName; + + /** 附件类型 **/ + private String fileType; + + /** 附件存放地址 **/ + private String realPath; + + /** URL地址 **/ + private String url; + +} diff --git a/src/main/java/com/org/oss/mapper/SysOssMapper.java b/src/main/java/com/org/oss/mapper/SysOssMapper.java new file mode 100644 index 0000000..b59705c --- /dev/null +++ b/src/main/java/com/org/oss/mapper/SysOssMapper.java @@ -0,0 +1,22 @@ +package com.org.oss.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.oss.entity.SysOss; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface SysOssMapper extends BaseMapper { + + @Select("SELECT * FROM sys_oss WHERE url = #{fileUrl}") + SysOss findByUrl(@Param("fileUrl") String fileUrl); + + @Select("SELECT * FROM sys_oss WHERE real_path = #{realPath}") + SysOss findByRealPath(@Param("realPath") String realPath); + + @Select("select * from sys_oss where real_path like concat('%', #{suffix})") + List findByRealPathSuffix(@Param("suffix") String suffix); +} diff --git a/src/main/java/com/org/oss/service/SysOssService.java b/src/main/java/com/org/oss/service/SysOssService.java new file mode 100644 index 0000000..ab39cee --- /dev/null +++ b/src/main/java/com/org/oss/service/SysOssService.java @@ -0,0 +1,288 @@ +package com.org.oss.service; + +import cn.hutool.core.io.FileUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.oss.entity.SysOss; +import com.org.oss.mapper.SysOssMapper; +import com.org.system.enums.YesOrNoState; +import com.org.utils.AjaxResult; +import com.org.utils.SecurityUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import com.org.utils.upload.UpLoadUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class SysOssService extends ServiceImpl { + + /** + * 分页查询 + * + * @param sysOss + * @return + */ + public List queryList(SysOss sysOss){ + log.info("SysOssService - queryList sysOss:{}", sysOss); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if(StringUtils.isNotEmpty(sysOss.getFileName())) queryWrapper.like(SysOss::getFileName, sysOss.getFileName()); + + return list(queryWrapper); + } + + /** + * 文件上传 + * + * @param file + * @param sourceId + * @param fileType + * @return + * @throws IOException + */ + public AjaxResult upload(MultipartFile file, String sourceId, String fileType) throws IOException { + log.info("SysOssService - upload file:{}", file); + log.info("SysOssService - upload sourceId:{}", sourceId); + log.info("SysOssService - upload fileType:{}", fileType); + + // 上传文件 + String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); + String url = UpLoadUtil.uploadSuffix(file.getBytes(), suffix); + String[] urlArr = url.split("/"); + String fileName = urlArr[urlArr.length - 1]; + + // String realPath = url.replace(UpLoadUtil.domain, ""); + String realPath = url.replace(UpLoadUtil.proxyServer, ""); + realPath = UpLoadUtil.diskPath + realPath; + + // 保存文件信息 + SysOss sysOss = new SysOss(); + sysOss.setSourceId(sourceId); + sysOss.setFileName(file.getOriginalFilename()); + sysOss.setNewName(fileName); + sysOss.setFileType(fileType); + sysOss.setRealPath(realPath); + sysOss.setUrl(url); + // 富文本上传图片 没带token 增加是否登录判断 + if (SecurityUtil.isLogin()) sysOss.setCreateBy(SecurityUtil.getUserId()); + sysOss.setCreateTime(new Date()); + sysOss.setIsDelete(YesOrNoState.NO.getState()); + + save(sysOss); + // 返回兼容UEditor的参数 + return AjaxResult.success().put("url", url) + .put("name", sysOss.getFileName()) + .put("id", sysOss.getId()) + .put("uid", sysOss.getId()) + .put("createTime", sysOss.getCreateTime()); + } + + /** + * 删除文件上传记录 + * + * @param ids + */ + public void delete(Integer[] ids){ + log.info("SysOssService - delete ids:{}", ids); + + for (Integer id : ids) { + try { + SysOss oss = getById(id); + log.info("SysOssService - delete oss:{}", oss); + + FileUtil.del(oss.getRealPath()); + } catch (Exception err) { + log.error("删除文件出现错误:" + id, err); + } + } + removeByIds(Arrays.asList(ids)); + } + + /** + * 根据文件全路径数组删除上传文件 + * + * @param urls + */ + public void deleteByUrl(String[] urls){ + log.info("SysOssService - deleteByUrl urls:{}", urls); + + for (String url : urls) { + try { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysOss::getUrl, url); + + SysOss sysOss = getOne(queryWrapper); + log.info("SysOssService - deleteByUrl sysOss:{}", sysOss); + + FileUtil.del(sysOss.getRealPath()); + removeById(sysOss.getId()); + } catch (Exception err) { + log.error("删除文件出现错误:" + url, err); + } + } + } + + public void show(String dateDir, String fileName){ + log.info("SysOssService - show dateDir:{}", dateDir); + log.info("SysOssService - show fileName:{}", fileName); + + fileName = UpLoadUtil.diskPath + "/" + dateDir + "/" + fileName; + log.info("SysOssService - show fileName:{}", fileName); + + SysOss oss = findByRealPath(fileName); + + // 如果是视频文件 则走视频文件方法 + if(fileName.toLowerCase().endsWith("mp4") || fileName.toLowerCase().endsWith("flv") + || fileName.toLowerCase().endsWith("avi") || fileName.toLowerCase().endsWith("rm") + || fileName.toLowerCase().endsWith("rmvb") || fileName.toLowerCase().endsWith("wmv") + || fileName.toLowerCase().endsWith("m3u8")) { + UpLoadUtil.getVideo(fileName); + return; + } + + UpLoadUtil.getFile(fileName, oss.getFileName()); + } + + public void show(String id){ + log.info("SysOssService - show id:{}", id); + + SysOss oss = getById(id); + if(oss == null || StringUtils.isEmpty(oss.getId())) return ; + + String fileName = oss.getRealPath(); + log.info("SysOssService - show fileName:{}", fileName); + + // 如果是视频文件 则走视频文件方法 + if(fileName.toLowerCase().endsWith("mp4") || fileName.toLowerCase().endsWith("flv") + || fileName.toLowerCase().endsWith("avi") || fileName.toLowerCase().endsWith("rm") + ||fileName.toLowerCase().endsWith("rmvb") || fileName.toLowerCase().endsWith("wmv")) { + UpLoadUtil.getVideo(fileName); + return; + } + + UpLoadUtil.getFile(fileName, oss.getFileName()); + } + + + /** + * 通过url获取sysOss + * @param fileUrl + */ + public SysOss findByUrl(String fileUrl) { + log.info("SysOssService - findByUrl fileUrl:{}", fileUrl); + SysOss sysOss = baseMapper.findByUrl(fileUrl); + log.info("SysOssService - findByUrl sysOss:{}", sysOss); + + if (sysOss == null || StringUtils.isNull(sysOss.getId())) throw new CustomException("文件未找到!"); + + return sysOss; + } + + /** + * 通过url获取sysOss + * @param realPath + */ + public SysOss findByRealPath(String realPath) { + log.info("SysOssService - findByRealPath realPath:{}", realPath); + SysOss sysOss = baseMapper.findByRealPath(realPath); + log.info("SysOssService - findByRealPath sysOss:{}", sysOss); + + if (sysOss == null || StringUtils.isNull(sysOss.getId())) throw new CustomException("文件未找到!"); + + return sysOss; + } + + + public AjaxResult uploadImg(MultipartFile file, String sourceId, String fileType, long fileSize) throws IOException { + log.info("SysOssService - uploadImg file:{}", file); + log.info("SysOssService - uploadImg sourceId:{}", sourceId); + log.info("SysOssService - uploadImg fileType:{}", fileType); + log.info("SysOssService - uploadImg fileSize:{}", fileSize); + + // 上传文件 + /*//压缩图片到指定大小以内 + byte[] bytes = PicUtils.compressPicForScale(file.getBytes(), fileSize); + ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); + String suffix = ".jpg";*/ + // 上传文件 + String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); + String url = UpLoadUtil.uploadSuffix(file.getBytes(), suffix); + String[] urlArr = url.split("/"); + String fileName = urlArr[urlArr.length - 1]; + + String realPath = url.replace(UpLoadUtil.proxyServer, ""); + realPath = UpLoadUtil.diskPath + realPath; + // String realPath = url.replace(UpLoadUtil.domain, ""); + + String originalFilename = file.getOriginalFilename(); + String suffix1 = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(); + originalFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")) + suffix1; + + // 保存文件信息 + SysOss sysOss = new SysOss(); + sysOss.setSourceId(sourceId); + sysOss.setFileName(originalFilename); + sysOss.setNewName(fileName); + sysOss.setFileType(fileType); + sysOss.setRealPath(realPath); + sysOss.setUrl(url); + sysOss.setCreateBy(SecurityUtil.getUserId()); + sysOss.setCreateTime(new Date()); + sysOss.setIsDelete(YesOrNoState.NO.getState()); + + save(sysOss); + // 返回兼容UEditor的参数 + return AjaxResult.success().put("url", url) + .put("name", sysOss.getFileName()) + .put("id", sysOss.getId()) + .put("uid", sysOss.getId()) + .put("createTime", sysOss.getCreateTime()); + } + + + + /** + * COS工作流回调 + * @param callbackStr + + public void cosCallback(String callbackStr) { + log.info("SysOssService - cosCallback callbackStr:{}", callbackStr); + + JSONObject jsonObject = JSONUtil.parseObj(callbackStr); + JSONObject workflowExecution = jsonObject.getJSONObject("WorkflowExecution"); + + String state = workflowExecution.getStr("State"); + log.info("SysOssService - cosCallback state:{}", state); + + if(!"Success".equals(state)) return; + + String object = workflowExecution.getStr("Object"); + log.info("SysOssService - cosCallback object:{}", object); + + if(Validator.isNotEmpty(object)){ + String url = object; + String bakUrl = String.format("%s_bak%s", object.substring(0, object.lastIndexOf(".")), object.substring(object.lastIndexOf("."))); + String transcodingUrl = String.format("%s_transcoding%s", object.substring(0, object.lastIndexOf(".")), object.substring(object.lastIndexOf("."))); + + log.info("SysOssService - cosCallback url:{}", url); + log.info("SysOssService - cosCallback bakUrl:{}", bakUrl); + log.info("SysOssService - cosCallback transcodingUrl:{}", transcodingUrl); + + // 备份源视频文件 + UpLoadUtil.copyObject(url, bakUrl); + UpLoadUtil.deleteObject(url); + + // 转移转码后的视频文件 + UpLoadUtil.copyObject(transcodingUrl, url); + UpLoadUtil.deleteObject(transcodingUrl); + } + } + */ +} diff --git a/src/main/java/com/org/system/annotation/CheckVerify.java b/src/main/java/com/org/system/annotation/CheckVerify.java new file mode 100644 index 0000000..fe0c7f1 --- /dev/null +++ b/src/main/java/com/org/system/annotation/CheckVerify.java @@ -0,0 +1,13 @@ +package com.org.system.annotation; + +import java.lang.annotation.*; + +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface CheckVerify { + public String phone() default ""; + public String type() default ""; + public String code() default ""; +} diff --git a/src/main/java/com/org/system/annotation/Excel.java b/src/main/java/com/org/system/annotation/Excel.java new file mode 100644 index 0000000..651f3f1 --- /dev/null +++ b/src/main/java/com/org/system/annotation/Excel.java @@ -0,0 +1,142 @@ +package com.org.system.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.math.BigDecimal; + +/** + * 自定义导出Excel数据注解 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Excel +{ + /** + * 导出时在excel中排序 + */ + public int sort() default Integer.MAX_VALUE; + + /** + * 导出到Excel中的名字. + */ + public String name() default ""; + + /** + * 日期格式, 如: yyyy-MM-dd + */ + public String dateFormat() default ""; + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + public String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + public String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + public String separator() default ","; + + /** + * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) + */ + public int scale() default -1; + + /** + * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN + */ + public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; + + /** + * 导出类型(0数字 1字符串) + */ + public ColumnType cellType() default ColumnType.STRING; + + /** + * 导出时在excel中每个列的高度 单位为字符 + */ + public double height() default 14; + + /** + * 导出时在excel中每个列的宽 单位为字符 + */ + public double width() default 16; + + /** + * 文字后缀,如% 90 变成90% + */ + public String suffix() default ""; + + /** + * 当值为空时,字段的默认值 + */ + public String defaultValue() default ""; + + /** + * 提示信息 + */ + public String prompt() default ""; + + /** + * 设置只能选择不能输入的列内容. + */ + public String[] combo() default {}; + + /** + * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. + */ + public boolean isExport() default true; + + /** + * 另一个类中的属性名称,支持多级获取,以小数点隔开 + */ + public String targetAttr() default ""; + + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + public boolean isStatistics() default false; + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + Type type() default Type.ALL; + + public enum Type + { + ALL(0), EXPORT(1), IMPORT(2); + private final int value; + + Type(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } + + public enum ColumnType + { + NUMERIC(0), STRING(1); + private final int value; + + ColumnType(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/org/system/annotation/Excels.java b/src/main/java/com/org/system/annotation/Excels.java new file mode 100644 index 0000000..58d09e0 --- /dev/null +++ b/src/main/java/com/org/system/annotation/Excels.java @@ -0,0 +1,18 @@ +package com.org.system.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解集 + * + * @author ruoyi + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Excels +{ + Excel[] value(); +} diff --git a/src/main/java/com/org/system/annotation/Log.java b/src/main/java/com/org/system/annotation/Log.java new file mode 100644 index 0000000..c9efc93 --- /dev/null +++ b/src/main/java/com/org/system/annotation/Log.java @@ -0,0 +1,26 @@ +package com.org.system.annotation; + +import com.org.system.enums.BusinessType; +import com.org.system.enums.OperatorType; + +import java.lang.annotation.*; + +/** 自定义操作日志记录注解 **/ +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log +{ + /** 模块 **/ + public String title() default ""; + + /** 功能 **/ + public BusinessType businessType() default BusinessType.OTHER; + + /** 操作人类别 **/ + public OperatorType operatorType() default OperatorType.MANAGE; + + /** 是否保存请求的参数 **/ + public boolean isSaveRequestData() default true; + +} diff --git a/src/main/java/com/org/system/aspectj/LogAspect.java b/src/main/java/com/org/system/aspectj/LogAspect.java new file mode 100644 index 0000000..38cd75e --- /dev/null +++ b/src/main/java/com/org/system/aspectj/LogAspect.java @@ -0,0 +1,198 @@ +package com.org.system.aspectj; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.servlet.ServletUtil; +import com.alibaba.fastjson.JSON; +import com.org.system.annotation.Log; +import com.org.system.config.async.AsyncFactory; +import com.org.system.config.async.AsyncManager; +import com.org.system.entity.LoginUser; +import com.org.system.entity.SysOperLog; +import com.org.system.enums.BusinessStatus; +import com.org.system.service.TokenService; +import com.org.utils.HttpServletUtil; +import com.org.utils.SpringUtil; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.HandlerMapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Map; + +/** 操作日志记录处理 **/ +@Aspect +@Component +public class LogAspect +{ + private static final Logger log = LoggerFactory.getLogger(LogAspect.class); + + // 配置织入点 + @Pointcut("@annotation(com.org.system.annotation.Log)") + public void logPointCut() { } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) + { + handleLog(joinPoint, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "logPointCut()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) { handleLog(joinPoint, e, null); } + + protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) { + try { + // 获得注解 + Log controllerLog = getAnnotationLog(joinPoint); + if (controllerLog == null) return; + + // 获取当前的用户 + LoginUser loginUser = SpringUtil.getBean(TokenService.class).getLoginUser(HttpServletUtil.getRequest()); + + // *========数据库日志=========*// + SysOperLog operLog = new SysOperLog(); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + operLog.setOperIp(ServletUtil.getClientIP(HttpServletUtil.getRequest(), "")); + // 返回参数 + operLog.setJsonResult(JSON.toJSONString(jsonResult)); + + operLog.setOperUrl(HttpServletUtil.getRequest().getRequestURI()); + + if (loginUser != null) operLog.setOperName(loginUser.getUser().getUserName()); + + if (e != null) { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StrUtil.subWithLength(e.getMessage(), 0, 2000)); + } + + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + + String methodName = joinPoint.getSignature().getName(); + + operLog.setMethod(className + "." + methodName + "()"); + + // 设置请求方式 + operLog.setRequestMethod(HttpServletUtil.getRequest().getMethod()); + + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog); + + operLog.setOperTime(new Date()); + + // 保存数据库 + AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("==前置通知异常=="); + log.error("异常信息:{}", exp); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception { + String requestMethod = operLog.getRequestMethod(); + if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { + String params = argsArrayToString(joinPoint.getArgs()); + operLog.setOperParam(StrUtil.subWithLength(params, 0, 2000)); + } else { + Map paramsMap = (Map) HttpServletUtil.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + operLog.setOperParam(StrUtil.subWithLength(paramsMap.toString(), 0, 2000)); + } + } + + /** + * 是否存在注解,如果存在就获取 + */ + private Log getAnnotationLog(JoinPoint joinPoint) throws Exception { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + + if (method != null) { + return method.getAnnotation(Log.class); + } + return null; + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) { + StringBuilder params = new StringBuilder(); + if (paramsArray != null && paramsArray.length > 0) { + for (int i = 0; i < paramsArray.length; i++) { + if (!isFilterObject(paramsArray[i])) { + Object jsonObj = null; + try { + jsonObj = JSON.toJSON(paramsArray[i]); + } catch (Exception e){ + log.error("{}", e); + } + if(jsonObj != null) params.append(jsonObj.toString()).append(" "); + } + } + } + return params.toString().trim(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + public boolean isFilterObject(final Object o) { + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse; + } +} diff --git a/src/main/java/com/org/system/config/async/AsyncFactory.java b/src/main/java/com/org/system/config/async/AsyncFactory.java new file mode 100644 index 0000000..cdf1d9e --- /dev/null +++ b/src/main/java/com/org/system/config/async/AsyncFactory.java @@ -0,0 +1,76 @@ +package com.org.system.config.async; + +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.org.system.entity.SysOperLog; +import com.org.system.service.SysOperLogService; +import com.org.utils.Constants; +import com.org.utils.HttpServletUtil; +import com.org.utils.SpringUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.TimerTask; + +/** 异步工厂(产生任务用) **/ +@Slf4j +public class AsyncFactory { + + /** + * 记录登录信息 + * + * @param username 用户名 + * @param status 状态 + * @param message 消息 + * @param args 列表 + * @return 任务task + */ + public static TimerTask recordLogininfor(final String username, final String status, final String message, + final Object... args) { + final UserAgent userAgent = UserAgentUtil.parse(HttpServletUtil.getRequest().getHeader("User-Agent")); + final String ip = ServletUtil.getClientIP(HttpServletUtil.getRequest(), ""); + return new TimerTask() { + @Override + public void run() { + String address = ""; + String os = userAgent.getOs().getName(); // 获取客户端操作系统 + String browser = userAgent.getBrowser().getName(); // 获取客户端浏览器 + + // 封装对象 + SysOperLog sysOperLog = new SysOperLog(); + sysOperLog.setTitle("用户登陆"); + sysOperLog.setMethod("/login"); + sysOperLog.setRequestMethod(HttpServletUtil.getRequest().getMethod()); + sysOperLog.setOperName(username); + sysOperLog.setOperIp(ip); + sysOperLog.setOperLocation(address); + sysOperLog.setErrorMsg(browser+";"+os+";"+message); + sysOperLog.setOperTime(new Date()); + + // 日志状态 + if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) sysOperLog.setStatus(Integer.parseInt(Constants.SUCCESS)); + else if (Constants.LOGIN_FAIL.equals(status)) sysOperLog.setStatus(Integer.parseInt(Constants.FAIL)); + + // 插入数据 + SpringUtil.getBean(SysOperLogService.class).save(sysOperLog); + } + }; + } + + /** + * 操作日志记录 + * + * @param sysOperLog 操作日志信息 + * @return 任务task + */ + public static TimerTask recordOper(final SysOperLog sysOperLog) { + return new TimerTask() { + @Override + public void run() { + // 远程查询操作地点 + SpringUtil.getBean(SysOperLogService.class).save(sysOperLog); + } + }; + } +} diff --git a/src/main/java/com/org/system/config/async/AsyncManager.java b/src/main/java/com/org/system/config/async/AsyncManager.java new file mode 100644 index 0000000..d4f415a --- /dev/null +++ b/src/main/java/com/org/system/config/async/AsyncManager.java @@ -0,0 +1,54 @@ +package com.org.system.config.async; + +import com.org.utils.HttpServletUtil; +import com.org.utils.SpringUtil; +import com.org.utils.Threads; +import org.springframework.web.context.request.RequestContextHolder; + +import java.util.TimerTask; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** 异步任务管理器 **/ +public class AsyncManager +{ + /** + * 操作延迟10毫秒 + */ + private final int OPERATE_DELAY_TIME = 10; + + /** + * 异步操作任务调度线程池 + */ + private ScheduledExecutorService executor = SpringUtil.getBean("scheduledExecutorService"); + + /** + * 单例模式 + */ + private AsyncManager(){} + + private static AsyncManager me = new AsyncManager(); + + public static AsyncManager me() + { + return me; + } + + /** + * 执行任务 + * + * @param task 任务 + */ + public void execute(TimerTask task) { + RequestContextHolder.setRequestAttributes(HttpServletUtil.getServletRequestAttributes(), true); + executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS); + } + + /** + * 停止任务线程池 + */ + public void shutdown() + { + Threads.shutdownAndAwaitTermination(executor); + } +} diff --git a/src/main/java/com/org/system/config/config.java b/src/main/java/com/org/system/config/config.java new file mode 100644 index 0000000..c2da5e9 --- /dev/null +++ b/src/main/java/com/org/system/config/config.java @@ -0,0 +1,10 @@ +package com.org.system.config; + +import org.springframework.context.annotation.Configuration; + +@Configuration +public class config { + + + +} diff --git a/src/main/java/com/org/system/config/redis/RedisCache.java b/src/main/java/com/org/system/config/redis/RedisCache.java new file mode 100644 index 0000000..660702e --- /dev/null +++ b/src/main/java/com/org/system/config/redis/RedisCache.java @@ -0,0 +1,204 @@ +package com.org.system.config.redis; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** spring redis 工具类 **/ +@SuppressWarnings(value = { "unchecked", "rawtypes" }) +@Component +public class RedisCache { + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String key, final T value) { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { + redisTemplate.opsForValue().set(key, value, timeout, timeUnit); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout) { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @param unit 时间单位 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout, final TimeUnit unit) { + return redisTemplate.expire(key, timeout, unit); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public T getCacheObject(final String key) { + ValueOperations operation = redisTemplate.opsForValue(); + return operation.get(key); + } + + /** + * 删除单个对象 + * + * @param key + */ + public boolean deleteObject(final String key) { + return redisTemplate.delete(key); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + * @return + */ + public long deleteObject(final Collection collection) { + return redisTemplate.delete(collection); + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public long setCacheList(final String key, final List dataList) { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(final String key) { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public long setCacheSet(final String key, final Set dataSet) { + Long count = redisTemplate.opsForSet().add(key, dataSet); + return count == null ? 0 : count; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(final String key) { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap(final String key, final Map dataMap) { + if (dataMap != null) redisTemplate.opsForHash().putAll(key, dataMap); + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(final String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public void setCacheMapValue(final String key, final String hKey, final T value) { + redisTemplate.opsForHash().put(key, hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public T getCacheMapValue(final String key, final String hKey) { + HashOperations opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public List getMultiCacheMapValue(final String key, final Collection hKeys) { + return redisTemplate.opsForHash().multiGet(key, hKeys); + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public Collection keys(final String pattern) { + return redisTemplate.keys(pattern); + } +} diff --git a/src/main/java/com/org/system/config/security/AuthenticationEntryPointImpl.java b/src/main/java/com/org/system/config/security/AuthenticationEntryPointImpl.java new file mode 100644 index 0000000..97df7a2 --- /dev/null +++ b/src/main/java/com/org/system/config/security/AuthenticationEntryPointImpl.java @@ -0,0 +1,28 @@ +package com.org.system.config.security; + +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.ContentType; +import com.alibaba.fastjson.JSONObject; +import com.org.utils.AjaxResult; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.Charset; + +/** 认证失败处理类 返回未授权 **/ +@Component +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable { + private static final long serialVersionUID = 1L; + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { + String msg = String.format("请求访问:%s,认证失败,无法访问系统资源", request.getRequestURI()); + ServletUtil.write(response, JSONObject.toJSONString(AjaxResult.error(HttpStatus.UNAUTHORIZED.value(), msg)), ContentType.JSON.toString(Charset.defaultCharset())); + } +} diff --git a/src/main/java/com/org/system/config/security/JwtAuthenticationTokenFilter.java b/src/main/java/com/org/system/config/security/JwtAuthenticationTokenFilter.java new file mode 100644 index 0000000..c201dcc --- /dev/null +++ b/src/main/java/com/org/system/config/security/JwtAuthenticationTokenFilter.java @@ -0,0 +1,39 @@ +package com.org.system.config.security; + +import com.org.system.entity.LoginUser; +import com.org.system.service.TokenService; +import com.org.utils.SecurityUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** token过滤器 验证token有效性 **/ +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { + @Autowired + private TokenService tokenService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { + LoginUser loginUser = tokenService.getLoginUser(request); + + if (null != loginUser && null == SecurityUtil.getAuthentication()) { + tokenService.verifyToken(loginUser); + + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities()); + authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + } + chain.doFilter(request, response); + } +} diff --git a/src/main/java/com/org/system/config/security/LogoutSuccessHandlerImpl.java b/src/main/java/com/org/system/config/security/LogoutSuccessHandlerImpl.java new file mode 100644 index 0000000..b6d2160 --- /dev/null +++ b/src/main/java/com/org/system/config/security/LogoutSuccessHandlerImpl.java @@ -0,0 +1,51 @@ +package com.org.system.config.security; + +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.ContentType; +import com.alibaba.fastjson.JSONObject; +import com.org.system.config.async.AsyncFactory; +import com.org.system.config.async.AsyncManager; +import com.org.system.entity.LoginUser; +import com.org.system.service.TokenService; +import com.org.utils.AjaxResult; +import com.org.utils.Constants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.Charset; + +/** 自定义退出处理类 返回成功 **/ +@Configuration +public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler +{ + @Autowired + private TokenService tokenService; + + /** + * 退出处理 + * + * @return + */ + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + LoginUser loginUser = tokenService.getLoginUser(request); + + if (null != loginUser) { + String userName = loginUser.getUsername(); + + // 删除用户缓存记录 + tokenService.delLoginUser(loginUser.getToken()); + + // 记录用户退出日志 + AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); + } + ServletUtil.write(response, JSONObject.toJSONString(AjaxResult.success("退出成功")), ContentType.JSON.toString(Charset.defaultCharset())); + } +} diff --git a/src/main/java/com/org/system/config/security/Md5PasswordEncoder.java b/src/main/java/com/org/system/config/security/Md5PasswordEncoder.java new file mode 100644 index 0000000..f58a6f6 --- /dev/null +++ b/src/main/java/com/org/system/config/security/Md5PasswordEncoder.java @@ -0,0 +1,67 @@ +package com.org.system.config.security; + +import cn.hutool.crypto.SecureUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Slf4j +public class Md5PasswordEncoder implements PasswordEncoder { + + private String salt; + + public void setSalt(String salt) { + this.salt = salt; + } + + private static Md5PasswordEncoder instance = new Md5PasswordEncoder(); + + private Md5PasswordEncoder() { + } + //以单例模式构造 + public static Md5PasswordEncoder getInstance() { + return instance; + } + + // 用户密码加盐 + private String mergePasswordAndSalt(CharSequence password) { + if (password == null) password = ""; + + if ((salt == null) || "".equals(salt)) { + return password.toString(); + } else { + return password + salt; + } + } + + /** + * MD5加密 + * + * @param rawPassword 原始密码 + * @return 加密后的md5密文 + */ + @Override + public String encode(CharSequence rawPassword) { + + String result = null; + try { + String passwordAndSalt = mergePasswordAndSalt(rawPassword); + + result = SecureUtil.md5(passwordAndSalt); + } catch (Exception ignored) { + + } + return result; + } + + /** + * 密码比较 + * + * @param rawPassword 原始密码 + * @param encodedPassword 加密后的密码 + * @return boolean + */ + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return encodedPassword.equalsIgnoreCase(encode(rawPassword)); + } +} diff --git a/src/main/java/com/org/system/config/security/SecurityConfig.java b/src/main/java/com/org/system/config/security/SecurityConfig.java new file mode 100644 index 0000000..fa2ceec --- /dev/null +++ b/src/main/java/com/org/system/config/security/SecurityConfig.java @@ -0,0 +1,124 @@ +package com.org.system.config.security; + +import com.org.system.service.CustomUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** spring security配置 **/ +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter +{ + /** 自定义用户认证逻辑 **/ + @Autowired + private CustomUserService customUserService; + /** 认证失败处理类 **/ + @Autowired + private AuthenticationEntryPointImpl unauthorizedHandler; + + /** 退出处理类 **/ + @Autowired + private LogoutSuccessHandlerImpl logoutSuccessHandler; + + /** token认证过滤器 **/ + @Autowired + private JwtAuthenticationTokenFilter authenticationTokenFilter; + + /** + * 解决 无法直接注入 AuthenticationManager + * + * @return + * @throws Exception + */ + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + /** + * anyRequest | 匹配所有请求路径 + * access | SpringEl表达式结果为true时可以访问 + * anonymous | 匿名可以访问 + * denyAll | 用户不能访问 + * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录) + * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问 + * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问 + * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问 + * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问 + * hasRole | 如果有参数,参数表示角色,则其角色可以访问 + * permitAll | 用户可以任意访问 + * rememberMe | 允许通过remember-me登录的用户访问 + * authenticated | 用户登录后可访问 + */ + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception + { + httpSecurity + // CSRF禁用,因为不使用session + .csrf().disable() + // 认证失败处理类 + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + // 基于token,所以不需要session + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + // 过滤请求 + .authorizeRequests() + + // 对于登录 login 允许匿名访问 + .antMatchers("/login").anonymous() + .antMatchers("/person/register/invitation").anonymous() + .antMatchers("/person/register/add").anonymous() + + // 文件下载接口例外 + .antMatchers("/sys/oss/show/**").anonymous() + .antMatchers("/common/download").anonymous() + + .antMatchers("/sys/ueditor/config").anonymous() + + // 获取短信验证码接口 + .antMatchers("/sys/sms/getCode").anonymous() + + // 获取数据词典项下拉选 + .antMatchers("/sys/dictionary/item/mobile/dropDown").anonymous() + + // 获取app版本管理相关信息 + .antMatchers("/sys/appVersion/getVersionNumByAppType","/sys/appVersion/clearVersionCache").anonymous() + + // COS队列回调 + // .antMatchers("/sys/oss/cos/callback").anonymous() + + // 除上面外的所有请求全部需要鉴权认证 + .anyRequest().authenticated() + .and() + .headers().frameOptions().disable(); + httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); + // 添加JWT filter + httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + // 添加CORS filter + // httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); + // httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); + } + + + /** + * 强散列哈希加密实现 + */ + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } + @Bean + public Md5PasswordEncoder passwordEncoder(){ return Md5PasswordEncoder.getInstance(); } + + /** 身份认证接口 **/ + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + /** user Details Service验证 **/ + auth.userDetailsService(customUserService).passwordEncoder(passwordEncoder()); + } +} diff --git a/src/main/java/com/org/system/config/thread/ThreadPoolConfig.java b/src/main/java/com/org/system/config/thread/ThreadPoolConfig.java new file mode 100644 index 0000000..ac15263 --- /dev/null +++ b/src/main/java/com/org/system/config/thread/ThreadPoolConfig.java @@ -0,0 +1,56 @@ +package com.org.system.config.thread; + +import com.org.utils.Threads; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +/** 线程池配置 **/ +@Configuration +public class ThreadPoolConfig +{ + // 核心线程池大小 + private int corePoolSize = 50; + + // 最大可创建的线程数 + private int maxPoolSize = 200; + + // 队列最大长度 + private int queueCapacity = 1000; + + // 线程池维护线程所允许的空闲时间 + private int keepAliveSeconds = 300; + + @Bean(name = "threadPoolTaskExecutor") + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setMaxPoolSize(maxPoolSize); + executor.setCorePoolSize(corePoolSize); + executor.setQueueCapacity(queueCapacity); + executor.setKeepAliveSeconds(keepAliveSeconds); + + // 线程池对拒绝任务(无线程可用)的处理策略 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() { + return new ScheduledThreadPoolExecutor(corePoolSize, + new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + } +} diff --git a/src/main/java/com/org/system/config/validation/Insert.java b/src/main/java/com/org/system/config/validation/Insert.java new file mode 100644 index 0000000..d694a25 --- /dev/null +++ b/src/main/java/com/org/system/config/validation/Insert.java @@ -0,0 +1,7 @@ +package com.org.system.config.validation; + +import javax.validation.groups.Default; + +/** 分组校验 新增 **/ +public interface Insert extends Default { +} diff --git a/src/main/java/com/org/system/config/validation/Update.java b/src/main/java/com/org/system/config/validation/Update.java new file mode 100644 index 0000000..f91e2b2 --- /dev/null +++ b/src/main/java/com/org/system/config/validation/Update.java @@ -0,0 +1,7 @@ +package com.org.system.config.validation; + +import javax.validation.groups.Default; + +/** 分组校验 修改 **/ +public interface Update extends Default { +} diff --git a/src/main/java/com/org/system/config/xss/EscapeUtil.java b/src/main/java/com/org/system/config/xss/EscapeUtil.java new file mode 100644 index 0000000..f913474 --- /dev/null +++ b/src/main/java/com/org/system/config/xss/EscapeUtil.java @@ -0,0 +1,118 @@ +package com.org.system.config.xss; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HTMLFilter; + +/** 转义和反转义工具类 **/ +public class EscapeUtil { + public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + + private static final char[][] TEXT = new char[64][]; + + static { + for (int i = 0; i < 64; i++) { + TEXT[i] = new char[] { (char) i }; + } + + // special HTML characters + TEXT['\''] = "'".toCharArray(); // 单引号 + TEXT['"'] = """.toCharArray(); // 单引号 + TEXT['&'] = "&".toCharArray(); // &符 + TEXT['<'] = "<".toCharArray(); // 小于号 + TEXT['>'] = ">".toCharArray(); // 大于号 + } + + /** + * 转义文本中的HTML字符为安全的字符 + * + * @param text 被转义的文本 + * @return 转义后的文本 + */ + public static String escape(String text) { + return encode(text); + } + + /** + * 还原被转义的HTML特殊字符 + * + * @param content 包含转义符的HTML内容 + * @return 转换后的字符串 + */ + public static String unescape(String content) { + return decode(content); + } + + /** + * 清除所有HTML标签,但是不删除标签内的内容 + * + * @param content 文本 + * @return 清除标签后的文本 + */ + public static String clean(String content) { + return new HTMLFilter().filter(content); + } + + /** + * Escape编码 + * + * @param text 被编码的文本 + * @return 编码后的字符 + */ + private static String encode(String text) { + int len; + if ((text == null) || ((len = text.length()) == 0)) { + return StrUtil.EMPTY; + } + StringBuilder buffer = new StringBuilder(len + (len >> 2)); + char c; + for (int i = 0; i < len; i++) { + c = text.charAt(i); + if (c < 64) { + buffer.append(TEXT[c]); + } else { + buffer.append(c); + } + } + return buffer.toString(); + } + + /** + * Escape解码 + * + * @param content 被转义的内容 + * @return 解码后的字符串 + */ + public static String decode(String content) + { + if (StrUtil.isEmpty(content)) { + return content; + } + + StringBuilder tmp = new StringBuilder(content.length()); + int lastPos = 0, pos = 0; + char ch; + while (lastPos < content.length()) { + pos = content.indexOf("%", lastPos); + if (pos == lastPos) { + if (content.charAt(pos + 1) == 'u') { + ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16); + tmp.append(ch); + lastPos = pos + 6; + } else { + ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16); + tmp.append(ch); + lastPos = pos + 3; + } + } else { + if (pos == -1) { + tmp.append(content.substring(lastPos)); + lastPos = content.length(); + } else { + tmp.append(content.substring(lastPos, pos)); + lastPos = pos; + } + } + } + return tmp.toString(); + } +} diff --git a/src/main/java/com/org/system/config/xss/FilterConfig.java b/src/main/java/com/org/system/config/xss/FilterConfig.java new file mode 100644 index 0000000..d11b624 --- /dev/null +++ b/src/main/java/com/org/system/config/xss/FilterConfig.java @@ -0,0 +1,53 @@ +package com.org.system.config.xss; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.DispatcherType; +import java.util.HashMap; +import java.util.Map; + +/** Filter配置 **/ +@Configuration +public class FilterConfig { + @Value("${xss.enabled}") + private String enabled; + + @Value("${xss.excludes}") + private String excludes; + + @Value("${xss.urlPatterns}") + private String urlPatterns; + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + public FilterRegistrationBean xssFilterRegistration() + { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new XssFilter()); + registration.addUrlPatterns(urlPatterns.split(",")); + registration.setName("xssFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + Map initParameters = new HashMap(); + initParameters.put("excludes", excludes); + initParameters.put("enabled", enabled); + registration.setInitParameters(initParameters); + return registration; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Bean + public FilterRegistrationBean someFilterRegistration() + { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new RepeatableFilter()); + registration.addUrlPatterns("/*"); + registration.setName("repeatableFilter"); + registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE); + return registration; + } + +} diff --git a/src/main/java/com/org/system/config/xss/HttpHelper.java b/src/main/java/com/org/system/config/xss/HttpHelper.java new file mode 100644 index 0000000..866cbeb --- /dev/null +++ b/src/main/java/com/org/system/config/xss/HttpHelper.java @@ -0,0 +1,39 @@ +package com.org.system.config.xss; + +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.ServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; + +/** 通用http工具封装 **/ +@Slf4j +public class HttpHelper { + + public static String getBodyString(ServletRequest request) { + StringBuilder sb = new StringBuilder(); + BufferedReader reader = null; + try (InputStream inputStream = request.getInputStream()) { + reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); + String line = ""; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } catch (IOException e) { + log.warn("getBodyString出现问题!"); + log.error("{}", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + log.error("{}", e); + } + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/org/system/config/xss/RepeatableFilter.java b/src/main/java/com/org/system/config/xss/RepeatableFilter.java new file mode 100644 index 0000000..e874a78 --- /dev/null +++ b/src/main/java/com/org/system/config/xss/RepeatableFilter.java @@ -0,0 +1,38 @@ +package com.org.system.config.xss; + +import cn.hutool.core.util.StrUtil; +import org.springframework.http.MediaType; + +import javax.servlet.FilterConfig; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** Repeatable 过滤器 **/ +public class RepeatableFilter implements Filter +{ + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ServletRequest requestWrapper = null; + if (request instanceof HttpServletRequest && StrUtil.equalsAnyIgnoreCase(request.getContentType(), + MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE)) { + requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); + } + if (null == requestWrapper) { + chain.doFilter(request, response); + } else { + chain.doFilter(requestWrapper, response); + } + } + + @Override + public void destroy() { + + } +} diff --git a/src/main/java/com/org/system/config/xss/RepeatedlyRequestWrapper.java b/src/main/java/com/org/system/config/xss/RepeatedlyRequestWrapper.java new file mode 100644 index 0000000..8a415ff --- /dev/null +++ b/src/main/java/com/org/system/config/xss/RepeatedlyRequestWrapper.java @@ -0,0 +1,57 @@ +package com.org.system.config.xss; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** 构建可重复读取inputStream的request **/ +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { + private final byte[] body; + + public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { + super(request); + request.setCharacterEncoding("UTF-8"); + response.setCharacterEncoding("UTF-8"); + + body = HttpHelper.getBodyString(request).getBytes("UTF-8"); + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + + return new ServletInputStream() { + + @Override + public int read() throws IOException { + return bais.read(); + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } +} diff --git a/src/main/java/com/org/system/config/xss/XssFilter.java b/src/main/java/com/org/system/config/xss/XssFilter.java new file mode 100644 index 0000000..f17865d --- /dev/null +++ b/src/main/java/com/org/system/config/xss/XssFilter.java @@ -0,0 +1,73 @@ +package com.org.system.config.xss; + +import cn.hutool.core.util.StrUtil; + +import javax.servlet.FilterConfig; +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** 防止XSS攻击的过滤器 **/ +public class XssFilter implements Filter { + /** 排除链接 **/ + public List excludes = new ArrayList<>(); + + /** xss过滤开关 **/ + public boolean enabled = false; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + String tempExcludes = filterConfig.getInitParameter("excludes"); + String tempEnabled = filterConfig.getInitParameter("enabled"); + if (StrUtil.isNotEmpty(tempExcludes)) { + String[] url = tempExcludes.split(","); + for (int i = 0; url != null && i < url.length; i++) { + excludes.add(url[i]); + } + } + if (StrUtil.isNotEmpty(tempEnabled)) { + enabled = Boolean.valueOf(tempEnabled); + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + if (handleExcludeURL(req, resp)) { + chain.doFilter(request, response); + return; + } + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { + if (!enabled) { + return true; + } + if (excludes == null || excludes.isEmpty()) { + return false; + } + String url = request.getServletPath(); + for (String pattern : excludes) { + Pattern p = Pattern.compile("^" + pattern); + Matcher m = p.matcher(url); + if (m.find()) { + return true; + } + } + return false; + } + + @Override + public void destroy() { + + } +} \ No newline at end of file diff --git a/src/main/java/com/org/system/config/xss/XssHttpServletRequestWrapper.java b/src/main/java/com/org/system/config/xss/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..71495af --- /dev/null +++ b/src/main/java/com/org/system/config/xss/XssHttpServletRequestWrapper.java @@ -0,0 +1,86 @@ +package com.org.system.config.xss; + +import cn.hutool.core.util.StrUtil; +import org.apache.commons.io.IOUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** XSS过滤处理 **/ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { + /** + * @param request + */ + public XssHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + } + + @Override + public String[] getParameterValues(String name) { + String[] values = super.getParameterValues(name); + if (values != null) { + int length = values.length; + String[] escapseValues = new String[length]; + for (int i = 0; i < length; i++) { + // 防xss攻击和过滤前后空格 + escapseValues[i] = EscapeUtil.clean(values[i]).trim(); + } + return escapseValues; + } + return super.getParameterValues(name); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + // 非json类型,直接返回 + if (!isJsonRequest()) { + return super.getInputStream(); + } + + // 为空,直接返回 + String json = IOUtils.toString(super.getInputStream(), "utf-8"); + if (StrUtil.isEmpty(json)) { + return super.getInputStream(); + } + + // xss过滤 + json = EscapeUtil.clean(json).trim(); + final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8")); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + + @Override + public int read() throws IOException { + return bis.read(); + } + }; + } + + /** + * 是否是Json请求 + * + */ + public boolean isJsonRequest() { + String header = super.getHeader(HttpHeaders.CONTENT_TYPE); + return MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(header) + || MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(header); + } +} \ No newline at end of file diff --git a/src/main/java/com/org/system/controller/BaseController.java b/src/main/java/com/org/system/controller/BaseController.java new file mode 100644 index 0000000..3cc26a2 --- /dev/null +++ b/src/main/java/com/org/system/controller/BaseController.java @@ -0,0 +1,87 @@ +package com.org.system.controller; + +import cn.hutool.core.date.DateUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.org.utils.AjaxResult; +import com.org.utils.SqlUtil; +import com.org.utils.StringUtils; +import com.org.utils.page.PageDomain; +import com.org.utils.page.TableDataInfo; +import com.org.utils.page.TableSupport; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; + +import java.beans.PropertyEditorSupport; +import java.util.Date; +import java.util.List; + +/** web层通用数据处理 **/ +public class BaseController { + + /** + * 将前台传递过来的日期格式的字符串,自动转化为Date类型 + * + * @param binder + */ + @InitBinder + public void initBinder(WebDataBinder binder) { + // Date 类型转换 + binder.registerCustomEditor(Date.class, new PropertyEditorSupport() { + @Override + public void setAsText(String text) { + setValue(DateUtil.parseDate(text)); + } + }); + } + + /** + * 设置请求分页数据 + * + */ + protected void startPage() { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Integer pageNum = pageDomain.getPageNum(); + Integer pageSize = pageDomain.getPageSize(); + if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) { + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + PageHelper.startPage(pageNum, pageSize, orderBy); + } + } + + /** + * 响应请求分页数据 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected TableDataInfo getDataTable(List list) { + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(HttpStatus.OK.value()); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(new PageInfo(list).getTotal()); + rspData.setPageNo(TableSupport.buildPageRequest().getPageNum()); + + return rspData; + } + + /** + * 响应返回结果 + * + * @param rows 影响行数 + * @return 操作结果 + */ + protected AjaxResult toAjax(int rows) { + return rows > 0 ? AjaxResult.success() : AjaxResult.error(); + } + protected AjaxResult toAjax(boolean bz) { + return bz == true ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 页面跳转 + */ + public String redirect(String url) { + return StringUtils.format("redirect:{}", url); + } +} diff --git a/src/main/java/com/org/system/controller/SysDataDictionaryController.java b/src/main/java/com/org/system/controller/SysDataDictionaryController.java new file mode 100644 index 0000000..599532b --- /dev/null +++ b/src/main/java/com/org/system/controller/SysDataDictionaryController.java @@ -0,0 +1,87 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.config.validation.Update; +import com.org.system.entity.SysDataDictionary; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysDataDictionaryService; +import com.org.utils.AjaxResult; +import com.org.utils.StringUtils; +import com.org.utils.page.TableDataInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RestController +@RequestMapping("sys/dictionary") +public class SysDataDictionaryController extends BaseController { + + @Autowired + private SysDataDictionaryService sysDataDictionaryService; + + // 新增 + @PostMapping("/add") + @PreAuthorize("@ss.hasPermi('sys:dictionary:edit')") + @Log(title = "词典分类新增", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestBody @Validated SysDataDictionary sysDataDictionary){ + log.info("SysDataDictionaryController - add sysDataDictionary:{}", sysDataDictionary); + + return toAjax(sysDataDictionaryService.saveOrUpdate(sysDataDictionary)); + } + + // 详情 + @PostMapping("/get") + @PreAuthorize("@ss.hasPermi('sys:dictionary:get')") + @Log(title = "词典分类详情", businessType = BusinessType.UPDATE) + public AjaxResult get(@RequestParam Long id){ + log.info("SysDataDictionaryController - get id:{}", id); + + return AjaxResult.success(sysDataDictionaryService.getById(id)); + } + + // 修改 + @PostMapping("/edit") + @PreAuthorize("@ss.hasPermi('sys:dictionary:edit')") + @Log(title = "词典分类修改", businessType = BusinessType.UPDATE) + public AjaxResult edit(@RequestBody @Validated(Update.class) SysDataDictionary sysDataDictionary){ + log.info("SysDataDictionaryController - edit sysDataDictionary:{}", sysDataDictionary); + + return toAjax(sysDataDictionaryService.saveOrUpdate(sysDataDictionary)); + } + + // 删除 + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('sys:dictionary:del')") + @Log(title = "词典分类删除", businessType = BusinessType.DELETE) + public AjaxResult del(@RequestParam String ids, @RequestParam String deleteReason){ + log.info("SysDataDictionaryController - del ids:{}", ids); + log.info("SysDataDictionaryController - del deleteReason:{}", deleteReason); + + if(StringUtils.isEmpty(ids)) return AjaxResult.success(); + + List idList = Arrays.asList(ids.split(",")).stream().map(idStr -> Long.parseLong(idStr)).collect(Collectors.toList()); + + return toAjax(sysDataDictionaryService.del(idList, deleteReason)); + } + + // 列表 + @GetMapping("/pageList") + @PreAuthorize("@ss.hasPermi('sys:dictionary:list')") + @Log(title = "词典分类列表", businessType = BusinessType.SELECT) + public TableDataInfo list(SysDataDictionary sysDataDictionary){ + log.info("SysDataDictionaryController - list sysDataDictionary:{}", sysDataDictionary); + + startPage(); + List list = sysDataDictionaryService.findList(sysDataDictionary); + + return getDataTable(list); + } + +} diff --git a/src/main/java/com/org/system/controller/SysDataDictionaryItemController.java b/src/main/java/com/org/system/controller/SysDataDictionaryItemController.java new file mode 100644 index 0000000..a79a73e --- /dev/null +++ b/src/main/java/com/org/system/controller/SysDataDictionaryItemController.java @@ -0,0 +1,137 @@ +package com.org.system.controller; + +import cn.hutool.core.lang.Dict; +import com.org.system.annotation.Log; +import com.org.system.config.validation.Update; +import com.org.system.entity.SysDataDictionaryItem; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysDataDictionaryItemService; +import com.org.utils.AjaxResult; +import com.org.utils.StringUtils; +import com.org.utils.page.TableDataInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RestController +@RequestMapping("sys/dictionary/item") +public class SysDataDictionaryItemController extends BaseController { + + @Autowired + private SysDataDictionaryItemService sysDataDictionaryItemService; + + // 新增 + @PostMapping("/add") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:edit')") + @Log(title = "词典项新增", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestBody @Validated SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemController - add sysDataDictionaryItem:{}", sysDataDictionaryItem); + + return toAjax(sysDataDictionaryItemService.saveOrUpdate(sysDataDictionaryItem)); + } + + // 详情 + @PostMapping("/get") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:get')") + @Log(title = "词典项详情", businessType = BusinessType.UPDATE) + public AjaxResult get(@RequestParam Long id){ + log.info("SysDataDictionaryItemController - get id:{}", id); + + return AjaxResult.success(sysDataDictionaryItemService.getById(id)); + } + + // 修改 + @PostMapping("/edit") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:edit')") + @Log(title = "词典项修改", businessType = BusinessType.UPDATE) + public AjaxResult edit(@RequestBody @Validated(Update.class) SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemController - edit sysDataDictionaryItem:{}", sysDataDictionaryItem); + + return toAjax(sysDataDictionaryItemService.saveOrUpdate(sysDataDictionaryItem)); + } + + // 删除 + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:del')") + @Log(title = "词典项删除", businessType = BusinessType.DELETE) + public AjaxResult del(@RequestParam String ids, @RequestParam String deleteReason){ + log.info("SysDataDictionaryItemController - del ids:{}", ids); + log.info("SysDataDictionaryItemController - del deleteReason:{}", deleteReason); + + if(StringUtils.isEmpty(ids)) return AjaxResult.success(); + + List idList = Arrays.asList(ids.split(",")).stream().map(idStr -> Long.parseLong(idStr)).collect(Collectors.toList()); + + return toAjax(sysDataDictionaryItemService.del(idList, deleteReason)); + } + + // 列表 + @GetMapping("/pageList") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:list')") + @Log(title = "词典项列表", businessType = BusinessType.SELECT) + public TableDataInfo pageList(SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemController - pageList sysDataDictionaryItem:{}", sysDataDictionaryItem); + + startPage(); + List list = sysDataDictionaryItemService.findList(sysDataDictionaryItem); + + return getDataTable(list); + } + + // 列表 + @GetMapping("/list") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:list')") + @Log(title = "词典项列表", businessType = BusinessType.SELECT) + public AjaxResult list(SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemController - list sysDataDictionaryItem:{}", sysDataDictionaryItem); + + List list = sysDataDictionaryItemService.findList(sysDataDictionaryItem); + + return AjaxResult.success(list); + } + + // 查询最大词典项值 + @GetMapping("/findMaxValue") + @PreAuthorize("@ss.hasPermi('sys:dictionary:item:list')") + @Log(title = "查询最大词典项值", businessType = BusinessType.SELECT) + public AjaxResult findMaxValue(SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemController - findMaxValue sysDataDictionaryItem:{}", sysDataDictionaryItem); + + if(StringUtils.isEmpty(sysDataDictionaryItem.getDictionaryCode())) return AjaxResult.error("词典项标识不能为空"); + + Integer maxValue = sysDataDictionaryItemService.findMaxValueByCode(sysDataDictionaryItem.getDictionaryCode()); + log.info("SysDataDictionaryItemController - findMaxValue sysDataDictionaryItem:{},maxValue:{}", sysDataDictionaryItem, maxValue); + + return AjaxResult.success(maxValue); + } + + // 词典项下拉选 + @GetMapping("/dropDown") + @Log(title = "词典项下拉选", businessType = BusinessType.SELECT) + public AjaxResult dropDown(String dictionaryCode){ + log.info("SysDataDictionaryItemController - dropDown dictionaryCode:{}", dictionaryCode); + + List list = sysDataDictionaryItemService.listByCode(dictionaryCode); + + return AjaxResult.success(list); + } + + // 词典项下拉选 + @GetMapping("/mobile/dropDown") + @Log(title = "词典项下拉选", businessType = BusinessType.SELECT) + public AjaxResult dropDownNoToken(String dictionaryCode){ + log.info("SysDataDictionaryItemController - dropDown dictionaryCode:{}", dictionaryCode); + + List list = sysDataDictionaryItemService.listByCode(dictionaryCode); + + return AjaxResult.success(list); + } + +} diff --git a/src/main/java/com/org/system/controller/SysLoginController.java b/src/main/java/com/org/system/controller/SysLoginController.java new file mode 100644 index 0000000..c0be761 --- /dev/null +++ b/src/main/java/com/org/system/controller/SysLoginController.java @@ -0,0 +1,72 @@ +package com.org.system.controller; + +import cn.hutool.core.util.StrUtil; +import com.org.system.annotation.Log; +import com.org.system.entity.LoginBody; +import com.org.system.entity.vo.PersonVo; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysLoginService; +import com.org.utils.AjaxResult; +import com.org.utils.Constants; +import com.org.utils.SecurityUtil; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +/** 登录验证 **/ +@Slf4j +@RestController +public class SysLoginController { + + @Autowired + private SysLoginService sysLoginService; + + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @PostMapping("/login") + @Log(title = "登陆系统", businessType = BusinessType.LOGIN) + public AjaxResult login(@RequestBody LoginBody loginBody) { + log.info("SysLoginController - login loginBody:{}", loginBody); + + if(loginBody == null) throw new CustomException("未找到登陆信息"); + + if(StrUtil.isEmpty(loginBody.getUsername()) || StrUtil.isEmpty(loginBody.getPassword())) + throw new CustomException("用户名或密码不能为空"); + + // 生成令牌 + Map result = sysLoginService.login(loginBody, true); + + return AjaxResult.success().put(Constants.TOKEN, result.get("token")) + .put("identity", result.get("identity")); + } + + @PostMapping("/getLoginUser") + @Log(title = "获取当前登录用户信息", businessType = BusinessType.LOGIN) + public AjaxResult getLoginUser(){ + log.info("SysLoginController - getLoginUser userId:{}", SecurityUtil.getUserId()); + + sysLoginService.setLoginUserRole(); + + return AjaxResult.success(SecurityUtil.getLoginUser()); + } + + @PostMapping("/getUserInfo") + @Log(title = "获取当前用户信息", businessType = BusinessType.LOGIN) + public AjaxResult getUserInfo(){ + log.info("SysLoginController - getUserInfo userId:{}", SecurityUtil.getUserId()); + + PersonVo personVo = sysLoginService.getUserInfo(SecurityUtil.getUserId()); + + return AjaxResult.success(personVo); + } + +} diff --git a/src/main/java/com/org/system/controller/SysMenuController.java b/src/main/java/com/org/system/controller/SysMenuController.java new file mode 100644 index 0000000..0556fb3 --- /dev/null +++ b/src/main/java/com/org/system/controller/SysMenuController.java @@ -0,0 +1,85 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.config.validation.Update; +import com.org.system.entity.SysMenu; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysMenuService; +import com.org.utils.AjaxResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("sys/menu") +public class SysMenuController extends BaseController { + + @Autowired + private SysMenuService sysMenuService; + + // 新增菜单 + @PostMapping("/add") + @PreAuthorize("@ss.hasPermi('sys:menu:add')") + @Log(title = "新增系统菜单", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestBody @Validated SysMenu sysMenu){ + log.info("SysMenuController - add sysMenu:{}", sysMenu); + + return toAjax(sysMenuService.add(sysMenu)); + } + + // 编辑菜单 + @PostMapping("/edit") + @PreAuthorize("@ss.hasPermi('sys:menu:edit')") + @Log(title = "编辑系统菜单", businessType = BusinessType.UPDATE) + public AjaxResult edit(@RequestBody @Validated(Update.class) SysMenu sysMenu){ + log.info("SysMenuController - edit sysMenu:{}", sysMenu); + + return toAjax(sysMenuService.edit(sysMenu)); + } + + // 删除菜单 + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('sys:menu:del')") + @Log(title = "删除系统菜单", businessType = BusinessType.DELETE) + public AjaxResult del(@RequestParam Long id, @RequestParam String deleteReason){ + log.info("SysMenuController - del id:{}", id); + log.info("SysMenuController - del deleteReason:{}", deleteReason); + + return toAjax(sysMenuService.del(id, deleteReason)); + } + + // 菜单列表 + @GetMapping("/list") + @PreAuthorize("@ss.hasPermi('sys:menu:list')") + @Log(title = "查询系统菜单", businessType = BusinessType.SELECT) + public AjaxResult menuList(SysMenu sysMenu){ + log.info("SysMenuController - list sysMenu:{}", sysMenu); + + List list = sysMenuService.queryList(sysMenu); + // 由于children属性存在,前端菜单树会加载children,故此处不处理,前端处理树结构,如果没有子节点,会删掉children属性 +// list = sysMenuService.buildMenuTree(list, 0L); + + return AjaxResult.success(list); + } + + @GetMapping("/tree") + @PreAuthorize("@ss.hasPermi('sys:menu:list')") + @Log(title = "菜单树", businessType = BusinessType.SELECT) + public AjaxResult tree(){ + List menuTree = sysMenuService.tree(); + return AjaxResult.success(menuTree); + } + + @GetMapping("/treeForGrant") + @PreAuthorize("@ss.hasPermi('sys:menu:list')") + @Log(title = "角色授权菜单树", businessType = BusinessType.SELECT) + public AjaxResult treeForGrant(){ + List menuTree = sysMenuService.treeForGrant(); + return AjaxResult.success(menuTree); + } +} diff --git a/src/main/java/com/org/system/controller/SysOperLogController.java b/src/main/java/com/org/system/controller/SysOperLogController.java new file mode 100644 index 0000000..b33ed17 --- /dev/null +++ b/src/main/java/com/org/system/controller/SysOperLogController.java @@ -0,0 +1,42 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.entity.SysOperLog; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysOperLogService; +import com.org.utils.page.TableDataInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("sys/operLog") +public class SysOperLogController extends BaseController { + + @Autowired + private SysOperLogService sysOssService; + + /** + * 分页查询 + * + * @return RestResponse + */ + @GetMapping("/list") + @PreAuthorize("@ss.hasPermi('sys:operLog:list')") + @Log(title = "系统文件分页查询", businessType = BusinessType.SELECT) + public TableDataInfo getList(SysOperLog sysOperLog) { + log.info("SysOperLogController - getList sysOperLog:{}", sysOperLog); + + startPage(); + List list = sysOssService.queryList(sysOperLog); + + return getDataTable(list); + } + +} diff --git a/src/main/java/com/org/system/controller/SysRoleController.java b/src/main/java/com/org/system/controller/SysRoleController.java new file mode 100644 index 0000000..8264639 --- /dev/null +++ b/src/main/java/com/org/system/controller/SysRoleController.java @@ -0,0 +1,105 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.config.validation.Update; +import com.org.system.entity.SysRole; +import com.org.system.enums.BusinessType; +import com.org.system.params.SysRoleGrantMenuParam; +import com.org.system.service.SysRoleService; +import com.org.utils.AjaxResult; +import com.org.utils.page.TableDataInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("sys/role") +public class SysRoleController extends BaseController { + + @Autowired + private SysRoleService sysRoleService; + + // 新增角色 + @PostMapping("/add") + @PreAuthorize("@ss.hasPermi('sys:role:add')") + @Log(title = "新增角色", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestBody @Validated SysRole sysRole){ + log.info("SysRoleController - add sysRole:{}", sysRole); + + return toAjax(sysRoleService.saveOrUpdate(sysRole)); + } + + // 编辑角色 + @PostMapping("/edit") + @PreAuthorize("@ss.hasPermi('sys:role:edit')") + @Log(title = "编辑角色", businessType = BusinessType.UPDATE) + public AjaxResult edit(@RequestBody @Validated(Update.class) SysRole sysRole){ + log.info("SysRoleController - edit sysRole:{}", sysRole); + + return toAjax(sysRoleService.saveOrUpdate(sysRole)); + } + + // 删除角色 + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('sys:role:del')") + @Log(title = "删除角色", businessType = BusinessType.DELETE) + public AjaxResult del(@RequestParam Long id){ + log.info("SysRoleController - del id:{}", id); + + return toAjax(sysRoleService.del(id)); + } + + // 角色分页列表 + @GetMapping("/pageList") + @PreAuthorize("@ss.hasPermi('sys:role:list')") + @Log(title = "查询角色", businessType = BusinessType.SELECT) + public TableDataInfo pageList(SysRole sysRole){ + log.info("SysRoleController - pageList sysRole:{}", sysRole); + + startPage(); + List list = sysRoleService.findList(sysRole); + log.info("SysRoleController - pageList list:{}", list); + + return getDataTable(list); + } + + // 角色列表 + @GetMapping("/list") + @PreAuthorize("@ss.hasPermi('sys:role:list')") + @Log(title = "查询角色", businessType = BusinessType.SELECT) + public AjaxResult list(){ + log.info("SysRoleController - list "); + + List list = sysRoleService.findList(new SysRole()); + log.info("SysRoleController - list list:{}", list); + + return AjaxResult.success(list); + } + + // 查询角色拥有菜单 + @PostMapping("/ownMenu") + @PreAuthorize("@ss.hasPermi('sys:role:ownMenu')") + @Log(title = "角色拥有菜单", businessType = BusinessType.SELECT) + public AjaxResult ownMenu(Long id){ + log.info("SysRoleController - ownMenu id:{}", id); + + return AjaxResult.success(sysRoleService.ownMenu(id)); + } + + // 角色授权菜单 + @PostMapping("/grantMenu") + @PreAuthorize("@ss.hasPermi('sys:role:grantMenu')") + @Log(title = "角色授权菜单", businessType = BusinessType.SELECT) + public AjaxResult grantMenu(@RequestBody @Validated SysRoleGrantMenuParam sysRoleGrantMenuParam){ + log.info("SysRoleController - grantMenu id:{}, grantMenuIdList{}", sysRoleGrantMenuParam.getId(), sysRoleGrantMenuParam.getGrantMenuIdList()); + + sysRoleService.grantMenu(sysRoleGrantMenuParam.getId(), sysRoleGrantMenuParam.getGrantMenuIdList()); + return AjaxResult.success(); + } + +} diff --git a/src/main/java/com/org/system/controller/SysRoleMenuController.java b/src/main/java/com/org/system/controller/SysRoleMenuController.java new file mode 100644 index 0000000..22f90f2 --- /dev/null +++ b/src/main/java/com/org/system/controller/SysRoleMenuController.java @@ -0,0 +1,69 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.entity.SysMenu; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysRoleMenuService; +import com.org.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("sys/role/menu") +public class SysRoleMenuController extends BaseController { + + @Autowired + private SysRoleMenuService sysRoleMenuService; + +// @PostMapping("add") +// @PreAuthorize("@ss.hasPermi('sys:role:menu:edit')") +// @Log(title = "系统角色菜单新增", businessType = BusinessType.INSERT) +// public AjaxResult add(@RequestParam Long roleId, @RequestParam String menuIds){ +// log.info("SysRoleMenuController - add roleId:{}", roleId); +// log.info("SysRoleMenuController - add menuIds:{}", menuIds); +// +// if(StringUtils.isNull(roleId)) return AjaxResult.error("角色ID不能为空"); +// +// List MenuIdList; +// if(StringUtils.isNotNull(menuIds)) +// MenuIdList = Arrays.asList(menuIds.split(",")).stream().map(menuIdStr -> Long.parseLong(menuIdStr)).collect(Collectors.toList()); +// else +// MenuIdList = new ArrayList<>(); +// +// return toAjax(sysRoleMenuService.save(roleId, MenuIdList)); +// } + + @GetMapping("/findMenuList") + @PreAuthorize("@ss.hasPermi('sys:role:menu:list')") + @Log(title = "系统角色菜单查询-根据角色ID查询菜单", businessType = BusinessType.SELECT) + public List findMenuList(@RequestParam Long roleId){ + log.info("SysRoleMenuController - findMenu roleId:{}", roleId); + + if(StringUtils.isNull(roleId)) return new ArrayList<>(); + + return sysRoleMenuService.findMenuListByRoleId(roleId); + } + +// @GetMapping("/findRoleList") +// @PreAuthorize("@ss.hasPermi('sys:role:menu:list')") +// @Log(title = "系统角色菜单查询-根据菜单ID查询角色", businessType = BusinessType.SELECT) +// public List findRoleList(@RequestParam Long menuId){ +// log.info("SysRoleMenuController - findRole menuId:{}", menuId); +// +// if(StringUtils.isNull(menuId)) return new ArrayList<>(); +// +// return sysRoleMenuService.findRoleListByMenuId(menuId); +// } + + + +} diff --git a/src/main/java/com/org/system/controller/SysUserController.java b/src/main/java/com/org/system/controller/SysUserController.java new file mode 100644 index 0000000..407c8cc --- /dev/null +++ b/src/main/java/com/org/system/controller/SysUserController.java @@ -0,0 +1,117 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.config.validation.Update; +import com.org.system.entity.SysUser; +import com.org.system.enums.BusinessType; +import com.org.system.params.SysUserGrantRoleParam; +import com.org.system.service.SysUserService; +import com.org.utils.AjaxResult; +import com.org.utils.StringUtils; +import com.org.utils.page.TableDataInfo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RestController +@RequestMapping("sys/user") +public class SysUserController extends BaseController{ + + @Autowired + private SysUserService sysUserService; + + @PostMapping("/add") + @PreAuthorize("@ss.hasPermi('sys:user:add')") + @Log(title = "系统用户新增", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestBody @Validated SysUser sysUser, @RequestParam String password){ + sysUser.setPassword(password); + log.info("SysUserController - add sysUser:{}", sysUser); + + return toAjax(sysUserService.saveOrUpdate(sysUser)); + } + + @PostMapping("/edit") + @PreAuthorize("@ss.hasPermi('sys:user:edit')") + @Log(title = "系统用户修改", businessType = BusinessType.UPDATE) + public AjaxResult edit(@RequestBody @Validated(Update.class) SysUser sysUser){ + log.info("SysUserController - edit sysUser:{}", sysUser); + + return toAjax(sysUserService.saveOrUpdate(sysUser)); + } + + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('sys:user:del')") + @Log(title = "系统用户删除", businessType = BusinessType.DELETE) + public AjaxResult del(String ids, String deleteReason){ + log.info("SysUserController - del ids:{}", ids); + log.info("SysUserController - del deleteReason:{}", deleteReason); + + if(StringUtils.isEmpty(ids)) return AjaxResult.success(); + + List idList = Arrays.asList(ids.split(",")).stream().map(idStr -> Long.parseLong(idStr)).collect(Collectors.toList()); + + return toAjax(sysUserService.del(idList, deleteReason)); + } + + @GetMapping("/pageList") + @PreAuthorize("@ss.hasPermi('sys:user:list')") + @Log(title = "系统用户查询", businessType = BusinessType.SELECT) + public TableDataInfo pageList(SysUser sysUser){ + log.info("SysUserController - pageList sysUser:{}", sysUser); + + startPage(); + List list = sysUserService.findList(sysUser); + + return getDataTable(list); + } + + + // 查询用户拥有角色 + @PostMapping("/ownRole") + @PreAuthorize("@ss.hasPermi('sys:user:ownRole')") + @Log(title = "用户_拥有角色", businessType = BusinessType.SELECT) + public AjaxResult ownRole(Long id){ + log.info("SysUserController - ownMenu id:{}", id); + + return AjaxResult.success(sysUserService.ownRole(id)); + } + + // 用户授权角色 + @PostMapping("/grantRole") + @PreAuthorize("@ss.hasPermi('sys:user:grantRole')") + @Log(title = "用户授权角色", businessType = BusinessType.SELECT) + public AjaxResult grantRole(@RequestBody @Validated SysUserGrantRoleParam param){ + log.info("SysUserController - grantMenu id:{}, grantRoleIdList{}", param.getId(), param.getGrantRoleIdList()); + + sysUserService.grantRole(param.getId(), param.getGrantRoleIdList()); + return AjaxResult.success(); + } + + // 重置密码 + @GetMapping("/resetPwd") + @PreAuthorize("@ss.hasPermi('sys:user:resetPwd')") + @Log(title = "重置密码", businessType = BusinessType.SELECT) + public AjaxResult resetPwd(@RequestParam Long id) { + log.info("SysUserController - resetPwd id:{}", id); + + return toAjax(sysUserService.resetPwd(id)); + } + + // 修改密码 + @GetMapping("/changePwd") +// @PreAuthorize("@ss.hasPermi('sys:user:changePwd')") + @Log(title = "修改密码", businessType = BusinessType.SELECT) + public AjaxResult changePwd(@RequestParam String oldPassword, @RequestParam("password") String password) { + log.info("SysUserController - changePwd oldPassword:{}", oldPassword); + log.info("SysUserController - changePwd password:{}", password); + + return toAjax(sysUserService.changePwd(oldPassword, password)); + } +} diff --git a/src/main/java/com/org/system/controller/SysUserRoleController.java b/src/main/java/com/org/system/controller/SysUserRoleController.java new file mode 100644 index 0000000..afd939e --- /dev/null +++ b/src/main/java/com/org/system/controller/SysUserRoleController.java @@ -0,0 +1,82 @@ +package com.org.system.controller; + +import com.org.system.annotation.Log; +import com.org.system.entity.SysRole; +import com.org.system.entity.SysUser; +import com.org.system.enums.BusinessType; +import com.org.system.service.SysUserRoleService; +import com.org.utils.AjaxResult; +import com.org.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@RestController +@RequestMapping("sys/user/role") +public class SysUserRoleController extends BaseController { + + @Autowired + private SysUserRoleService sysUserRoleService; + + // 新增 + @PostMapping("/add") + @PreAuthorize("@ss.hasPermi('sys:user:role:edit')") + @Log(title = "系统用户角色新增", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestParam Long userId, @RequestParam String roleIds){ + log.info("SysUserRoleController - add userId:{}", userId); + log.info("SysUserRoleController - add roleIds:{}", roleIds); + + if(StringUtils.isEmpty(roleIds)) return AjaxResult.error("角色ID不能为空"); + + List roleIdList = Arrays.asList(roleIds.split(",")).stream().map(roleIdStr -> Long.parseLong(roleIdStr)).collect(Collectors.toList()); + + return toAjax(sysUserRoleService.save(userId, roleIdList)); + } + + // 删除 + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('sys:user:role:edit')") + @Log(title = "系统用户角色删除", businessType = BusinessType.DELETE) + public AjaxResult del(@RequestParam Long userId, @RequestParam String roleIds){ + log.info("SysUserRoleController - del userId:{}", userId); + log.info("SysUserRoleController - del roleIds:{}", roleIds); + + if(StringUtils.isNull(roleIds)) return AjaxResult.error("角色ID不能为空"); + + List roleIdList = Arrays.asList(roleIds.split(",")).stream().map(roleIdStr -> Long.parseLong(roleIdStr)).collect(Collectors.toList()); + + return toAjax(sysUserRoleService.delByUserIdAndRoleId(userId, roleIdList)); + } + + // 根据用户ID查询角色信息 + @GetMapping("/findRoleList") + @PreAuthorize("@ss.hasPermi('sys:user:role:list')") + @Log(title = "系统用户角色查询-根据角色ID查询角色", businessType = BusinessType.SELECT) + public List findRoleList(@RequestParam Long userId){ + log.info("SysUserRoleController - findRoleList userId:{}", userId); + + if(StringUtils.isNull(userId)) return new ArrayList<>(); + + return sysUserRoleService.findRoleListByUserId(userId); + } + + // 根据角色ID查询用户信息 + @GetMapping("/findUserList") + @PreAuthorize("@ss.hasPermi('sys:user:role:list')") + @Log(title = "系统用户角色查询-根据角色ID查询用户", businessType = BusinessType.SELECT) + public List findUserList(@RequestParam Long roleId){ + log.info("SysUserRoleController - findUserList roleId:{}", roleId); + + if(StringUtils.isNull(roleId)) return new ArrayList<>(); + + return sysUserRoleService.findUserListByRoleId(roleId); + } + +} diff --git a/src/main/java/com/org/system/entity/BaseEntity.java b/src/main/java/com/org/system/entity/BaseEntity.java new file mode 100644 index 0000000..4d37493 --- /dev/null +++ b/src/main/java/com/org/system/entity/BaseEntity.java @@ -0,0 +1,44 @@ +package com.org.system.entity; + +import cn.hutool.core.date.DatePattern; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class BaseEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** 创建者 **/ + private Long createBy; + + /** 创建时间 **/ + @JsonFormat(pattern= DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") + private Date createTime; + + /** 更新者 **/ + private Long updateBy; + + /** 更新时间 **/ + @JsonFormat(pattern=DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") + private Date updateTime; + + /** 是否删除 1-是,0-否 **/ + private Integer isDelete; + + /** 删除者 **/ + private Long deleteBy; + + /** 删除时间 **/ + @JsonFormat(pattern=DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") + private Date deleteTime; + + /** 删除理由 **/ + private String deleteReason; + + /** 备注 **/ + private String remark; + +} diff --git a/src/main/java/com/org/system/entity/LoginBody.java b/src/main/java/com/org/system/entity/LoginBody.java new file mode 100644 index 0000000..e44d9f8 --- /dev/null +++ b/src/main/java/com/org/system/entity/LoginBody.java @@ -0,0 +1,15 @@ +package com.org.system.entity; + +import lombok.Data; + +/** 用户登录对象 **/ +@Data +public class LoginBody { + /** 帐号 **/ + private String username; + /** 密码 **/ + private String password; + /** 角色编码 默认平台管理员**/ + private String roleCode; + +} diff --git a/src/main/java/com/org/system/entity/LoginUser.java b/src/main/java/com/org/system/entity/LoginUser.java new file mode 100644 index 0000000..fe39ad4 --- /dev/null +++ b/src/main/java/com/org/system/entity/LoginUser.java @@ -0,0 +1,119 @@ +package com.org.system.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.org.system.pojo.LoginMenuTreeNode; +import lombok.Data; +import lombok.experimental.Accessors; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 登录用户身份权限 + * + */ +@Data +@Accessors(chain = true) +public class LoginUser implements UserDetails { + private static final long serialVersionUID = 1L; + + /** 用户唯一标识 **/ + private String token; + + /** 登录时间 **/ + private Long loginTime; + + /** 过期时间 **/ + private Long expireTime; + + /** 登录IP地址 **/ + private String ipaddr; + + /** 登录地点 **/ + private String loginLocation; + + /** 浏览器类型 **/ + private String browser; + + /** 操作系统 **/ + private String os; + + /** 用户信息 **/ + private SysUser user; + + /** 所有角色信息 **/ + private List roleList; + + /** 当前角色编码 **/ + private String currentRoleCode; + + /** 当前角色信息 **/ + private SysRole currentRole; + + /** 权限列表 **/ + private Set permissions; + + /** 登录菜单信息,AntDesign版本菜单 **/ + private List menus; + + /** 是否管理员 **/ + public boolean ifAdmin(){ + if("admin".equals(this.user.getUserName())) return true; + return false; + } + + + + + + + @JsonIgnore + @Override + public String getPassword(){ return user.getPassword(); } + + @Override + public String getUsername(){ return user.getUserName(); } + + public String getName(){ return user.getName(); } + + /** 账户是否未过期,过期无法验证 **/ + @JsonIgnore + @Override + public boolean isAccountNonExpired() + { + return true; + } + + /** 指定用户是否解锁,锁定的用户无法进行身份验证 **/ + @JsonIgnore + @Override + public boolean isAccountNonLocked() + { + return true; + } + + /** 指示是否已过期的用户的凭据(密码),过期的凭据防止认证 **/ + @JsonIgnore + @Override + public boolean isCredentialsNonExpired() + { + return true; + } + + /** 是否可用 ,禁用的用户不能身份验证 **/ + @JsonIgnore + @Override + public boolean isEnabled() + { + return true; + } + + @Override + public Collection getAuthorities() + { + return null; + } +} diff --git a/src/main/java/com/org/system/entity/SysDataDictionary.java b/src/main/java/com/org/system/entity/SysDataDictionary.java new file mode 100644 index 0000000..7c6f75a --- /dev/null +++ b/src/main/java/com/org/system/entity/SysDataDictionary.java @@ -0,0 +1,27 @@ +package com.org.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.org.system.config.validation.Update; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** 系统词典分类表 **/ +@Data +public class SysDataDictionary extends BaseEntity { + + /** 词典分类ID **/ + @TableId(type = IdType.AUTO) + @NotNull(message = "词典分类ID不能为空", groups = {Update.class}) + private Long id; + + /** 词典标识(键) **/ + private String dictionaryCode; + + /** 词典名称 **/ + @NotEmpty(message = "词典名称不能为空") + private String dictionaryName; + +} diff --git a/src/main/java/com/org/system/entity/SysDataDictionaryItem.java b/src/main/java/com/org/system/entity/SysDataDictionaryItem.java new file mode 100644 index 0000000..e1f3a98 --- /dev/null +++ b/src/main/java/com/org/system/entity/SysDataDictionaryItem.java @@ -0,0 +1,43 @@ +package com.org.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.org.system.config.validation.Update; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** 系统词典项表 **/ +@Data +public class SysDataDictionaryItem extends BaseEntity { + + /** 词典项ID **/ + @TableId(type = IdType.AUTO) + @NotNull(message = "词典项ID不能为空", groups = {Update.class}) + private Long id; + + /** 词典标识(键) **/ + @NotEmpty(message = "词典标识不能为空") + private String dictionaryCode; + + /** 词典项目名称 **/ + @NotEmpty(message = "词典项名称不能为空") + private String name; + + /** 词典项目值 **/ + @NotNull(message = "词典项值不能为空") + private Integer value; + + /** 所属上级值顶级默认-1 **/ + @NotNull(message = "所属上级不能为空") + private Integer parentid; + + /** 备注说明 **/ + private String description; + + /** 显示顺序 **/ + @NotNull(message = "显示顺序不能为空", groups = {Update.class}) + private Integer sortid; + +} diff --git a/src/main/java/com/org/system/entity/SysMenu.java b/src/main/java/com/org/system/entity/SysMenu.java new file mode 100644 index 0000000..17c7a1f --- /dev/null +++ b/src/main/java/com/org/system/entity/SysMenu.java @@ -0,0 +1,67 @@ +package com.org.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.org.system.config.validation.Update; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; + +/** 菜单表 **/ +@Data +public class SysMenu extends BaseEntity { + + /** 菜单ID **/ + @TableId(type = IdType.AUTO) + @NotNull(message = "菜单ID不能为空", groups = Update.class) + private Long id; + + /** 菜单名称 **/ + @NotEmpty(message = "菜单名称不能为空") + private String name; + + /** 菜单编码 **/ + @NotEmpty(message = "菜单编码不能为空") + private String code; + + /** 上级菜单ID **/ + @NotNull(message = "上级菜单ID不能为空") + private Long pid; + + /** + * 父ids + */ + private String pids; + + /** 菜单类型 0目录 1菜单 2按钮 3-服务级(待定) **/ + @NotNull(message = "菜单类型不能为空") + private Integer type; + + /** + * 路由地址 + */ + private String router; + + /** + * 组件地址 + */ + private String component; + + /** 权限标识 **/ + private String permission; + + /** 是否显示 1-是 0-否 **/ + @NotNull(message = "是否显示不能为空") + private Integer visible; + + /** 顺序号 **/ + private Integer intCode; + + @TableField(exist = false) + private List children = new ArrayList<>(); + +} diff --git a/src/main/java/com/org/system/entity/SysOperLog.java b/src/main/java/com/org/system/entity/SysOperLog.java new file mode 100644 index 0000000..d38a06c --- /dev/null +++ b/src/main/java/com/org/system/entity/SysOperLog.java @@ -0,0 +1,69 @@ +package com.org.system.entity; + +import cn.hutool.core.date.DatePattern; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + +/** 操作日志记录表 oper_log **/ +@Data +public class SysOperLog { + /** 日志主键 */ + @TableId(type = IdType.AUTO) + private Long id; + + /** 操作模块 */ + private String title; + + /** 业务类型(0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据) */ + private Integer businessType; + + /** 业务类型数组 */ + @TableField(exist = false) + private Integer[] businessTypes; + + /** 请求方法 */ + private String method; + + /** 请求方式 */ + private String requestMethod; + + /** 操作类别(0其它 1后台用户 2手机端用户) */ + private Integer operatorType; + + /** 操作人员 */ + private String operName; + + /** 部门名称 */ + private String deptName; + + /** 请求url */ + private String operUrl; + + /** 操作地址 */ + private String operIp; + + /** 操作地点 */ + private String operLocation; + + /** 请求参数 */ + private String operParam; + + /** 返回参数 */ + private String jsonResult; + + /** 操作状态(0正常 1异常) */ + private Integer status; + + /** 错误消息 */ + private String errorMsg; + + /** 操作时间 */ + @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") + private Date operTime; + +} diff --git a/src/main/java/com/org/system/entity/SysRole.java b/src/main/java/com/org/system/entity/SysRole.java new file mode 100644 index 0000000..41d4e00 --- /dev/null +++ b/src/main/java/com/org/system/entity/SysRole.java @@ -0,0 +1,53 @@ +package com.org.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.org.system.config.validation.Update; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** 系统角色表 **/ +@Data +public class SysRole extends BaseEntity { + + public static final Long PLATFORM_MANAGER_ROLE = 2L; + + // 服务人员 + public static final Long SERVICE_ROLE = 3L; + + // 供养人员 + public static final Long SUPPORT_ROLE = 4L; + + // 医养结合护理人员 + public static final Long TEND_ROLE = 5L; + + public static final String STUDENT_ROLE_CODE = "student"; + + /** 角色ID **/ + @NotNull(message = "角色ID不能为空", groups = {Update.class}) + @TableId(type = IdType.AUTO) + private Long id; + + /** 角色名称 **/ + @NotEmpty(message = "角色名称不能为空") + private String name; + + /** + * 编码 + */ + private String code; + + /** + * 排序 + */ + private Integer sort; + + /** 角色所属组织ID **/ + private Long orgCode; + + /** 父级角色ID **/ + private Long parentId; + +} diff --git a/src/main/java/com/org/system/entity/SysRoleMenu.java b/src/main/java/com/org/system/entity/SysRoleMenu.java new file mode 100644 index 0000000..de13192 --- /dev/null +++ b/src/main/java/com/org/system/entity/SysRoleMenu.java @@ -0,0 +1,27 @@ +package com.org.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotNull; + +/** 角色菜单 **/ +@Data +@Accessors(chain = true) +public class SysRoleMenu { + + /** 主键ID **/ + @TableId(type = IdType.AUTO) + private Long id; + + /** 角色ID **/ + @NotNull(message = "角色ID不能为空") + private Long roleId; + + /** 菜单ID **/ + @NotNull(message = "菜单ID不能为空") + private Long menuId; + +} diff --git a/src/main/java/com/org/system/entity/SysUser.java b/src/main/java/com/org/system/entity/SysUser.java new file mode 100644 index 0000000..2c33704 --- /dev/null +++ b/src/main/java/com/org/system/entity/SysUser.java @@ -0,0 +1,88 @@ +package com.org.system.entity; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.util.IdcardUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.org.system.config.validation.Update; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Data +public class SysUser extends BaseEntity { + + public static final String DEFAULT_PASSWORD = "Aqpx123456"; + + /** 用户ID **/ + @TableId(type = IdType.AUTO) + @NotNull(message = "用户ID不能为空", groups = {Update.class}) + private Long id; + + /** 姓名 */ + @NotEmpty(message = "姓名不能为空") + private String name; + + /** 用户名称 **/ + @NotEmpty(message = "用户名称不能为空") + private String userName; + + /** 用户昵称 **/ + private String nickName; + + /** 用户邮箱 **/ + private String email; + + /** 手机号码 **/ + private String phone; + + /** 微信OpenId **/ + @JsonIgnore + private String wxOpenId; + + /** 用户性别 0-未知 1-男 2-女 **/ + private int sex; + + /** 用户头像 **/ + private String avatar; + + /** 用户密码 **/ + @JsonIgnore + private String password; + + /** 用户SALT **/ + @JsonIgnore + private String salt; + + /** 用户状态 0-停用 1-正常 2-注册 **/ + private Integer status; + + /** 最后登录IP **/ + private String loginIp; + + /** 最后登录时间 **/ + @JsonFormat(pattern= DatePattern.NORM_DATETIME_PATTERN, timezone = "GMT+8") + private Date loginDate; + + /** 登录次数 **/ + private Integer loginCount; + public Integer getLoginCount(){ return this.loginCount == null ? 0 : this.loginCount; } + + /** 身份证号码 **/ + private String idCardNo; + + /** 年龄 */ + @TableField(exist = false) + private Integer age; + public int getAge() { + if(this.idCardNo == null){ return 0; } + // 通过身份证号计算年龄 + return this.age = IdcardUtil.getAgeByIdCard(this.getIdCardNo()); + } + +} diff --git a/src/main/java/com/org/system/entity/SysUserRole.java b/src/main/java/com/org/system/entity/SysUserRole.java new file mode 100644 index 0000000..c90b510 --- /dev/null +++ b/src/main/java/com/org/system/entity/SysUserRole.java @@ -0,0 +1,23 @@ +package com.org.system.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; +import lombok.experimental.Accessors; + +/** 系统用户角色 **/ +@Data +@Accessors(chain = true) +public class SysUserRole { + + /** 主键ID **/ + @TableId(type = IdType.AUTO) + private Long id; + + /** 用户ID **/ + private Long userId; + + /** 角色ID **/ + private Long roleId; + +} diff --git a/src/main/java/com/org/system/entity/vo/PersonVo.java b/src/main/java/com/org/system/entity/vo/PersonVo.java new file mode 100644 index 0000000..b902bd8 --- /dev/null +++ b/src/main/java/com/org/system/entity/vo/PersonVo.java @@ -0,0 +1,48 @@ +package com.org.system.entity.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.math.BigDecimal; + +@Data +@Accessors(chain = true) +public class PersonVo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 学员id */ + private Long id; + + /** 部门信息 */ + private Long orgId; + + private Long userId; + + private Long personId; + + /** 姓名 */ + private String name; + + /* 用户名 */ + private String userName; + + /** 用户性别 0-未知 1-男 2-女 **/ + private int sex; + + /** 是否管理员 2:否 1:是 */ + private Integer isAdmin; + + /* 单位信息 */ + private String unit; + + /* 部门信息 */ + private String dept; + + /** 年度学时 */ + private BigDecimal yearClassHour; + + /** 累计学时 */ + private BigDecimal sumClassHour; +} diff --git a/src/main/java/com/org/system/enums/BusinessStatus.java b/src/main/java/com/org/system/enums/BusinessStatus.java new file mode 100644 index 0000000..3dd5954 --- /dev/null +++ b/src/main/java/com/org/system/enums/BusinessStatus.java @@ -0,0 +1,10 @@ +package com.org.system.enums; + +/** 操作状态 **/ +public enum BusinessStatus { + /** 成功 **/ + SUCCESS, + + /** 失败 **/ + FAIL, +} diff --git a/src/main/java/com/org/system/enums/BusinessType.java b/src/main/java/com/org/system/enums/BusinessType.java new file mode 100644 index 0000000..fa860b8 --- /dev/null +++ b/src/main/java/com/org/system/enums/BusinessType.java @@ -0,0 +1,40 @@ +package com.org.system.enums; + +/** 业务操作类型 **/ +public enum BusinessType { + /** 其它 **/ + OTHER, + + /** 新增 **/ + INSERT, + + /** 修改 **/ + UPDATE, + + /** 删除 **/ + DELETE, + + /** 查询 **/ + SELECT, + + /** 授权 **/ + GRANT, + + /** 导出 **/ + EXPORT, + + /** 导入 **/ + IMPORT, + + /** 强退 **/ + FORCE, + + /** 生成代码 **/ + GENCODE, + + /** 清空数据 **/ + CLEAN, + + /** 登陆 **/ + LOGIN, +} diff --git a/src/main/java/com/org/system/enums/MenuTypeEnum.java b/src/main/java/com/org/system/enums/MenuTypeEnum.java new file mode 100644 index 0000000..5190694 --- /dev/null +++ b/src/main/java/com/org/system/enums/MenuTypeEnum.java @@ -0,0 +1,34 @@ +package com.org.system.enums; + +import lombok.Getter; + +/** + * 菜单类型枚举 + */ +@Getter +public enum MenuTypeEnum { + + /** + * 目录 + */ + DIR(0, "目录"), + + /** + * 菜单 + */ + MENU(1, "菜单"), + + /** + * 按钮 + */ + BTN(2, "按钮"); + + private final Integer code; + + private final String message; + + MenuTypeEnum(Integer code, String message) { + this.code = code; + this.message = message; + } +} diff --git a/src/main/java/com/org/system/enums/OperatorType.java b/src/main/java/com/org/system/enums/OperatorType.java new file mode 100644 index 0000000..c17b1b3 --- /dev/null +++ b/src/main/java/com/org/system/enums/OperatorType.java @@ -0,0 +1,14 @@ +package com.org.system.enums; + +/** 操作人类别 **/ +public enum OperatorType +{ + /** 其它 **/ + OTHER, + + /** 后台用户 **/ + MANAGE, + + /** 手机端用户 **/ + MOBILE +} diff --git a/src/main/java/com/org/system/enums/SmsType.java b/src/main/java/com/org/system/enums/SmsType.java new file mode 100644 index 0000000..dd9b7a9 --- /dev/null +++ b/src/main/java/com/org/system/enums/SmsType.java @@ -0,0 +1,31 @@ +package com.org.system.enums; + +/** 短信类型 **/ +public enum SmsType { + REGISTER("register"), CHANGEMOBILE("changeMobile"); + + private final String value; + + SmsType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + /** + * 根据value获取枚举 + * @param value + * @return + */ + public static SmsType getSmsType(String value) { + SmsType[] smsTypeArr = SmsType.values(); + for (int i = 0; i < smsTypeArr.length; i++) { + if (smsTypeArr[i].getValue().equals(value)) { + return smsTypeArr[i]; + } + } + return null; + } +} diff --git a/src/main/java/com/org/system/enums/YesOrNoState.java b/src/main/java/com/org/system/enums/YesOrNoState.java new file mode 100644 index 0000000..b7facf1 --- /dev/null +++ b/src/main/java/com/org/system/enums/YesOrNoState.java @@ -0,0 +1,15 @@ +package com.org.system.enums; + +/** 删除状态 **/ +public enum YesOrNoState { + YES(1),NO(0); + private final int state; + + YesOrNoState(int state) { + this.state = state; + } + + public int getState() { + return state; + } +} diff --git a/src/main/java/com/org/system/mapper/SysDataDictionaryItemMapper.java b/src/main/java/com/org/system/mapper/SysDataDictionaryItemMapper.java new file mode 100644 index 0000000..48b0aaf --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysDataDictionaryItemMapper.java @@ -0,0 +1,39 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysDataDictionaryItem; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface SysDataDictionaryItemMapper extends BaseMapper { + + @Select("select max(sortid) from sys_data_dictionary_item where dictionary_code = #{dictionaryCode}") + public Integer findMaxSortidByCode(@Param("dictionaryCode") String dictionaryCode); + + @Select("select max(value) from sys_data_dictionary_item where dictionary_code = #{dictionaryCode}") + public Integer findMaxValueByCode(@Param("dictionaryCode") String dictionaryCode); + + + /** + * 通过名称和code 查询词典项 + * @param name + * @param dictionaryCode + * @return 返回一条数据 + */ + @Select("SELECT * FROM sys_data_dictionary_item WHERE name=#{name} AND dictionary_code=#{dictionaryCode} ") + SysDataDictionaryItem findByNameAndCode(@Param("name") String name, String dictionaryCode); + + /** + * 通过值和code 查询词典项 + * @param value + * @param dictionaryCode + * @return + */ + @Select("SELECT * FROM sys_data_dictionary_item WHERE value=#{value} AND dictionary_code=#{dictionaryCode} ") + SysDataDictionaryItem findByValueAndCode(@Param("value") int value, String dictionaryCode); + + @Select("select name from sys_data_dictionary_item where dictionary_code = #{dictonaryCode} and value = #{value} and is_delete=0") + String findDictonaryBydictonaryCode(@Param("dictonaryCode") String dictonaryCode, @Param("value") Integer value); +} diff --git a/src/main/java/com/org/system/mapper/SysDataDictionaryMapper.java b/src/main/java/com/org/system/mapper/SysDataDictionaryMapper.java new file mode 100644 index 0000000..190dcd6 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysDataDictionaryMapper.java @@ -0,0 +1,10 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysDataDictionary; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysDataDictionaryMapper extends BaseMapper { + +} diff --git a/src/main/java/com/org/system/mapper/SysMenuMapper.java b/src/main/java/com/org/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..0fd2eb4 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysMenuMapper.java @@ -0,0 +1,15 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysMenu; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface SysMenuMapper extends BaseMapper { + + @Select("select max(int_code) from sys_menu where parent_id = #{parentId}") + public Integer findMaxIntCodeByParentId(@Param("parentId") Long parentId); + +} diff --git a/src/main/java/com/org/system/mapper/SysOperLogMapper.java b/src/main/java/com/org/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..afcba00 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysOperLogMapper.java @@ -0,0 +1,11 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysOperLog; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysOperLogMapper extends BaseMapper { + + +} diff --git a/src/main/java/com/org/system/mapper/SysOrgMapper.java b/src/main/java/com/org/system/mapper/SysOrgMapper.java new file mode 100644 index 0000000..74ac365 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysOrgMapper.java @@ -0,0 +1,12 @@ +//package com.xinmei.system.mapper; +// +//import com.baomidou.mybatisplus.core.mapper.BaseMapper; +//import com.xinmei.system.entity.SysOrg; +//import org.apache.ibatis.annotations.Mapper; +// +//@Mapper +//public interface SysOrgMapper extends BaseMapper { +// +// +// +//} diff --git a/src/main/java/com/org/system/mapper/SysRoleMapper.java b/src/main/java/com/org/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..c7b7888 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysRoleMapper.java @@ -0,0 +1,12 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysRole; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SysRoleMapper extends BaseMapper { + + + +} diff --git a/src/main/java/com/org/system/mapper/SysRoleMenuMapper.java b/src/main/java/com/org/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..d338105 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,31 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysMenu; +import com.org.system.entity.SysRole; +import com.org.system.entity.SysRoleMenu; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface SysRoleMenuMapper extends BaseMapper { + + @Delete("delete from sys_role_menu where role_id = #{roleId}") + public Integer delByRoleId(@Param("roleId") Long roleId); + +// @Delete("delete from sys_role_menu where menu_id = #{menuId}") +// public Integer delByMenuId(@Param("menuId") Long menuId); + + @Delete("delete from sys_role_menu where role_id = #{roleId} and menu_id = #{menuId}") + public Integer delByRoleIdAndMenuId(@Param("roleId") Long roleId, @Param("menuId") Long menuId); + + @Select("select menu.* from sys_menu menu left join sys_role_menu rm on menu.id = rm.menu_id where rm.role_id = #{roleId} and menu.is_delete = 0 order by menu.int_code") + public List findMenuListByRoleId(@Param("roleId") Long roleId); + + @Select("select role.* from sys_role role left join sys_role_menu rm on role.id = rm.role_id where rm.menu_id = #{menuId} and role.is_delete = 0") + public List findRoleListByMenuId(@Param("menuId") Long menuId); +} diff --git a/src/main/java/com/org/system/mapper/SysUserMapper.java b/src/main/java/com/org/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..f5b91a1 --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysUserMapper.java @@ -0,0 +1,18 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface SysUserMapper extends BaseMapper { + + @Select("select * from sys_user where user_name = #{userName} and is_delete = 0") + public SysUser findByUserName(@Param("userName") String userName); + + @Select("select * from sys_user where (user_name = #{userName} or phone = #{userName}) and is_delete = 0 order by create_time desc limit 1") + public SysUser findByUserNameOrPhone(@Param("userName") String userName); + +} diff --git a/src/main/java/com/org/system/mapper/SysUserRoleMapper.java b/src/main/java/com/org/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..8565d9e --- /dev/null +++ b/src/main/java/com/org/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,32 @@ +package com.org.system.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.system.entity.SysRole; +import com.org.system.entity.SysUser; +import com.org.system.entity.SysUserRole; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface SysUserRoleMapper extends BaseMapper { + + @Delete("delete from sys_user_role where user_id = #{userId}") + public Integer delByUserId(@Param("userId") Long userId); + + @Delete("delete from sys_user_role where role_id = #{roleId}") + public Integer delByRoleId(@Param("roleId") Long roleId); + + @Delete("delete from sys_user_role where user_id = #{userId} and role_id = #{roleId}") + public Integer delByUserIdAndRoleId(@Param("userId") Long userId, @Param("roleId") Long roleId); + + @Select("select user.* from sys_user user left join sys_user_role ur on user.id = ur.user_id where ur.role_id = #{roleId} and user.is_delete = 0") + public List findUserListByRoleId(@Param("roleId") Long roleId); + + @Select("select role.* from sys_role role left join sys_user_role ur on role.id = ur.role_id where ur.user_id = #{userid} and role.is_delete = 0") + public List findRoleListByUserId(@Param("userid") Long userid); + +} diff --git a/src/main/java/com/org/system/params/SysRoleGrantMenuParam.java b/src/main/java/com/org/system/params/SysRoleGrantMenuParam.java new file mode 100644 index 0000000..fa16bc0 --- /dev/null +++ b/src/main/java/com/org/system/params/SysRoleGrantMenuParam.java @@ -0,0 +1,26 @@ +package com.org.system.params; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 系统角色分配菜单参数 + */ +@Data +public class SysRoleGrantMenuParam { + + /** + * 主键 + */ + @NotNull(message = "id不能为空,请检查id参数") + private Long id; + + /** + * 授权菜单 + */ + @NotNull(message = "授权菜单不能为空,请检查grantMenuIdList参数") + private List grantMenuIdList; + +} diff --git a/src/main/java/com/org/system/params/SysUserGrantRoleParam.java b/src/main/java/com/org/system/params/SysUserGrantRoleParam.java new file mode 100644 index 0000000..d0145b8 --- /dev/null +++ b/src/main/java/com/org/system/params/SysUserGrantRoleParam.java @@ -0,0 +1,26 @@ +package com.org.system.params; + +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 用户分配角色参数 + */ +@Data +public class SysUserGrantRoleParam { + + /** + * 主键 + */ + @NotNull(message = "id不能为空,请检查id参数") + private Long id; + + /** + * 授权角色 + */ + @NotNull(message = "授权角色不能为空,请检查grantRoleIdList参数") + private List grantRoleIdList; + +} diff --git a/src/main/java/com/org/system/pojo/LoginMenuTreeNode.java b/src/main/java/com/org/system/pojo/LoginMenuTreeNode.java new file mode 100644 index 0000000..d66e49e --- /dev/null +++ b/src/main/java/com/org/system/pojo/LoginMenuTreeNode.java @@ -0,0 +1,88 @@ +package com.org.system.pojo; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 登录菜单 + */ +@Data +public class LoginMenuTreeNode implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * id + */ + private Long id; + + /** + * 父id + */ + private Long pid; + + /** + * 路由名称, 必须设置,且不能重名 + */ + private String name; + + /** + * 组件 + */ + private String component; + + /** + * 重定向地址, 访问这个路由时, 自定进行重定向 + */ + private String redirect; + + /** + * 路由元信息(路由附带扩展信息) + */ + private Meta meta; + + /** + * 路径 + */ + private String path; + + /** + * 控制路由和子路由是否显示在 sidebar + */ + private boolean hidden; + + /** + * 路由元信息内部类 + */ + @Data + public class Meta implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 路由标题, 用于显示面包屑, 页面标题 *推荐设置 + */ + public String title; + + /** + * 图标 + */ + public String icon; + + /** + * 是否可见 + */ + public boolean show; + + /** + * 如需外部打开,增加:_blank + */ + public String target; + + /** + * 内链打开http链接 + */ + public String link; + + } + +} diff --git a/src/main/java/com/org/system/service/CustomUserService.java b/src/main/java/com/org/system/service/CustomUserService.java new file mode 100644 index 0000000..bd83020 --- /dev/null +++ b/src/main/java/com/org/system/service/CustomUserService.java @@ -0,0 +1,50 @@ +package com.org.system.service; + +import com.org.system.config.security.Md5PasswordEncoder; +import com.org.system.entity.LoginUser; +import com.org.system.entity.SysUser; +import com.org.utils.exception.BaseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.InternalAuthenticationServiceException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +/** + * 用户验证处理 + * + */ +@Service +public class CustomUserService implements UserDetailsService { + private static final Logger log = LoggerFactory.getLogger(CustomUserService.class); + + @Autowired + private SysUserService sysUserService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // SysUser user = sysUserService.findByUserName(username); + SysUser user = sysUserService.findByUserNameOrPhone(username); + if (user == null) { + log.info("登录用户:{} 不存在.", username); + // throw new UsernameNotFoundException("登录用户:" + username + " 不存在"); + throw new InternalAuthenticationServiceException("登录用户:" + username + " 不存在"); + } else if (1 == user.getIsDelete()) { + log.info("登录用户:{} 已被删除.", username); + throw new BaseException("对不起,您的账号:" + username + " 已被删除"); + } else if (0 == user.getStatus()) { + log.info("登录用户:{} 已被停用.", username); + throw new BaseException("对不起,您的账号:" + username + " 已停用"); + } + Md5PasswordEncoder.getInstance().setSalt(user.getSalt()); + return createLoginUser(user); + } + + public UserDetails createLoginUser(SysUser user) { + // 这里可以查询用户权限放入 LoginUser 内 + return new LoginUser().setUser(user); + } +} diff --git a/src/main/java/com/org/system/service/PermissionService.java b/src/main/java/com/org/system/service/PermissionService.java new file mode 100644 index 0000000..74399bd --- /dev/null +++ b/src/main/java/com/org/system/service/PermissionService.java @@ -0,0 +1,153 @@ +package com.org.system.service; + +import com.org.system.entity.LoginUser; +import com.org.utils.HttpServletUtil; +import com.org.utils.SecurityUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.Set; + +/** 自定义权限实现 **/ +@Service("ss") +public class PermissionService { + /** 所有权限标识 **/ + public static final String ALL_PERMISSION = "*:*:*"; + + /** 管理员角色权限标识 **/ + private static final String SUPER_ADMIN = "admin"; + + private static final String ROLE_DELIMETER = ","; + + private static final String PERMISSION_DELIMETER = ","; + + @Autowired + private TokenService tokenService; + + /** + * 验证用户是否具备某权限 + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + public boolean hasPermi(String permission) { + if (StringUtils.isEmpty(permission)) return false; + +// LoginUser loginUser = tokenService.getLoginUser(HttpServletUtil.getRequest()); + LoginUser loginUser = SecurityUtil.getLoginUser(); + if (null == loginUser || CollectionUtils.isEmpty(loginUser.getPermissions())) return false; + + return hasPermissions(loginUser.getPermissions(), permission); + } + + /** + * 验证用户是否不具备某权限,与 hasPermi逻辑相反 + * + * @param permission 权限字符串 + * @return 用户是否不具备某权限 + */ + public boolean lacksPermi(String permission) + { + return hasPermi(permission) != true; + } + + /** + * 验证用户是否具有以下任意一个权限 + * + * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermi(String permissions) { + if (StringUtils.isEmpty(permissions)) return false; + + LoginUser loginUser = tokenService.getLoginUser(HttpServletUtil.getRequest()); + if (null == loginUser || CollectionUtils.isEmpty(loginUser.getPermissions())) return false; + + Set authorities = loginUser.getPermissions(); + for (String permission : permissions.split(PERMISSION_DELIMETER)) { + if (permission != null && hasPermissions(authorities, permission)) return true; + } + return false; + } + + /** + * 判断用户是否拥有某个角色 + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ + /*public boolean hasRole(String role) + { + if (StringUtils.isEmpty(role)) + { + return false; + } + LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) + { + return false; + } + for (SysRole sysRole : loginUser.getUser().getRoles()) + { + String roleKey = sysRole.getRoleKey(); + if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) + { + return true; + } + } + return false; + }*/ + + /** + * 验证用户是否不具备某角色,与 isRole逻辑相反。 + * + * @param role 角色名称 + * @return 用户是否不具备某角色 + */ + /*public boolean lacksRole(String role) + { + return hasRole(role) != true; + }*/ + + /** + * 验证用户是否具有以下任意一个角色 + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + /* + public boolean hasAnyRoles(String roles) + { + if (StringUtils.isEmpty(roles)) + { + return false; + } + LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); + if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) + { + return false; + } + for (String role : roles.split(ROLE_DELIMETER)) + { + if (hasRole(role)) + { + return true; + } + } + return false; + } + */ + + /** + * 判断是否包含权限 + * + * @param permissions 权限列表 + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ + private boolean hasPermissions(Set permissions, String permission) { + return permissions.contains(ALL_PERMISSION) || permissions.contains(permission.trim()); + } +} diff --git a/src/main/java/com/org/system/service/SysDataDictionaryItemService.java b/src/main/java/com/org/system/service/SysDataDictionaryItemService.java new file mode 100644 index 0000000..b2ba0be --- /dev/null +++ b/src/main/java/com/org/system/service/SysDataDictionaryItemService.java @@ -0,0 +1,243 @@ +package com.org.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Dict; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysDataDictionaryItem; +import com.org.system.enums.YesOrNoState; +import com.org.system.mapper.SysDataDictionaryItemMapper; +import com.org.utils.SecurityUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class SysDataDictionaryItemService extends ServiceImpl { + + /** + * 新增或修改词典项 + * + * @param sysDataDictionaryItem + * @return + */ + public boolean saveOrUpdate(SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemService - saveOrUpdate sysDataDictionaryItem:{}", sysDataDictionaryItem); + + if(StringUtils.isNull(sysDataDictionaryItem.getId())){ + //校验参数,检查是否存在相同的名称和值 + checkParam(sysDataDictionaryItem, false); + // 新增 + if(null == sysDataDictionaryItem.getSortid()) sysDataDictionaryItem.setSortid(findMaxSortidByCode(sysDataDictionaryItem.getDictionaryCode())); + sysDataDictionaryItem.setCreateBy(SecurityUtil.getUserId()); + sysDataDictionaryItem.setCreateTime(new Date()); + sysDataDictionaryItem.setIsDelete(YesOrNoState.NO.getState()); + log.info("SysDataDictionaryItemService - saveOrUpdate save sysDataDictionaryItem:{}", sysDataDictionaryItem); + + return save(sysDataDictionaryItem); + } else { + //校验参数,检查是否存在相同的名称和值 + checkParam(sysDataDictionaryItem, true); + + // 修改 + SysDataDictionaryItem sysDataDictionaryItemOld = getById(sysDataDictionaryItem.getId()); + if(sysDataDictionaryItemOld == null || StringUtils.isNull(sysDataDictionaryItemOld.getId())) + throw new CustomException("未找到词典项"); + + sysDataDictionaryItem.setCreateBy(null); + sysDataDictionaryItem.setCreateTime(null); + sysDataDictionaryItem.setIsDelete(null); + sysDataDictionaryItem.setUpdateBy(SecurityUtil.getUserId()); + sysDataDictionaryItem.setUpdateTime(new Date()); + log.info("SysDataDictionaryItemService - saveOrUpdate update sysDataDictionaryItem:{}", sysDataDictionaryItem); + + return updateById(sysDataDictionaryItem); + } + } + + /** + * 校验参数,检查是否存在相同的名称 + */ + private void checkParam(SysDataDictionaryItem dictionary, boolean isExcludeSelf) { + Long id = dictionary.getId(); + String name = dictionary.getName(); + Integer value = dictionary.getValue(); + + LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>(); + queryWrapperByName.eq(SysDataDictionaryItem::getName, name) + .eq(SysDataDictionaryItem::getDictionaryCode, dictionary.getDictionaryCode()) + .eq(SysDataDictionaryItem::getIsDelete, YesOrNoState.NO.getState()); + + LambdaQueryWrapper queryWrapperByCode = new LambdaQueryWrapper<>(); + queryWrapperByCode.eq(SysDataDictionaryItem::getValue, value) + .eq(SysDataDictionaryItem::getDictionaryCode, dictionary.getDictionaryCode()) + .eq(SysDataDictionaryItem::getIsDelete, YesOrNoState.NO.getState()); + + //是否排除自己,如果排除自己则不查询自己的id + if (isExcludeSelf) { + queryWrapperByName.ne(SysDataDictionaryItem::getId, id); + queryWrapperByCode.ne(SysDataDictionaryItem::getId, id); + } + int countByName = this.count(queryWrapperByName); + int countByCode = this.count(queryWrapperByCode); + + if (countByName >= 1) { + throw new CustomException("名称重复,请检查名称参数"); + } + if (countByCode >= 1) { + throw new CustomException("词典项值重复,请检查词典项值参数"); + } + } + + /** + * 删除词典项 + * + * @param idList + * @param deleteReason + * @return + */ + public boolean del(List idList, String deleteReason){ + log.info("SysDataDictionaryItemService - del idList:{}", idList); + log.info("SysDataDictionaryItemService - del deleteReason:{}", deleteReason); + + List delList = new ArrayList<>(); + for (Long id : idList) { + if(id == null) continue; + + SysDataDictionaryItem sysDataDictionaryItem = getById(id); + if(sysDataDictionaryItem == null || sysDataDictionaryItem.getId() == null) continue; + + sysDataDictionaryItem.setIsDelete(YesOrNoState.YES.getState()); + sysDataDictionaryItem.setDeleteBy(SecurityUtil.getUserId()); + sysDataDictionaryItem.setDeleteTime(new Date()); + log.info("SysDataDictionaryItemService - del sysDataDictionaryItem:{}", sysDataDictionaryItem); + + delList.add(sysDataDictionaryItem); + } + + return updateBatchById(delList); + } + + /** + * 词典项查询 + * + * @param sysDataDictionaryItem + * @return + */ + public List findList(SysDataDictionaryItem sysDataDictionaryItem){ + log.info("SysDataDictionaryItemService - findList sysDataDictionaryItem:{}", sysDataDictionaryItem); + + if(StringUtils.isEmpty(sysDataDictionaryItem.getDictionaryCode())) throw new CustomException("词典标识不能为空"); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDataDictionaryItem::getIsDelete, YesOrNoState.NO.getState()) + .eq(SysDataDictionaryItem::getDictionaryCode, sysDataDictionaryItem.getDictionaryCode()); + + if(StringUtils.isNotEmpty(sysDataDictionaryItem.getName())) + queryWrapper.like(SysDataDictionaryItem::getName, sysDataDictionaryItem.getName()); + if(StringUtils.isNotNull(sysDataDictionaryItem.getValue())) + queryWrapper.like(SysDataDictionaryItem::getValue, sysDataDictionaryItem.getValue()); + + //根据排序升序排列,序号越小越在前 + queryWrapper.orderByAsc(SysDataDictionaryItem::getSortid); + + return list(queryWrapper); + } + + /** + * 根据词典标识获取该标识下的词典项最大显示顺序 + * + * @param dictionaryCode + * @return + */ + private Integer findMaxSortidByCode(String dictionaryCode){ + log.info("SysDataDictionaryItemService - findMaxSortidByCode dictionaryCode:{}", dictionaryCode); + + Integer sortid = baseMapper.findMaxSortidByCode(dictionaryCode); + log.info("SysDataDictionaryItemService - findMaxSortidByCode sortid:{}", sortid); + + if(StringUtils.isNull(sortid)) sortid = 0; + sortid++; + log.info("SysDataDictionaryItemService - findMaxSortidByCode sortid:{}", sortid); + + return sortid; + } + + /** + * 根据词典标识获取该标识下的词典项最大词典项目值 + * + * @param dictionaryCode + * @return + */ + public Integer findMaxValueByCode(String dictionaryCode){ + log.info("SysDataDictionaryItemService - findMaxValueByCode dictionaryCode:{}", dictionaryCode); + + Integer value = baseMapper.findMaxValueByCode(dictionaryCode); + log.info("SysDataDictionaryItemService - findMaxValueByCode value:{}", value); + + if(StringUtils.isNull(value)) value = 0; + value++; + log.info("SysDataDictionaryItemService - findMaxValueByCode value:{}", value); + + return value; + } + + + public List listByCode(String dictionaryCode) { + //构造查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); + queryWrapper.eq(SysDataDictionaryItem::getDictionaryCode, dictionaryCode) + .eq(SysDataDictionaryItem::getIsDelete, YesOrNoState.NO.getState()); + //根据排序升序排列,序号越小越在前 + queryWrapper.orderByAsc(SysDataDictionaryItem::getSortid); + //查询dictTypeId下所有的字典项 + List results = this.list(queryWrapper); + + //抽取code和value封装到map返回 + List dictList = CollectionUtil.newArrayList(); + results.forEach(sysDictData -> { + Dict dict = Dict.create(); + dict.put("id", sysDictData.getId()); + dict.put("name", sysDictData.getName()); + dict.put("value", sysDictData.getValue()); + dict.put("parentid", sysDictData.getParentid()); + dictList.add(dict); + }); + + return dictList; + } + + /** + * 通过课程的 + * @param dictonaryCode 字典code + * @param value 字典value + * @return + */ + public String findDictonaryBydictonaryCode(String dictonaryCode,Integer value){ + log.info("SysDataDictionaryItemService - findDictonaryBydictonaryCode dictonaryCode:{}", dictonaryCode); + log.info("SysDataDictionaryItemService - findDictonaryBydictonaryCode value:{}", value); + return baseMapper.findDictonaryBydictonaryCode(dictonaryCode,value); + } + + public SysDataDictionaryItem getByCodeAndName(String dictionaryCode, String name) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDataDictionaryItem::getDictionaryCode, dictionaryCode); + queryWrapper.eq(SysDataDictionaryItem::getName, name); + queryWrapper.eq(SysDataDictionaryItem::getIsDelete, YesOrNoState.NO.getState()); + return baseMapper.selectOne(queryWrapper); + } + + public SysDataDictionaryItem getByCodeAndValue(String dictionaryCode, String value) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDataDictionaryItem::getDictionaryCode, dictionaryCode); + queryWrapper.eq(SysDataDictionaryItem::getValue, value); + queryWrapper.eq(SysDataDictionaryItem::getIsDelete, YesOrNoState.NO.getState()); + return baseMapper.selectOne(queryWrapper); + } +} diff --git a/src/main/java/com/org/system/service/SysDataDictionaryService.java b/src/main/java/com/org/system/service/SysDataDictionaryService.java new file mode 100644 index 0000000..c773c95 --- /dev/null +++ b/src/main/java/com/org/system/service/SysDataDictionaryService.java @@ -0,0 +1,153 @@ +package com.org.system.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysDataDictionary; +import com.org.system.enums.YesOrNoState; +import com.org.system.mapper.SysDataDictionaryMapper; +import com.org.utils.SecurityUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class SysDataDictionaryService extends ServiceImpl { + + /** + * 新增或修改词典分类 + * + * @param sysDataDictionary + * @return + */ + public boolean saveOrUpdate(SysDataDictionary sysDataDictionary){ + log.info("SysDataDictionaryService - saveOrUpdate sysDataDictionary:{}", sysDataDictionary); + + if(sysDataDictionary.getId() == null){ + //校验参数,检查是否存在相同的名称和编码 + checkParam(sysDataDictionary, false); + // 新增词典分类 + sysDataDictionary.setDictionaryCode(findDictionaryCode()); + sysDataDictionary.setCreateBy(SecurityUtil.getUserId()); + sysDataDictionary.setCreateTime(new Date()); + sysDataDictionary.setIsDelete(YesOrNoState.NO.getState()); + log.info("SysDataDictionaryService - saveOrUpdate save sysDataDictionary:{}", sysDataDictionary); + + return save(sysDataDictionary); + }else{ + //校验参数,检查是否存在相同的名称和编码 + checkParam(sysDataDictionary, true); + + // 修改词典分类 + SysDataDictionary sysDataDictionaryOld = getById(sysDataDictionary.getId()); + if(sysDataDictionaryOld == null || sysDataDictionaryOld.getId() == null) + throw new CustomException("未找到词典分类"); + + sysDataDictionaryOld.setDictionaryName(sysDataDictionary.getDictionaryName()); + sysDataDictionaryOld.setUpdateBy(SecurityUtil.getUserId()); + sysDataDictionaryOld.setUpdateTime(new Date()); + log.info("SysDataDictionaryService - saveOrUpdate save sysDataDictionary:{}", sysDataDictionaryOld); + + return updateById(sysDataDictionaryOld); + } + + } + + /** + * 校验参数,检查是否存在相同的名称 + */ + private void checkParam(SysDataDictionary dictionary, boolean isExcludeSelf) { + Long id = dictionary.getId(); + String name = dictionary.getDictionaryName(); + String code = dictionary.getDictionaryCode(); + + LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>(); + queryWrapperByName.eq(SysDataDictionary::getDictionaryName, name) + .eq(SysDataDictionary::getIsDelete, YesOrNoState.NO.getState()); + + LambdaQueryWrapper queryWrapperByCode = new LambdaQueryWrapper<>(); + queryWrapperByCode.eq(SysDataDictionary::getDictionaryCode, code) + .eq(SysDataDictionary::getIsDelete, YesOrNoState.NO.getState()); + + //是否排除自己,如果排除自己则不查询自己的id + if (isExcludeSelf) { + queryWrapperByName.ne(SysDataDictionary::getId, id); + queryWrapperByCode.ne(SysDataDictionary::getId, id); + } + int countByName = this.count(queryWrapperByName); + int countByCode = this.count(queryWrapperByCode); + + if (countByName >= 1) { + throw new CustomException("名称重复,请检查名称参数"); + } + if (countByCode >= 1) { + throw new CustomException("编码重复,请检查编码参数"); + } + } + + /** + * 删除词典分类 + * + * @param idList + * @param deleteReason + * @return + */ + public boolean del(List idList, String deleteReason){ + log.info("SysDataDictionaryService - del idList:{}", idList); + log.info("SysDataDictionaryService - del deleteReason:{}", deleteReason); + + List delList = new ArrayList<>(); + for (Long id : idList) { + if(id == null) continue; + + SysDataDictionary sysDataDictionary = getById(id); + if(sysDataDictionary == null || sysDataDictionary.getId() == null) continue; + + sysDataDictionary.setIsDelete(YesOrNoState.YES.getState()); + sysDataDictionary.setDeleteBy(SecurityUtil.getUserId()); + sysDataDictionary.setDeleteTime(new Date()); + log.info("SysDataDictionaryService - del sysDataDictionary:{}", sysDataDictionary); + + delList.add(sysDataDictionary); + } + + return updateBatchById(delList); + } + + /** + * 词典分类查询 + * + * @param sysDataDictionary + * @return + */ + public List findList(SysDataDictionary sysDataDictionary){ + log.info("SysDataDictionaryService - findList sysDataDictionary:{}", sysDataDictionary); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDataDictionary::getIsDelete, YesOrNoState.NO.getState()); + + if(StringUtils.isNotEmpty(sysDataDictionary.getDictionaryCode())) + queryWrapper.like(SysDataDictionary::getDictionaryCode, sysDataDictionary.getDictionaryCode()); + if(StringUtils.isNotEmpty(sysDataDictionary.getDictionaryName())) + queryWrapper.like(SysDataDictionary::getDictionaryName, sysDataDictionary.getDictionaryName()); + + return list(queryWrapper); + } + + /** + * 获取词典标识 + * + * @return + */ + private String findDictionaryCode(){ + int count = count(); + + return String.format("%04d", count+1); + } + +} diff --git a/src/main/java/com/org/system/service/SysLoginService.java b/src/main/java/com/org/system/service/SysLoginService.java new file mode 100644 index 0000000..7545959 --- /dev/null +++ b/src/main/java/com/org/system/service/SysLoginService.java @@ -0,0 +1,165 @@ +package com.org.system.service; + +import cn.hutool.core.util.ObjectUtil; +import com.org.system.config.async.AsyncFactory; +import com.org.system.config.async.AsyncManager; +import com.org.system.entity.*; +import com.org.system.entity.vo.PersonVo; +import com.org.system.pojo.LoginMenuTreeNode; +import com.org.utils.Constants; +import com.org.utils.MessageUtil; +import com.org.utils.SecurityUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import com.org.utils.exception.UserPasswordNotMatchException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.*; + +/** 登录校验方法 **/ +@Slf4j +@Service +public class SysLoginService { + @Autowired + private TokenService tokenService; + @Resource + private AuthenticationManager authenticationManager; + @Autowired + private SysUserService sysUserService; + @Autowired + private SysUserRoleService sysUserRoleService; + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysRoleMenuService sysRoleMenuService; + @Autowired + private SysMenuService sysMenuService; + + /** + * 登录验证 + * + * @param loginBody 登陆用户实体 + * @return 结果 + */ + public Map login(LoginBody loginBody, boolean isCheckState) { + + // todo 这里加验证码 + // todo 这里加验证码 + // todo 这里加验证码 + + // 用户验证 + Authentication authentication = null; + try { + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginBody.getUsername(), loginBody.getPassword())); + } catch (Exception e) { + if (e instanceof BadCredentialsException) { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginBody.getUsername(), Constants.LOGIN_FAIL, MessageUtil.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } else { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginBody.getUsername(), Constants.LOGIN_FAIL, e.getMessage())); + throw new CustomException(e.getMessage()); + } + } + + AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginBody.getUsername(), Constants.LOGIN_SUCCESS, "登陆成功")); + + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + loginUser.getUser().setLoginCount(loginUser.getUser().getLoginCount() + 1); + sysUserService.updateById(loginUser.getUser()); + + // 登录时校验是否存在角色 + SysUserRole sysUserRole = sysUserRoleService.getByUserIdAndRoleCode(loginUser.getUser().getId(), loginBody.getRoleCode()); + if(ObjectUtil.isEmpty(sysUserRole)) throw new CustomException("当前用户没有该角色"); + + Integer status = loginUser.getUser().getStatus(); + // 登录时是否校验账号状态 + if (isCheckState && status != 1) { + String msg = status == 2 ? "审核中,请稍后再试": "已停用"; + throw new CustomException("您的账号" + msg); + } + + loginUser.setCurrentRoleCode(loginBody.getRoleCode()); + + Map result = new HashMap<>(); + + // 生成token + String token = tokenService.createToken(loginUser); + result.put("token", token); + return result; + } + + /** + * 设置登陆用户当前角色信息 + * + */ + public void setLoginUserRole(){ + log.info("SysLoginService - setLoginUserRole roleCode:{}", SecurityUtil.getLoginUser().getCurrentRoleCode()); + + // 获取当前登录账号的所有角色信息 + List sysRoleList = null; + if(!SecurityUtil.getLoginUser().ifAdmin()) sysRoleList = sysUserRoleService.findRoleListByUserId(SecurityUtil.getUserId()); + else sysRoleList = sysRoleService.findAll(); + SecurityUtil.getLoginUser().setRoleList(sysRoleList); + + // 获取当前登录账号的当前角色信息 + SysRole sysRole = null; + for (SysRole role : sysRoleList) { if(SecurityUtil.getLoginUser().getCurrentRoleCode().equals(role.getCode())) sysRole = role; } + if(ObjectUtil.isEmpty(sysRole)) throw new CustomException("当前用户没有该角色"); + SecurityUtil.getLoginUser().setCurrentRole(sysRole); + + + // 获取当前登录账号当前角色的菜单 + List sysMenuList = null; + if(!SecurityUtil.getLoginUser().ifAdmin()) sysMenuList = sysRoleMenuService.findMenuListByRoleId(sysRole.getId()); + else sysMenuList = sysMenuService.findAll(); + List loginMenuTreeNodeList = sysMenuService.convertSysMenuToLoginMenu(sysMenuList); + SecurityUtil.getLoginUser().setMenus(loginMenuTreeNodeList); + + // 获取当前登录账号当前角色的权限 + Set permissions = new HashSet<>(); + if(SecurityUtil.getLoginUser().ifAdmin()){ + permissions.add(PermissionService.ALL_PERMISSION); + } else { + for (SysMenu sysMenu : sysMenuList) { if(StringUtils.isNotEmpty(sysMenu.getPermission())) permissions.add(sysMenu.getPermission()); } + } + SecurityUtil.getLoginUser().setPermissions(permissions); + + tokenService.refreshToken(SecurityUtil.getLoginUser()); + + } + + public PersonVo getUserInfo(Long userId) { + PersonVo personVo = new PersonVo(); + /*XmPerson person = xmPersonService.getByUserId(userId); + if (person == null) throw new CustomException("未查询到人员信息"); + PersonVo personVo = new PersonVo(); + BeanUtils.copyProperties(person, personVo); + SysOrg sysOrg = sysOrgService.getById(person.getOrgId()); + if (sysOrg.getType() == 1) { + // 如果组织为单位,则直接返回单位名称 + personVo.setUnit(sysOrg.getName()); + } else { + // 先查询出部门信息,再查询所属单位 + SysOrg parentOrg = sysOrgService.findUnitByOrgId(sysOrg.getPid()); + personVo.setUnit(parentOrg.getName()); + personVo.setDept(sysOrg.getName()); + } + personVo.setPersonId(person.getId()); + + // 学时 + BigDecimal yearClassHour = studyRecordService.getBaseMapper().getYearSumStudyHours(person.getId()); + personVo.setYearClassHour(yearClassHour); + BigDecimal sumClassHour = studyRecordService.getBaseMapper().getSumStudyHours(person.getId()); + personVo.setSumClassHour(sumClassHour);*/ + + return personVo; + } +} diff --git a/src/main/java/com/org/system/service/SysMenuService.java b/src/main/java/com/org/system/service/SysMenuService.java new file mode 100644 index 0000000..aa5c31a --- /dev/null +++ b/src/main/java/com/org/system/service/SysMenuService.java @@ -0,0 +1,339 @@ +package com.org.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysMenu; +import com.org.system.enums.MenuTypeEnum; +import com.org.system.enums.YesOrNoState; +import com.org.system.mapper.SysMenuMapper; +import com.org.system.pojo.LoginMenuTreeNode; +import com.org.utils.SecurityUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class SysMenuService extends ServiceImpl { + + @Autowired + private SysUserRoleService sysUserRoleService; + + @Autowired + private SysRoleMenuService sysRoleMenuService; + + @Transactional(rollbackFor = Exception.class) + public boolean add(SysMenu sysMenu) { + // 校验参数 + checkParam(sysMenu, false); + + + // 设置新的pid + String newPids = createNewPids(sysMenu.getPid()); + sysMenu.setPids(newPids); + + // 设置启用状态 + sysMenu.setCreateBy(SecurityUtil.getUserId()); + sysMenu.setCreateTime(new Date()); + sysMenu.setIsDelete(YesOrNoState.NO.getState()); + + return this.save(sysMenu); + } + + @Transactional(rollbackFor = Exception.class) + public boolean edit(SysMenu sysMenu) { + + // 校验参数 + checkParam(sysMenu, true); + + // 获取修改的菜单的旧数据(库中的) + SysMenu oldMenu = getById(sysMenu.getId()); + if(oldMenu == null || oldMenu.getId() == null) throw new CustomException("未找到菜单"); + + // 本菜单旧的pids + Long oldPid = oldMenu.getPid(); + String oldPids = oldMenu.getPids(); + + // 生成新的pid和pids + Long newPid = sysMenu.getPid(); + String newPids = this.createNewPids(sysMenu.getPid()); + + // 父节点有变化,更新子节点 + if (!newPid.equals(oldPid)) { + // 查找所有叶子节点,包含子节点的子节点 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.like(SysMenu::getPids, "[" + oldMenu.getId() + "]"); + List list = this.list(queryWrapper); + + list.forEach(child -> { + String oldParentCodesPrefix = oldPids + "[" + oldMenu.getId() + "]" + ","; + String oldParentCodesSuffix = child.getPids().substring(oldParentCodesPrefix.length()); + // 子节点pids组成 = 当前菜单新pids + 当前菜单id + 子节点自己的pids后缀 + String menuParentCodes = newPids + "[" + oldMenu.getId() + "]" + "," + oldParentCodesSuffix; + child.setPids(menuParentCodes); + }); + this.updateBatchById(list); + } + + // 设置新的pids + sysMenu.setPids(newPids); + return this.updateById(sysMenu); + } + + /** + * 校验参数 + */ + private void checkParam(SysMenu sysMenu, boolean isExcludeSelf) { + //菜单类型(字典 0目录 1菜单 2按钮) + Integer type = sysMenu.getType(); + + String router = sysMenu.getRouter(); + + String permission = sysMenu.getPermission(); + + if (!MenuTypeEnum.BTN.getCode().equals(type) && ObjectUtil.isEmpty(router)) { + throw new CustomException("路由地址为空,请检查router参数"); + } + + if (MenuTypeEnum.BTN.getCode().equals(type)) { + if (ObjectUtil.isEmpty(permission)) { + throw new CustomException("权限标识为空,请检查permission参数"); + } + } + + // 如果是编辑菜单时候,pid和id不能一致,一致会导致无限递归 + if (isExcludeSelf) { + if (sysMenu.getId().equals(sysMenu.getPid())) { + throw new CustomException("父级菜单不能为当前节点,请重新选择父级菜单"); + } + + // 如果是编辑,父id不能为自己的子节点 + List childIdListById = this.getChildIdListById(sysMenu.getId()); + if(ObjectUtil.isNotEmpty(childIdListById)) { + if(childIdListById.contains(sysMenu.getPid())) { + throw new CustomException("父节点不能为本节点的子节点,请重新选择父节点"); + } + } + } + + Long id = sysMenu.getId(); + String name = sysMenu.getName(); + String code = sysMenu.getCode(); + + LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>(); + queryWrapperByName.eq(SysMenu::getName, name) + .eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()); + + LambdaQueryWrapper queryWrapperByCode = new LambdaQueryWrapper<>(); + queryWrapperByCode.eq(SysMenu::getCode, code) + .eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()); + + if (isExcludeSelf) { + queryWrapperByName.ne(SysMenu::getId, id); + queryWrapperByCode.ne(SysMenu::getId, id); + } + int countByName = this.count(queryWrapperByName); + int countByCode = this.count(queryWrapperByCode); + + if (countByName >= 1) { + throw new CustomException("菜单名称重复,请检查name参数"); + } + if (countByCode >= 1) { + throw new CustomException("菜单编码重复,请检查code参数"); + } + } + /** + * 创建pids的值 + *

+ * 如果pid是0顶级节点,pids就是 [0], + *

+ * 如果pid不是顶级节点,pids就是 pid菜单的pids + [pid] + , + */ + private String createNewPids(Long pid) { + if (pid.equals(0L)) { + return "[" + 0 + "]" + + ","; + } else { + //获取父菜单 + SysMenu parentMenu = this.getById(pid); + return parentMenu.getPids() + + "[" + pid + "]" + + ","; + } + } + + /** + * 根据菜单ID删除菜单 + * + * @param id + * @return + */ + @Transactional + public boolean del(Long id, String deleteReason){ + log.info("SysMenuService - del - id:{}", id); + + //级联删除子节点 + List childIdList = this.getChildIdListById(id); + childIdList.add(id); + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.in(SysMenu::getId, childIdList) + .set(SysMenu::getIsDelete, YesOrNoState.YES.getState()) + .set(SysMenu::getDeleteBy, SecurityUtil.getUserId()) + .set(SysMenu::getDeleteTime, new Date()) + .set(SysMenu::getDeleteReason, deleteReason); + boolean flag = this.update(updateWrapper); + + // 删除角色菜单引用 + sysRoleMenuService.deleteRoleMenuListByMenuIdList(childIdList); + + return flag; + } + + /** + * 根据节点id获取所有子节点id集合 + */ + private List getChildIdListById(Long id) { + List childIdList = CollectionUtil.newArrayList(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.like(SysMenu::getPids, "[" + id + "]"); + this.list(queryWrapper).forEach(sysMenu -> childIdList.add(sysMenu.getId())); + return childIdList; + } + + /** + * 查询菜单列表 + * @param sysMenu + * @return + */ + public List queryList(SysMenu sysMenu) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()); + //根据菜单名称模糊查询 + if (StringUtils.isNotEmpty(sysMenu.getName())) { + queryWrapper.like(SysMenu::getName, sysMenu.getName()); + } + //根据排序升序排列,序号越小越在前 + queryWrapper.orderByAsc(SysMenu::getIntCode); + List sysMenuList = this.list(queryWrapper); + return sysMenuList; + } + + public List findAll(){ + log.info("SysMenuService - findAll userid:{}", SecurityUtil.getUserId()); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()).orderByAsc(SysMenu::getIntCode); + + return this.list(queryWrapper); + } + + /** + * 查出并组装树形结构 + * @param list 所有节点菜单 + * @param pid 父级id + * @return + */ + public List buildMenuTree(List list, Long pid){ + //组装数据 + List collect = list.stream().filter(sysMenu -> { + return pid.equals(sysMenu.getPid()); + }).map(sysMenu -> { + sysMenu.setChildren(getChildren(sysMenu, list)); + return sysMenu; + }).collect(Collectors.toList()); + return collect; + } + + /** + * 在所有列表中查询当前项的子项 + * @param o 当前节点 + * @param all 所有数据 + */ + private List getChildren(SysMenu o, List all){ + List children = all.stream().filter((sysMenu) -> { + return o.getId().equals(sysMenu.getPid()); + }).map(sysMenu -> { + sysMenu.setChildren(getChildren(sysMenu, all)); + return sysMenu; + }).collect(Collectors.toList()); + return children; + } + + /** + * 获取系统菜单树,用于新增,编辑时选择上级节点 + * @return + */ + public List tree() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()); + List allMenu = list(queryWrapper); + allMenu = this.buildMenuTree(allMenu, 0L); + return allMenu; + } + + /** + * 获取系统菜单树,用于给角色授权时选择 + */ + public List treeForGrant() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()); + //如果是超级管理员给角色授权菜单时可选择所有菜单 + if (SecurityUtil.getLoginUser().ifAdmin()) { + // 不加任何判断条件 + } else { + //非超级管理员则获取自己拥有的菜单,分配给人员,防止越级授权 + Long userId = SecurityUtil.getUserId(); + List roleIdList = sysUserRoleService.getUserRoleIdList(userId); + if (ObjectUtil.isNotEmpty(roleIdList)) { + List menuIdList = sysRoleMenuService.getRoleMenuIdList(roleIdList); + if (ObjectUtil.isNotEmpty(menuIdList)) { + queryWrapper.in(SysMenu::getId, menuIdList); + } else { + //如果角色的菜单为空,则查不到菜单 + return CollectionUtil.newArrayList(); + } + } else { + //如果角色为空,则根本没菜单 + return CollectionUtil.newArrayList(); + } + } + queryWrapper.orderByAsc(SysMenu::getIntCode); + List allMenu = list(queryWrapper); + allMenu = this.buildMenuTree(allMenu, 0L); + return allMenu; + } + + /** + * 将SysMenu格式菜单转换为LoginMenuTreeNode菜单 + */ + public List convertSysMenuToLoginMenu(List sysMenuList) { + List antDesignMenuTreeNodeList = CollectionUtil.newArrayList(); + sysMenuList.forEach(sysMenu -> { + if(sysMenu.getType() != MenuTypeEnum.BTN.getCode()) { + LoginMenuTreeNode loginMenuTreeNode = new LoginMenuTreeNode(); + loginMenuTreeNode.setComponent(sysMenu.getComponent()); + loginMenuTreeNode.setId(sysMenu.getId()); + loginMenuTreeNode.setName(sysMenu.getCode()); + loginMenuTreeNode.setPath(sysMenu.getRouter()); + loginMenuTreeNode.setPid(sysMenu.getPid()); + LoginMenuTreeNode.Meta mateItem = new LoginMenuTreeNode().new Meta(); + mateItem.setTitle(sysMenu.getName()); + //是否可见 + mateItem.setShow(YesOrNoState.YES.getState() == sysMenu.getVisible()); + loginMenuTreeNode.setMeta(mateItem); + antDesignMenuTreeNodeList.add(loginMenuTreeNode); + } + }); + return antDesignMenuTreeNodeList; + } +} diff --git a/src/main/java/com/org/system/service/SysOperLogService.java b/src/main/java/com/org/system/service/SysOperLogService.java new file mode 100644 index 0000000..8539db4 --- /dev/null +++ b/src/main/java/com/org/system/service/SysOperLogService.java @@ -0,0 +1,23 @@ +package com.org.system.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysOperLog; +import com.org.system.mapper.SysOperLogMapper; +import com.org.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +public class SysOperLogService extends ServiceImpl { + public List queryList(SysOperLog sysOperLog) { + log.info("SysOperLogService - queryList sysOperLog:{}", sysOperLog); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if(StringUtils.isNotEmpty(sysOperLog.getTitle())) queryWrapper.like(SysOperLog::getTitle, sysOperLog.getTitle()); + + return list(queryWrapper); + } +} diff --git a/src/main/java/com/org/system/service/SysRoleMenuService.java b/src/main/java/com/org/system/service/SysRoleMenuService.java new file mode 100644 index 0000000..ffa45d4 --- /dev/null +++ b/src/main/java/com/org/system/service/SysRoleMenuService.java @@ -0,0 +1,64 @@ +package com.org.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysMenu; +import com.org.system.entity.SysRoleMenu; +import com.org.system.mapper.SysRoleMenuMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class SysRoleMenuService extends ServiceImpl { + + public List getRoleMenuIdList(List roleIdList) { + if(ObjectUtil.isNotEmpty(roleIdList)) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(SysRoleMenu::getRoleId, roleIdList); + return this.list(queryWrapper).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); + } + return CollectionUtil.newArrayList(); + } + + public void grantMenu(Long roleId, List grantMenuIdList) { + //删除所拥有菜单 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysRoleMenu::getRoleId, roleId); + this.remove(queryWrapper); + //授权菜单 + grantMenuIdList.forEach(menuId -> { + SysRoleMenu sysRoleMenu = new SysRoleMenu(); + sysRoleMenu.setRoleId(roleId); + sysRoleMenu.setMenuId(menuId); + this.save(sysRoleMenu); + }); + } + + public void deleteRoleMenuListByMenuIdList(List menuIdList) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(SysRoleMenu::getMenuId, menuIdList); + this.remove(queryWrapper); + } + + public void deleteRoleMenuListByRoleId(Long roleId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysRoleMenu::getRoleId, roleId); + this.remove(queryWrapper); + } + + /** + * 根据角色ID获取菜单 + * @param roleId + * @return + */ + public List findMenuListByRoleId(Long roleId) { + return baseMapper.findMenuListByRoleId(roleId); + + } +} diff --git a/src/main/java/com/org/system/service/SysRoleService.java b/src/main/java/com/org/system/service/SysRoleService.java new file mode 100644 index 0000000..e544077 --- /dev/null +++ b/src/main/java/com/org/system/service/SysRoleService.java @@ -0,0 +1,178 @@ +package com.org.system.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysRole; +import com.org.system.enums.YesOrNoState; +import com.org.system.mapper.SysRoleMapper; +import com.org.utils.SecurityUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class SysRoleService extends ServiceImpl { + + @Autowired + private SysRoleMenuService sysRoleMenuService; + + @Autowired + private SysUserRoleService sysUserRoleService; + + /** + * 新增或修改 + * + * @param sysRole + * @return + */ + public boolean saveOrUpdate(SysRole sysRole){ + log.info("SysRoleService - saveOrUpdate sysRole:{}", sysRole); + + if(StringUtils.isNull(sysRole.getId())){ + //校验参数,检查是否存在相同的名称和编码 + checkParam(sysRole, false); + // 新增 + sysRole.setParentId(sysRole.getParentId() == null ? -1 : sysRole.getParentId()); + sysRole.setCreateBy(SecurityUtil.getUserId()); + sysRole.setCreateTime(new Date()); + sysRole.setIsDelete(YesOrNoState.NO.getState()); + log.info("SysRoleService - saveOrUpdate save sysRole:{}", sysRole); + + return save(sysRole); + } else { + //校验参数,检查是否存在相同的名称和编码 + checkParam(sysRole, true); + // 修改 + SysRole sysRoleOld = querySysRole(sysRole.getId()); + + sysRoleOld.setName(sysRole.getName()); + sysRoleOld.setCode(sysRole.getCode()); + sysRoleOld.setSort(sysRole.getSort()); + + sysRoleOld.setOrgCode(sysRole.getOrgCode()); + sysRoleOld.setParentId(sysRole.getParentId()); + sysRoleOld.setUpdateBy(SecurityUtil.getUserId()); + sysRoleOld.setUpdateTime(new Date()); + log.info("SysRoleService - saveOrUpdate update sysRole:{}", sysRoleOld); + + return updateById(sysRoleOld); + } + } + + /** + * 校验参数,检查是否存在相同的名称 + */ + private void checkParam(SysRole sysRole, boolean isExcludeSelf) { + Long id = sysRole.getId(); + String name = sysRole.getName(); + String code = sysRole.getCode(); + + LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>(); + queryWrapperByName.eq(SysRole::getName, name) + .eq(SysRole::getIsDelete, YesOrNoState.NO.getState()); + + LambdaQueryWrapper queryWrapperByCode = new LambdaQueryWrapper<>(); + queryWrapperByCode.eq(SysRole::getCode, code) + .eq(SysRole::getIsDelete, YesOrNoState.NO.getState()); + + //是否排除自己,如果排除自己则不查询自己的id + if (isExcludeSelf) { + queryWrapperByName.ne(SysRole::getId, id); + queryWrapperByCode.ne(SysRole::getId, id); + } + int countByName = this.count(queryWrapperByName); + int countByCode = this.count(queryWrapperByCode); + + if (countByName >= 1) { + throw new CustomException("角色名称重复,请检查name参数"); + } + if (countByCode >= 1) { + throw new CustomException("角色编码重复,请检查code参数"); + } + } + + /** + * 获取系统角色 + */ + private SysRole querySysRole(Long id) { + SysRole sysRole = this.getById(id); + if (ObjectUtil.isNull(sysRole)) { + throw new CustomException("角色不存在"); + } + return sysRole; + } + + /** + * 删除 + */ + @Transactional + public boolean del(Long id){ + SysRole sysRole = querySysRole(id); + + // 删除角色菜单引用 + sysRoleMenuService.deleteRoleMenuListByRoleId(sysRole.getId()); + // 删除用户角色引用 + sysUserRoleService.delByRoleId(sysRole.getId()); + + sysRole.setIsDelete(YesOrNoState.YES.getState()); + sysRole.setDeleteBy(SecurityUtil.getUserId()); + sysRole.setDeleteTime(new Date()); + + return updateById(sysRole); + } + + /** + * 查询角色 + * + * @param sysRole + * @return + */ + public List findList(SysRole sysRole){ + log.info("SysRoleService - findList - sysRole:{}", sysRole); + + if(sysRole.getParentId() == null) sysRole.setParentId(-1L); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysRole::getParentId, sysRole.getParentId()) + .eq(SysRole::getIsDelete, YesOrNoState.NO.getState()); + + if(StringUtils.isNotEmpty(sysRole.getName())) queryWrapper.like(SysRole::getName, sysRole.getName()); + if(StringUtils.isNotNull(sysRole.getOrgCode())) queryWrapper.eq(SysRole::getOrgCode, sysRole.getOrgCode()); + + return list(queryWrapper); + } + + /** + * 查询所有角色信息 + * @return + */ + public List findAll(){ + log.info("SysRoleService - findAll - userId:{}", SecurityUtil.getUserId()); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysRole::getIsDelete, YesOrNoState.NO.getState()); + + return list(queryWrapper); + } + + public List ownMenu(Long id) { + SysRole sysRole = querySysRole(id); + return sysRoleMenuService.getRoleMenuIdList(CollectionUtil.newArrayList(sysRole.getId())); + } + + @Transactional(rollbackFor = Exception.class) + public void grantMenu(Long id, List grantMenuIdList) { + this.querySysRole(id); + sysRoleMenuService.grantMenu(id, grantMenuIdList); + } + +} diff --git a/src/main/java/com/org/system/service/SysUserRoleService.java b/src/main/java/com/org/system/service/SysUserRoleService.java new file mode 100644 index 0000000..6ac59c3 --- /dev/null +++ b/src/main/java/com/org/system/service/SysUserRoleService.java @@ -0,0 +1,157 @@ +package com.org.system.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.entity.SysRole; +import com.org.system.entity.SysUser; +import com.org.system.entity.SysUserRole; +import com.org.system.mapper.SysUserRoleMapper; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class SysUserRoleService extends ServiceImpl { + + /** + * 新能用户角色 + * + * @param userId + * @param roleIdList + * @return + */ + @Transactional + public boolean save(Long userId, List roleIdList){ + log.info("SysUserRoleService - save userId:{}", userId); + log.info("SysUserRoleService - save roleIdList:{}", roleIdList); + + if(StringUtils.isNull(userId)) throw new CustomException("用户ID不能为空"); + if(StringUtils.isNull(roleIdList) || roleIdList.size() == 0) throw new CustomException("角色ID不能为空"); + + List sysUserRoleList = new ArrayList<>(); + for (Long roleId : roleIdList) { + if(StringUtils.isNull(roleId)) continue; + + sysUserRoleList.add(new SysUserRole().setUserId(userId).setRoleId(roleId)); + } + + return saveBatch(sysUserRoleList); + } + + /** + * 根据用户ID删除 + * + * @param userId + * @return + */ + public boolean delByUserId(Long userId){ + log.info("SysUserRoleService - delByUserId userId:{}", userId); + + if(StringUtils.isNull(userId)) throw new CustomException("用户ID不能为空"); + + return baseMapper.delByUserId(userId) > 0; + } + + /** + * 根据角色ID删除 + * + * @param roleId + * @return + */ + public boolean delByRoleId(Long roleId){ + log.info("SysUserRoleService - delByRoleId roleId:{}", roleId); + + if(StringUtils.isNull(roleId)) throw new CustomException("角色ID不能为空"); + + return baseMapper.delByRoleId(roleId) > 0; + } + + /** + * 根据用户ID和角色ID删除 + * + * @param userId + * @param roleIdList + * @return + */ + @Transactional + public boolean delByUserIdAndRoleId(Long userId, List roleIdList){ + log.info("SysUserRoleService - delByUserIdAndRoleId userId:{}", userId); + log.info("SysUserRoleService - delByUserIdAndRoleId roleIdList:{}", roleIdList); + + if(StringUtils.isNull(userId)) throw new CustomException("用户ID不能为空"); + if(StringUtils.isNull(roleIdList) || roleIdList.size() == 0) throw new CustomException("角色ID不能为空"); + + for (Long roleId : roleIdList) { + baseMapper.delByUserIdAndRoleId(userId, roleId); + } + + return true; + } + + /** + * 根据角色ID获取用户 + * + * @param roleId + * @return + */ + public List findUserListByRoleId(Long roleId){ + log.info("SysUserRoleService - findUserListByRoleId roleId:{}", roleId); + + if(StringUtils.isNull(roleId)) return new ArrayList<>(); + + return baseMapper.findUserListByRoleId(roleId); + } + + /** + * 根据用户ID获取角色 + * + * @param userid + * @return + */ + public List findRoleListByUserId(Long userid){ + log.info("SysUserRoleService - findRoleListByUserId roleId:{}", userid); + + if(StringUtils.isNull(userid)) return new ArrayList<>(); + + return baseMapper.findRoleListByUserId(userid); + } + + /* 2021-08-28 新增方法*/ + + public List getUserRoleIdList(Long userId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUserRole::getUserId, userId); + + return this.list(queryWrapper).stream().map(SysUserRole::getRoleId).collect(Collectors.toList()); + } + + public void grantRole(Long userId, List grantRoleIdList) { + //删除所拥有角色 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUserRole::getUserId, userId); + this.remove(queryWrapper); + //授权角色 + grantRoleIdList.forEach(roleId -> { + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setUserId(userId); + sysUserRole.setRoleId(roleId); + this.save(sysUserRole); + }); + } + + public SysUserRole getByUserIdAndRoleCode(Long userId, String roleCode) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUserRole::getUserId, userId); + queryWrapper.inSql(SysUserRole::getRoleId, "select id from sys_role where is_delete = 0 and code = '" + roleCode + "'"); + queryWrapper.last("limit 1"); + return this.getOne(queryWrapper); + } + +} diff --git a/src/main/java/com/org/system/service/SysUserService.java b/src/main/java/com/org/system/service/SysUserService.java new file mode 100644 index 0000000..6764a60 --- /dev/null +++ b/src/main/java/com/org/system/service/SysUserService.java @@ -0,0 +1,234 @@ +package com.org.system.service; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.DigestUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.config.security.Md5PasswordEncoder; +import com.org.system.entity.SysUser; +import com.org.system.enums.YesOrNoState; +import com.org.system.mapper.SysUserMapper; +import com.org.utils.SecurityUtil; +import com.org.utils.SpringUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class SysUserService extends ServiceImpl { + + @Autowired + private SysUserRoleService sysUserRoleService; + + /** + * 新增或修改系统用户 + * + * @param sysUser + * @return + */ + public boolean saveOrUpdate(SysUser sysUser){ + log.info("SysUserService - saveOrUpdate sysUser:{}", sysUser); + + if(StringUtils.isNull(sysUser.getId())){ + // 新增 + checkParam(sysUser, false); + + sysUser.setSalt(DigestUtil.md5Hex(sysUser.getUserName())); + + Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance(); + md5PasswordEncoder.setSalt(sysUser.getSalt()); + sysUser.setPassword(md5PasswordEncoder.encode(sysUser.getPassword())); + + sysUser.setStatus(1); + sysUser.setCreateBy(SecurityUtil.getUserId()); + sysUser.setCreateTime(new Date()); + sysUser.setIsDelete(YesOrNoState.NO.getState()); + log.info("SysUserService - saveOrUpdate save sysUser:{}", sysUser); + + return save(sysUser); + } else { + // 修改 + checkParam(sysUser, true); + + SysUser sysUserOld = getById(sysUser.getId()); + if(StringUtils.isNull(sysUserOld) || StringUtils.isNull(sysUserOld.getId())) + throw new CustomException("未找到要修改的用户"); + + // 禁止修改的内容 + sysUser.setSalt(null); + sysUser.setPassword(null); + sysUser.setWxOpenId(null); + + sysUser.setUpdateBy(SecurityUtil.getUserId()); + sysUser.setUpdateTime(new Date()); + log.info("SysUserService - saveOrUpdate update sysUser:{}", sysUser); + + return updateById(sysUser); + } + } + + /** + * 校验参数,检查是否存在相同的账号 + */ + private void checkParam(SysUser sysUser, boolean isExcludeSelf) { + Long id = sysUser.getId(); + String userName = sysUser.getUserName(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUser::getUserName, userName) + .eq(SysUser::getIsDelete, YesOrNoState.NO.getState()); + //是否排除自己,如果是则查询条件排除自己id + if (isExcludeSelf) { + queryWrapper.ne(SysUser::getId, id); + } + int countByAccount = this.count(queryWrapper); + //大于等于1个则表示重复 + if (countByAccount >= 1) { + throw new CustomException("用户名:" + sysUser.getUserName() + "已存在"); + } + } + + /** + * 根据用户ID删除用户 + * + * @param idList + * @param deleteReason + * @return + */ + public boolean del(List idList, String deleteReason){ + log.info("SysUserService - del idList:{}", idList); + log.info("SysUserService - del deleteReason:{}", deleteReason); + + if(StringUtils.isNull(idList) || idList.size() == 0) return true; + + List sysUserList = new ArrayList<>(); + for (Long id : idList) { + SysUser sysUser = getById(id); + + if(StringUtils.isNull(sysUser) || StringUtils.isNull(sysUser.getId())) continue; + + // 删除用户角色引用 + SpringUtil.getBean(SysUserRoleService.class).delByUserId(sysUser.getId()); + + sysUser.setIsDelete(YesOrNoState.YES.getState()); + sysUser.setDeleteBy(SecurityUtil.getUserId()); + sysUser.setDeleteTime(new Date()); + sysUser.setDeleteReason(deleteReason); + log.info("SysUserService - del sysUser:{}", sysUser); + + sysUserList.add(sysUser); + } + + return updateBatchById(sysUserList); + } + + /** + * 系统用户查询 + * + * @param sysUser + * @return + */ + public List findList(SysUser sysUser){ + log.info("SysUserService - findList sysUser:{}", sysUser); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUser::getIsDelete, YesOrNoState.NO.getState()); + + if(StringUtils.isNotEmpty(sysUser.getName())) queryWrapper.like(SysUser::getName, sysUser.getName()); + if(StringUtils.isNotEmpty(sysUser.getUserName())) queryWrapper.like(SysUser::getUserName, sysUser.getUserName()); + if(StringUtils.isNotEmpty(sysUser.getPhone())) queryWrapper.like(SysUser::getPhone, sysUser.getPhone()); + + return list(queryWrapper); + } + + /** + * 根据登录名查询系统用户 + * + * @param userName + * @return + */ + public SysUser findByUserName(String userName){ + log.info("SysUserService - findByUserName userName:{}", userName); + return baseMapper.findByUserName(userName); + } + + /** + * 根据登录名或电话查询系统用户 + * + * @param userName + * @return + */ + public SysUser findByUserNameOrPhone(String userName) { + log.info("SysUserService - findByUserNameOrPhone userName:{}", userName); + return baseMapper.findByUserNameOrPhone(userName); + } + + /** + * 获取系统用户 + */ + private SysUser querySysUser(Long id) { + SysUser sysUser = this.getById(id); + if (ObjectUtil.isNull(sysUser)) { + throw new CustomException("用户不存在"); + } + return sysUser; + } + + public List ownRole(Long id) { + SysUser sysUser = this.querySysUser(id); + return sysUserRoleService.getUserRoleIdList(sysUser.getId()); + } + + @Transactional(rollbackFor = Exception.class) + public void grantRole(Long id, List grantRoleIdList) { + this.querySysUser(id); + sysUserRoleService.grantRole(id, grantRoleIdList); + } + + // 重置密码 + @Transactional + public boolean resetPwd(Long id) { + // 修改用户密码 + SysUser sysUser = this.getById(id); + if (ObjectUtil.isNull(sysUser)) { + throw new CustomException("未查询到用户信息"); + } + sysUser.setSalt(DigestUtil.md5Hex(sysUser.getUserName())); + + Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance(); + md5PasswordEncoder.setSalt(sysUser.getSalt()); + sysUser.setPassword(md5PasswordEncoder.encode(SysUser.DEFAULT_PASSWORD)); + return updateById(sysUser); + } + + // 修改密码 + @Transactional + public boolean changePwd(String oldPassword, String password) { + // 修改用户密码 + SysUser sysUser = this.getById(SecurityUtil.getUserId()); + if (ObjectUtil.isNull(sysUser)) { + throw new CustomException("未查询到用户信息"); + } + + Md5PasswordEncoder.getInstance().setSalt(sysUser.getSalt()); + if(!Md5PasswordEncoder.getInstance().matches(oldPassword, sysUser.getPassword())){ + throw new CustomException("原密码不正确!"); + } + + Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance(); + md5PasswordEncoder.setSalt(sysUser.getSalt()); + sysUser.setPassword(md5PasswordEncoder.encode(password)); + + sysUser.setUpdateBy(sysUser.getId()); + sysUser.setUpdateTime(new Date()); + + return updateById(sysUser); + } +} diff --git a/src/main/java/com/org/system/service/TokenService.java b/src/main/java/com/org/system/service/TokenService.java new file mode 100644 index 0000000..8a99943 --- /dev/null +++ b/src/main/java/com/org/system/service/TokenService.java @@ -0,0 +1,190 @@ +package com.org.system.service; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.org.system.entity.LoginUser; +import com.org.system.config.redis.RedisCache; +import com.org.utils.Constants; +import com.org.utils.HttpServletUtil; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** token验证处理 **/ +@Service +public class TokenService +{ + // 令牌自定义标识 + @Value("${token.header}") + private String header; + + // 令牌秘钥 + @Value("${token.secret}") + private String secret; + + // 令牌有效期(默认30分钟) + @Value("${token.expireTime}") + private int expireTime; + + protected static final long MILLIS_SECOND = 1000; + + protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; + + private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L; + + @Autowired + private RedisCache redisCache; + + /** + * 获取用户身份信息 + * + * @return 用户信息 + */ + public LoginUser getLoginUser(HttpServletRequest request) { + // 获取请求携带的令牌 + String token = getToken(request); + if (StringUtils.isNotEmpty(token)) { + Claims claims = parseToken(token); + // 解析对应的权限以及用户信息 + String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); + String userKey = getTokenKey(uuid); + LoginUser user = redisCache.getCacheObject(userKey); + return user; + } + return null; + } + + /** + * 设置用户身份信息 + */ + public void setLoginUser(LoginUser loginUser) { + if (null != loginUser && StringUtils.isNotEmpty(loginUser.getToken())) refreshToken(loginUser); + } + + /** + * 删除用户身份信息 + */ + public void delLoginUser(String token) { + if (StringUtils.isNotEmpty(token)) { + String userKey = getTokenKey(token); + redisCache.deleteObject(userKey); + } + } + + /** + * 创建令牌 + * + * @param loginUser 用户信息 + * @return 令牌 + */ + public String createToken(LoginUser loginUser) { + String token = IdUtil.fastUUID(); + loginUser.setToken(token); + setUserAgent(loginUser); + refreshToken(loginUser); + + Map claims = new HashMap<>(); + claims.put(Constants.LOGIN_USER_KEY, token); + return createToken(claims); + } + + /** + * 验证令牌有效期,相差不足20分钟,自动刷新缓存 + * + * @param loginUser + * @return 令牌 + */ + public void verifyToken(LoginUser loginUser) { + long expireTime = loginUser.getExpireTime(); + long currentTime = System.currentTimeMillis(); + if (expireTime - currentTime <= MILLIS_MINUTE_TEN) refreshToken(loginUser); + } + + /** + * 刷新令牌有效期 + * + * @param loginUser 登录信息 + */ + public void refreshToken(LoginUser loginUser) { + loginUser.setLoginTime(System.currentTimeMillis()); + loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); + // 根据uuid将loginUser缓存 + String userKey = getTokenKey(loginUser.getToken()); + redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); + } + + /** + * 设置用户代理信息 + * + * @param loginUser 登录信息 + */ + public void setUserAgent(LoginUser loginUser) { + UserAgent userAgent = UserAgentUtil.parse(HttpServletUtil.getRequest().getHeader("User-Agent")); + String ip = ServletUtil.getClientIP(HttpServletUtil.getRequest(), ""); + loginUser.setIpaddr(ip); + loginUser.setLoginLocation(""); + loginUser.setBrowser(userAgent.getBrowser().getName()); + loginUser.setOs(userAgent.getOs().getName()); + } + + /** + * 从数据声明生成令牌 + * + * @param claims 数据声明 + * @return 令牌 + */ + private String createToken(Map claims) { + String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact(); + return token; + } + + /** + * 从令牌中获取数据声明 + * + * @param token 令牌 + * @return 数据声明 + */ + private Claims parseToken(String token) { + return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); + } + + /** + * 从令牌中获取用户名 + * + * @param token 令牌 + * @return 用户名 + */ + public String getUsernameFromToken(String token) { + Claims claims = parseToken(token); + return claims.getSubject(); + } + + /** + * 获取请求token + * + * @param request + * @return token + */ + private String getToken(HttpServletRequest request) { + String token = request.getHeader(header); + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) { + token = token.replace(Constants.TOKEN_PREFIX, ""); + } + return token; + } + + private String getTokenKey(String uuid) { + return Constants.LOGIN_TOKEN_KEY + uuid; + } +} diff --git a/src/main/java/com/org/ueditor/controller/UeditorContorller.java b/src/main/java/com/org/ueditor/controller/UeditorContorller.java new file mode 100644 index 0000000..b85e12e --- /dev/null +++ b/src/main/java/com/org/ueditor/controller/UeditorContorller.java @@ -0,0 +1,46 @@ +package com.org.ueditor.controller; + +import com.org.oss.service.SysOssService; +import com.org.system.annotation.Log; +import com.org.system.enums.BusinessType; +import com.org.ueditor.domain.UeditorConfig; +import com.org.ueditor.domain.UeditorConfigJson; +import com.org.utils.AjaxResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +@Slf4j +@RestController +@RequestMapping("sys/ueditor") +public class UeditorContorller { + + @Autowired + private SysOssService sysOssService; + + @Log(title = "富文本上传", businessType = BusinessType.INSERT) + @RequestMapping("/config") + public Object ueditorConfig(MultipartFile upfile, String action) throws IOException { + log.info("UeditorContorller - ueditorConfig action:{}", action); + + switch (action) { + case "config": + log.info("UeditorContorller - ueditorConfig get config json"); + return new UeditorConfigJson(); + case "uploadimage": + log.info("UeditorContorller - ueditorConfig uploadimage"); + + AjaxResult upload = sysOssService.upload(upfile, "ueditor", "ueditor"); + + String url = upload.get("zoomUrl") != null ? upload.get("zoomUrl").toString() : upload.get("url").toString(); + url = String.format("%s?width=1024", url); + return new UeditorConfig("SUCCESS", url, upfile.getSize(), upfile.getContentType(), upfile.getOriginalFilename(), upfile.getOriginalFilename()); + } + return "请求失败"; + } + +} diff --git a/src/main/java/com/org/ueditor/domain/UeditorConfig.java b/src/main/java/com/org/ueditor/domain/UeditorConfig.java new file mode 100644 index 0000000..a30528a --- /dev/null +++ b/src/main/java/com/org/ueditor/domain/UeditorConfig.java @@ -0,0 +1,29 @@ +package com.org.ueditor.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UeditorConfig { + + /* 状态 */ + private String state; + + /* 回显路径 */ + private String url; + + /* 大小 */ + private long size; + + /* 类型 */ + private String type; + + /* 文件title */ + private String title; + + /* 名称 */ + private String original; +} diff --git a/src/main/java/com/org/ueditor/domain/UeditorConfigJson.java b/src/main/java/com/org/ueditor/domain/UeditorConfigJson.java new file mode 100644 index 0000000..63ab942 --- /dev/null +++ b/src/main/java/com/org/ueditor/domain/UeditorConfigJson.java @@ -0,0 +1,140 @@ +package com.org.ueditor.domain; + +import lombok.Data; + +@Data +public class UeditorConfigJson { + + /* 上传图片配置项 */ + /* 执行上传图片的action名称 */ + private String imageActionName = "uploadimage"; + /* 提交的图片表单名称 */ + private String imageFieldName = "upfile"; + /* 上传大小限制,单位B */ + private long imageMaxSize = 2048000; + /* 上传图片格式显示 */ + private String[] imageAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"}; + /* 是否压缩图片;默认是true */ + private boolean imageCompressEnable = true; + /* 图片压缩最长边限制 */ + private long imageCompressBorder = 1600; + /* 插入的图片浮动方式 */ + private String imageInsertAlign = "none"; + /* 图片访问路径前缀 */ + private String imageUrlPrefix = ""; + /* 上传保存路径;可以自定义保存路径和文件名格式 */ + /* {filename} 会替换成原文件名;配置这项需要注意中文乱码问题 */ + /* {rand:6} 会替换成随机数;后面的数字是随机数的位数 */ + /* {time} 会替换成时间戳 */ + /* {yyyy} 会替换成四位年份 */ + /* {yy} 会替换成两位年份 */ + /* {mm} 会替换成两位月份 */ + /* {dd} 会替换成两位日期 */ + /* {hh} 会替换成两位小时 */ + /* {ii} 会替换成两位分钟 */ + /* {ss} 会替换成两位秒 */ + /* 非法字符 \ : * ? " < > | */ + /* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */ + private String imagePathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}"; + + + /* 涂鸦图片上传配置项 */ + /* 执行上传涂鸦的action名称 */ + private String scrawlActionName = "uploadscrawl"; + /* 提交的图片表单名称 */ + private String scrawlFieldName = "upfile"; + /* 上传保存路径;可以自定义保存路径和文件名格式 */ + private String scrawlPathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}"; + /* 上传大小限制,单位B */ + private long scrawlMaxSize = 2048000; + /* 图片访问路径前缀 */ + private String scrawlUrlPrefix = ""; + private String scrawlInsertAlign = "none"; + + /* 截图工具上传 */ + /* 执行上传截图的action名称 */ + private String snapscreenActionName = "uploadimage"; + /* 上传保存路径;可以自定义保存路径和文件名格式 */ + private String snapscreenPathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}"; + /* 图片访问路径前缀 */ + private String snapscreenUrlPrefix = ""; + /* 插入的图片浮动方式 */ + private String snapscreenInsertAlign = "none"; + + /* 抓取远程图片配置 */ + private String[] catcherLocalDomain = new String[]{"127.0.0.1", "localhost", "img.baidu.com"}; + /* 执行抓取远程图片的action名称 */ + private String catcherActionName = "catchimage"; + /* 提交的图片列表表单名称 */ + private String catcherFieldName = "source"; + /* 上传保存路径;可以自定义保存路径和文件名格式 */ + private String catcherPathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}"; + /* 图片访问路径前缀 */ + private String catcherUrlPrefix = ""; + /* 上传大小限制,单位B */ + private long catcherMaxSize = 2048000; + /* 抓取图片格式显示 */ + private String[] catcherAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"}; + + /* 上传视频配置 */ + /* 执行上传视频的action名称 */ + private String videoActionName = "uploadvideo"; + /* 提交的视频表单名称 */ + private String videoFieldName = "upfile"; + /* 上传保存路径;可以自定义保存路径和文件名格式 */ + private String videoPathFormat = "/ueditor/jsp/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}"; + /* 视频访问路径前缀 */ + private String videoUrlPrefix = ""; + /* 上传大小限制,单位B,默认100MB */ + private long videoMaxSize = 102400000; + /* 上传视频格式显示 */ + private String[] videoAllowFiles = new String[]{".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", + ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"}; + + /* 上传文件配置 */ + /* controller里;执行上传视频的action名称 */ + private String fileActionName = "uploadfile"; + /* 提交的文件表单名称 */ + private String fileFieldName = "upfile"; + /* 上传保存路径;可以自定义保存路径和文件名格式 */ + private String filePathFormat = "/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}"; + /* 文件访问路径前缀 */ + private String fileUrlPrefix = ""; + /* 上传大小限制,单位B,默认50MB */ + private long fileMaxSize = 51200000; + /* 上传文件格式显示 */ + private String[] fileAllowFiles = new String[]{ ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf", ".mkv", + ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", + ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", ".xlsx", + ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"}; + + /* 列出指定目录下的图片 */ + /* 执行图片管理的action名称 */ + private String imageManagerActionName = "listimage"; + /* 指定要列出图片的目录 */ + private String imageManagerListPath = "/ueditor/jsp/upload/image/"; + /* 每次列出文件数量 */ + private long imageManagerListSize = 20; + /* 图片访问路径前缀 */ + private String imageManagerUrlPrefix = ""; + /* 插入的图片浮动方式 */ + private String imageManagerInsertAlign = "none"; + /* 列出的文件类型 */ + private String[] imageManagerAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"}; + + /* 列出指定目录下的文件 */ + /* 执行文件管理的action名称 */ + private String fileManagerActionName = "listfile"; + /* 指定要列出文件的目录 */ + private String fileManagerListPath = "/ueditor/jsp/upload/file/"; + /* 文件访问路径前缀 */ + private String fileManagerUrlPrefix = ""; + /* 每次列出文件数量 */ + private long fileManagerListSize = 20; + /* 列出的文件类型 */ + private String[] fileManagerAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf", + ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", + ".wav", ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", + ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"}; + +} diff --git a/src/main/java/com/org/utils/AjaxResult.java b/src/main/java/com/org/utils/AjaxResult.java new file mode 100644 index 0000000..a64e5ce --- /dev/null +++ b/src/main/java/com/org/utils/AjaxResult.java @@ -0,0 +1,119 @@ +package com.org.utils; + +import org.springframework.http.HttpStatus; + +import java.util.HashMap; + +/** 操作消息提醒 **/ +public class AjaxResult extends HashMap { + private static final long serialVersionUID = 1L; + + /** 状态码 */ + public static final String CODE_TAG = "code"; + + /** 返回内容 */ + public static final String MSG_TAG = "msg"; + + /** 数据对象 */ + public static final String DATA_TAG = "data"; + + /** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息 **/ + public AjaxResult() { } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + */ + public AjaxResult(int code, String msg){ + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + * @param data 数据对象 + */ + public AjaxResult(int code, String msg, Object data){ + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (data != null) super.put(DATA_TAG, data); + } + + /** + * 返回成功消息 + * + * @return 成功消息 + */ + public static AjaxResult success() { return AjaxResult.success("操作成功"); } + + /** + * 返回成功数据 + * + * @return 成功消息 + */ + public static AjaxResult success(Object data) { return AjaxResult.success("操作成功", data); } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @return 成功消息 + */ + public static AjaxResult success(String msg) { return AjaxResult.success(msg, null); } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 成功消息 + */ + public static AjaxResult success(String msg, Object data) { return new AjaxResult(HttpStatus.OK.value(), msg, data); } + + /** + * 返回错误消息 + * + * @return + */ + public static AjaxResult error() + { + return AjaxResult.error("操作失败"); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(String msg) { return AjaxResult.error(msg, null); } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult error(String msg, Object data) { return new AjaxResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg, data); } + + /** + * 返回错误消息 + * + * @param code 状态码 + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(int code, String msg) { return new AjaxResult(code, msg, null); } + + @Override + public AjaxResult put(String key, Object value) { + super.put(key, value); + return this; + } +} diff --git a/src/main/java/com/org/utils/Constants.java b/src/main/java/com/org/utils/Constants.java new file mode 100644 index 0000000..f0cd92c --- /dev/null +++ b/src/main/java/com/org/utils/Constants.java @@ -0,0 +1,140 @@ +package com.org.utils; + +/** 通用常量信息 **/ +public class Constants +{ + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + public static final String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + public static final String FAIL = "1"; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + * 验证码 redis key + */ + public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; + + /** + * 登录用户 redis key + */ + public static final String LOGIN_TOKEN_KEY = "login_tokens:"; + + /** + * 防重提交 redis key + */ + public static final String REPEAT_SUBMIT_KEY = "repeat_submit:"; + + /** + * 验证码有效期(分钟) + */ + public static final Integer CAPTCHA_EXPIRATION = 2; + + /** + * 令牌 + */ + public static final String TOKEN = "token"; + + /** + * 令牌前缀 + */ + public static final String TOKEN_PREFIX = "Bearer "; + + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_KEY = "login_user_key"; + + /** + * 用户ID + */ + public static final String JWT_USERID = "userid"; + + /** + * 用户名称 + */ + public static final String JWT_USERNAME = "sub"; + + /** + * 用户头像 + */ + public static final String JWT_AVATAR = "avatar"; + + /** + * 创建时间 + */ + public static final String JWT_CREATED = "created"; + + /** + * 用户权限 + */ + public static final String JWT_AUTHORITIES = "authorities"; + + /** + * 参数管理 cache key + */ + public static final String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache key + */ + public static final String SYS_DICT_KEY = "sys_dict:"; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; + + /** + * app版本管理 cache key + */ + public static final String SYS_APP_VERSION_KEY = "sys_app_version:"; + + /** + * app版本强制升级版本号 cache key + */ + public static final String SYS_APP_VERSION_FORCE_KEY = "sys_app_version_force:"; + + /** + * app版本强制升级版本号 cache key + */ + public static final String SYS_APP_VERSION_NOTICE_KEY = "sys_app_version_notice:"; +} diff --git a/src/main/java/com/org/utils/HttpServletUtil.java b/src/main/java/com/org/utils/HttpServletUtil.java new file mode 100644 index 0000000..77cd3c7 --- /dev/null +++ b/src/main/java/com/org/utils/HttpServletUtil.java @@ -0,0 +1,82 @@ +package com.org.utils; + +import cn.hutool.core.convert.Convert; +import com.org.utils.exception.CustomException; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class HttpServletUtil { + + public static ServletRequestAttributes getServletRequestAttributes(){ + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + + if(requestAttributes == null) throw new CustomException("获取 RequestAttributes 异常"); + + return (ServletRequestAttributes) requestAttributes; + } + + /** + * 获取 HttpServletRequest + * + * @return + */ + public static HttpServletRequest getRequest(){ + return getServletRequestAttributes().getRequest(); + } + + /** + * 获取 HttpServletResponse + * + * @return + */ + public static HttpServletResponse getResponse(){ + return getServletRequestAttributes().getResponse(); + } + + /** + * 获取String参数 + * + * @param name + * @return + */ + public static String getParameter(String name) { + return getRequest().getParameter(name); + } + + /** + * 获取String参数 + * + * @param name + * @param defaultValue + * @return + */ + public static String getParameter(String name, String defaultValue) { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Integer参数 + * + * @param name + * @return + */ + public static Integer getParameterToInt(String name) { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取Integer参数 + * + * @param name + * @param defaultValue + * @return + */ + public static Integer getParameterToInt(String name, Integer defaultValue) { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + +} diff --git a/src/main/java/com/org/utils/ImagePicUtil.java b/src/main/java/com/org/utils/ImagePicUtil.java new file mode 100644 index 0000000..070f497 --- /dev/null +++ b/src/main/java/com/org/utils/ImagePicUtil.java @@ -0,0 +1,113 @@ +package com.org.utils; + +import cn.hutool.core.img.ImgUtil; +import cn.hutool.core.lang.Validator; +import lombok.extern.slf4j.Slf4j; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.*; + +@Slf4j +public class ImagePicUtil { + // 缩放至的宽度 + public static int zoomWidth = 1024; + // 缩略图的宽度 + public static int thumbnailWidth = 400; + + /** + * 图片缩放 + * @param filePath + * @param width + * @param fileName + * @return + */ + public static MultipartFile getImagePic(String filePath, int width, String fileName){ + log.info("ImagePicUtil - getImagePic filePath:{}", filePath); + log.info("ImagePicUtil - getImagePic width:{}", width); + log.info("ImagePicUtil - getImagePic fileName:{}", fileName); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + Image image = ImageIO.read(new File(filePath)); + + int image_width = image.getWidth(null); + log.info("ImagePicUtil - getImagePic image_width:{}", image_width); + + if(image_width <= width){ + log.info("ImagePicUtil - getImagePic not scale"); + return null; + } + + float scale = Float.parseFloat(String.valueOf(width)) / Float.parseFloat(String.valueOf(image_width)); + log.info("ImagePicUtil - getImagePic scale:{}", scale); + + // 等比缩放图片 + Image scaleImage = ImgUtil.scale(image, scale); + + // Image 转 BufferedImage + BufferedImage bufferedImage = new BufferedImage(scaleImage.getWidth(null), scaleImage.getHeight(null), BufferedImage.TYPE_3BYTE_BGR); + Graphics g = bufferedImage.getGraphics(); + g.drawImage(scaleImage, 0, 0, null); + + // 获取文件后缀 + String suffix = filePath.substring(filePath.lastIndexOf(".")+1); + + //将newImage写入字节数组输出流 + ImageIO.write( bufferedImage, suffix, baos ); + } catch (IOException e) { + log.error("{}", e); + } finally { + try { + baos.flush(); + baos.close(); + } catch (IOException e) { + log.error("PDFUtil - imgToPdf error {}", e); + } + } + + MockMultipartFile mockMultipartFile = new MockMultipartFile(fileName, fileName, "image/jpeg", baos.toByteArray()); + log.info("ImagePicUtil - getImagePic ok ..."); + + return mockMultipartFile; + } + + /** + * 通过文件路径 + * @param path + * @return true-支持 false-不支持 + */ + public static boolean checkImageByPath(String path) { + log.info("ImagePicUtil - checkImageByPath path:{}", path); + // 文本课件没有封面 + if (Validator.isEmpty(path)) return true; + + // 获取文件后缀,并且转换小写 + String suffix = path.substring(path.lastIndexOf(".")+1).toLowerCase(); + log.info("ImagePicUtil - checkImageByPath suffix:{}", suffix); + + String str = constMap1.get(suffix); + log.info("ImagePicUtil - checkImageByPath str:{}", str); + if (Validator.isNotEmpty(str)) return true; + + return false; + } + + /** + * 支持的图片 + */ + private static final Map constMap1 = new HashMap() { + { + put("jpg", "jpg"); + put("jpeg", "jpeg"); + put("png", "png"); + } + }; + +} diff --git a/src/main/java/com/org/utils/MessageUtil.java b/src/main/java/com/org/utils/MessageUtil.java new file mode 100644 index 0000000..cf82283 --- /dev/null +++ b/src/main/java/com/org/utils/MessageUtil.java @@ -0,0 +1,19 @@ +package com.org.utils; + +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; + +/** 获取i18n资源文件 **/ +public class MessageUtil { + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) { + MessageSource messageSource = SpringUtil.getBean(MessageSource.class); + return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); + } +} diff --git a/src/main/java/com/org/utils/SecurityUtil.java b/src/main/java/com/org/utils/SecurityUtil.java new file mode 100644 index 0000000..293b3da --- /dev/null +++ b/src/main/java/com/org/utils/SecurityUtil.java @@ -0,0 +1,53 @@ +package com.org.utils; + +import com.org.system.entity.LoginUser; +import com.org.utils.exception.CustomException; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +/** 安全服务工具类 **/ +public class SecurityUtil { + + /** 获取Authentication **/ + public static Authentication getAuthentication() { return SecurityContextHolder.getContext().getAuthentication(); } + + /** + * 当前是否登录 + * + * @return + */ + public static boolean isLogin(){ + String principal = getAuthentication().getPrincipal().toString(); + if("anonymousUser".equals(principal)) return false; + return true; + } + + /** 获取用户 **/ + public static LoginUser getLoginUser() { + try { + return (LoginUser) getAuthentication().getPrincipal(); + } catch (Exception e) { + throw new CustomException("获取用户信息异常", HttpStatus.UNAUTHORIZED.value()); + } + } + + /** 获取用户ID **/ + public static Long getUserId() { + try { + return getLoginUser().getUser().getId(); + } catch (Exception e) { + throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value()); + } + } + + /** 获取用户账户 **/ + public static String getUsername() { + try { + return getLoginUser().getUsername(); + } catch (Exception e) { + throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value()); + } + } + +} diff --git a/src/main/java/com/org/utils/SpringUtil.java b/src/main/java/com/org/utils/SpringUtil.java new file mode 100644 index 0000000..c780ef8 --- /dev/null +++ b/src/main/java/com/org/utils/SpringUtil.java @@ -0,0 +1,111 @@ +package com.org.utils; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** spring工具类 方便在非spring管理环境中获取bean **/ +@Component +public final class SpringUtil implements BeanFactoryPostProcessor, ApplicationContextAware +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + private static ApplicationContext applicationContext; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtil.beanFactory = beanFactory; } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtil.applicationContext = applicationContext; } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException { return (T) beanFactory.getBean(name); } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws BeansException + * + */ + public static T getBean(Class clz) throws BeansException { return (T) beanFactory.getBean(clz); } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) { return beanFactory.containsBean(name); } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { return beanFactory.isSingleton(name); } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { return beanFactory.getType(name); } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { return beanFactory.getAliases(name); } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { return (T) AopContext.currentProxy(); } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() { return applicationContext.getEnvironment().getActiveProfiles(); } + + /** + * 获取当前的环境配置,当有多个环境配置时,只获取第一个 + * + * @return 当前的环境配置 + */ + public static String getActiveProfile() { + final String[] activeProfiles = getActiveProfiles(); + + if(activeProfiles == null || activeProfiles.length == 0) return null; + return activeProfiles[0]; + } +} diff --git a/src/main/java/com/org/utils/SqlUtil.java b/src/main/java/com/org/utils/SqlUtil.java new file mode 100644 index 0000000..220efd3 --- /dev/null +++ b/src/main/java/com/org/utils/SqlUtil.java @@ -0,0 +1,32 @@ +package com.org.utils; + +import com.org.utils.exception.BaseException; + +/** sql操作工具类 **/ +public class SqlUtil { + /** 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) **/ + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + * + * @param value + * @return + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) + throw new BaseException("参数不符合规范,不能进行查询"); + + return value; + } + + /** + * 验证 order by 语法是否符合规范 + * + * @param value + * @return + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } +} diff --git a/src/main/java/com/org/utils/StringUtils.java b/src/main/java/com/org/utils/StringUtils.java new file mode 100644 index 0000000..f674d6f --- /dev/null +++ b/src/main/java/com/org/utils/StringUtils.java @@ -0,0 +1,370 @@ +package com.org.utils; + +import cn.hutool.core.text.StrFormatter; + +import java.util.*; + +/** 字符串工具类 **/ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + if (str == null) return NULLSTR; + + if (start < 0) start = str.length() + start; + if (start < 0) start = 0; + + if (start > str.length()) return NULLSTR; + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + if (str == null) return NULLSTR; + + if (end < 0) end = str.length() + end; + if (start < 0) start = str.length() + start; + + if (end > str.length()) end = str.length(); + if (start > end) return NULLSTR; + + if (start < 0) start = 0; + if (end < 0) end = 0; + + return str.substring(start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + if (isEmpty(params) || isEmpty(template)) return template; + + return StrFormatter.format(template, params); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static final Set str2Set(String str, String sep) { + return new HashSet(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList(); + + if (StringUtils.isEmpty(str)) return list; + + // 过滤空白字符串 + if (filterBlank && StringUtils.isBlank(str)) return list; + + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && StringUtils.isBlank(string)) continue; + + if (trim) string = string.trim(); + + list.add(string); + } + + return list; + } + + /** + * 下划线转驼峰命名 + */ + public static String toUnderScoreCase(String str) { + if (str == null) return null; + + StringBuilder sb = new StringBuilder(); + + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + + if (i > 0) preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + else preCharIsUpperCase = false; + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) sb.append(SEPARATOR); + else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) sb.append(SEPARATOR); + + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + if (str != null && strs != null) { + for (String s : strs) { + if (str.equalsIgnoreCase(trim(s))) return true; + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + StringBuilder result = new StringBuilder(); + + if (name == null || name.isEmpty()) return ""; + else if (!name.contains("_")) return name.substring(0, 1).toUpperCase() + name.substring(1); + + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) continue; + + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + + return result.toString(); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + if (s == null) return null; + + s = s.toLowerCase(); + + StringBuilder sb = new StringBuilder(s.length()); + + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + + /** + * 获取固定长度的随机数字字符串 + * + * @param strLength + * 长度 + * @return 指定长度的随机数字字符串 + * + */ + public static String getFixLenNumString(int strLength) { + StringBuilder result = new StringBuilder(); + + Random random = new Random(); + + for (int i = 0; i < strLength; i++) { + result.append(random.nextInt(10)); + } + + return result.toString(); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } +} \ No newline at end of file diff --git a/src/main/java/com/org/utils/Threads.java b/src/main/java/com/org/utils/Threads.java new file mode 100644 index 0000000..98a90e2 --- /dev/null +++ b/src/main/java/com/org/utils/Threads.java @@ -0,0 +1,71 @@ +package com.org.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.*; + +/** 线程相关工具类 **/ +@Slf4j +public class Threads { + + /** sleep等待,单位为毫秒 **/ + public static void sleep(long milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + log.error("{}", e); + return; + } + } + + /** + * 停止线程池 + * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. + * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. + * 如果仍人超時,則強制退出. + * 另对在shutdown时线程本身被调用中断做了处理. + */ + public static void shutdownAndAwaitTermination(ExecutorService pool) { + if (pool != null && !pool.isShutdown()) { + pool.shutdown(); + try { + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + log.info("Pool did not terminate"); + } + } + } catch (InterruptedException ie) { + log.error("{}", ie); + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + /** + * 打印线程异常信息 + */ + public static void printException(Runnable r, Throwable t) { + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) { + future.get(); + } + } catch (CancellationException ce) { + log.error("{}", ce); + t = ce; + } catch (ExecutionException ee) { + log.error("{}", ee); + t = ee.getCause(); + } catch (InterruptedException ie) { + log.error("{}", ie); + Thread.currentThread().interrupt(); + } + } + if (t != null) { + log.error("{}", t); + } + } +} diff --git a/src/main/java/com/org/utils/core/IdParams.java b/src/main/java/com/org/utils/core/IdParams.java new file mode 100644 index 0000000..50930f0 --- /dev/null +++ b/src/main/java/com/org/utils/core/IdParams.java @@ -0,0 +1,19 @@ +package com.org.utils.core; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * Id请求参数对象 + */ +@Data +public class IdParams { + + /** + * 主键 + */ + @NotNull(message = "ID不能为空") + private Long id; + +} diff --git a/src/main/java/com/org/utils/core/PageParams.java b/src/main/java/com/org/utils/core/PageParams.java new file mode 100644 index 0000000..b18e605 --- /dev/null +++ b/src/main/java/com/org/utils/core/PageParams.java @@ -0,0 +1,29 @@ +package com.org.utils.core; + +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +/** + * 分页参数对象 + */ +@Data +public class PageParams { + + /** + * 页码,默认为1 + */ + @NotNull(message = "页码不能为空") + @Min(value = 1, message ="页码不能小于1") + private Integer pageNum = 1; + + /** + * 分页大小 + */ + @NotNull(message = "分页大小不能为空") + @Min(value = 1, message = "分页大小不能小于1") + @Max(value = 100, message = "分页大小不能大于100") + private Integer pageSize = 10; +} diff --git a/src/main/java/com/org/utils/exception/BaseException.java b/src/main/java/com/org/utils/exception/BaseException.java new file mode 100644 index 0000000..edca38e --- /dev/null +++ b/src/main/java/com/org/utils/exception/BaseException.java @@ -0,0 +1,80 @@ +package com.org.utils.exception; + +import cn.hutool.core.util.StrUtil; +import com.org.utils.MessageUtil; + +/** 基础异常 **/ +public class BaseException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** 所属模块 **/ + private String module; + + /** 错误码 **/ + private String code; + + /** 错误码对应的参数 **/ + private Object[] args; + + /** 错误消息 **/ + private String defaultMessage; + + public BaseException(String module, String code, Object[] args, String defaultMessage) { + this.module = module; + this.code = code; + this.args = args; + this.defaultMessage = defaultMessage; + } + + public BaseException(String module, String code, Object[] args) + { + this(module, code, args, null); + } + + public BaseException(String module, String defaultMessage) + { + this(module, null, null, defaultMessage); + } + + public BaseException(String code, Object[] args) + { + this(null, code, args, null); + } + + public BaseException(String defaultMessage) + { + this(null, null, null, defaultMessage); + } + + @Override + public String getMessage() { + String message = null; + if (!StrUtil.isEmpty(code)) { + message = MessageUtil.message(code, args); + } + if (message == null) { + message = defaultMessage; + } + return message; + } + + public String getModule() + { + return module; + } + + public String getCode() + { + return code; + } + + public Object[] getArgs() + { + return args; + } + + public String getDefaultMessage() + { + return defaultMessage; + } +} diff --git a/src/main/java/com/org/utils/exception/CustomException.java b/src/main/java/com/org/utils/exception/CustomException.java new file mode 100644 index 0000000..8e67d62 --- /dev/null +++ b/src/main/java/com/org/utils/exception/CustomException.java @@ -0,0 +1,39 @@ +package com.org.utils.exception; + +/** 自定义异常 **/ +public class CustomException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + private Integer code; + + private String message; + + public CustomException(String message) + { + this.message = message; + } + + public CustomException(String message, Integer code) + { + this.message = message; + this.code = code; + } + + public CustomException(String message, Throwable e) + { + super(message, e); + this.message = message; + } + + @Override + public String getMessage() + { + return message; + } + + public Integer getCode() + { + return code; + } +} diff --git a/src/main/java/com/org/utils/exception/GlobalExceptionHandler.java b/src/main/java/com/org/utils/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..977b47f --- /dev/null +++ b/src/main/java/com/org/utils/exception/GlobalExceptionHandler.java @@ -0,0 +1,88 @@ +package com.org.utils.exception; + +import com.org.utils.AjaxResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AccountExpiredException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.validation.BindException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.NoHandlerFoundException; + +/** 全局异常处理器 **/ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + /** + * 基础异常 + */ + @ExceptionHandler(BaseException.class) + public AjaxResult baseException(BaseException e) + { + return AjaxResult.error(e.getMessage()); + } + + /** + * 业务异常 + */ + @ExceptionHandler(CustomException.class) + public AjaxResult businessException(CustomException e) { + if (null == e.getCode()) { + return AjaxResult.error(e.getMessage()); + } + return AjaxResult.error(e.getCode(), e.getMessage()); + } + + @ExceptionHandler(NoHandlerFoundException.class) + public AjaxResult handlerNoFoundException(Exception e) { + log.error(e.getMessage(), e); + return AjaxResult.error(HttpStatus.NOT_FOUND.value(), "路径不存在,请检查路径是否正确"); + } + + @ExceptionHandler(AccessDeniedException.class) + public AjaxResult handleAuthorizationException(AccessDeniedException e) { + log.error(e.getMessage()); + return AjaxResult.error(HttpStatus.FORBIDDEN.value(), "没有权限,请联系管理员授权"); + } + + @ExceptionHandler(AccountExpiredException.class) + public AjaxResult handleAccountExpiredException(AccountExpiredException e) { + log.error(e.getMessage(), e); + return AjaxResult.error(e.getMessage()); + } + + @ExceptionHandler(UsernameNotFoundException.class) + public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e) { + log.error(e.getMessage(), e); + return AjaxResult.error(e.getMessage()); + } + + @ExceptionHandler(Exception.class) + public AjaxResult handleException(Exception e) { + log.error(e.getMessage(), e); + return AjaxResult.error(e.getMessage()); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(BindException.class) + public AjaxResult validatedBindException(BindException e) { + log.error(e.getMessage(), e); + String message = e.getAllErrors().get(0).getDefaultMessage(); + return AjaxResult.error(message); + } + + /** + * 自定义验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public Object validExceptionHandler(MethodArgumentNotValidException e) { + log.error(e.getMessage(), e); + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + return AjaxResult.error(message); + } +} diff --git a/src/main/java/com/org/utils/exception/UserException.java b/src/main/java/com/org/utils/exception/UserException.java new file mode 100644 index 0000000..e4f8039 --- /dev/null +++ b/src/main/java/com/org/utils/exception/UserException.java @@ -0,0 +1,11 @@ +package com.org.utils.exception; + +/** 用户信息异常类 **/ +public class UserException extends BaseException { + private static final long serialVersionUID = 1L; + + public UserException(String code, Object[] args) + { + super("user", code, args, null); + } +} diff --git a/src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java b/src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java new file mode 100644 index 0000000..d82b7fd --- /dev/null +++ b/src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java @@ -0,0 +1,12 @@ +package com.org.utils.exception; + +/** 用户密码不正确或不符合规范异常类 **/ +public class UserPasswordNotMatchException extends UserException +{ + private static final long serialVersionUID = 1L; + + public UserPasswordNotMatchException() + { + super("user.password.not.match", null); + } +} diff --git a/src/main/java/com/org/utils/page/PageDomain.java b/src/main/java/com/org/utils/page/PageDomain.java new file mode 100644 index 0000000..20e87ef --- /dev/null +++ b/src/main/java/com/org/utils/page/PageDomain.java @@ -0,0 +1,28 @@ +package com.org.utils.page; + + +import com.org.utils.StringUtils; +import lombok.Data; + +/** 分页数据 **/ +@Data +public class PageDomain { + /** 当前记录起始索引 */ + private Integer pageNum; + + /** 每页显示记录数 */ + private Integer pageSize; + + /** 排序列 */ + private String orderByColumn; + + /** 排序的方向desc或者asc */ + private String isAsc = "asc"; + + public String getOrderBy() { + if (StringUtils.isEmpty(orderByColumn)) return ""; + + return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc; + } + +} diff --git a/src/main/java/com/org/utils/page/TableDataInfo.java b/src/main/java/com/org/utils/page/TableDataInfo.java new file mode 100644 index 0000000..1b9372b --- /dev/null +++ b/src/main/java/com/org/utils/page/TableDataInfo.java @@ -0,0 +1,47 @@ +package com.org.utils.page; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** 表格分页数据对象 **/ +@Data +public class TableDataInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** 总记录数 **/ + private long total; + + /** 当前页码 **/ + private int pageNo; + + /** 列表数据 **/ + private List rows; + + /** 消息状态码 **/ + private int code; + + /** 消息内容 **/ + private String msg; + + /** + * 表格数据对象 + * + */ + public TableDataInfo() { + } + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, int total, int pageNo) { + this.rows = list; + this.total = total; + this.pageNo = pageNo; + } + +} diff --git a/src/main/java/com/org/utils/page/TableSupport.java b/src/main/java/com/org/utils/page/TableSupport.java new file mode 100644 index 0000000..71d003e --- /dev/null +++ b/src/main/java/com/org/utils/page/TableSupport.java @@ -0,0 +1,34 @@ +package com.org.utils.page; + +import com.org.utils.HttpServletUtil; + +/** 表格数据处理 **/ +public class TableSupport { + /** 当前记录起始索引 **/ + public static final String PAGE_NUM = "pageNum"; + + /** 每页显示记录数 **/ + public static final String PAGE_SIZE = "pageSize"; + + /** 排序列 **/ + public static final String ORDER_BY_COLUMN = "orderByColumn"; + + /** 排序的方向 "desc" 或者 "asc". **/ + public static final String IS_ASC = "isAsc"; + + /** 封装分页对象 **/ + public static PageDomain getPageDomain() { + PageDomain pageDomain = new PageDomain(); + + pageDomain.setPageNum(HttpServletUtil.getParameterToInt(PAGE_NUM)); + pageDomain.setPageSize(HttpServletUtil.getParameterToInt(PAGE_SIZE)); + pageDomain.setOrderByColumn(HttpServletUtil.getParameter(ORDER_BY_COLUMN)); + pageDomain.setIsAsc(HttpServletUtil.getParameter(IS_ASC)); + return pageDomain; + } + + public static PageDomain buildPageRequest() + { + return getPageDomain(); + } +} diff --git a/src/main/java/com/org/utils/poi/ExcelUtil.java b/src/main/java/com/org/utils/poi/ExcelUtil.java new file mode 100644 index 0000000..1681ed8 --- /dev/null +++ b/src/main/java/com/org/utils/poi/ExcelUtil.java @@ -0,0 +1,977 @@ +package com.org.utils.poi; + +import cn.hutool.core.convert.Convert; +import com.org.system.annotation.Excel; +import com.org.system.annotation.Excel.ColumnType; +import com.org.system.annotation.Excel.Type; +import com.org.system.annotation.Excels; +import com.org.system.service.SysDataDictionaryItemService; +import com.org.utils.AjaxResult; +import com.org.utils.SpringUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import com.org.utils.reflect.ReflectUtils; +import com.org.utils.upload.CommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; + +import java.io.*; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Excel相关处理 + * + * @author ruoyi + */ +@Slf4j +public class ExcelUtil { + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + /** + * 实体对象 + */ + public Class clazz; + + public ExcelUtil(Class clazz) + { + this.clazz = clazz; + } + + public void init(List list, String sheetName, Type type) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + createExcelField(); + createWorkbook(); + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) throws Exception + { + return importExcel(StringUtils.EMPTY, is); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(String sheetName, InputStream is) throws Exception + { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + Sheet sheet = null; + if (StringUtils.isNotEmpty(sheetName)) + { + // 如果指定sheet名,则取指定sheet中的内容. + sheet = wb.getSheet(sheetName); + } + else + { + // 如果传入的sheet名不存在则默认指向第1个sheet. + sheet = wb.getSheetAt(0); + } + + if (sheet == null) + { + throw new IOException("文件sheet不存在"); + } + + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows > 0) + { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(0); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { + Cell cell = heard.getCell(i); + if (StringUtils.isNotNull(cell)) + { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else + { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + Field[] allFields = clazz.getDeclaredFields(); + // 定义一个map用于存放列的序号和field. + Map fieldsMap = new HashMap(); + for (int col = 0; col < allFields.length; col++) + { + Field field = allFields[col]; + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + // 设置类的私有字段属性可访问. + field.setAccessible(true); + Integer column = cellMap.get(attr.name()); + if (column != null) + { + fieldsMap.put(column, field); + } + } + } + for (int i = 1; i < rows; i++) + { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) + { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = fieldsMap.get(entry.getKey()); + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) + { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) + { + val = StringUtils.substringBefore(s, ".0"); + } + else + { + val = Convert.toStr(val); + } + } + else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toInt(val); + } + else if (Long.TYPE == fieldType || Long.class == fieldType) + { + val = Convert.toLong(val); + } + else if (Double.TYPE == fieldType || Double.class == fieldType) + { + val = Convert.toDouble(val); + } + else if (Float.TYPE == fieldType || Float.class == fieldType) + { + val = Convert.toFloat(val); + } + else if (BigDecimal.class == fieldType) + { + val = Convert.toBigDecimal(val); + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { + val = cn.hutool.core.date.DateUtil.parse(val.toString()); + } + else if (val instanceof Double) + { + val = DateUtil.getJavaDate((Double) val); + } + } + else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) + { + val = Convert.toBool(val, false); + } + if (StringUtils.isNotNull(fieldType)) + { + Excel attr = field.getAnnotation(Excel.class); + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) + { + propertyName = field.getName() + "." + attr.targetAttr(); + } + else if (StringUtils.isNotEmpty(attr.readConverterExp())) + { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + else if (StringUtils.isNotEmpty(attr.dictType())) + { + val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult exportExcel(List list, String sheetName) + { + this.init(list, sheetName, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName) + { + this.init(null, sheetName, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() + { + OutputStream out = null; + try + { + // 取出一共有多少个sheet. + double sheetNo = Math.ceil(list.size() / sheetSize); + for (int index = 0; index <= sheetNo; index++) + { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(0); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + this.createCell(excel, row, column++); + } + if (Type.EXPORT.equals(type)) + { + fillExcelData(index, row); + addStatisticsRow(); + } + } + String filename = encodingFilename(sheetName); + out = new FileOutputStream(getAbsoluteFile(filename)); + wb.write(out); + return AjaxResult.success("导出成功", filename); + } + catch (Exception e) + { + log.error("导出Excel异常{}", e.getMessage()); + throw new CustomException("导出Excel失败,请联系网站管理员!"); + } + finally + { + if (wb != null) + { + try + { + wb.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + if (out != null) + { + try + { + out.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + public void fillExcelData(int index, Row row) + { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + for (int i = startNo; i < endNo; i++) + { + row = sheet.createRow(i + 1 - startNo); + // 得到导出对象. + T vo = (T) list.get(i); + int column = 0; + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + // 设置实体类私有属性可访问 + field.setAccessible(true); + this.addCell(excel, row, vo, field, column++); + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) + { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); + + return styles; + } + + /** + * 创建单元格 + */ + public Cell createCell(Excel attr, Row row, int column) + { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get("header")); + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType()) + { + cell.setCellType(CellType.STRING); + cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); + } + else if (ColumnType.NUMERIC == attr.cellType()) + { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } + + /** + * 创建表格样式 + */ + public void setDataValidation(Excel attr, Row row, int column) + { + if (attr.name().indexOf("注:") >= 0) + { + sheet.setColumnWidth(column, 6000); + } + else + { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + row.setHeight((short) (attr.height() * 20)); + } + // 如果设置了提示信息则鼠标放上去提示. + if (StringUtils.isNotEmpty(attr.prompt())) + { + // 这里默认设了2-101列提示. + setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); + } + // 如果设置了combo属性则本列只能选择不能输入 + if (attr.combo().length > 0) + { + // 这里默认设了2-101列只能选择不能输入. + setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); + } + } + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 设置行高 + row.setHeight((short) (attr.height() * 20)); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(column); + cell.setCellStyle(styles.get("data")); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) + { + cell.setCellValue(cn.hutool.core.date.DateUtil.format((Date) value, dateFormat)); + } + else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); + } + else + { + // 设置列类型 + setCellVo(value, attr, cell); + } + addStatisticsData(column, Convert.toStr(value), attr); + } + } + catch (Exception e) + { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示 + * + * @param sheet 表单 + * @param promptTitle 提示标题 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + dataValidation.createPromptBox(promptTitle, promptContent); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框. + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + * @return 设置好的sheet. + */ + public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(separator, propertyValue)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[0].equals(value)) + { + propertyString.append(itemArray[1] + separator); + break; + } + } + } + else + { + if (itemArray[0].equals(propertyValue)) + { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(separator, propertyValue)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[1].equals(value)) + { + propertyString.append(itemArray[0] + separator); + break; + } + } + } + else + { + if (itemArray[1].equals(propertyValue)) + { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) + { + return SpringUtil.getBean(SysDataDictionaryItemService.class).findDictonaryBydictonaryCode(dictType, Integer.parseInt(dictValue)); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) { + return ""; + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) + { + if (entity != null && entity.isStatistics()) + { + Double temp = 0D; + if (!statistics.containsKey(index)) + { + statistics.put(index, temp); + } + try + { + temp = Double.valueOf(text); + } + catch (NumberFormatException e) + { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() + { + if (statistics.size() > 0) + { + Cell cell = null; + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) + { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } + } + + /** + * 编码文件名 + */ + public String encodingFilename(String filename) + { + filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) + { + String downloadPath = CommonUtil.downloadPath + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception + { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) + { + String target = excel.targetAttr(); + if (target.indexOf(".") > -1) + { + String[] targets = target.split("[.]"); + for (String name : targets) + { + o = getValue(o, name); + } + } + else + { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception + { + if (StringUtils.isNotEmpty(name)) + { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + private void createExcelField() + { + this.fields = new ArrayList(); + List tempFields = new ArrayList<>(); + tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); + tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); + for (Field field : tempFields) + { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) + { + putToField(field, field.getAnnotation(Excel.class)); + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) + { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel excel : excels) + { + putToField(field, excel); + } + } + } + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + } + + /** + * 放到字段集合中 + */ + private void putToField(Field field, Excel attr) + { + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { + this.fields.add(new Object[] { field, attr }); + } + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(double sheetNo, int index) + { + this.sheet = wb.createSheet(); + this.styles = createStyles(wb); + // 设置工作表的名称. + if (sheetNo == 0) + { + wb.setSheetName(index, sheetName); + } + else + { + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) + { + if (row == null) + { + return row; + } + Object val = ""; + try + { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) + { + if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) + { + val = cell.getNumericCellValue(); + if (HSSFDateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } + else + { + if ((Double) val % 1 > 0) + { + val = new BigDecimal(val.toString()); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellTypeEnum() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellTypeEnum() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellTypeEnum() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } +} \ No newline at end of file diff --git a/src/main/java/com/org/utils/reflect/ReflectUtils.java b/src/main/java/com/org/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..da0e6a2 --- /dev/null +++ b/src/main/java/com/org/utils/reflect/ReflectUtils.java @@ -0,0 +1,402 @@ +package com.org.utils.reflect; + +import cn.hutool.core.convert.Convert; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.time.DateUtils; +import org.apache.poi.ss.usermodel.DateUtil; + +import java.lang.reflect.*; +import java.util.Date; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + */ +@Slf4j +@SuppressWarnings("rawtypes") +public class ReflectUtils +{ + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) + { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) + { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, E value) + { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) + { + if (i < names.length - 1) + { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + } + else + { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + invokeMethodByName(object, setterMethodName, new Object[] { value }); + } + } + } + + /** + * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. + */ + @SuppressWarnings("unchecked") + public static E getFieldValue(final Object obj, final String fieldName) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + log.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return null; + } + E result = null; + try + { + result = (E) field.get(obj); + } + catch (IllegalAccessException e) + { + log.error("不可能抛出的异常{}", e.getMessage()); + } + return result; + } + + /** + * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. + */ + public static void setFieldValue(final Object obj, final String fieldName, final E value) + { + Field field = getAccessibleField(obj, fieldName); + if (field == null) + { + // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + log.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return; + } + try + { + field.set(obj, value); + } + catch (IllegalAccessException e) + { + log.error("不可能抛出的异常: {}", e.getMessage()); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符. + * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. + * 同时匹配方法名+参数类型, + */ + @SuppressWarnings("unchecked") + public static E invokeMethod(final Object obj, final String methodName, final Class[] parameterTypes, + final Object[] args) + { + if (obj == null || methodName == null) + { + return null; + } + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) + { + log.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + */ + @SuppressWarnings("unchecked") + public static E invokeMethodByName(final Object obj, final String methodName, final Object[] args) + { + Method method = getAccessibleMethodByName(obj, methodName, args.length); + if (method == null) + { + // 如果为空不报错,直接返回空。 + log.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); + return null; + } + try + { + // 类型转换(将参数数据类型转换为目标方法参数类型) + Class[] cs = method.getParameterTypes(); + for (int i = 0; i < cs.length; i++) + { + if (args[i] != null && !args[i].getClass().equals(cs[i])) + { + if (cs[i] == String.class) + { + args[i] = Convert.toStr(args[i]); + if (StringUtils.endsWith((String) args[i], ".0")) + { + args[i] = StringUtils.substringBefore((String) args[i], ".0"); + } + } + else if (cs[i] == Integer.class) + { + args[i] = Convert.toInt(args[i]); + } + else if (cs[i] == Long.class) + { + args[i] = Convert.toLong(args[i]); + } + else if (cs[i] == Double.class) + { + args[i] = Convert.toDouble(args[i]); + } + else if (cs[i] == Float.class) + { + args[i] = Convert.toFloat(args[i]); + } + else if (cs[i] == Date.class) + { + if (args[i] instanceof String) + { + args[i] = DateUtils.parseDate(args[i].toString()); + } + else + { + args[i] = DateUtil.getJavaDate((Double) args[i]); + } + } + else if (cs[i] == boolean.class || cs[i] == Boolean.class) + { + args[i] = Convert.toBool(args[i]); + } + } + } + return (E) method.invoke(obj, args); + } + catch (Exception e) + { + String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; + throw convertReflectionExceptionToUnchecked(msg, e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(fieldName, "fieldName can't be blank"); + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) + { + try + { + Field field = superClass.getDeclaredField(fieldName); + makeAccessible(field); + return field; + } + catch (NoSuchFieldException e) + { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 匹配函数名+参数类型。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethod(final Object obj, final String methodName, + final Class... parameterTypes) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + try + { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); + makeAccessible(method); + return method; + } + catch (NoSuchMethodException e) + { + continue; + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) + { + // 为空不报错。直接返回 null + if (obj == null) + { + return null; + } + Validate.notBlank(methodName, "methodName can't be blank"); + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) + { + Method[] methods = searchType.getDeclaredMethods(); + for (Method method : methods) + { + if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) + { + makeAccessible(method); + return method; + } + } + } + return null; + } + + /** + * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Method method) + { + if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.isAccessible()) + { + method.setAccessible(true); + } + } + + /** + * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 + */ + public static void makeAccessible(Field field) + { + if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) + || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) + { + field.setAccessible(true); + } + } + + /** + * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 + * 如无法找到, 返回Object.class. + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) + { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + */ + public static Class getClassGenricType(final Class clazz, final int index) + { + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) + { + log.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) + { + log.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) + { + log.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + public static Class getUserClass(Object instance) + { + if (instance == null) + { + throw new RuntimeException("Instance must not be null"); + } + Class clazz = instance.getClass(); + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) + { + Class superClass = clazz.getSuperclass(); + if (superClass != null && !Object.class.equals(superClass)) + { + return superClass; + } + } + return clazz; + + } + + /** + * 将反射时的checked exception转换为unchecked exception. + */ + public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) + { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) + { + return new IllegalArgumentException(msg, e); + } + else if (e instanceof InvocationTargetException) + { + return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); + } + return new RuntimeException(msg, e); + } +} diff --git a/src/main/java/com/org/utils/spring/SpringUtils.java b/src/main/java/com/org/utils/spring/SpringUtils.java new file mode 100644 index 0000000..e1da481 --- /dev/null +++ b/src/main/java/com/org/utils/spring/SpringUtils.java @@ -0,0 +1,144 @@ +package com.org.utils.spring; + +import com.org.utils.StringUtils; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * spring工具类 方便在非spring管理环境中获取bean + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + private static ApplicationContext applicationContext; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + SpringUtils.beanFactory = beanFactory; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + SpringUtils.applicationContext = applicationContext; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws org.springframework.beans.BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException + { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws org.springframework.beans.BeansException + * + */ + public static T getBean(Class clz) throws BeansException + { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) + { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) + { + return (T) AopContext.currentProxy(); + } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() + { + return applicationContext.getEnvironment().getActiveProfiles(); + } + + /** + * 获取当前的环境配置,当有多个环境配置时,只获取第一个 + * + * @return 当前的环境配置 + */ + public static String getActiveProfile() + { + final String[] activeProfiles = getActiveProfiles(); + return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; + } +} diff --git a/src/main/java/com/org/utils/upload/CommonUtil.java b/src/main/java/com/org/utils/upload/CommonUtil.java new file mode 100644 index 0000000..8c8dbd9 --- /dev/null +++ b/src/main/java/com/org/utils/upload/CommonUtil.java @@ -0,0 +1,98 @@ +package com.org.utils.upload; + +import cn.hutool.core.util.IdUtil; +import com.org.utils.HttpServletUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import javax.imageio.stream.FileImageOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.File; + +@Slf4j +@Component +public class CommonUtil { + + public static String downloadPath; + + @Value("${oss.downloadPath}") + public void setDownloadPath(String downloadPath){ + this.downloadPath = downloadPath; + if(!this.downloadPath.endsWith(File.separator)) this.downloadPath += File.separator; + } + + public static String getDownloadPath(){ + log.info("CommonUtil - getDownloadPath downloadPath:{}", downloadPath); + return downloadPath; + } + + /** + * 通用文件下载 + * + * @param fileName + * @param delete + */ + public static void download(String fileName, boolean delete){ + log.info("commonUtil - download fileName:{}", fileName); + log.info("commonUtil - download delete:{}", delete); + + try{ + if (!FileUtils.checkAllowDownload(fileName)) { + throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); + } + String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); + String filePath = downloadPath + fileName; + + HttpServletResponse response = HttpServletUtil.getResponse(); + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, realFileName); + FileUtils.writeBytes(filePath, response.getOutputStream()); + + if (delete) FileUtils.deleteFile(filePath); + } catch (Exception e) { + log.error("下载文件失败 {}", e); + } + } + + /** + * 通用下载文件保存 + * + * @param data + * @param fileName + * @return + */ + public static String saveFile(byte[] data, String fileName) { + log.info("commonUtil - saveFile fileName:{}", fileName); + + if (data.length < 3 ) throw new CustomException("上传文件为空"); + + try { + fileName = IdUtil.simpleUUID() + "-" + fileName; + String dateDir = fileName.split("/")[1]; + + //文件夹 + File dirFile = new File(downloadPath); + if (!dirFile.exists()) dirFile.mkdirs(); + + File file = new File(downloadPath + fileName); + if (!file.exists()) file.createNewFile(); + + //打开输入流 + FileImageOutputStream imageOutput = new FileImageOutputStream(file); + imageOutput.write(data, 0, data.length); + imageOutput.close(); + } catch (Exception e) { + log.error("{}", e); + throw new CustomException("上传文件失败", e); + } + + return fileName; + } + + +} diff --git a/src/main/java/com/org/utils/upload/FileTypeUtils.java b/src/main/java/com/org/utils/upload/FileTypeUtils.java new file mode 100644 index 0000000..de1ae6c --- /dev/null +++ b/src/main/java/com/org/utils/upload/FileTypeUtils.java @@ -0,0 +1,39 @@ +package com.org.utils.upload; + +import org.apache.commons.lang3.StringUtils; + +import java.io.File; + +/** 文件类型工具类 **/ +public class FileTypeUtils { + /** + * 获取文件类型 + *

+ * 例如: ruoyi.txt, 返回: txt + * + * @param file 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(File file) { + if (null == file) { + return StringUtils.EMPTY; + } + return getFileType(file.getName()); + } + + /** + * 获取文件类型 + *

+ * 例如: ruoyi.txt, 返回: txt + * + * @param fileName 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(String fileName) { + int separatorIndex = fileName.lastIndexOf("."); + if (separatorIndex < 0) { + return ""; + } + return fileName.substring(separatorIndex + 1).toLowerCase(); + } +} \ No newline at end of file diff --git a/src/main/java/com/org/utils/upload/FileUtils.java b/src/main/java/com/org/utils/upload/FileUtils.java new file mode 100644 index 0000000..875c10c --- /dev/null +++ b/src/main/java/com/org/utils/upload/FileUtils.java @@ -0,0 +1,248 @@ +package com.org.utils.upload; + +import cn.hutool.core.codec.Base64; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** 文件处理工具类 **/ +@Slf4j +public class FileUtils extends org.apache.commons.io.FileUtils { + public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; + + /** + * 输出指定文件的byte数组 + * + * @param filePath 文件路径 + * @param os 输出流 + * @return + */ + public static void writeBytes(String filePath, OutputStream os) throws IOException { + FileInputStream fis = null; + + try { + File file = new File(filePath); + if (!file.exists()) { + throw new FileNotFoundException(filePath); + } + + fis = new FileInputStream(file); + byte[] b = new byte[1024]; + int length; + while ((length = fis.read(b)) > 0) { + os.write(b, 0, length); + } + } catch (IOException e) { + throw e; + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException e1) { + log.error("{}", e1); + } + } + if (fis != null) { + try { + fis.close(); + } catch (IOException e1) { + log.error("{}", e1); + } + } + } + } + + /** + * 删除文件 + * + * @param filePath 文件 + * @return + */ + public static boolean deleteFile(String filePath) { + boolean flag = false; + + File file = new File(filePath); + + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + file.delete(); + flag = true; + } + + return flag; + } + + /** + * 文件名称验证 + * + * @param filename 文件名称 + * @return true 正常 false 非法 + */ + public static boolean isValidFilename(String filename) { + return filename.matches(FILENAME_PATTERN); + } + + /** + * 检查文件是否可下载 + * + * @param resource 需要下载的文件 + * @return true 正常 false 非法 + */ + public static boolean checkAllowDownload(String resource) { + // 禁止目录上跳级别 + if (StringUtils.contains(resource, "..")) { + return false; + } + + // 检查允许下载的文件规则 + if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) { + return true; + } + + // 不在允许下载的文件规则 + return false; + } + + /** + * 下载文件名重新编码 + * + * @param request 请求对象 + * @param fileName 文件名 + * @return 编码后的文件名 + */ + public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException { + final String agent = request.getHeader("USER-AGENT"); + String filename = fileName; + if (agent.contains("MSIE")) { + // IE浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + filename = filename.replace("+", " "); + } else if (agent.contains("Firefox")) { + // 火狐浏览器 + filename = new String(fileName.getBytes(), "ISO8859-1"); + } else if (agent.contains("Chrome")) { + // google浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } else { + // 其它浏览器 + filename = URLEncoder.encode(filename, "utf-8"); + } + return filename; + } + + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + * @return + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException { + String percentEncodedFileName = percentEncode(realFileName); + + StringBuilder contentDispositionValue = new StringBuilder(); + contentDispositionValue.append("attachment; filename=") + .append(percentEncodedFileName) + .append(";") + .append("filename*=") + .append("utf-8''") + .append(percentEncodedFileName); + + response.setHeader("Content-disposition", contentDispositionValue.toString()); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) throws UnsupportedEncodingException { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); + return encode.replaceAll("\\+", "%20"); + } + + /** + * 文件转Base64 + * @param fileUrl + * @return + */ + public static String fileToBase64(String fileUrl) { + if(StringUtils.isEmpty(fileUrl)) return null; + + if(fileUrl.startsWith("http")) return urlFileToBase64(fileUrl); + + String base64 = null; + FileInputStream fin = null; + try { + fin = new FileInputStream(new File(fileUrl)); + byte[] buff = new byte[fin.available()]; + fin.read(buff); + base64 = Base64.encode(buff); + } catch (FileNotFoundException e) { + log.error("{}", e); + throw new CustomException("文件转Base64异常"); + } catch (IOException e) { + log.error("{}", e); + throw new CustomException("文件转Base64异常"); + } finally { + if (fin != null) { + try { + fin.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return base64; + } + + /** + * 将网络路径图片转为base64的格式 + * @param fileUrl 请求网络路径 + * @throws Exception + */ + public static String urlFileToBase64(String fileUrl) { + if(StringUtils.isEmpty(fileUrl)) return null; + + String base64 = null; + ByteArrayOutputStream data = new ByteArrayOutputStream(); + + try { + // 创建URL + URL url = new URL(fileUrl); + byte[] by = new byte[1024]; + + // 创建链接 + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setConnectTimeout(5 * 1000); + InputStream is = conn.getInputStream(); + + // 将内容读取内存中 + int len = -1; + while ((len = is.read(by)) != -1) { + data.write(by, 0, len); + } + + base64 = Base64.encode(data.toByteArray()); + + // 关闭流 + is.close(); + } catch (IOException e) { + log.error("{}", e); + } + + return base64; + } + +} diff --git a/src/main/java/com/org/utils/upload/MimeTypeUtils.java b/src/main/java/com/org/utils/upload/MimeTypeUtils.java new file mode 100644 index 0000000..31dd863 --- /dev/null +++ b/src/main/java/com/org/utils/upload/MimeTypeUtils.java @@ -0,0 +1,48 @@ +package com.org.utils.upload; + +/** 媒体类型工具类 **/ +public class MimeTypeUtils { + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; + + public static final String[] FLASH_EXTENSION = { "swf", "flv" }; + + public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb" }; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // pdf + "pdf" }; + + public static String getExtension(String prefix) { + switch (prefix) { + case IMAGE_PNG: + return "png"; + case IMAGE_JPG: + return "jpg"; + case IMAGE_JPEG: + return "jpeg"; + case IMAGE_BMP: + return "bmp"; + case IMAGE_GIF: + return "gif"; + default: + return ""; + } + } +} diff --git a/src/main/java/com/org/utils/upload/UpLoadUtil.java b/src/main/java/com/org/utils/upload/UpLoadUtil.java new file mode 100644 index 0000000..61c01f3 --- /dev/null +++ b/src/main/java/com/org/utils/upload/UpLoadUtil.java @@ -0,0 +1,305 @@ +package com.org.utils.upload; + +import cn.hutool.core.date.DateUtil; +import com.org.utils.HttpServletUtil; +import com.org.utils.ImagePicUtil; +import com.org.utils.StringUtils; +import com.org.utils.exception.CustomException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.stream.FileImageOutputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLEncoder; +import java.util.Date; +import java.util.UUID; + +/** 服务器存储 **/ +@Slf4j +@Component +public class UpLoadUtil { + + public static String diskPath; + public static String proxyServer; + + @Value("${oss.diskPath}") + public void setDiskPath(String diskPath){ + UpLoadUtil.diskPath = diskPath; + } + @Value("${oss.proxyServer}") + public void setProxyServer(String proxyServer){ + UpLoadUtil.proxyServer = proxyServer; + } + + public static String upload(byte[] data, String path) { + if (data.length < 3 || "".equals(path)) throw new CustomException("上传文件为空"); + + //本地存储必需要以"/"开头 + if (!path.startsWith("/")) path = "/" + path; + + try { + String fileName = diskPath + path; + String dateDir = path.split("/")[1]; + + //文件夹 + File dirFile = new File(diskPath + "/" + dateDir); + if (!dirFile.exists()) dirFile.mkdirs(); + + File file = new File(fileName); + if (!file.exists()) file.createNewFile(); + + //打开输入流 + FileImageOutputStream imageOutput = new FileImageOutputStream(file); + imageOutput.write(data, 0, data.length); + imageOutput.close(); + } catch (Exception e) { + log.error("{}", e); + throw new CustomException("上传文件失败", e); + } + + return proxyServer + path; +// return uploadCOS(path); + } + + public static String upload(InputStream inputStream, String path) { + try { + byte[] data = IOUtils.toByteArray(inputStream); + return upload(data, path); + } catch (IOException e) { + log.error("{}",e); + throw new CustomException("上传文件失败", e); + } + } + + + /** + * 文件路径 + * + * @param prefix 前缀 + * @param suffix 后缀 + * @return 返回上传路径 + */ + public static String getPath(String prefix, String suffix) { + //生成uuid + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + //文件路径 + String path = DateUtil.format(new Date(), "yyyyMMdd") + "/" + uuid; + + if (StringUtils.isNotBlank(prefix)) path = prefix + "/" + path; + + return path + suffix; + } + + public static String uploadSuffix(byte[] data, String suffix) { + return upload(data, getPath("", suffix)); + } + + public static String uploadSuffix(InputStream inputStream, String suffix) { + return upload(inputStream, getPath("", suffix)); + } + + /** + * 获取文件 + * + * @param fileFullPath + */ + public static void getFile(String fileFullPath, String fileName){ + log.info("UpLoadUtil - getFile fileFullPath:{}", fileFullPath); + + HttpServletResponse response = HttpServletUtil.getResponse(); + HttpServletRequest request = HttpServletUtil.getRequest(); + + File file = new File(fileFullPath); + if (!file.exists()) return; + + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + byte[] data = null; + + if (fileFullPath.toLowerCase().endsWith("png") || fileFullPath.toLowerCase().endsWith("jpeg") + || fileFullPath.toLowerCase().endsWith("bmp") || fileFullPath.toLowerCase().endsWith("gif") + || fileFullPath.toLowerCase().endsWith("jpg")) { + response.setContentType("image/jpeg"); + + // 如果是图片 则走图片是否缩放检查 + data = getImage(fileFullPath, request); + } else if (fileFullPath.toLowerCase().endsWith("pdf")) { + response.setContentType(MediaType.APPLICATION_PDF_VALUE); + } else { + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + } + + if(data == null){ + data = new byte[(int) file.length()]; + int length = fis.read(data); + } + + // 设置下载文件的名称 + setHeader(request, response, fileName); + + ServletOutputStream stream = response.getOutputStream(); + stream.write(data); + stream.flush(); + stream.close(); + } catch (Exception e) { + log.error("{}", e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + log.error("{}", e); + } + } + } + } + + /** + * 设置下载文件的文件名称 + * @param request + * @param response + * @param fileName + * @return + */ + private static boolean setHeader(HttpServletRequest request, HttpServletResponse response, String fileName) { + try { + response.setContentType("application/octet-stream"); + response.setHeader("content-type", "application/octet-stream"); + String browser = request.getHeader("User-Agent"); + if (-1 < browser.indexOf("MSIE 6.0") || -1 < browser.indexOf("MSIE 7.0")) { + // IE6, IE7 浏览器 + response.addHeader("content-disposition", "attachment;filename=" + + new String(fileName.getBytes(), "ISO8859-1")); + } else if (-1 < browser.indexOf("MSIE 8.0")) { + // IE8 + response.addHeader("content-disposition", "attachment;filename=" + + URLEncoder.encode(fileName, "UTF-8")); + } else if (-1 < browser.indexOf("MSIE 9.0")) { + // IE9 + response.addHeader("content-disposition", "attachment;filename=" + + URLEncoder.encode(fileName, "UTF-8")); + } else if (-1 < browser.indexOf("Chrome")) { + // 谷歌 + response.addHeader("content-disposition", + "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8")); + } else if (-1 < browser.indexOf("Safari")) { + // 苹果 + response.addHeader("content-disposition", "attachment;filename=" + + new String(fileName.getBytes(), "ISO8859-1")); + } else { + // 火狐或者其他的浏览器 + response.addHeader("content-disposition", + "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8")); + } + return true; + } catch (Exception e) { + log.error(e.getMessage()); + return false; + } + } + + /** + * 获取视频 + * + * @param fileFullPath + */ + public static void getVideo(String fileFullPath) { + log.info("UpLoadUtil - getVideo fileFullPath:{}", fileFullPath); + + HttpServletRequest request = HttpServletUtil.getRequest(); + HttpServletResponse response = HttpServletUtil.getResponse(); + + response.reset(); + + String rangeInHeader = request.getHeader("Range");//形如bytes=xxx-xxx + + File file = new File(fileFullPath); + long contentLength = file.length(), start = 0, end = 0; + + if(StringUtils.isNotEmpty(rangeInHeader)){ + String[] range = rangeInHeader.split("=")[1].split("-"); + start = Long.valueOf(range[0]); + if(range.length > 1) end = Long.valueOf(range[1]); + } + + long requestSize = 0; + if(end != 0 && end > start) requestSize = end - start + 1; + else requestSize = Integer.MAX_VALUE; + + response.setContentType("multipart/byteranges"); + response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("Last-Modified", new Date().toString()); + + //第一次请求只返回content length来让客户端请求多次实际数据 + if(StringUtils.isEmpty(rangeInHeader)){ + response.setHeader("Content-length", contentLength + ""); + } else { + //以后的多次以断点续传的方式来返回视频数据 + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206 + + if(end > 0){ + response.setHeader("Content-length", "" + requestSize); + response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + contentLength); + }else{ + response.setHeader("Content-length", contentLength - start + ""); + response.setHeader("Content-Range", "bytes "+ start + "-" + (contentLength - 1) + "/" + contentLength); + } + + } + + try (BufferedInputStream br = new BufferedInputStream(new FileInputStream(file))) { + + //---------跳过已传输过的字节-------------- + br.skip(start); + OutputStream out = response.getOutputStream(); + + //-----------向输出流写入数据--------- + int len; + int needSize = Integer.parseInt(String.valueOf(requestSize)); + byte[] buffer = new byte[4096]; + + while ((len = br.read(buffer)) > 0) { + if(requestSize < buffer.length){ + out.write(buffer, 0, needSize); + } else{ + out.write(buffer, 0, len); + if(len < buffer.length) break; + } + needSize -= buffer.length; + } + + } catch (Exception e) { + log.error("{}", e); + } + } + + /** + * 根据传入的宽度获取固定宽度的图片 + * @param fileFullPath + * @param request + * @return + * @throws IOException + */ + private static byte[] getImage(String fileFullPath, HttpServletRequest request) throws IOException { + log.info("UpLoadUtil - getImage fileFullPath:{}", fileFullPath); + + String width = request.getParameter("width"); + + if(StringUtils.isNotEmpty(width)){ + MultipartFile imagePic = ImagePicUtil.getImagePic(fileFullPath, Integer.parseInt(width), "temp.jpg"); + + if(imagePic == null) return null; + return imagePic.getBytes(); + } + + return null; + } +} diff --git a/src/main/java/com/org/web/honor/controller/BcHonorShowController.java b/src/main/java/com/org/web/honor/controller/BcHonorShowController.java new file mode 100644 index 0000000..574bc38 --- /dev/null +++ b/src/main/java/com/org/web/honor/controller/BcHonorShowController.java @@ -0,0 +1,83 @@ +package com.org.web.honor.controller; + +import com.org.system.annotation.Log; +import com.org.system.controller.BaseController; +import com.org.system.enums.BusinessType; +import com.org.utils.AjaxResult; +import com.org.utils.core.IdParams; +import com.org.utils.page.TableDataInfo; +import com.org.web.honor.domain.BcHonorShow; +import com.org.web.honor.service.BcHonorShowService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/honor/show") +public class BcHonorShowController extends BaseController { + + @Autowired + BcHonorShowService bcHonorShowService; + + /** + * 新增 + */ + @PostMapping("/addOrUpdate") + @PreAuthorize("@ss.hasPermi('honor:show:add')") + @Log(title = "荣誉橱窗展示新增/编辑", businessType = BusinessType.INSERT) + public AjaxResult add(@Validated @RequestBody BcHonorShow bcHonorShow) { + log.info("BcHonorShowController - add bcHonorShow:{}", bcHonorShow); + + return AjaxResult.success(bcHonorShowService.executeSaveOrUpdate(bcHonorShow)); + } + + /** + * 删除 + */ + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('honor:show:del')") + @Log(title = "荣誉橱窗展示删除", businessType = BusinessType.DELETE) + public AjaxResult del(@Validated @RequestBody IdParams params) { + log.info("BcHonorShowController - del params:{}", params); + + return AjaxResult.success(bcHonorShowService.del(params.getId())); + } + + /** + * 详情 + */ + @PostMapping("/detail") + @PreAuthorize("@ss.hasAnyPermi('honor:show:detail')") + @Log(title = "荣誉橱窗展示详情", businessType = BusinessType.SELECT) + public AjaxResult detail(@Validated @RequestBody IdParams params) { + log.info("BcHonorShowController - detail params:{}", params); + + return AjaxResult.success(bcHonorShowService.getById(params.getId())); + } + + /** + * 列表查询 + */ + @GetMapping("/list") + @PreAuthorize("@ss.hasAnyPermi('honor:show:detail')") + @Log(title = "荣誉橱窗展示列表查询", businessType = BusinessType.SELECT) + public TableDataInfo list(BcHonorShow params) { + + log.info("BcHonorShowController - list params:{}", params); + + startPage(); + + List list = bcHonorShowService.listShow(params); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + + +} diff --git a/src/main/java/com/org/web/honor/domain/BcHonorShow.java b/src/main/java/com/org/web/honor/domain/BcHonorShow.java new file mode 100644 index 0000000..f094020 --- /dev/null +++ b/src/main/java/com/org/web/honor/domain/BcHonorShow.java @@ -0,0 +1,44 @@ +package com.org.web.honor.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + + +/** + * 荣誉橱窗展示 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_honor_show") +public class BcHonorShow extends BaseEntity { + + /** id */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 展示类型 + */ + private Integer type; + + /** + * 标题 + */ + private String title; + + /** + * 内容 + */ + private String content; + + /** + * 附件 + */ + private String files; + + public BcHonorShow() {} +} diff --git a/src/main/java/com/org/web/honor/mapper/BcHonorShowMapper.java b/src/main/java/com/org/web/honor/mapper/BcHonorShowMapper.java new file mode 100644 index 0000000..90c24cd --- /dev/null +++ b/src/main/java/com/org/web/honor/mapper/BcHonorShowMapper.java @@ -0,0 +1,26 @@ +package com.org.web.honor.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.honor.domain.BcHonorShow; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface BcHonorShowMapper extends BaseMapper { + + @Select("") + List queryList(BcHonorShow params); + +} diff --git a/src/main/java/com/org/web/honor/service/BcHonorShowService.java b/src/main/java/com/org/web/honor/service/BcHonorShowService.java new file mode 100644 index 0000000..94e197b --- /dev/null +++ b/src/main/java/com/org/web/honor/service/BcHonorShowService.java @@ -0,0 +1,61 @@ +package com.org.web.honor.service; + + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.enums.YesOrNoState; +import com.org.utils.SecurityUtil; +import com.org.utils.exception.CustomException; +import com.org.web.honor.domain.BcHonorShow; +import com.org.web.honor.mapper.BcHonorShowMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +@Service +@Slf4j +public class BcHonorShowService extends ServiceImpl { + + /** + * 新增或编辑 + */ + public boolean executeSaveOrUpdate(BcHonorShow bcHonorShow) { + log.info("BcHonorShowService - executeSaveOrUpdate bcHonorShow:{}", bcHonorShow); + + if (ObjectUtil.isEmpty(bcHonorShow.getId())) { + bcHonorShow.setCreateBy(SecurityUtil.getUserId()); + bcHonorShow.setCreateTime(new Date()); + bcHonorShow.setIsDelete(YesOrNoState.NO.getState()); + } else { + bcHonorShow.setUpdateBy(SecurityUtil.getUserId()); + bcHonorShow.setUpdateTime(new Date()); + } + return saveOrUpdate(bcHonorShow); + } + + /** + * 删除 + */ + public boolean del(Long id) { + log.info("BcHonorShowService - del id:{}", id); + + BcHonorShow bcHonorShow = getById(id); + if (ObjectUtil.isEmpty(bcHonorShow)) { + throw new CustomException("删除记录不存在"); + } + bcHonorShow.setIsDelete(YesOrNoState.YES.getState()); + bcHonorShow.setDeleteBy(SecurityUtil.getUserId()); + bcHonorShow.setDeleteTime(new Date()); + return updateById(bcHonorShow); + } + + /** + * 列表查询 + */ + public List listShow(BcHonorShow params) { + return baseMapper.queryList(params); + } + +} diff --git a/src/main/java/com/org/web/hospital/controller/BcHospitalRecordController.java b/src/main/java/com/org/web/hospital/controller/BcHospitalRecordController.java new file mode 100644 index 0000000..c470bd2 --- /dev/null +++ b/src/main/java/com/org/web/hospital/controller/BcHospitalRecordController.java @@ -0,0 +1,117 @@ +package com.org.web.hospital.controller; + +import com.org.system.annotation.Log; +import com.org.system.controller.BaseController; +import com.org.system.enums.BusinessType; +import com.org.utils.AjaxResult; +import com.org.utils.core.IdParams; +import com.org.utils.page.TableDataInfo; +import com.org.web.hospital.domain.BcHospitalRecord; +import com.org.web.hospital.service.BcHospitalRecordService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/hospital/record") +public class BcHospitalRecordController extends BaseController { + + @Autowired + BcHospitalRecordService hospitalRecordService; + + /** + * 新增 + */ + @PostMapping("/addOrUpdate") + @PreAuthorize("@ss.hasPermi('hospital:record:add')") + @Log(title = "入住退房管理新增/编辑", businessType = BusinessType.INSERT) + public AjaxResult add(@Validated @RequestBody BcHospitalRecord bcHospitalRecord) { + log.info("BcHospitalRecordController - add bcHospitalRecord:{}", bcHospitalRecord); + + return AjaxResult.success(hospitalRecordService.executeSaveOrUpdate(bcHospitalRecord)); + } + + /** + * 删除 + */ + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('hospital:record:del')") + @Log(title = "入住退房管理删除", businessType = BusinessType.DELETE) + public AjaxResult del(@Validated @RequestBody IdParams params) { + log.info("BcHospitalRecordController - del params:{}", params); + + return AjaxResult.success(hospitalRecordService.del(params.getId())); + } + + /** + * 详情 + */ + @PostMapping("/detail") + @PreAuthorize("@ss.hasAnyPermi('hospital:record:detail')") + @Log(title = "入住退房管理详情", businessType = BusinessType.SELECT) + public AjaxResult detail(@Validated @RequestBody IdParams params) { + log.info("BcHospitalRecordController - detail params:{}", params); + + return AjaxResult.success(hospitalRecordService.getDetail(params.getId())); + } + + /** + * 列表查询 + */ + @PostMapping("/list") + @PreAuthorize("@ss.hasAnyPermi('hospital:record:list')") + @Log(title = "入住退房管理列表查询", businessType = BusinessType.SELECT) + public TableDataInfo list(@RequestBody BcHospitalRecord params) { + log.info("BcRoomController - list params:{}", params); + + startPage(); + + List list = hospitalRecordService.queryList(params); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + + /** + * 列表查询 + */ + @GetMapping("/checkin/list") + @PreAuthorize("@ss.hasAnyPermi('hospital:record:list')") + @Log(title = "入住退房管理列表查询", businessType = BusinessType.SELECT) + public TableDataInfo checkinList(BcHospitalRecord params) { + log.info("BcRoomController - checkinList params:{}", params); + + startPage(); + + List list = hospitalRecordService.checkinList(params); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + + /** + * 列表查询 + */ + @GetMapping("/checkout/list") + @PreAuthorize("@ss.hasAnyPermi('hospital:record:list')") + @Log(title = "入住退房管理列表查询", businessType = BusinessType.SELECT) + public TableDataInfo checkoutList(BcHospitalRecord params) { + log.info("BcRoomController - checkoutList params:{}", params); + + startPage(); + + List list = hospitalRecordService.checkoutList(params); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + +} diff --git a/src/main/java/com/org/web/hospital/domain/BcHospitalRecord.java b/src/main/java/com/org/web/hospital/domain/BcHospitalRecord.java new file mode 100644 index 0000000..ba985cb --- /dev/null +++ b/src/main/java/com/org/web/hospital/domain/BcHospitalRecord.java @@ -0,0 +1,94 @@ +package com.org.web.hospital.domain; + +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.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + + +/** + * 入院/退房记录 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_hospital_record") +public class BcHospitalRecord extends BaseEntity { + + /** id */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 人员id + */ + private Long personId; + + /** + * 房间id + */ + private Long roomId; + + /** + * 床位id + */ + private Long bedId; + + /** + * 入住时间 + */ + private Date checkInTime; + + /** + * 退房时间 + */ + private Date checkOutTime; + + /** + * 辅具使用情况 + */ + private String deviceUsage; + + /** + * 用药情况 + */ + private String medication; + + /** + * 医嘱 + */ + private String doctorAdvice; + + /** + * 特殊说明 + */ + private String specialInstruction; + + + /** + * 记录类型 1-入院 2-出院 + */ + @TableField(exist = false) + private Integer type; + + /** + * 人员名称 + */ + @TableField(exist = false) + private String personName; + /** + * 房间名称 + */ + @TableField(exist = false) + private String roomName; + /** + * 床位名称 + */ + @TableField(exist = false) + private String bedName; + +} diff --git a/src/main/java/com/org/web/hospital/mapper/BcHospitalRecordMapper.java b/src/main/java/com/org/web/hospital/mapper/BcHospitalRecordMapper.java new file mode 100644 index 0000000..833b0a5 --- /dev/null +++ b/src/main/java/com/org/web/hospital/mapper/BcHospitalRecordMapper.java @@ -0,0 +1,73 @@ +package com.org.web.hospital.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.hospital.domain.BcHospitalRecord; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface BcHospitalRecordMapper extends BaseMapper { + + @Select("") + List queryList(BcHospitalRecord record); + + @Select("") + List checkList(BcHospitalRecord record); + + @Select("" ) + BcHospitalRecord getLastRecordByPersonId(@Param("personId") Long personId, @Param("bedId") Long bedId); +} diff --git a/src/main/java/com/org/web/hospital/service/BcHospitalRecordService.java b/src/main/java/com/org/web/hospital/service/BcHospitalRecordService.java new file mode 100644 index 0000000..1b20599 --- /dev/null +++ b/src/main/java/com/org/web/hospital/service/BcHospitalRecordService.java @@ -0,0 +1,155 @@ +package com.org.web.hospital.service; + + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.enums.YesOrNoState; +import com.org.utils.SecurityUtil; +import com.org.utils.exception.CustomException; +import com.org.web.hospital.domain.BcHospitalRecord; +import com.org.web.hospital.mapper.BcHospitalRecordMapper; +import com.org.web.person.domain.BcPersonSupport; +import com.org.web.person.service.BcPersonSupportService; +import com.org.web.room.domain.BcRoom; +import com.org.web.room.domain.BcRoomBed; +import com.org.web.room.service.BcRoomBedService; +import com.org.web.room.service.BcRoomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +@Service +@Slf4j +public class BcHospitalRecordService extends ServiceImpl { + + @Autowired + BcPersonSupportService personSupportService; + + @Autowired + BcRoomService bcRoomService; + + @Autowired + BcRoomBedService bcRoomBedService; + + @Transactional + public boolean executeSaveOrUpdate(BcHospitalRecord record) { + log.info("BcHospitalRecordService - executeSaveOrUpdate record:{}", record); + + + if (ObjectUtil.isEmpty(record.getId())) { + checkParams(record, false); + + record.setCreateBy(SecurityUtil.getUserId()); + record.setCreateTime(new Date()); + record.setIsDelete(YesOrNoState.NO.getState()); + + record.setCheckInTime(new Date()); // 入住时间 + + } else { + if (record.getType() == 1) checkParams(record, true); + + record.setUpdateBy(SecurityUtil.getUserId()); + record.setUpdateTime(new Date()); + + if (record.getType() == 2) { + // 退房 查询是否存在入住信息 +// BcHospitalRecord lastRecordByPersonId = baseMapper.getLastRecordByPersonId(record.getPersonId()); + record.setCheckOutTime(new Date()); // 退房时间 + } + } + saveOrUpdate(record); + + return true; + } + + public void checkParams(BcHospitalRecord record, boolean isExcludeSelf) { + BcPersonSupport oldPerson = personSupportService.getById(record.getPersonId()); + if (ObjectUtil.isNull(oldPerson)) { + throw new CustomException("人员不存在"); + } + + BcRoomBed roomBed = bcRoomBedService.getById(record.getBedId()); + if (ObjectUtil.isNull(roomBed)) { + throw new CustomException("房间床位不存在"); + } + + // 入住 查询该人员是否存在其他入住信息 + BcHospitalRecord lastRecord = baseMapper.getLastRecordByPersonId(record.getPersonId(), null); + boolean personFlag = true; + if (null != lastRecord ) { // 存在入住信息且退房时间为空 + if (isExcludeSelf && lastRecord.getId() != record.getId()) personFlag = false; + + if (!isExcludeSelf || !personFlag) { // 新增时 或 编辑不一样了 + BcRoom bcRoom = bcRoomService.getById(lastRecord.getRoomId()); + BcRoomBed bcRoomBed = bcRoomBedService.getById(lastRecord.getBedId()); + throw new CustomException("人员已存在入住记录,房间床位为:" + bcRoom.getName() + bcRoomBed.getName()); + } + } + + // 入住 查询该床位是否存在其他入住信息 + BcHospitalRecord lastRecordBed = baseMapper.getLastRecordByPersonId(null, record.getBedId()); + boolean bedFlag = true; + if (null != lastRecordBed ) { // 存在入住信息且退房时间为空 + if (isExcludeSelf && lastRecordBed.getId() != record.getId()) bedFlag = false; + + if (!isExcludeSelf || !bedFlag) { // 新增时 或 编辑不一样了 + throw new CustomException("床位已使用,请选择其他房间床位"); + } + } + } + + public BcHospitalRecord getDetail(Long id) { + BcHospitalRecord record = this.getById(id); + if (null != record) { + // 查询人员名称 + BcPersonSupport oldPerson = personSupportService.getById(record.getPersonId()); + record.setPersonName(oldPerson.getName()); + } + return record; + } + + /** + * 列表查询 + */ + public List queryList(BcHospitalRecord record) { + log.info("BcHospitalRecordService - queryList record:{}", record); + + return baseMapper.queryList(record); + } + + public List checkinList(BcHospitalRecord record) { + log.info("BcHospitalRecordService - checkinList record:{}", record); + + record.setType(1); + return baseMapper.checkList(record); + } + + public List checkoutList(BcHospitalRecord record) { + log.info("BcHospitalRecordService - checkoutList record:{}", record); + + record.setType(2); + return baseMapper.checkList(record); + } + + /** + * 删除 + */ + public boolean del(Long id) { + log.info("BcHonorShowService - del id:{}", id); + + BcHospitalRecord hospitalRecord = getById(id); + if (ObjectUtil.isEmpty(hospitalRecord)) { + throw new CustomException("删除记录不存在"); + } + hospitalRecord.setIsDelete(YesOrNoState.YES.getState()); + hospitalRecord.setDeleteBy(SecurityUtil.getUserId()); + hospitalRecord.setDeleteTime(new Date()); + return updateById(hospitalRecord); + } + + +} diff --git a/src/main/java/com/org/web/person/controller/BcPersonServiceController.java b/src/main/java/com/org/web/person/controller/BcPersonServiceController.java new file mode 100644 index 0000000..7030057 --- /dev/null +++ b/src/main/java/com/org/web/person/controller/BcPersonServiceController.java @@ -0,0 +1,82 @@ +package com.org.web.person.controller; + +import com.org.system.annotation.Log; +import com.org.system.controller.BaseController; +import com.org.system.enums.BusinessType; +import com.org.utils.AjaxResult; +import com.org.utils.core.IdParams; +import com.org.utils.page.TableDataInfo; +import com.org.web.person.domain.BcPersonService; +import com.org.web.person.service.BcPersonServiceService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/person/service") +public class BcPersonServiceController extends BaseController { + + @Autowired + BcPersonServiceService serviceService; + + /** + * 新增 + */ + @PostMapping("/addOrUpdate") + @PreAuthorize("@ss.hasPermi('person:service:add')") + @Log(title = "服务人员新增/编辑", businessType = BusinessType.INSERT) + public AjaxResult add(@Validated @RequestBody BcPersonService params) { + log.info("BcRoomController - add params:{}", params); + + return AjaxResult.success(serviceService.executeSaveOrUpdate(params)); + } + + /** + * 删除 + */ + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('person:service:del')") + @Log(title = "服务人员删除", businessType = BusinessType.DELETE) + public AjaxResult del(@Validated @RequestBody IdParams params) { + log.info("BcRoomController - del params:{}", params); + + return AjaxResult.success(serviceService.del(params.getId())); + } + + /** + * 详情 + */ + @PostMapping("/detail") + @PreAuthorize("@ss.hasAnyPermi('person:service:detail')") + @Log(title = "服务人员详情", businessType = BusinessType.SELECT) + public AjaxResult detail(@Validated @RequestBody IdParams params) { + log.info("BcRoomController - detail params:{}", params); + + return AjaxResult.success(serviceService.get(params.getId())); + } + + /** + * 列表查询 + */ + @GetMapping("/list") + @PreAuthorize("@ss.hasAnyPermi('person:service:detail')") + @Log(title = "服务人员列表查询", businessType = BusinessType.SELECT) + public TableDataInfo list(BcPersonService params) { + log.info("BcRoomController - list params:{}", params); + + startPage(); + + List list = serviceService.queryList(params); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + + +} diff --git a/src/main/java/com/org/web/person/controller/BcPersonSupportController.java b/src/main/java/com/org/web/person/controller/BcPersonSupportController.java new file mode 100644 index 0000000..01f4d04 --- /dev/null +++ b/src/main/java/com/org/web/person/controller/BcPersonSupportController.java @@ -0,0 +1,82 @@ +package com.org.web.person.controller; + +import com.org.system.annotation.Log; +import com.org.system.controller.BaseController; +import com.org.system.enums.BusinessType; +import com.org.utils.AjaxResult; +import com.org.utils.core.IdParams; +import com.org.utils.page.TableDataInfo; +import com.org.web.person.domain.BcPersonSupport; +import com.org.web.person.service.BcPersonSupportService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/person/support") +public class BcPersonSupportController extends BaseController { + + @Autowired + BcPersonSupportService supportService; + + /** + * 新增 + */ + @PostMapping("/addOrUpdate") + @PreAuthorize("@ss.hasPermi('person:support:add')") + @Log(title = "供养人员新增/编辑", businessType = BusinessType.INSERT) + public AjaxResult add(@Validated @RequestBody BcPersonSupport params) { + log.info("BcPersonSupportController - add params:{}", params); + + return AjaxResult.success(supportService.executeSaveOrUpdate(params)); + } + + /** + * 删除 + */ + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('person:support:del')") + @Log(title = "供养人员删除", businessType = BusinessType.DELETE) + public AjaxResult del(@Validated @RequestBody IdParams params) { + log.info("BcPersonSupportController - del params:{}", params); + + return AjaxResult.success(supportService.del(params.getId())); + } + + /** + * 详情 + */ + @PostMapping("/detail") + @PreAuthorize("@ss.hasAnyPermi('person:support:detail')") + @Log(title = "供养人员详情", businessType = BusinessType.SELECT) + public AjaxResult detail(@Validated @RequestBody IdParams params) { + log.info("BcPersonSupportController - detail params:{}", params); + + return AjaxResult.success(supportService.get(params.getId())); + } + + /** + * 列表查询 + */ + @GetMapping("/list") + @PreAuthorize("@ss.hasAnyPermi('person:support:list')") + @Log(title = "供养人员列表查询", businessType = BusinessType.SELECT) + public TableDataInfo list(BcPersonSupport params) { + log.info("BcPersonSupportController - list params:{}", params); + + startPage(); + + List list = supportService.queryList(params); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + + +} diff --git a/src/main/java/com/org/web/person/domain/BcPersonFamily.java b/src/main/java/com/org/web/person/domain/BcPersonFamily.java new file mode 100644 index 0000000..8bffbdf --- /dev/null +++ b/src/main/java/com/org/web/person/domain/BcPersonFamily.java @@ -0,0 +1,51 @@ +package com.org.web.person.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 人员-家庭成员 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_person_family") +public class BcPersonFamily extends BaseEntity { + + /** id */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 人员id + */ + private Long personId; + + /** + * 与人员关系 + */ + private String relation; + + /** + * 家庭成员姓名 + */ + private String familyName; + + /** + * 身份证号 + */ + private String idCardNo; + + /** + * 联系电话 + */ + private String phone; + + /** + * 工作单位 + */ + private String workInfo; +} diff --git a/src/main/java/com/org/web/person/domain/BcPersonService.java b/src/main/java/com/org/web/person/domain/BcPersonService.java new file mode 100644 index 0000000..860f098 --- /dev/null +++ b/src/main/java/com/org/web/person/domain/BcPersonService.java @@ -0,0 +1,109 @@ +package com.org.web.person.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 服务人员 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_person_service") +public class BcPersonService extends BaseEntity { + + /** 用户ID */ + private Long id; + + /** + * 姓名 + */ + private String name; + + /** + * 身份证号码 + */ + private String idCardNo; + + /** + * 出生日期 + */ + private Date birthday; + + /** + * 性别 1-男 0-女 + */ + private Integer sex; + + /** + * 手机号码 + */ + private String phone; + + /** + * 岗位 + */ + private String jobs; + + /** + * 婚姻状况 1-未婚 2-已婚 3-离异 99-未知 + */ + private Integer maritalStatus; + + /** + * 籍贯 + */ + private String nativePlace; + + /** + * 民族 + */ + private String nation; + + /** + * 身体状况 + */ + private String health; + + /** + * 疾病史 + */ + private String diseaseHistory; + + /** + * 获得奖项 + */ + private String awards; + + /** + * 受到处罚 + */ + private String punish; + + /** + * 参加的培训课程 + */ + private String train; + + /** + * 获得的证书 + */ + private String certificate; + + /** + * 账号名称 + */ + @TableField(exist = false) + private String userName; + + /** ---------------- 家庭成员 ------------------ */ + + @TableField(exist = false) + private List familyList = new ArrayList<>(); +} diff --git a/src/main/java/com/org/web/person/domain/BcPersonSupport.java b/src/main/java/com/org/web/person/domain/BcPersonSupport.java new file mode 100644 index 0000000..b1bab68 --- /dev/null +++ b/src/main/java/com/org/web/person/domain/BcPersonSupport.java @@ -0,0 +1,210 @@ +package com.org.web.person.domain; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.util.IdcardUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotEmpty; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 供养人员 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_person_support") +public class BcPersonSupport extends BaseEntity { + + /** 用户ID */ + private Long id; + + /** + * 姓名 + */ + @NotEmpty(message = "姓名不能为空") + private String name; + + /** + * 身份证号码 + */ + @NotEmpty(message = "身份证不能为空") + private String idCardNo; + + /** + * 性别 1-男 0-女 2-未知 + */ + private Integer sex; + public Integer getSex() { + if (StrUtil.isEmptyIfStr(idCardNo)) return null; + return IdcardUtil.getGenderByIdCard(idCardNo); + } + + /** + * 手机号码 + */ + private String phone; + + /** + * 户籍地址 + */ + private String residenceAddress; + + /** + * 户籍村属 + */ + private String residenceVillage; + + /** + * 人员类型 1-供养人员 2-医养结合护理人员 + */ + private Integer type; + + /** + * 供养方式 + */ + private String supportType; + + /** + * 是否残疾 1-是 0-否 + */ + private Integer ifDisabled; + + /** + * 残疾等级 + */ + private String disabilityLevel; + + /** + * 自理情况登记 + */ + private String selfCare; + + /** + * 是否精准扶贫户 1-是 0-否 + */ + private Integer ifHelpPoor; + + /** + * 特困供养金发放金额-合计金额 + */ + private BigDecimal hardshipAllowanceTotal; + + /** + * 特困供养金发放金额-基本生活补助金额 + */ + private BigDecimal hardshipAllowanceBasic; + + /** + * 特困供养金发放金额-护理照料补贴金额 + */ + private BigDecimal hardshipAllowanceCare; + + /** + * 补贴发放账户 + */ + private String allowanceAccount; + + /** + * 纳入时间 + */ + @JsonFormat(pattern = DatePattern.NORM_DATE_PATTERN, timezone = "GMT+8") + private Date bringTime; + + /** ---------------- 详细信息 ------------------ */ + + /** + * 婚姻状况 1-未婚 2-已婚 3-离异 99-未知 + */ + private Integer maritalStatus; + + /** + * 身体状况 + */ + private String health; + + /** + * 辅具使用情况 + */ + private String deviceUsage; + + /** + * 用药情况 + */ + private String medication; + + /** + * 疾病史 + */ + private String diseaseHistory; + + /** + * 过敏史 + */ + private String allergyHistory; + + /** + * 精神状态 + */ + private String mentality; + + /** + * 饮食习惯 + */ + private String eatingHabits; + + /** + * 运动习惯 + */ + private String exerciseHabits; + + /** + * 睡眠情况 + */ + private String sleepQuality; + + /** + * 服药情况 + */ + private String medicationStatus; + + /** + * 卫生情况 + */ + private String hygiene; + + /** + * 喜好的文艺、体育等方面的活动 + */ + private String favoriteActivity; + + /** + * 共建共享志愿活动记录 + */ + private String activityRecord; + + /** + * 医嘱 + */ + private String doctorAdvice; + + /** + * 特殊说明 + */ + private String specialInstruction; + + + /** ---------------- 家庭成员 ------------------ */ + + @TableField(exist = false) + private List familyList = new ArrayList<>(); + +} diff --git a/src/main/java/com/org/web/person/enums/PersonTypeEnums.java b/src/main/java/com/org/web/person/enums/PersonTypeEnums.java new file mode 100644 index 0000000..d093b80 --- /dev/null +++ b/src/main/java/com/org/web/person/enums/PersonTypeEnums.java @@ -0,0 +1,25 @@ +package com.org.web.person.enums; + +/** 人员类型 **/ +public enum PersonTypeEnums { + + PERSON_SUPPORT(1, "供养人员"), + + PERSON_CARE(2, "医养结合护理人员"); + + Integer type; + String desc; + + PersonTypeEnums(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } +} diff --git a/src/main/java/com/org/web/person/mapper/BcPersonFamilyMapper.java b/src/main/java/com/org/web/person/mapper/BcPersonFamilyMapper.java new file mode 100644 index 0000000..3a7c806 --- /dev/null +++ b/src/main/java/com/org/web/person/mapper/BcPersonFamilyMapper.java @@ -0,0 +1,41 @@ +package com.org.web.person.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.person.domain.BcPersonFamily; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; + +@Mapper +public interface BcPersonFamilyMapper extends BaseMapper { + + @Select("select * " + + "from bc_person_family " + + "where is_delete = 0 " + + "and person_id = #{personId} ") + List listByPersonId(@Param("personId") Long personId); + + @Update("update bc_person_family set is_delete = 1, delete_by = #{deleteBy}, delete_time = now() " + + "where is_delete = 0 " + + "and person_id = #{personId} ") + void deleteByPersonId(@Param("personId") Long personId, @Param("deleteBy") Long deleteBy); + + @Update("") + void deleteWithout(@Param("personId") Long personId, @Param("idList") List idList, @Param("deleteBy") Long deleteBy); + +} diff --git a/src/main/java/com/org/web/person/mapper/BcPersonServiceMapper.java b/src/main/java/com/org/web/person/mapper/BcPersonServiceMapper.java new file mode 100644 index 0000000..50406e9 --- /dev/null +++ b/src/main/java/com/org/web/person/mapper/BcPersonServiceMapper.java @@ -0,0 +1,34 @@ +package com.org.web.person.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.person.domain.BcPersonService; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface BcPersonServiceMapper extends BaseMapper { + + @Select("") + List queryList(BcPersonService person); + +} diff --git a/src/main/java/com/org/web/person/mapper/BcPersonSupportMapper.java b/src/main/java/com/org/web/person/mapper/BcPersonSupportMapper.java new file mode 100644 index 0000000..d6e2096 --- /dev/null +++ b/src/main/java/com/org/web/person/mapper/BcPersonSupportMapper.java @@ -0,0 +1,36 @@ +package com.org.web.person.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.person.domain.BcPersonSupport; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface BcPersonSupportMapper extends BaseMapper { + + @Select("" ) + List queryList(BcPersonSupport person); + +} diff --git a/src/main/java/com/org/web/person/service/BcPersonFamilyService.java b/src/main/java/com/org/web/person/service/BcPersonFamilyService.java new file mode 100644 index 0000000..dd76e52 --- /dev/null +++ b/src/main/java/com/org/web/person/service/BcPersonFamilyService.java @@ -0,0 +1,74 @@ +package com.org.web.person.service; + + +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.enums.YesOrNoState; +import com.org.utils.SecurityUtil; +import com.org.web.person.domain.BcPersonFamily; +import com.org.web.person.mapper.BcPersonFamilyMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; + +@Service +@Slf4j +public class BcPersonFamilyService extends ServiceImpl { + + /** + * 新增或编辑 + */ + @Transactional(rollbackFor = Exception.class) + public void executeSaveOrUpdate(Long personId, List newList) { + Long userId = SecurityUtil.getUserId(); + + List resultList = newList.stream() + .filter(person -> Validator.isNotEmpty(person.getFamilyName()) || Validator.isNotEmpty(person.getRelation()) || + Validator.isNotEmpty(person.getPhone()) || Validator.isNotEmpty(person.getWorkInfo()) )// 这里是过滤条件 + .collect(Collectors.toList()); + for (BcPersonFamily bcPersonFamily : resultList) { + if (ObjectUtil.isEmpty(bcPersonFamily.getId())) { + bcPersonFamily.setCreateBy(userId); + bcPersonFamily.setCreateTime(new Date()); + bcPersonFamily.setIsDelete(YesOrNoState.NO.getState()); + } else { + bcPersonFamily.setUpdateBy(userId); + bcPersonFamily.setUpdateTime(new Date()); + } + + bcPersonFamily.setPersonId(personId); + } + this.saveOrUpdateBatch(resultList); + + List idList = resultList.stream().map(i -> i.getId()).collect(toList()); + // 删除编辑中没有的数据 + baseMapper.deleteWithout(personId, idList, userId); + } + + /** + * 列表 + */ + public List listByPersonId(Long personId) { + log.info("BcPersonFamilyService - listByPersonId personId:{}", personId); + + return baseMapper.listByPersonId(personId); + } + + /** + * 删除 + */ + public boolean delByPersonId(Long personId) { + log.info("BcPersonFamilyService - del personId:{}", personId); + + baseMapper.deleteByPersonId(personId, SecurityUtil.getUserId()); + + return true; + } +} diff --git a/src/main/java/com/org/web/person/service/BcPersonServiceService.java b/src/main/java/com/org/web/person/service/BcPersonServiceService.java new file mode 100644 index 0000000..1952294 --- /dev/null +++ b/src/main/java/com/org/web/person/service/BcPersonServiceService.java @@ -0,0 +1,162 @@ +package com.org.web.person.service; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.DigestUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.config.security.Md5PasswordEncoder; +import com.org.system.entity.SysRole; +import com.org.system.entity.SysUser; +import com.org.system.enums.YesOrNoState; +import com.org.system.service.SysUserRoleService; +import com.org.system.service.SysUserService; +import com.org.utils.SecurityUtil; +import com.org.utils.exception.CustomException; +import com.org.web.person.domain.BcPersonFamily; +import com.org.web.person.domain.BcPersonService; +import com.org.web.person.mapper.BcPersonServiceMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +@Service +@Slf4j +public class BcPersonServiceService extends ServiceImpl { + + + @Autowired + SysUserService sysUserService; + + @Autowired + SysUserRoleService sysUserRoleService; + + @Autowired + BcPersonFamilyService familyService; + + + @Transactional + public boolean executeSaveOrUpdate(BcPersonService person) { + log.info("BcPersonServiceService - executeSaveOrUpdate person:{}", person); + if (null == person.getId()) { + return executeSave(person); + } else { + return executeUpdate(person); + } + } + + + // 新增人员 + private boolean executeSave(BcPersonService person) { + + // 新建用户 + SysUser sysUser = new SysUser(); + BeanUtils.copyProperties(person, sysUser); + sysUser.setUserName(person.getIdCardNo()); + sysUser.setNickName(person.getName()); + + sysUser.setSalt(DigestUtil.md5Hex(sysUser.getUserName())); + Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance(); + md5PasswordEncoder.setSalt(sysUser.getSalt()); + sysUser.setPassword(md5PasswordEncoder.encode(SysUser.DEFAULT_PASSWORD)); + + sysUser.setStatus(1); + sysUser.setCreateTime(new Date()); + sysUser.setIsDelete(YesOrNoState.NO.getState()); + sysUserService.save(sysUser); + + // 保存用户角色信息 + sysUserRoleService.save(sysUser.getId(), CollectionUtil.newArrayList(SysRole.SERVICE_ROLE)); + + + // 新增人员信息 + person.setId(sysUser.getId()); // 人员的id为sysUser的id + person.setCreateTime(new Date()); + person.setIsDelete(YesOrNoState.NO.getState()); + this.save(person); + + // 新增家庭成员子表数据 + familyService.executeSaveOrUpdate(person.getId(), person.getFamilyList()); + + return true; + } + + private boolean executeUpdate(BcPersonService person) { + person.setUpdateBy(SecurityUtil.getUserId()); + person.setUpdateTime(new Date()); + + BcPersonService oldPerson = getById(person.getId()); + if (ObjectUtil.isNull(oldPerson)) { + throw new CustomException("人员不存在"); + } + + // 修改用户 + SysUser sysUser = sysUserService.getById(person.getId()); + if (ObjectUtil.isNull(sysUser)) { + throw new CustomException("未查询到用户信息"); + } + + sysUser.setUserName(person.getIdCardNo()); + sysUser.setNickName(person.getName()); + sysUser.setName(person.getName()); + sysUser.setIdCardNo(person.getIdCardNo()); + sysUser.setPhone(person.getPhone()); + sysUserService.saveOrUpdate(sysUser); + + // 编辑家庭成员子表数据 + familyService.executeSaveOrUpdate(person.getId(), person.getFamilyList()); + + return updateById(person); + } + + @Transactional + public boolean del(Long id) { + log.info("BcPersonServiceService - del id:{}", id); + + BcPersonService person = getById(id); + if (ObjectUtil.isNull(person)) { + throw new CustomException("删除数据不存在"); + } + person.setIsDelete(YesOrNoState.YES.getState()); + person.setDeleteBy(SecurityUtil.getUserId()); + person.setDeleteTime(new Date()); + + // 删除用户 + sysUserService.del(CollectionUtil.newArrayList(person.getId()), "人员删除"); + + // 删除家庭成员 + familyService.delByPersonId(person.getId()); + + return updateById(person); + } + + /** + * 详情 + */ + public BcPersonService get(Long id) { + log.info("BcPersonServiceService - get id:{}", id); + + BcPersonService person = getById(id); + + // 查询家庭成员 + List familyList = familyService.listByPersonId(id); + + person.setFamilyList(familyList); + + return person; + } + + /** + * 列表查询 + */ + public List queryList(BcPersonService person) { + log.info("BcPersonServiceService - queryList person:{}", person); + + return baseMapper.queryList(person); + } +} diff --git a/src/main/java/com/org/web/person/service/BcPersonSupportService.java b/src/main/java/com/org/web/person/service/BcPersonSupportService.java new file mode 100644 index 0000000..2afc446 --- /dev/null +++ b/src/main/java/com/org/web/person/service/BcPersonSupportService.java @@ -0,0 +1,162 @@ +package com.org.web.person.service; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.DigestUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.config.security.Md5PasswordEncoder; +import com.org.system.entity.SysRole; +import com.org.system.entity.SysUser; +import com.org.system.enums.YesOrNoState; +import com.org.system.service.SysUserRoleService; +import com.org.system.service.SysUserService; +import com.org.utils.SecurityUtil; +import com.org.utils.exception.CustomException; +import com.org.web.person.domain.BcPersonFamily; +import com.org.web.person.domain.BcPersonSupport; +import com.org.web.person.mapper.BcPersonSupportMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +@Service +@Slf4j +public class BcPersonSupportService extends ServiceImpl { + + @Autowired + SysUserService sysUserService; + + @Autowired + SysUserRoleService sysUserRoleService; + + @Autowired + BcPersonFamilyService familyService; + + + @Transactional + public boolean executeSaveOrUpdate(BcPersonSupport person) { + log.info("BcPersonSupportService - executeSaveOrUpdate person:{}", person); + if (null == person.getId()) { + return executeSave(person); + } else { + return executeUpdate(person); + } + } + + + // 新增人员 + private boolean executeSave(BcPersonSupport person) { + + // 新建用户 + SysUser sysUser = new SysUser(); + BeanUtils.copyProperties(person, sysUser); + sysUser.setUserName(person.getIdCardNo()); + sysUser.setNickName(person.getName()); + + sysUser.setSalt(DigestUtil.md5Hex(sysUser.getUserName())); + Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance(); + md5PasswordEncoder.setSalt(sysUser.getSalt()); + sysUser.setPassword(md5PasswordEncoder.encode(SysUser.DEFAULT_PASSWORD)); + + sysUser.setStatus(1); + sysUser.setCreateTime(new Date()); + sysUser.setIsDelete(YesOrNoState.NO.getState()); + sysUserService.save(sysUser); + + // 保存用户角色信息 + sysUserRoleService.save(sysUser.getId(), CollectionUtil.newArrayList(person.getType() == 1 ? SysRole.SUPPORT_ROLE : SysRole.TEND_ROLE)); + + + // 新增人员信息 + person.setId(sysUser.getId()); // 人员的id为sysUser的id + person.setCreateTime(new Date()); + person.setIsDelete(YesOrNoState.NO.getState()); + this.save(person); + + // 新增家庭成员子表数据 + familyService.executeSaveOrUpdate(person.getId(), person.getFamilyList()); + + return true; + } + + private boolean executeUpdate(BcPersonSupport person) { + person.setUpdateBy(SecurityUtil.getUserId()); + person.setUpdateTime(new Date()); + + BcPersonSupport oldPerson = getById(person.getId()); + if (ObjectUtil.isNull(oldPerson)) { + throw new CustomException("人员不存在"); + } + + // 修改用户 + SysUser sysUser = sysUserService.getById(person.getId()); + if (ObjectUtil.isNull(sysUser)) { + throw new CustomException("未查询到用户信息"); + } + + sysUser.setUserName(person.getIdCardNo()); + sysUser.setNickName(person.getName()); + sysUser.setName(person.getName()); + sysUser.setIdCardNo(person.getIdCardNo()); + sysUser.setPhone(person.getPhone()); + sysUserService.saveOrUpdate(sysUser); + + // 编辑家庭成员子表数据 + familyService.executeSaveOrUpdate(person.getId(), person.getFamilyList()); + + return updateById(person); + } + + @Transactional + public boolean del(Long id) { + log.info("BcPersonSupportService - del id:{}", id); + + BcPersonSupport person = getById(id); + if (ObjectUtil.isNull(person)) { + throw new CustomException("删除数据不存在"); + } + person.setIsDelete(YesOrNoState.YES.getState()); + person.setDeleteBy(SecurityUtil.getUserId()); + person.setDeleteTime(new Date()); + + // 删除用户 + sysUserService.del(CollectionUtil.newArrayList(person.getId()), "人员删除"); + + // 删除家庭成员 + familyService.delByPersonId(person.getId()); + + return updateById(person); + } + + /** + * 详情 + */ + public BcPersonSupport get(Long id) { + log.info("BcPersonSupportService - get id:{}", id); + + BcPersonSupport person = getById(id); + + // 查询家庭成员 + List familyList = familyService.listByPersonId(id); + + person.setFamilyList(familyList); + + return person; + } + + /** + * 列表查询 + */ + public List queryList(BcPersonSupport person) { + log.info("BcPersonSupportService - queryList person:{}", person); + + return baseMapper.queryList(person); + } + +} diff --git a/src/main/java/com/org/web/room/controller/BcRoomController.java b/src/main/java/com/org/web/room/controller/BcRoomController.java new file mode 100644 index 0000000..84df671 --- /dev/null +++ b/src/main/java/com/org/web/room/controller/BcRoomController.java @@ -0,0 +1,125 @@ +package com.org.web.room.controller; + +import com.org.system.annotation.Log; +import com.org.system.controller.BaseController; +import com.org.system.enums.BusinessType; +import com.org.utils.AjaxResult; +import com.org.utils.core.IdParams; +import com.org.utils.page.TableDataInfo; +import com.org.web.room.domain.BcRoom; +import com.org.web.room.domain.BcRoomBed; +import com.org.web.room.service.BcRoomBedService; +import com.org.web.room.service.BcRoomService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/room") +public class BcRoomController extends BaseController { + + @Autowired + BcRoomService bcRoomService; + + @Autowired + BcRoomBedService bcRoomBedService; + + /** + * 新增 + */ + @PostMapping("/addOrUpdate") + @PreAuthorize("@ss.hasPermi('room:add')") + @Log(title = "房间新增/编辑", businessType = BusinessType.INSERT) + public AjaxResult addOrUpdate(@Validated @RequestBody BcRoom bcRoom) { + log.info("BcRoomController - addOrUpdate bcRoom:{}", bcRoom); + + return AjaxResult.success(bcRoomService.executeSaveOrUpdate(bcRoom)); + } + + /** + * 删除 + */ + @PostMapping("/del") + @PreAuthorize("@ss.hasPermi('room:del')") + @Log(title = "房间删除", businessType = BusinessType.DELETE) + public AjaxResult del(@Validated @RequestBody IdParams params) { + log.info("BcRoomController - del params:{}", params); + + return AjaxResult.success(bcRoomService.del(params.getId())); + } + + /** + * 详情 + */ + @PostMapping("/detail") + @PreAuthorize("@ss.hasAnyPermi('room:detail')") + @Log(title = "房间详情", businessType = BusinessType.SELECT) + public AjaxResult detail(@Validated @RequestBody IdParams params) { + log.info("BcRoomController - detail params:{}", params); + + return AjaxResult.success(bcRoomService.get(params.getId())); + } + + /** + * 列表查询 + */ + @GetMapping("/list") + @PreAuthorize("@ss.hasAnyPermi('room:detail')") + @Log(title = "房间列表查询", businessType = BusinessType.SELECT) + public TableDataInfo list(BcRoom bcRoom) { + log.info("BcRoomController - list "); + + startPage(); + + List list = bcRoomService.queryList(bcRoom); + + TableDataInfo dataTable = getDataTable(list); + + return dataTable; + } + + /** + * 查询所有房间 + */ + @PostMapping("/listAllRoom") + @PreAuthorize("@ss.hasAnyPermi('room:listBed')") + @Log(title = "床位列表查询", businessType = BusinessType.SELECT) + public AjaxResult listAllRoom() { + + List list = bcRoomService.getBaseMapper().queryList(new BcRoom()); + + return AjaxResult.success(list); + } + + /** + * 查询所有床位 + */ + @PostMapping("/listAllBed") + @PreAuthorize("@ss.hasAnyPermi('room:listBed')") + @Log(title = "床位列表查询", businessType = BusinessType.SELECT) + public AjaxResult listAllBed() { + + List list = bcRoomBedService.getBaseMapper().listAllRoom(); + + return AjaxResult.success(list); + } + + /** + * 根据房间id查询床位 + */ + @PostMapping("/listBed") + @PreAuthorize("@ss.hasAnyPermi('room:listBed')") + @Log(title = "床位列表查询", businessType = BusinessType.SELECT) + public AjaxResult listBed(@RequestBody IdParams params) { + log.info("BcRoomController - listBed params:{}", params); + + List list = bcRoomBedService.listByRoomId(params.getId()); + + return AjaxResult.success(list); + } +} diff --git a/src/main/java/com/org/web/room/domain/BcRoom.java b/src/main/java/com/org/web/room/domain/BcRoom.java new file mode 100644 index 0000000..ba91bc0 --- /dev/null +++ b/src/main/java/com/org/web/room/domain/BcRoom.java @@ -0,0 +1,51 @@ +package com.org.web.room.domain; + +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.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.List; + +/** + * 房间 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_room") +public class BcRoom extends BaseEntity { + + /** id */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 房间名称 + */ + private String name; + + /** + * 房间床位数量 + */ + private Integer bedNumber; + + /** + * 房间类型 + */ + private Integer roomType; + + /** + * 房间类型 + */ + @TableField(exist = false) + private String roomTypeName; + + /** 床位列表 **/ + @TableField(exist = false) + private List roomBedList = new ArrayList<>(); + +} diff --git a/src/main/java/com/org/web/room/domain/BcRoomBed.java b/src/main/java/com/org/web/room/domain/BcRoomBed.java new file mode 100644 index 0000000..42fd084 --- /dev/null +++ b/src/main/java/com/org/web/room/domain/BcRoomBed.java @@ -0,0 +1,32 @@ +package com.org.web.room.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.org.system.entity.BaseEntity; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 房间床位 + */ +@Data +@Accessors(chain = true) +@TableName(value ="bc_room_bed") +public class BcRoomBed extends BaseEntity { + + /** id */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 床位名称 + */ + private String name; + + /** + * 房间id + */ + private Long roomId; + +} diff --git a/src/main/java/com/org/web/room/mapper/BcRoomBedMapper.java b/src/main/java/com/org/web/room/mapper/BcRoomBedMapper.java new file mode 100644 index 0000000..58aaedf --- /dev/null +++ b/src/main/java/com/org/web/room/mapper/BcRoomBedMapper.java @@ -0,0 +1,46 @@ +package com.org.web.room.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.room.domain.BcRoomBed; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; + +import java.util.List; + +@Mapper +public interface BcRoomBedMapper extends BaseMapper { + + @Select("select * " + + "from bc_room_bed " + + "where is_delete = 0 " + + "and room_id = #{roomId} ") + List listByRoomId(@Param("roomId") Long roomId); + + @Select("select * " + + "from bc_room_bed " + + "where is_delete = 0 ") + List listAllRoom(); + + @Update("update bc_room_bed set is_delete = 1, delete_by = #{deleteBy}, delete_time = now() " + + "where is_delete = 0 " + + "and room_id = #{roomId} ") + void deleteByRoomId(@Param("roomId") Long roomId, @Param("deleteBy") Long deleteBy); + + @Update("") + void deleteWithout(@Param("roomId") Long roomId, @Param("idList") List idList, @Param("deleteBy") Long deleteBy); + +} diff --git a/src/main/java/com/org/web/room/mapper/BcRoomMapper.java b/src/main/java/com/org/web/room/mapper/BcRoomMapper.java new file mode 100644 index 0000000..8ae2b4c --- /dev/null +++ b/src/main/java/com/org/web/room/mapper/BcRoomMapper.java @@ -0,0 +1,30 @@ +package com.org.web.room.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.org.web.room.domain.BcRoom; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface BcRoomMapper extends BaseMapper { + + @Select("") + List queryList(BcRoom room); + +} diff --git a/src/main/java/com/org/web/room/service/BcRoomBedService.java b/src/main/java/com/org/web/room/service/BcRoomBedService.java new file mode 100644 index 0000000..bd469fe --- /dev/null +++ b/src/main/java/com/org/web/room/service/BcRoomBedService.java @@ -0,0 +1,70 @@ +package com.org.web.room.service; + + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.enums.YesOrNoState; +import com.org.utils.SecurityUtil; +import com.org.web.room.domain.BcRoomBed; +import com.org.web.room.mapper.BcRoomBedMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +@Service +@Slf4j +public class BcRoomBedService extends ServiceImpl { + + /** + * 新增或编辑 + */ + @Transactional(rollbackFor = Exception.class) + public void executeSaveOrUpdate(Long roomId, List resultList) { + Long userId = SecurityUtil.getUserId(); + + for (BcRoomBed bcRoomBed : resultList) { + if (ObjectUtil.isEmpty(bcRoomBed.getId())) { + bcRoomBed.setCreateBy(userId); + bcRoomBed.setCreateTime(new Date()); + bcRoomBed.setIsDelete(YesOrNoState.NO.getState()); + } else { + bcRoomBed.setUpdateBy(userId); + bcRoomBed.setUpdateTime(new Date()); + } + + bcRoomBed.setRoomId(roomId); + } + this.saveOrUpdateBatch(resultList); + + List idList = resultList.stream().map(i -> i.getId()).collect(toList()); + // 删除编辑中没有的数据 + baseMapper.deleteWithout(roomId, idList, userId); + } + + /** + * 列表 + */ + public List listByRoomId(Long roomId) { + log.info("BcRoomBedService - listByRoomId roomId:{}", roomId); + + return baseMapper.listByRoomId(roomId); + } + + /** + * 删除 + */ + public boolean delByRoomId(Long roomId) { + log.info("BcRoomBedService - del roomId:{}", roomId); + + baseMapper.deleteByRoomId(roomId, SecurityUtil.getUserId()); + + return true; + } + + +} diff --git a/src/main/java/com/org/web/room/service/BcRoomService.java b/src/main/java/com/org/web/room/service/BcRoomService.java new file mode 100644 index 0000000..d7bd07c --- /dev/null +++ b/src/main/java/com/org/web/room/service/BcRoomService.java @@ -0,0 +1,107 @@ +package com.org.web.room.service; + + +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.org.system.enums.YesOrNoState; +import com.org.system.service.SysDataDictionaryItemService; +import com.org.utils.SecurityUtil; +import com.org.utils.exception.CustomException; +import com.org.web.room.domain.BcRoom; +import com.org.web.room.domain.BcRoomBed; +import com.org.web.room.mapper.BcRoomMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class BcRoomService extends ServiceImpl { + + @Autowired + private BcRoomBedService bcRoomBedService; + + @Autowired + SysDataDictionaryItemService sysDataDictionaryItemService; + + /** + * 新增或编辑 + */ + @Transactional(rollbackFor = Exception.class) + public boolean executeSaveOrUpdate(BcRoom bcRoom) { + log.info("BcRoomService - executeSaveOrUpdate bcRoom:{}", bcRoom); + + if (ObjectUtil.isEmpty(bcRoom.getId())) { + bcRoom.setCreateBy(SecurityUtil.getUserId()); + bcRoom.setCreateTime(new Date()); + bcRoom.setIsDelete(YesOrNoState.NO.getState()); + } else { + bcRoom.setUpdateBy(SecurityUtil.getUserId()); + bcRoom.setUpdateTime(new Date()); + } + + List resultList = bcRoom.getRoomBedList().stream() + .filter(person -> Validator.isNotEmpty(person.getName()) )// 这里是过滤条件 + .collect(Collectors.toList()); + bcRoom.setBedNumber(resultList.size()); + + saveOrUpdate(bcRoom); + + // 插入床位子表数据 + bcRoomBedService.executeSaveOrUpdate(bcRoom.getId(), resultList); + + return true; + } + + /** + * 详情 + */ + public BcRoom get(Long id) { + BcRoom bcRoom = getById(id); + + // 查询床位数据 + List roomBedList = bcRoomBedService.listByRoomId(id); + + bcRoom.setRoomBedList(roomBedList); + + return bcRoom; + } + + /** + * 列表查询 + */ + public List queryList(BcRoom bcRoom) { + List list = baseMapper.queryList(bcRoom); + for (BcRoom room : list) { + //获取 房间类别 + room.setRoomTypeName(sysDataDictionaryItemService.findDictonaryBydictonaryCode("0010", room.getRoomType())); + } + return list; + } + + /** + * 删除 + */ + public boolean del(Long id) { + log.info("BcRoomService - del id:{}", id); + + BcRoom bcRoom = getById(id); + if (ObjectUtil.isEmpty(bcRoom)) { + throw new CustomException("删除记录不存在"); + } + bcRoom.setIsDelete(YesOrNoState.YES.getState()); + bcRoom.setDeleteBy(SecurityUtil.getUserId()); + bcRoom.setDeleteTime(new Date()); + + bcRoomBedService.delByRoomId(id); + + return updateById(bcRoom); + } + +} diff --git a/src/main/java/com/org/web/utils/Dictionary.java b/src/main/java/com/org/web/utils/Dictionary.java new file mode 100644 index 0000000..daa4a48 --- /dev/null +++ b/src/main/java/com/org/web/utils/Dictionary.java @@ -0,0 +1,32 @@ +package com.org.web.utils; + +import com.org.system.entity.SysDataDictionaryItem; +import com.org.system.service.SysDataDictionaryItemService; +import com.org.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Dictionary { + + /** + * 根据字典Code和Value获取字典项详情 + * 走redis缓存 + * + * @param code + * @param value + * @return + */ + public static SysDataDictionaryItem getDictionaryItem(String code, String value) { + try { + SysDataDictionaryItem item = SpringUtils.getBean(SysDataDictionaryItemService.class).getByCodeAndValue(code, value); + + if(item == null) item = new SysDataDictionaryItem(); + + return item; + } catch (Exception err) { + log.error("获取字典缓存出错:", err); + return new SysDataDictionaryItem(); + } + } + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..99f2f25 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,97 @@ +server: + port: 8080 + servlet: + context-path: / + tomcat: + uri-encoding: UTF-8 + max-threads: 800 + min-spare-threads: 30 + +token: + header: Authorization + secret: abcdefghijklmnopqrstuvwxyz + expireTime: 1800000 + +logging: + level: + com.org: debug + org.springframework: warn + +spring: + messages: + basename: message/messages + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/welfare?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: root + redis: + password: yjhon.com + host: 121.196.96.144 + port: 6379 + database: 10 + timeout: 10s + lettuce: + pool: + min-idle: 0 + max-idle: 8 + max-active: 8 + max-wait: -1ms + # 文件上传 + servlet: + multipart: + max-file-size: 100MB + max-request-size: 200MB + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + locale: zh_CN + +mybatis-plus: + mapper-locations: classpath*:mapper/**/*.xml + #实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.org.**.domain + global-config: + #主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID"; + id-type: 0 + #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断" + field-strategy: 2 + #驼峰下划线转换 + db-column-underline: false + #刷新mapper 调试神器 + refresh-mapper: true + #数据库大写下划线转换 + #capital-mode: true + # Sequence序列接口实现类配置 + #key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator + #逻辑删除配置 + logic-delete-value: -1 + logic-not-delete-value: 0 + #自定义填充策略接口实现 + #meta-object-handler: com.baomidou.springboot.xxx + #自定义SQL注入器 + #sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + call-setters-on-nulls: true + +pagehelper: + helperDialect: mysql + reasonable: true + supportMethodsArguments: false + params: count=countSql + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice/* + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* + +oss: + proxyServer: "/welfare/sys/oss/show" + diskPath: "/Users/welfare/Downloads/home/upload" + downloadPath: "/Users/welfare/Downloads/home/download" diff --git a/src/main/resources/message/messages.properties b/src/main/resources/message/messages.properties new file mode 100644 index 0000000..55ee6fa --- /dev/null +++ b/src/main/resources/message/messages.properties @@ -0,0 +1,37 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.jcaptcha.testCode.error=测试授权码错误 +user.not.exists=用户不存在/密码错误 +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟 +user.password.delete=对不起,您的账号已被删除 +user.blocked=用户已封禁,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 + +length.not.valid=长度必须在{min}到{max}个字符之间 + +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.password.not.valid=* 5-50个字符 + +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 + +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 + +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] diff --git a/src/main/resources/static/题目导入模板.xls b/src/main/resources/static/题目导入模板.xls new file mode 100644 index 0000000000000000000000000000000000000000..74c2ce20efa11685d2ea179cbce978817916ae2a GIT binary patch literal 6656 zcmeHL>u*#=6hC)+x7`&=w=bZrtm`6uQ`$m>(m=O_elR{ts9F=&(3UOIpg?L(>?hX; ze(;fCFfkYtLLxE7q+(1^qcPh*fM_6%(ND$1#BZX}R1~}Ze&^opK6>w3pfM@w?EYrv zo;x#V&Y3f3=Gj^DV1q*soi9FqyG_Ttl8SWHSI^auIU zOyd`w=dXNc6rfRJjn#4h+{fgo4C_3O=IieGu1q{eia$%oMh?U?G-{+?c@%galJAuv zj&bq!cIv%7F@?5?BkY1J(moKs8VU+zo61 zg1|jM2)Gvr0~>++fK5OxPzTfl4L~E%1T+Jiffj(is1;=!&~86(L)l^1x1-zvbOJkV z8uhc1vNhoMVHFF#@@4U*qNxa~Fo>(LhzsVF+QpC1T~tnB-HjfJ!AwVCj-&Fdx(XU7 zw{K|a(;l6}kU`r_U{1S?Lfkbxu+u7?7xq2glxzO6w)#r*U22UY@e_$wu0L-mPk18Q z?oG|Zny*1_$YV_)ck<#mk}(+lP(>%SIOG`$2mt?=qmffjE7}^PIFRO1v>p^n>E~3F==EjC}HwJv?HuMCR zXs5dzmbgxH&1UA_&SKmx-41d+1((<6BvASSlq# zq#Jlt`tOUQ(-%3lccXJur}lR;-O&32C1kSn%=2CK@TWyh)BP^=Mi+XM3%z*({j>-7 zoVX-e2I7TUmd3qWmc@&-ERPpxSrIprg9caeB&_0d21Pg_`{fAy?+6aRHl-IZNXnwO zEBz5(oU-U!;IW@Bz5{d~L|2Vd7jf%t@SaRz$rHZrH$Y4l&majl(z+&L*5x zKH;#|xgD54w{cd;Do>^*<1U5y7V9~;8hH$NHlBH<$a#13$&C+xz5MX-zV3rcZ&Z4d z<}WEFp22w&wI&;k7x8AwOx^Te*4D3RUOV6V=kB_Udi{L;T6aT6{T%$RAG4bMg_3ek zkl^AV{xjXF(vZjS263pz4i~f)v)!IDxkzPb8zt|0rqw&q#{Vvvl#=&9n5|?)h<%W- zqvHR&)Y+%@Vcv4Kgt4Vxu3%5ThVYKhM$WS*<5?Z64nGIk3e`jF<9tSTGbhjfcD?UN z;G?&E(p2~9_pP9v0{D%K@A-@rXPm$oHUe-Sg8;qV(*XU_1w1gmHKAO_t&D{SWFI2; zkn|y1Ka7Cr5Y7Xp2(#MrXD1%IY_Ki;mV4mDIM#Xo9}=gROlsFaV%i|-!CF?)W47|}04H}^ea2RLU&l-8*E^ZW7I z$H^{Hx>^29#CCp|<;(!^sZX)m;W(pjhNKL~5@gUye@T4J!4L%99yK{<++ yG2CZH@P;YZ*0=`(Ks&6o1Nmlrm1)7fiTCgpJa1F5=dGvZtp8h=I^FYj + \ No newline at end of file