From 70d8fb2fe4545602fac34a2f2bb16b39cebf7679 Mon Sep 17 00:00:00 2001 From: bai <173792339@qq.com> Date: Thu, 8 Aug 2024 16:51:26 +0800 Subject: [PATCH] =?UTF-8?q?fix():=E5=A2=9E=E5=8A=A0=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E6=B8=A0=E9=81=93=E7=9A=84=E6=9E=9A=E4=B8=BE=E5=92=8C=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/compiler.xml | 13 + .idea/encodings.xml | 7 + .idea/inspectionProfiles/Project_Default.xml | 68 + .idea/jarRepositories.xml | 45 + .idea/misc.xml | 12 + .idea/uiDesigner.xml | 124 ++ .idea/vcs.xml | 6 + pom.xml | 186 +++ .../muyu/common/core/annotation/Excel.java | 176 +++ .../muyu/common/core/annotation/Excels.java | 17 + .../common/core/constant/CacheConstants.java | 58 + .../muyu/common/core/constant/Constants.java | 134 ++ .../common/core/constant/GenConstants.java | 186 +++ .../muyu/common/core/constant/HttpStatus.java | 93 ++ .../core/constant/ScheduleConstants.java | 56 + .../core/constant/SecurityConstants.java | 48 + .../core/constant/ServiceNameConstants.java | 23 + .../common/core/constant/TokenConstants.java | 24 + .../common/core/constant/UserConstants.java | 113 ++ .../core/context/SecurityContextHolder.java | 83 ++ .../com/muyu/common/core/domain/Result.java | 118 ++ .../muyu/common/core/enums/SysPayType.java | 44 + .../muyu/common/core/enums/SystemYesNo.java | 27 + .../muyu/common/core/enums/UserStatus.java | 26 + .../core/exception/CaptchaException.java | 14 + .../core/exception/CheckedException.java | 26 + .../core/exception/DemoModeException.java | 13 + .../core/exception/GlobalException.java | 51 + .../core/exception/InnerAuthException.java | 14 + .../core/exception/PreAuthorizeException.java | 13 + .../core/exception/ServiceException.java | 65 + .../common/core/exception/UtilException.java | 22 + .../exception/auth/NotLoginException.java | 14 + .../auth/NotPermissionException.java | 20 + .../core/exception/auth/NotRoleException.java | 20 + .../core/exception/base/BaseException.java | 69 + .../core/exception/file/FileException.java | 17 + .../FileNameLengthLimitExceededException.java | 14 + .../file/FileSizeLimitExceededException.java | 14 + .../exception/file/FileUploadException.java | 52 + .../file/InvalidExtensionException.java | 67 + .../core/exception/job/TaskException.java | 29 + .../user/CaptchaExpireException.java | 14 + .../core/exception/user/UserException.java | 16 + .../user/UserPasswordNotMatchException.java | 14 + .../muyu/common/core/feign/FeginConfig.java | 19 + .../com/muyu/common/core/text/CharsetKit.java | 94 ++ .../com/muyu/common/core/text/Convert.java | 903 ++++++++++++ .../muyu/common/core/text/StrFormatter.java | 77 ++ .../com/muyu/common/core/utils/DateUtils.java | 158 +++ .../muyu/common/core/utils/ExceptionUtil.java | 35 + .../com/muyu/common/core/utils/JwtUtils.java | 165 +++ .../com/muyu/common/core/utils/PageUtils.java | 32 + .../muyu/common/core/utils/ServletUtils.java | 289 ++++ .../muyu/common/core/utils/SpringUtils.java | 114 ++ .../muyu/common/core/utils/StringUtils.java | 504 +++++++ .../common/core/utils/bean/BeanUtils.java | 107 ++ .../core/utils/bean/BeanValidators.java | 22 + .../common/core/utils/file/FileTypeUtils.java | 85 ++ .../common/core/utils/file/FileUtils.java | 223 +++ .../common/core/utils/file/ImageUtils.java | 69 + .../common/core/utils/file/MimeTypeUtils.java | 56 + .../common/core/utils/html/EscapeUtil.java | 145 ++ .../common/core/utils/html/HTMLFilter.java | 498 +++++++ .../muyu/common/core/utils/ip/IpUtils.java | 331 +++++ .../core/utils/poi/ExcelHandlerAdapter.java | 23 + .../muyu/common/core/utils/poi/ExcelUtil.java | 1230 +++++++++++++++++ .../core/utils/reflect/ReflectUtils.java | 324 +++++ .../muyu/common/core/utils/sign/Base64.java | 256 ++++ .../muyu/common/core/utils/sql/SqlUtil.java | 59 + .../muyu/common/core/utils/uuid/IdUtils.java | 44 + .../com/muyu/common/core/utils/uuid/Seq.java | 78 ++ .../com/muyu/common/core/utils/uuid/UUID.java | 450 ++++++ .../core/validation/ValidationConfig.java | 14 + .../validation/custom/IsSystemPayType.java | 21 + .../core/validation/custom/IsSystemYesNo.java | 18 + .../custom/SystemPayTypeValidator.java | 12 + .../custom/SystemYesNoValidator.java | 13 + .../core/web/controller/BaseController.java | 129 ++ .../common/core/web/domain/BaseEntity.java | 85 ++ .../common/core/web/domain/TreeEntity.java | 47 + .../muyu/common/core/web/page/PageDomain.java | 93 ++ .../common/core/web/page/TableDataInfo.java | 45 + .../common/core/web/page/TableSupport.java | 53 + .../java/com/muyu/common/core/xss/Xss.java | 27 + .../muyu/common/core/xss/XssValidator.java | 31 + ...ot.autoconfigure.AutoConfiguration.imports | 2 + ...ot.autoconfigure.AutoConfiguration.imports | 2 + .../core/annotation/Excel$ColumnType.class | Bin 0 -> 1474 bytes .../common/core/annotation/Excel$Type.class | Bin 0 -> 1429 bytes .../muyu/common/core/annotation/Excel.class | Bin 0 -> 2053 bytes .../muyu/common/core/annotation/Excels.class | Bin 0 -> 449 bytes .../common/core/constant/CacheConstants.class | Bin 0 -> 878 bytes .../muyu/common/core/constant/Constants.class | Bin 0 -> 1774 bytes .../common/core/constant/GenConstants.class | Bin 0 -> 2727 bytes .../common/core/constant/HttpStatus.class | Bin 0 -> 905 bytes .../constant/ScheduleConstants$Status.class | Bin 0 -> 1555 bytes .../core/constant/ScheduleConstants.class | Bin 0 -> 755 bytes .../core/constant/SecurityConstants.class | Bin 0 -> 750 bytes .../core/constant/ServiceNameConstants.class | Bin 0 -> 527 bytes .../common/core/constant/TokenConstants.class | Bin 0 -> 526 bytes .../common/core/constant/UserConstants.class | Bin 0 -> 1167 bytes .../core/context/SecurityContextHolder.class | Bin 0 -> 3440 bytes .../core/domain/Result$ResultBuilder.class | Bin 0 -> 2303 bytes .../com/muyu/common/core/domain/Result.class | Bin 0 -> 7130 bytes .../muyu/common/core/enums/SysPayType.class | Bin 0 -> 3821 bytes .../muyu/common/core/enums/SystemYesNo.class | Bin 0 -> 2801 bytes .../muyu/common/core/enums/UserStatus.class | Bin 0 -> 1579 bytes .../core/exception/CaptchaException.class | Bin 0 -> 469 bytes .../core/exception/CheckedException.class | Bin 0 -> 972 bytes .../core/exception/DemoModeException.class | Bin 0 -> 416 bytes .../core/exception/GlobalException.class | Bin 0 -> 1035 bytes .../core/exception/InnerAuthException.class | Bin 0 -> 479 bytes .../exception/PreAuthorizeException.class | Bin 0 -> 428 bytes .../core/exception/ServiceException.class | Bin 0 -> 1327 bytes .../common/core/exception/UtilException.class | Bin 0 -> 824 bytes .../exception/auth/NotLoginException.class | Bin 0 -> 486 bytes .../auth/NotPermissionException.class | Bin 0 -> 772 bytes .../exception/auth/NotRoleException.class | Bin 0 -> 742 bytes .../core/exception/base/BaseException.class | Bin 0 -> 1604 bytes .../core/exception/file/FileException.class | Bin 0 -> 679 bytes ...FileNameLengthLimitExceededException.class | Bin 0 -> 776 bytes .../file/FileSizeLimitExceededException.class | Bin 0 -> 734 bytes .../exception/file/FileUploadException.class | Bin 0 -> 1389 bytes ...ption$InvalidFlashExtensionException.class | Bin 0 -> 803 bytes ...ption$InvalidImageExtensionException.class | Bin 0 -> 803 bytes ...ption$InvalidMediaExtensionException.class | Bin 0 -> 803 bytes ...ption$InvalidVideoExtensionException.class | Bin 0 -> 803 bytes .../file/InvalidExtensionException.class | Bin 0 -> 2255 bytes .../exception/job/TaskException$Code.class | Bin 0 -> 1548 bytes .../core/exception/job/TaskException.class | Bin 0 -> 1152 bytes .../user/CaptchaExpireException.class | Bin 0 -> 536 bytes .../core/exception/user/UserException.class | Bin 0 -> 645 bytes .../user/UserPasswordNotMatchException.class | Bin 0 -> 560 bytes .../muyu/common/core/feign/FeginConfig.class | Bin 0 -> 647 bytes .../muyu/common/core/text/CharsetKit.class | Bin 0 -> 1822 bytes .../com/muyu/common/core/text/Convert.class | Bin 0 -> 14494 bytes .../muyu/common/core/text/StrFormatter.class | Bin 0 -> 1851 bytes .../muyu/common/core/utils/DateUtils.class | Bin 0 -> 4847 bytes .../common/core/utils/ExceptionUtil.class | Bin 0 -> 1362 bytes .../com/muyu/common/core/utils/JwtUtils.class | Bin 0 -> 4023 bytes .../muyu/common/core/utils/PageUtils.class | Bin 0 -> 1410 bytes .../muyu/common/core/utils/ServletUtils.class | Bin 0 -> 10517 bytes .../muyu/common/core/utils/SpringUtils.class | Bin 0 -> 2375 bytes .../muyu/common/core/utils/StringUtils.class | Bin 0 -> 8432 bytes .../common/core/utils/bean/BeanUtils.class | Bin 0 -> 2746 bytes .../core/utils/bean/BeanValidators.class | Bin 0 -> 1244 bytes .../core/utils/file/FileTypeUtils.class | Bin 0 -> 2017 bytes .../common/core/utils/file/FileUtils.class | Bin 0 -> 5216 bytes .../common/core/utils/file/ImageUtils.class | Bin 0 -> 2296 bytes .../core/utils/file/MimeTypeUtils.class | Bin 0 -> 1898 bytes .../common/core/utils/html/EscapeUtil.class | Bin 0 -> 3371 bytes .../common/core/utils/html/HTMLFilter.class | Bin 0 -> 13885 bytes .../muyu/common/core/utils/ip/IpUtils.class | Bin 0 -> 6726 bytes .../core/utils/poi/ExcelHandlerAdapter.class | Bin 0 -> 299 bytes .../common/core/utils/poi/ExcelUtil.class | Bin 0 -> 39722 bytes .../core/utils/reflect/ReflectUtils.class | Bin 0 -> 11066 bytes .../muyu/common/core/utils/sign/Base64.class | Bin 0 -> 4504 bytes .../muyu/common/core/utils/sql/SqlUtil.class | Bin 0 -> 1847 bytes .../muyu/common/core/utils/uuid/IdUtils.class | Bin 0 -> 729 bytes .../com/muyu/common/core/utils/uuid/Seq.class | Bin 0 -> 2289 bytes .../common/core/utils/uuid/UUID$Holder.class | Bin 0 -> 600 bytes .../muyu/common/core/utils/uuid/UUID.class | Bin 0 -> 6895 bytes .../core/validation/ValidationConfig.class | Bin 0 -> 1025 bytes .../validation/custom/IsSystemPayType.class | Bin 0 -> 887 bytes .../validation/custom/IsSystemYesNo.class | Bin 0 -> 881 bytes .../custom/SystemPayTypeValidator.class | Bin 0 -> 1097 bytes .../custom/SystemYesNoValidator.class | Bin 0 -> 1090 bytes .../web/controller/BaseController$1.class | Bin 0 -> 1007 bytes .../core/web/controller/BaseController.class | Bin 0 -> 3471 bytes .../domain/BaseEntity$BaseEntityBuilder.class | Bin 0 -> 3335 bytes .../BaseEntity$BaseEntityBuilderImpl.class | Bin 0 -> 1228 bytes .../common/core/web/domain/BaseEntity.class | Bin 0 -> 7046 bytes .../domain/TreeEntity$TreeEntityBuilder.class | Bin 0 -> 3373 bytes .../TreeEntity$TreeEntityBuilderImpl.class | Bin 0 -> 1618 bytes .../common/core/web/domain/TreeEntity.class | Bin 0 -> 5462 bytes .../common/core/web/page/PageDomain.class | Bin 0 -> 2627 bytes .../TableDataInfo$TableDataInfoBuilder.class | Bin 0 -> 2827 bytes .../common/core/web/page/TableDataInfo.class | Bin 0 -> 3966 bytes .../common/core/web/page/TableSupport.class | Bin 0 -> 1534 bytes .../com/muyu/common/core/xss/Xss.class | Bin 0 -> 819 bytes .../muyu/common/core/xss/XssValidator.class | Bin 0 -> 1593 bytes target/cloud-common-core-3.6.3.jar | Bin 0 -> 146314 bytes target/maven-archiver/pom.properties | 3 + .../compile/default-compile/createdFiles.lst | 94 ++ .../compile/default-compile/inputFiles.lst | 78 ++ 187 files changed, 9430 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 pom.xml create mode 100644 src/main/java/com/muyu/common/core/annotation/Excel.java create mode 100644 src/main/java/com/muyu/common/core/annotation/Excels.java create mode 100644 src/main/java/com/muyu/common/core/constant/CacheConstants.java create mode 100644 src/main/java/com/muyu/common/core/constant/Constants.java create mode 100644 src/main/java/com/muyu/common/core/constant/GenConstants.java create mode 100644 src/main/java/com/muyu/common/core/constant/HttpStatus.java create mode 100644 src/main/java/com/muyu/common/core/constant/ScheduleConstants.java create mode 100644 src/main/java/com/muyu/common/core/constant/SecurityConstants.java create mode 100644 src/main/java/com/muyu/common/core/constant/ServiceNameConstants.java create mode 100644 src/main/java/com/muyu/common/core/constant/TokenConstants.java create mode 100644 src/main/java/com/muyu/common/core/constant/UserConstants.java create mode 100644 src/main/java/com/muyu/common/core/context/SecurityContextHolder.java create mode 100644 src/main/java/com/muyu/common/core/domain/Result.java create mode 100644 src/main/java/com/muyu/common/core/enums/SysPayType.java create mode 100644 src/main/java/com/muyu/common/core/enums/SystemYesNo.java create mode 100644 src/main/java/com/muyu/common/core/enums/UserStatus.java create mode 100644 src/main/java/com/muyu/common/core/exception/CaptchaException.java create mode 100644 src/main/java/com/muyu/common/core/exception/CheckedException.java create mode 100644 src/main/java/com/muyu/common/core/exception/DemoModeException.java create mode 100644 src/main/java/com/muyu/common/core/exception/GlobalException.java create mode 100644 src/main/java/com/muyu/common/core/exception/InnerAuthException.java create mode 100644 src/main/java/com/muyu/common/core/exception/PreAuthorizeException.java create mode 100644 src/main/java/com/muyu/common/core/exception/ServiceException.java create mode 100644 src/main/java/com/muyu/common/core/exception/UtilException.java create mode 100644 src/main/java/com/muyu/common/core/exception/auth/NotLoginException.java create mode 100644 src/main/java/com/muyu/common/core/exception/auth/NotPermissionException.java create mode 100644 src/main/java/com/muyu/common/core/exception/auth/NotRoleException.java create mode 100644 src/main/java/com/muyu/common/core/exception/base/BaseException.java create mode 100644 src/main/java/com/muyu/common/core/exception/file/FileException.java create mode 100644 src/main/java/com/muyu/common/core/exception/file/FileNameLengthLimitExceededException.java create mode 100644 src/main/java/com/muyu/common/core/exception/file/FileSizeLimitExceededException.java create mode 100644 src/main/java/com/muyu/common/core/exception/file/FileUploadException.java create mode 100644 src/main/java/com/muyu/common/core/exception/file/InvalidExtensionException.java create mode 100644 src/main/java/com/muyu/common/core/exception/job/TaskException.java create mode 100644 src/main/java/com/muyu/common/core/exception/user/CaptchaExpireException.java create mode 100644 src/main/java/com/muyu/common/core/exception/user/UserException.java create mode 100644 src/main/java/com/muyu/common/core/exception/user/UserPasswordNotMatchException.java create mode 100644 src/main/java/com/muyu/common/core/feign/FeginConfig.java create mode 100644 src/main/java/com/muyu/common/core/text/CharsetKit.java create mode 100644 src/main/java/com/muyu/common/core/text/Convert.java create mode 100644 src/main/java/com/muyu/common/core/text/StrFormatter.java create mode 100644 src/main/java/com/muyu/common/core/utils/DateUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/ExceptionUtil.java create mode 100644 src/main/java/com/muyu/common/core/utils/JwtUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/PageUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/ServletUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/SpringUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/StringUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/bean/BeanUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/bean/BeanValidators.java create mode 100644 src/main/java/com/muyu/common/core/utils/file/FileTypeUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/file/FileUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/file/ImageUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/file/MimeTypeUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/html/EscapeUtil.java create mode 100644 src/main/java/com/muyu/common/core/utils/html/HTMLFilter.java create mode 100644 src/main/java/com/muyu/common/core/utils/ip/IpUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.java create mode 100644 src/main/java/com/muyu/common/core/utils/poi/ExcelUtil.java create mode 100644 src/main/java/com/muyu/common/core/utils/reflect/ReflectUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/sign/Base64.java create mode 100644 src/main/java/com/muyu/common/core/utils/sql/SqlUtil.java create mode 100644 src/main/java/com/muyu/common/core/utils/uuid/IdUtils.java create mode 100644 src/main/java/com/muyu/common/core/utils/uuid/Seq.java create mode 100644 src/main/java/com/muyu/common/core/utils/uuid/UUID.java create mode 100644 src/main/java/com/muyu/common/core/validation/ValidationConfig.java create mode 100644 src/main/java/com/muyu/common/core/validation/custom/IsSystemPayType.java create mode 100644 src/main/java/com/muyu/common/core/validation/custom/IsSystemYesNo.java create mode 100644 src/main/java/com/muyu/common/core/validation/custom/SystemPayTypeValidator.java create mode 100644 src/main/java/com/muyu/common/core/validation/custom/SystemYesNoValidator.java create mode 100644 src/main/java/com/muyu/common/core/web/controller/BaseController.java create mode 100644 src/main/java/com/muyu/common/core/web/domain/BaseEntity.java create mode 100644 src/main/java/com/muyu/common/core/web/domain/TreeEntity.java create mode 100644 src/main/java/com/muyu/common/core/web/page/PageDomain.java create mode 100644 src/main/java/com/muyu/common/core/web/page/TableDataInfo.java create mode 100644 src/main/java/com/muyu/common/core/web/page/TableSupport.java create mode 100644 src/main/java/com/muyu/common/core/xss/Xss.java create mode 100644 src/main/java/com/muyu/common/core/xss/XssValidator.java create mode 100644 src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 target/classes/com/muyu/common/core/annotation/Excel$ColumnType.class create mode 100644 target/classes/com/muyu/common/core/annotation/Excel$Type.class create mode 100644 target/classes/com/muyu/common/core/annotation/Excel.class create mode 100644 target/classes/com/muyu/common/core/annotation/Excels.class create mode 100644 target/classes/com/muyu/common/core/constant/CacheConstants.class create mode 100644 target/classes/com/muyu/common/core/constant/Constants.class create mode 100644 target/classes/com/muyu/common/core/constant/GenConstants.class create mode 100644 target/classes/com/muyu/common/core/constant/HttpStatus.class create mode 100644 target/classes/com/muyu/common/core/constant/ScheduleConstants$Status.class create mode 100644 target/classes/com/muyu/common/core/constant/ScheduleConstants.class create mode 100644 target/classes/com/muyu/common/core/constant/SecurityConstants.class create mode 100644 target/classes/com/muyu/common/core/constant/ServiceNameConstants.class create mode 100644 target/classes/com/muyu/common/core/constant/TokenConstants.class create mode 100644 target/classes/com/muyu/common/core/constant/UserConstants.class create mode 100644 target/classes/com/muyu/common/core/context/SecurityContextHolder.class create mode 100644 target/classes/com/muyu/common/core/domain/Result$ResultBuilder.class create mode 100644 target/classes/com/muyu/common/core/domain/Result.class create mode 100644 target/classes/com/muyu/common/core/enums/SysPayType.class create mode 100644 target/classes/com/muyu/common/core/enums/SystemYesNo.class create mode 100644 target/classes/com/muyu/common/core/enums/UserStatus.class create mode 100644 target/classes/com/muyu/common/core/exception/CaptchaException.class create mode 100644 target/classes/com/muyu/common/core/exception/CheckedException.class create mode 100644 target/classes/com/muyu/common/core/exception/DemoModeException.class create mode 100644 target/classes/com/muyu/common/core/exception/GlobalException.class create mode 100644 target/classes/com/muyu/common/core/exception/InnerAuthException.class create mode 100644 target/classes/com/muyu/common/core/exception/PreAuthorizeException.class create mode 100644 target/classes/com/muyu/common/core/exception/ServiceException.class create mode 100644 target/classes/com/muyu/common/core/exception/UtilException.class create mode 100644 target/classes/com/muyu/common/core/exception/auth/NotLoginException.class create mode 100644 target/classes/com/muyu/common/core/exception/auth/NotPermissionException.class create mode 100644 target/classes/com/muyu/common/core/exception/auth/NotRoleException.class create mode 100644 target/classes/com/muyu/common/core/exception/base/BaseException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/FileException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/FileNameLengthLimitExceededException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/FileSizeLimitExceededException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/FileUploadException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidFlashExtensionException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidImageExtensionException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidMediaExtensionException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidVideoExtensionException.class create mode 100644 target/classes/com/muyu/common/core/exception/file/InvalidExtensionException.class create mode 100644 target/classes/com/muyu/common/core/exception/job/TaskException$Code.class create mode 100644 target/classes/com/muyu/common/core/exception/job/TaskException.class create mode 100644 target/classes/com/muyu/common/core/exception/user/CaptchaExpireException.class create mode 100644 target/classes/com/muyu/common/core/exception/user/UserException.class create mode 100644 target/classes/com/muyu/common/core/exception/user/UserPasswordNotMatchException.class create mode 100644 target/classes/com/muyu/common/core/feign/FeginConfig.class create mode 100644 target/classes/com/muyu/common/core/text/CharsetKit.class create mode 100644 target/classes/com/muyu/common/core/text/Convert.class create mode 100644 target/classes/com/muyu/common/core/text/StrFormatter.class create mode 100644 target/classes/com/muyu/common/core/utils/DateUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/ExceptionUtil.class create mode 100644 target/classes/com/muyu/common/core/utils/JwtUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/PageUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/ServletUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/SpringUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/StringUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/bean/BeanUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/bean/BeanValidators.class create mode 100644 target/classes/com/muyu/common/core/utils/file/FileTypeUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/file/FileUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/file/ImageUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/file/MimeTypeUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/html/EscapeUtil.class create mode 100644 target/classes/com/muyu/common/core/utils/html/HTMLFilter.class create mode 100644 target/classes/com/muyu/common/core/utils/ip/IpUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.class create mode 100644 target/classes/com/muyu/common/core/utils/poi/ExcelUtil.class create mode 100644 target/classes/com/muyu/common/core/utils/reflect/ReflectUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/sign/Base64.class create mode 100644 target/classes/com/muyu/common/core/utils/sql/SqlUtil.class create mode 100644 target/classes/com/muyu/common/core/utils/uuid/IdUtils.class create mode 100644 target/classes/com/muyu/common/core/utils/uuid/Seq.class create mode 100644 target/classes/com/muyu/common/core/utils/uuid/UUID$Holder.class create mode 100644 target/classes/com/muyu/common/core/utils/uuid/UUID.class create mode 100644 target/classes/com/muyu/common/core/validation/ValidationConfig.class create mode 100644 target/classes/com/muyu/common/core/validation/custom/IsSystemPayType.class create mode 100644 target/classes/com/muyu/common/core/validation/custom/IsSystemYesNo.class create mode 100644 target/classes/com/muyu/common/core/validation/custom/SystemPayTypeValidator.class create mode 100644 target/classes/com/muyu/common/core/validation/custom/SystemYesNoValidator.class create mode 100644 target/classes/com/muyu/common/core/web/controller/BaseController$1.class create mode 100644 target/classes/com/muyu/common/core/web/controller/BaseController.class create mode 100644 target/classes/com/muyu/common/core/web/domain/BaseEntity$BaseEntityBuilder.class create mode 100644 target/classes/com/muyu/common/core/web/domain/BaseEntity$BaseEntityBuilderImpl.class create mode 100644 target/classes/com/muyu/common/core/web/domain/BaseEntity.class create mode 100644 target/classes/com/muyu/common/core/web/domain/TreeEntity$TreeEntityBuilder.class create mode 100644 target/classes/com/muyu/common/core/web/domain/TreeEntity$TreeEntityBuilderImpl.class create mode 100644 target/classes/com/muyu/common/core/web/domain/TreeEntity.class create mode 100644 target/classes/com/muyu/common/core/web/page/PageDomain.class create mode 100644 target/classes/com/muyu/common/core/web/page/TableDataInfo$TableDataInfoBuilder.class create mode 100644 target/classes/com/muyu/common/core/web/page/TableDataInfo.class create mode 100644 target/classes/com/muyu/common/core/web/page/TableSupport.class create mode 100644 target/classes/com/muyu/common/core/xss/Xss.class create mode 100644 target/classes/com/muyu/common/core/xss/XssValidator.class create mode 100644 target/cloud-common-core-3.6.3.jar create mode 100644 target/maven-archiver/pom.properties create mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..14c4c06 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..ee9f695 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,68 @@ + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b870255 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..67e1e61 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b57633a --- /dev/null +++ b/pom.xml @@ -0,0 +1,186 @@ + + + + com.muyu + cloud-common + 1.0.0 + + 4.0.0 + 3.6.3 + cloud-common-core + + + + cloud-common-core核心模块 + + + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + + org.springframework + spring-context-support + + + + + org.springframework + spring-web + + + + + com.alibaba + transmittable-thread-local + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + + + + + com.baomidou + mybatis-plus-spring-boot3-starter + 3.5.6 + + + com.github.jsqlparser + jsqlparser + + + org.mybatis + mybatis + + + + + + org.mybatis + mybatis + 3.5.16 + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + com.fasterxml.jackson.core + jackson-databind + + + + + com.alibaba.fastjson2 + fastjson2 + + + + + io.jsonwebtoken + jjwt + + + + + org.apache.commons + commons-lang3 + + + + + commons-io + commons-io + + + + + org.apache.poi + poi-ooxml + + + + + + jakarta.servlet + jakarta.servlet-api + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + + + + + + javax.annotation + javax.annotation-api + + + + + org.projectlombok + lombok + + + + + org.apache.skywalking + apm-toolkit-trace + + + + + org.apache.skywalking + apm-toolkit-logback-1.x + + + + cn.hutool + hutool-all + + + + io.swagger.core.v3 + swagger-annotations-jakarta + + + + + com.dtflys.forest + forest-spring-boot3-starter + + + + + + + + + diff --git a/src/main/java/com/muyu/common/core/annotation/Excel.java b/src/main/java/com/muyu/common/core/annotation/Excel.java new file mode 100644 index 0000000..36180e5 --- /dev/null +++ b/src/main/java/com/muyu/common/core/annotation/Excel.java @@ -0,0 +1,176 @@ +package com.muyu.common.core.annotation; + +import com.muyu.common.core.utils.poi.ExcelHandlerAdapter; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; + +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数据注解 + * + * @author muyu + */ +@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 ""; + + /** + * 读取内容转表达式 (如: 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; + + /** + * 导出时在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 {}; + + /** + * 是否需要纵向合并单元格,应对需求:含有list集合单元格) + */ + public boolean needMerge () default false; + + /** + * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. + */ + public boolean isExport () default true; + + /** + * 另一个类中的属性名称,支持多级获取,以小数点隔开 + */ + public String targetAttr () default ""; + + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + public boolean isStatistics () default false; + + /** + * 导出类型(0数字 1字符串) + */ + public ColumnType cellType () default ColumnType.STRING; + + /** + * 导出列头背景颜色 + */ + public IndexedColors headerBackgroundColor () default IndexedColors.GREY_50_PERCENT; + + /** + * 导出列头字体颜色 + */ + public IndexedColors headerColor () default IndexedColors.WHITE; + + /** + * 导出单元格背景颜色 + */ + public IndexedColors backgroundColor () default IndexedColors.WHITE; + + /** + * 导出单元格字体颜色 + */ + public IndexedColors color () default IndexedColors.BLACK; + + /** + * 导出字段对齐方式 + */ + public HorizontalAlignment align () default HorizontalAlignment.CENTER; + + /** + * 自定义数据处理器 + */ + public Class handler () default ExcelHandlerAdapter.class; + + /** + * 自定义数据处理器参数 + */ + public String[] args () default {}; + + /** + * 字段类型(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), IMAGE(2); + private final int value; + + ColumnType (int value) { + this.value = value; + } + + public int value () { + return this.value; + } + } +} diff --git a/src/main/java/com/muyu/common/core/annotation/Excels.java b/src/main/java/com/muyu/common/core/annotation/Excels.java new file mode 100644 index 0000000..f8fc165 --- /dev/null +++ b/src/main/java/com/muyu/common/core/annotation/Excels.java @@ -0,0 +1,17 @@ +package com.muyu.common.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解集 + * + * @author muyu + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Excels { + Excel[] value (); +} diff --git a/src/main/java/com/muyu/common/core/constant/CacheConstants.java b/src/main/java/com/muyu/common/core/constant/CacheConstants.java new file mode 100644 index 0000000..532c9f2 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/CacheConstants.java @@ -0,0 +1,58 @@ +package com.muyu.common.core.constant; + +/** + * 缓存常量信息 + * + * @author muyu + */ +public class CacheConstants { + /** + * 缓存有效期,默认720(分钟) + */ + public final static long EXPIRATION = 720; + + /** + * 缓存刷新时间,默认120(分钟) + */ + public final static long REFRESH_TIME = 120; + + /** + * 密码最大错误次数 + */ + public final static int PASSWORD_MAX_RETRY_COUNT = 5; + + /** + * 密码锁定时间,默认10(分钟) + */ + public final static long PASSWORD_LOCK_TIME = 10; + + /** + * 权限缓存前缀 + */ + public final static String LOGIN_TOKEN_KEY = "login_tokens:"; + + /** + * 验证码 redis key + */ + public static final String CAPTCHA_CODE_KEY = "captcha_codes:"; + + /** + * 参数管理 cache key + */ + public static final String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache key + */ + public static final String SYS_DICT_KEY = "sys_dict:"; + + /** + * 登录账户密码错误次数 redis key + */ + public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; + + /** + * 登录IP黑名单 cache key + */ + public static final String SYS_LOGIN_BLACKIPLIST = SYS_CONFIG_KEY + "sys.login.blackIPList"; +} diff --git a/src/main/java/com/muyu/common/core/constant/Constants.java b/src/main/java/com/muyu/common/core/constant/Constants.java new file mode 100644 index 0000000..a3540fc --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/Constants.java @@ -0,0 +1,134 @@ +package com.muyu.common.core.constant; + +/** + * 通用常量信息 + * + * @author muyu + */ +public class Constants { + /** + * UTF-8 字符集 + */ + public static final String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + + /** + * www主域 + */ + public static final String WWW = "www."; + + /** + * RMI 远程方法调用 + */ + public static final String LOOKUP_RMI = "rmi:"; + + /** + * LDAP 远程方法调用 + */ + public static final String LOOKUP_LDAP = "ldap:"; + + /** + * LDAPS 远程方法调用 + */ + public static final String LOOKUP_LDAPS = "ldaps:"; + + /** + * http请求 + */ + public static final String HTTP = "http://"; + + /** + * https请求 + */ + public static final String HTTPS = "https://"; + + /** + * 成功标记 + */ + public static final Integer SUCCESS = 200; + + /** + * 失败标记 + */ + public static final Integer FAIL = 500; + + /** + * 登录成功状态 + */ + public static final String LOGIN_SUCCESS_STATUS = "0"; + + /** + * 登录失败状态 + */ + public static final String LOGIN_FAIL_STATUS = "1"; + + /** + * 登录成功 + */ + public static final String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + public static final String LOGOUT = "Logout"; + + /** + * 注册 + */ + public static final String REGISTER = "Register"; + + /** + * 登录失败 + */ + public static final String LOGIN_FAIL = "Error"; + + /** + * 当前记录起始索引 + */ + 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 final long CAPTCHA_EXPIRATION = 2; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; + + /** + * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全) + */ + public static final String[] JSON_WHITELIST_STR = {"org.springframework", "com.muyu"}; + + /** + * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) + */ + public static final String[] JOB_WHITELIST_STR = {"com.muyu"}; + + /** + * 定时任务违规的字符 + */ + public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", + "org.springframework", "org.apache", "com.muyu.common.core.utils.file"}; +} diff --git a/src/main/java/com/muyu/common/core/constant/GenConstants.java b/src/main/java/com/muyu/common/core/constant/GenConstants.java new file mode 100644 index 0000000..fde9967 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/GenConstants.java @@ -0,0 +1,186 @@ +package com.muyu.common.core.constant; + +/** + * 代码生成通用常量 + * + * @author muyu + */ +public class GenConstants { + /** + * 单表(增删改查) + */ + public static final String TPL_CRUD = "crud"; + + /** + * 树表(增删改查) + */ + public static final String TPL_TREE = "tree"; + + /** + * 主子表(增删改查) + */ + public static final String TPL_SUB = "sub"; + + /** + * 树编码字段 + */ + public static final String TREE_CODE = "treeCode"; + + /** + * 树父编码字段 + */ + public static final String TREE_PARENT_CODE = "treeParentCode"; + + /** + * 树名称字段 + */ + public static final String TREE_NAME = "treeName"; + + /** + * 上级菜单ID字段 + */ + public static final String PARENT_MENU_ID = "parentMenuId"; + + /** + * 上级菜单名称字段 + */ + public static final String PARENT_MENU_NAME = "parentMenuName"; + + /** + * 数据库字符串类型 + */ + public static final String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"}; + + /** + * 数据库文本类型 + */ + public static final String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"}; + + /** + * 数据库时间类型 + */ + public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"}; + + /** + * 数据库数字类型 + */ + public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", + "bigint", "float", "double", "decimal"}; + + /** + * 页面不需要编辑字段 + */ + public static final String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"}; + + /** + * 页面不需要显示的列表字段 + */ + public static final String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by", + "update_time"}; + + /** + * 页面不需要查询字段 + */ + public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark"}; + + /** + * Entity基类字段 + */ + public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"}; + + /** + * Tree基类字段 + */ + public static final String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors"}; + + /** + * 文本框 + */ + public static final String HTML_INPUT = "input"; + + /** + * 文本域 + */ + public static final String HTML_TEXTAREA = "textarea"; + + /** + * 下拉框 + */ + public static final String HTML_SELECT = "select"; + + /** + * 单选框 + */ + public static final String HTML_RADIO = "radio"; + + /** + * 复选框 + */ + public static final String HTML_CHECKBOX = "checkbox"; + + /** + * 日期控件 + */ + public static final String HTML_DATETIME = "datetime"; + + /** + * 图片上传控件 + */ + public static final String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** + * 文件上传控件 + */ + public static final String HTML_FILE_UPLOAD = "fileUpload"; + + /** + * 富文本控件 + */ + public static final String HTML_EDITOR = "editor"; + + /** + * 字符串类型 + */ + public static final String TYPE_STRING = "String"; + + /** + * 整型 + */ + public static final String TYPE_INTEGER = "Integer"; + + /** + * 长整型 + */ + public static final String TYPE_LONG = "Long"; + + /** + * 浮点型 + */ + public static final String TYPE_DOUBLE = "Double"; + + /** + * 高精度计算类型 + */ + public static final String TYPE_BIGDECIMAL = "BigDecimal"; + + /** + * 时间类型 + */ + public static final String TYPE_DATE = "Date"; + + /** + * 模糊查询 + */ + public static final String QUERY_LIKE = "LIKE"; + + /** + * 相等查询 + */ + public static final String QUERY_EQ = "EQ"; + + /** + * 需要 + */ + public static final String REQUIRE = "1"; +} diff --git a/src/main/java/com/muyu/common/core/constant/HttpStatus.java b/src/main/java/com/muyu/common/core/constant/HttpStatus.java new file mode 100644 index 0000000..36e0783 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/HttpStatus.java @@ -0,0 +1,93 @@ +package com.muyu.common.core.constant; + +/** + * 返回状态码 + * + * @author muyu + */ +public class HttpStatus { + /** + * 操作成功 + */ + public static final int SUCCESS = 200; + + /** + * 对象创建成功 + */ + public static final int CREATED = 201; + + /** + * 请求已经被接受 + */ + public static final int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + public static final int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + public static final int MOVED_PERM = 301; + + /** + * 重定向 + */ + public static final int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + public static final int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static final int BAD_REQUEST = 400; + + /** + * 未授权 + */ + public static final int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static final int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static final int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static final int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static final int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static final int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static final int ERROR = 500; + + /** + * 接口未实现 + */ + public static final int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + public static final int WARN = 601; +} diff --git a/src/main/java/com/muyu/common/core/constant/ScheduleConstants.java b/src/main/java/com/muyu/common/core/constant/ScheduleConstants.java new file mode 100644 index 0000000..b5bceb0 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/ScheduleConstants.java @@ -0,0 +1,56 @@ +package com.muyu.common.core.constant; + +/** + * 任务调度通用常量 + * + * @author muyu + */ +public class ScheduleConstants { + public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; + + /** + * 执行目标key + */ + public static final String TASK_PROPERTIES = "TASK_PROPERTIES"; + + /** + * 默认 + */ + public static final String MISFIRE_DEFAULT = "0"; + + /** + * 立即触发执行 + */ + public static final String MISFIRE_IGNORE_MISFIRES = "1"; + + /** + * 触发一次执行 + */ + public static final String MISFIRE_FIRE_AND_PROCEED = "2"; + + /** + * 不触发立即执行 + */ + public static final String MISFIRE_DO_NOTHING = "3"; + + public enum Status { + /** + * 正常 + */ + NORMAL("0"), + /** + * 暂停 + */ + PAUSE("1"); + + private String value; + + private Status (String value) { + this.value = value; + } + + public String getValue () { + return value; + } + } +} diff --git a/src/main/java/com/muyu/common/core/constant/SecurityConstants.java b/src/main/java/com/muyu/common/core/constant/SecurityConstants.java new file mode 100644 index 0000000..c862929 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/SecurityConstants.java @@ -0,0 +1,48 @@ +package com.muyu.common.core.constant; + +/** + * 权限相关通用常量 + * + * @author muyu + */ +public class SecurityConstants { + /** + * 用户ID字段 + */ + public static final String DETAILS_USER_ID = "user_id"; + + /** + * 用户名字段 + */ + public static final String DETAILS_USERNAME = "username"; + + /** + * 授权信息字段 + */ + public static final String AUTHORIZATION_HEADER = "authorization"; + + /** + * 请求来源 + */ + public static final String FROM_SOURCE = "from-source"; + + /** + * 内部请求 + */ + public static final String INNER = "inner"; + + /** + * 用户标识 + */ + public static final String USER_KEY = "user_key"; + + /** + * 登录用户 + */ + public static final String LOGIN_USER = "login_user"; + + /** + * 角色权限 + */ + public static final String ROLE_PERMISSION = "role_permission"; +} diff --git a/src/main/java/com/muyu/common/core/constant/ServiceNameConstants.java b/src/main/java/com/muyu/common/core/constant/ServiceNameConstants.java new file mode 100644 index 0000000..bb59b70 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/ServiceNameConstants.java @@ -0,0 +1,23 @@ +package com.muyu.common.core.constant; + +/** + * 服务名称 + * + * @author muyu + */ +public class ServiceNameConstants { + /** + * 认证服务的serviceid + */ + public static final String AUTH_SERVICE = "cloud-auth"; + + /** + * 系统模块的serviceid + */ + public static final String SYSTEM_SERVICE = "cloud-system"; + + /** + * 文件服务的serviceid + */ + public static final String FILE_SERVICE = "cloud-file"; +} diff --git a/src/main/java/com/muyu/common/core/constant/TokenConstants.java b/src/main/java/com/muyu/common/core/constant/TokenConstants.java new file mode 100644 index 0000000..38abd57 --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/TokenConstants.java @@ -0,0 +1,24 @@ +package com.muyu.common.core.constant; + +/** + * Token的Key常量 + * + * @author muyu + */ +public class TokenConstants { + /** + * 令牌自定义标识 + */ + public static final String AUTHENTICATION = "Authorization"; + + /** + * 令牌前缀 + */ + public static final String PREFIX = "Bearer "; + + /** + * 令牌秘钥 + */ + public final static String SECRET = "abcdefghijklmnsalieopadfaqawefwerstuvwxyz"; + +} diff --git a/src/main/java/com/muyu/common/core/constant/UserConstants.java b/src/main/java/com/muyu/common/core/constant/UserConstants.java new file mode 100644 index 0000000..0df401c --- /dev/null +++ b/src/main/java/com/muyu/common/core/constant/UserConstants.java @@ -0,0 +1,113 @@ +package com.muyu.common.core.constant; + +/** + * 用户常量信息 + * + * @author muyu + */ +public class UserConstants { + /** + * 平台内系统用户的唯一标志 + */ + public static final String SYS_USER = "SYS_USER"; + + /** + * 正常状态 + */ + public static final String NORMAL = "0"; + + /** + * 异常状态 + */ + public static final String EXCEPTION = "1"; + + /** + * 用户封禁状态 + */ + public static final String USER_DISABLE = "1"; + + /** + * 角色封禁状态 + */ + public static final String ROLE_DISABLE = "1"; + + /** + * 部门正常状态 + */ + public static final String DEPT_NORMAL = "0"; + + /** + * 部门停用状态 + */ + public static final String DEPT_DISABLE = "1"; + + /** + * 字典正常状态 + */ + public static final String DICT_NORMAL = "0"; + + /** + * 是否为系统默认(是) + */ + public static final String YES = "Y"; + + /** + * 是否菜单外链(是) + */ + public static final String YES_FRAME = "0"; + + /** + * 是否菜单外链(否) + */ + public static final String NO_FRAME = "1"; + + /** + * 菜单类型(目录) + */ + public static final String TYPE_DIR = "M"; + + /** + * 菜单类型(菜单) + */ + public static final String TYPE_MENU = "C"; + + /** + * 菜单类型(按钮) + */ + public static final String TYPE_BUTTON = "F"; + + /** + * Layout组件标识 + */ + public final static String LAYOUT = "Layout"; + + /** + * ParentView组件标识 + */ + public final static String PARENT_VIEW = "ParentView"; + + /** + * InnerLink组件标识 + */ + public final static String INNER_LINK = "InnerLink"; + + /** + * 校验是否唯一的返回标识 + */ + public final static boolean UNIQUE = true; + public final static boolean NOT_UNIQUE = false; + + /** + * 用户名长度限制 + */ + public static final int USERNAME_MIN_LENGTH = 2; + + public static final int USERNAME_MAX_LENGTH = 20; + + /** + * 密码长度限制 + */ + public static final int PASSWORD_MIN_LENGTH = 5; + + public static final int PASSWORD_MAX_LENGTH = 20; +} diff --git a/src/main/java/com/muyu/common/core/context/SecurityContextHolder.java b/src/main/java/com/muyu/common/core/context/SecurityContextHolder.java new file mode 100644 index 0000000..80ea42b --- /dev/null +++ b/src/main/java/com/muyu/common/core/context/SecurityContextHolder.java @@ -0,0 +1,83 @@ +package com.muyu.common.core.context; + +import com.alibaba.ttl.TransmittableThreadLocal; +import com.muyu.common.core.constant.SecurityConstants; +import com.muyu.common.core.text.Convert; +import com.muyu.common.core.utils.StringUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 获取当前线程变量中的 用户id、用户名称、Token等信息 + * 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取 + * + * @author muyu + */ +public class SecurityContextHolder { + private static final TransmittableThreadLocal> THREAD_LOCAL = new TransmittableThreadLocal<>(); + + public static void set (String key, Object value) { + Map map = getLocalMap(); + map.put(key, value == null ? StringUtils.EMPTY : value); + } + + public static String get (String key) { + Map map = getLocalMap(); + return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY)); + } + + public static T get (String key, Class clazz) { + Map map = getLocalMap(); + return StringUtils.cast(map.getOrDefault(key, null)); + } + + public static Map getLocalMap () { + Map map = THREAD_LOCAL.get(); + if (map == null) { + map = new ConcurrentHashMap(); + THREAD_LOCAL.set(map); + } + return map; + } + + public static void setLocalMap (Map threadLocalMap) { + THREAD_LOCAL.set(threadLocalMap); + } + + public static Long getUserId () { + return Convert.toLong(get(SecurityConstants.DETAILS_USER_ID), 0L); + } + + public static void setUserId (String account) { + set(SecurityConstants.DETAILS_USER_ID, account); + } + + public static String getUserName () { + return get(SecurityConstants.DETAILS_USERNAME); + } + + public static void setUserName (String username) { + set(SecurityConstants.DETAILS_USERNAME, username); + } + + public static String getUserKey () { + return get(SecurityConstants.USER_KEY); + } + + public static void setUserKey (String userKey) { + set(SecurityConstants.USER_KEY, userKey); + } + + public static String getPermission () { + return get(SecurityConstants.ROLE_PERMISSION); + } + + public static void setPermission (String permissions) { + set(SecurityConstants.ROLE_PERMISSION, permissions); + } + + public static void remove () { + THREAD_LOCAL.remove(); + } +} diff --git a/src/main/java/com/muyu/common/core/domain/Result.java b/src/main/java/com/muyu/common/core/domain/Result.java new file mode 100644 index 0000000..7f5fe8f --- /dev/null +++ b/src/main/java/com/muyu/common/core/domain/Result.java @@ -0,0 +1,118 @@ +package com.muyu.common.core.domain; + +import com.muyu.common.core.constant.Constants; +import com.muyu.common.core.constant.HttpStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author muyu + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Tag(name = "公共返回值",description = "系统公共返回值,统一返回格式内容") +public class Result implements Serializable { + /** + * 成功 + */ + public static final int SUCCESS = Constants.SUCCESS; + /** + * 失败 + */ + public static final int FAIL = Constants.FAIL; + /** + * 警告 + */ + public static final int WARN = HttpStatus.WARN; + + private static final long serialVersionUID = 1L; + @Schema(defaultValue = "200",type = "Integer",description = "返回状态码200表示成功 其余表示异常 详细请查看每个接口") + private int code; + + @Schema(defaultValue = "操作成功",type = "String",description = "返回状态码的描述") + private String msg; + + @Schema(description = "返回数据") + private T data; + + public static Result success () { + return restResult(null, SUCCESS, null); + } + + public static Result success (T data) { + return restResult(data, SUCCESS, null); + } + + public static Result success (T data, String msg) { + return restResult(data, SUCCESS, msg); + } + + public static Result error () { + return restResult(null, FAIL, null); + } + + public static Result error (String msg) { + return restResult(null, FAIL, msg); + } + + public static Result error (T data) { + return restResult(data, FAIL, null); + } + + public static Result error (T data, String msg) { + return restResult(data, FAIL, msg); + } + + public static Result error (int code, String msg) { + return restResult(null, code, msg); + } + + + + public static Result warn () { + return restResult(null, WARN, null); + } + + public static Result warn (String msg) { + return restResult(null, WARN, msg); + } + + public static Result warn (T data) { + return restResult(data, WARN, null); + } + + public static Result warn (T data, String msg) { + return restResult(data, WARN, msg); + } + + public static Result warn (int code, String msg) { + return restResult(null, code, msg); + } + + private static Result restResult (T data, int code, String msg) { + return Result.builder() + .code(code) + .data(data) + .msg(msg) + .build(); + } + + public static Boolean isError (Result ret) { + return !isSuccess(ret); + } + + public static Boolean isSuccess (Result ret) { + return Result.SUCCESS == ret.getCode(); + } + +} diff --git a/src/main/java/com/muyu/common/core/enums/SysPayType.java b/src/main/java/com/muyu/common/core/enums/SysPayType.java new file mode 100644 index 0000000..96a6243 --- /dev/null +++ b/src/main/java/com/muyu/common/core/enums/SysPayType.java @@ -0,0 +1,44 @@ +package com.muyu.common.core.enums; + +import lombok.Getter; + +import java.util.Arrays; + +@Getter +public enum SysPayType { + + ALPAY("aliPay","支付宝"), + WECHATPAY("wechatPay","微信支付"), + JDPAY("jdPay","京东支付"); + + + + private final String code; + private final String info; + + SysPayType(String code,String info){ + this.code=code; + this.info=info; + } + + public static boolean isCode(String code){ + return Arrays.stream(values()) + .map(SysPayType::getCode) + .anyMatch(s->s.equals(code)); + } + + /** + * 通过code查询渠道商的名称 + * @param code + * @return 返回渠道商的名称 + */ + public static String getInfoByCode(String code){ + return Arrays.stream(values()) + .filter(s->s.getCode().equals(code)) + .findFirst() + .map(SysPayType::getInfo) + .orElseGet(()->"没有该渠道商"); + } + + +} diff --git a/src/main/java/com/muyu/common/core/enums/SystemYesNo.java b/src/main/java/com/muyu/common/core/enums/SystemYesNo.java new file mode 100644 index 0000000..c52e68b --- /dev/null +++ b/src/main/java/com/muyu/common/core/enums/SystemYesNo.java @@ -0,0 +1,27 @@ +package com.muyu.common.core.enums; + +import lombok.Getter; + +import java.util.Arrays; + +@Getter +public enum SystemYesNo { + + YES("Y","是"),NO("N","否"); + + private final String code; + private final String info; + + SystemYesNo(String code,String info){ + this.code=code; + this.info=info; + } + + public static boolean isCode(String code){ + return Arrays.stream(values()) + .map(SystemYesNo::getCode) + .anyMatch(s -> s.equals(code)); + } + + +} diff --git a/src/main/java/com/muyu/common/core/enums/UserStatus.java b/src/main/java/com/muyu/common/core/enums/UserStatus.java new file mode 100644 index 0000000..32ff39a --- /dev/null +++ b/src/main/java/com/muyu/common/core/enums/UserStatus.java @@ -0,0 +1,26 @@ +package com.muyu.common.core.enums; + +/** + * 用户状态 + * + * @author muyu + */ +public enum UserStatus { + OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除"); + + private final String code; + private final String info; + + UserStatus (String code, String info) { + this.code = code; + this.info = info; + } + + public String getCode () { + return code; + } + + public String getInfo () { + return info; + } +} diff --git a/src/main/java/com/muyu/common/core/exception/CaptchaException.java b/src/main/java/com/muyu/common/core/exception/CaptchaException.java new file mode 100644 index 0000000..eb32d0b --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/CaptchaException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception; + +/** + * 验证码错误异常类 + * + * @author muyu + */ +public class CaptchaException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public CaptchaException (String msg) { + super(msg); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/CheckedException.java b/src/main/java/com/muyu/common/core/exception/CheckedException.java new file mode 100644 index 0000000..4f12893 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/CheckedException.java @@ -0,0 +1,26 @@ +package com.muyu.common.core.exception; + +/** + * 检查异常 + * + * @author muyu + */ +public class CheckedException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public CheckedException (String message) { + super(message); + } + + public CheckedException (Throwable cause) { + super(cause); + } + + public CheckedException (String message, Throwable cause) { + super(message, cause); + } + + public CheckedException (String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/DemoModeException.java b/src/main/java/com/muyu/common/core/exception/DemoModeException.java new file mode 100644 index 0000000..82249cf --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/DemoModeException.java @@ -0,0 +1,13 @@ +package com.muyu.common.core.exception; + +/** + * 演示模式异常 + * + * @author muyu + */ +public class DemoModeException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public DemoModeException () { + } +} diff --git a/src/main/java/com/muyu/common/core/exception/GlobalException.java b/src/main/java/com/muyu/common/core/exception/GlobalException.java new file mode 100644 index 0000000..b14e03c --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/GlobalException.java @@ -0,0 +1,51 @@ +package com.muyu.common.core.exception; + +/** + * 全局异常 + * + * @author muyu + */ +public class GlobalException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + *

+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public GlobalException () { + } + + public GlobalException (String message) { + this.message = message; + } + + public String getDetailMessage () { + return detailMessage; + } + + public GlobalException setDetailMessage (String detailMessage) { + this.detailMessage = detailMessage; + return this; + } + + @Override + public String getMessage () { + return message; + } + + public GlobalException setMessage (String message) { + this.message = message; + return this; + } +} diff --git a/src/main/java/com/muyu/common/core/exception/InnerAuthException.java b/src/main/java/com/muyu/common/core/exception/InnerAuthException.java new file mode 100644 index 0000000..f211c7f --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/InnerAuthException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception; + +/** + * 内部认证异常 + * + * @author muyu + */ +public class InnerAuthException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public InnerAuthException (String message) { + super(message); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/PreAuthorizeException.java b/src/main/java/com/muyu/common/core/exception/PreAuthorizeException.java new file mode 100644 index 0000000..6cb8636 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/PreAuthorizeException.java @@ -0,0 +1,13 @@ +package com.muyu.common.core.exception; + +/** + * 权限异常 + * + * @author muyu + */ +public class PreAuthorizeException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public PreAuthorizeException () { + } +} diff --git a/src/main/java/com/muyu/common/core/exception/ServiceException.java b/src/main/java/com/muyu/common/core/exception/ServiceException.java new file mode 100644 index 0000000..5039bc0 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/ServiceException.java @@ -0,0 +1,65 @@ +package com.muyu.common.core.exception; + +/** + * 业务异常 + * + * @author muyu + */ +public final class ServiceException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + *

+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public ServiceException () { + } + + public ServiceException (String message) { + this.message = message; + } + + public ServiceException (String message, Integer code) { + this.message = message; + this.code = code; + } + + public String getDetailMessage () { + return detailMessage; + } + + public ServiceException setDetailMessage (String detailMessage) { + this.detailMessage = detailMessage; + return this; + } + + @Override + public String getMessage () { + return message; + } + + public ServiceException setMessage (String message) { + this.message = message; + return this; + } + + public Integer getCode () { + return code; + } +} diff --git a/src/main/java/com/muyu/common/core/exception/UtilException.java b/src/main/java/com/muyu/common/core/exception/UtilException.java new file mode 100644 index 0000000..8de4bbf --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/UtilException.java @@ -0,0 +1,22 @@ +package com.muyu.common.core.exception; + +/** + * 工具类异常 + * + * @author muyu + */ +public class UtilException extends RuntimeException { + private static final long serialVersionUID = 8247610319171014183L; + + public UtilException (Throwable e) { + super(e.getMessage(), e); + } + + public UtilException (String message) { + super(message); + } + + public UtilException (String message, Throwable throwable) { + super(message, throwable); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/auth/NotLoginException.java b/src/main/java/com/muyu/common/core/exception/auth/NotLoginException.java new file mode 100644 index 0000000..40293bf --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/auth/NotLoginException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception.auth; + +/** + * 未能通过的登录认证异常 + * + * @author muyu + */ +public class NotLoginException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public NotLoginException (String message) { + super(message); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/auth/NotPermissionException.java b/src/main/java/com/muyu/common/core/exception/auth/NotPermissionException.java new file mode 100644 index 0000000..e464840 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/auth/NotPermissionException.java @@ -0,0 +1,20 @@ +package com.muyu.common.core.exception.auth; + +import org.apache.commons.lang3.StringUtils; + +/** + * 未能通过的权限认证异常 + * + * @author muyu + */ +public class NotPermissionException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public NotPermissionException (String permission) { + super(permission); + } + + public NotPermissionException (String[] permissions) { + super(StringUtils.join(permissions, ",")); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/auth/NotRoleException.java b/src/main/java/com/muyu/common/core/exception/auth/NotRoleException.java new file mode 100644 index 0000000..53a1522 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/auth/NotRoleException.java @@ -0,0 +1,20 @@ +package com.muyu.common.core.exception.auth; + +import org.apache.commons.lang3.StringUtils; + +/** + * 未能通过的角色认证异常 + * + * @author muyu + */ +public class NotRoleException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public NotRoleException (String role) { + super(role); + } + + public NotRoleException (String[] roles) { + super(StringUtils.join(roles, ",")); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/base/BaseException.java b/src/main/java/com/muyu/common/core/exception/base/BaseException.java new file mode 100644 index 0000000..9bb1356 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/base/BaseException.java @@ -0,0 +1,69 @@ +package com.muyu.common.core.exception.base; + +/** + * 基础异常 + * + * @author muyu + */ +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); + } + + 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/muyu/common/core/exception/file/FileException.java b/src/main/java/com/muyu/common/core/exception/file/FileException.java new file mode 100644 index 0000000..ae2e184 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/file/FileException.java @@ -0,0 +1,17 @@ +package com.muyu.common.core.exception.file; + +import com.muyu.common.core.exception.base.BaseException; + +/** + * 文件信息异常类 + * + * @author muyu + */ +public class FileException extends BaseException { + private static final long serialVersionUID = 1L; + + public FileException (String code, Object[] args, String msg) { + super("file", code, args, msg); + } + +} diff --git a/src/main/java/com/muyu/common/core/exception/file/FileNameLengthLimitExceededException.java b/src/main/java/com/muyu/common/core/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000..3a85df3 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception.file; + +/** + * 文件名称超长限制异常类 + * + * @author muyu + */ +public class FileNameLengthLimitExceededException extends FileException { + private static final long serialVersionUID = 1L; + + public FileNameLengthLimitExceededException (int defaultFileNameLength) { + super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}, "the filename is too long"); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/file/FileSizeLimitExceededException.java b/src/main/java/com/muyu/common/core/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000..7570be5 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception.file; + +/** + * 文件名大小限制异常类 + * + * @author muyu + */ +public class FileSizeLimitExceededException extends FileException { + private static final long serialVersionUID = 1L; + + public FileSizeLimitExceededException (long defaultMaxSize) { + super("upload.exceed.maxSize", new Object[]{defaultMaxSize}, "the filesize is too large"); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/file/FileUploadException.java b/src/main/java/com/muyu/common/core/exception/file/FileUploadException.java new file mode 100644 index 0000000..94341ab --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/file/FileUploadException.java @@ -0,0 +1,52 @@ +package com.muyu.common.core.exception.file; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + * 文件上传异常类 + * + * @author muyu + */ +public class FileUploadException extends Exception { + + private static final long serialVersionUID = 1L; + + private final Throwable cause; + + public FileUploadException () { + this(null, null); + } + + public FileUploadException (final String msg) { + this(msg, null); + } + + public FileUploadException (String msg, Throwable cause) { + super(msg); + this.cause = cause; + } + + @Override + public void printStackTrace (PrintStream stream) { + super.printStackTrace(stream); + if (cause != null) { + stream.println("Caused by:"); + cause.printStackTrace(stream); + } + } + + @Override + public void printStackTrace (PrintWriter writer) { + super.printStackTrace(writer); + if (cause != null) { + writer.println("Caused by:"); + cause.printStackTrace(writer); + } + } + + @Override + public Throwable getCause () { + return cause; + } +} diff --git a/src/main/java/com/muyu/common/core/exception/file/InvalidExtensionException.java b/src/main/java/com/muyu/common/core/exception/file/InvalidExtensionException.java new file mode 100644 index 0000000..3a993c2 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/file/InvalidExtensionException.java @@ -0,0 +1,67 @@ +package com.muyu.common.core.exception.file; + +import java.util.Arrays; + +/** + * 文件上传 误异常类 + * + * @author muyu + */ +public class InvalidExtensionException extends FileUploadException { + private static final long serialVersionUID = 1L; + + private String[] allowedExtension; + private String extension; + private String filename; + + public InvalidExtensionException (String[] allowedExtension, String extension, String filename) { + super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]"); + this.allowedExtension = allowedExtension; + this.extension = extension; + this.filename = filename; + } + + public String[] getAllowedExtension () { + return allowedExtension; + } + + public String getExtension () { + return extension; + } + + public String getFilename () { + return filename; + } + + public static class InvalidImageExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidImageExtensionException (String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidFlashExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidFlashExtensionException (String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidMediaExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidMediaExtensionException (String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidVideoExtensionException extends InvalidExtensionException { + private static final long serialVersionUID = 1L; + + public InvalidVideoExtensionException (String[] allowedExtension, String extension, String filename) { + super(allowedExtension, extension, filename); + } + } +} diff --git a/src/main/java/com/muyu/common/core/exception/job/TaskException.java b/src/main/java/com/muyu/common/core/exception/job/TaskException.java new file mode 100644 index 0000000..aee364a --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/job/TaskException.java @@ -0,0 +1,29 @@ +package com.muyu.common.core.exception.job; + +/** + * 计划策略异常 + * + * @author muyu + */ +public class TaskException extends Exception { + private static final long serialVersionUID = 1L; + + private Code code; + + public TaskException (String msg, Code code) { + this(msg, code, null); + } + + public TaskException (String msg, Code code, Exception nestedEx) { + super(msg, nestedEx); + this.code = code; + } + + public Code getCode () { + return code; + } + + public enum Code { + TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE + } +} diff --git a/src/main/java/com/muyu/common/core/exception/user/CaptchaExpireException.java b/src/main/java/com/muyu/common/core/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000..a95a57b --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/user/CaptchaExpireException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception.user; + +/** + * 验证码失效异常类 + * + * @author muyu + */ +public class CaptchaExpireException extends UserException { + private static final long serialVersionUID = 1L; + + public CaptchaExpireException () { + super("user.jcaptcha.expire", null); + } +} diff --git a/src/main/java/com/muyu/common/core/exception/user/UserException.java b/src/main/java/com/muyu/common/core/exception/user/UserException.java new file mode 100644 index 0000000..f113749 --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/user/UserException.java @@ -0,0 +1,16 @@ +package com.muyu.common.core.exception.user; + +import com.muyu.common.core.exception.base.BaseException; + +/** + * 用户信息异常类 + * + * @author muyu + */ +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/muyu/common/core/exception/user/UserPasswordNotMatchException.java b/src/main/java/com/muyu/common/core/exception/user/UserPasswordNotMatchException.java new file mode 100644 index 0000000..7615cda --- /dev/null +++ b/src/main/java/com/muyu/common/core/exception/user/UserPasswordNotMatchException.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.exception.user; + +/** + * 用户密码不正确或不符合规范异常类 + * + * @author muyu + */ +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/muyu/common/core/feign/FeginConfig.java b/src/main/java/com/muyu/common/core/feign/FeginConfig.java new file mode 100644 index 0000000..77a12fe --- /dev/null +++ b/src/main/java/com/muyu/common/core/feign/FeginConfig.java @@ -0,0 +1,19 @@ +package com.muyu.common.core.feign; + +import feign.Contract; +import org.springframework.cloud.openfeign.support.SpringMvcContract; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FeginConfig { +// @Bean +// public Contract feignConfiguration() { +// return new feign.Contract.Default(); +// } + + @Bean + public Contract feignConfiguration() { + return new SpringMvcContract(); + } +} diff --git a/src/main/java/com/muyu/common/core/text/CharsetKit.java b/src/main/java/com/muyu/common/core/text/CharsetKit.java new file mode 100644 index 0000000..fe5e9fa --- /dev/null +++ b/src/main/java/com/muyu/common/core/text/CharsetKit.java @@ -0,0 +1,94 @@ +package com.muyu.common.core.text; + +import com.muyu.common.core.utils.StringUtils; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * 字符集工具类 + * + * @author muyu + */ +public class CharsetKit { + /** + * ISO-8859-1 + */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** + * UTF-8 + */ + public static final String UTF_8 = "UTF-8"; + /** + * GBK + */ + public static final String GBK = "GBK"; + + /** + * ISO-8859-1 + */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** + * UTF-8 + */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** + * GBK + */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * + * @return Charset + */ + public static Charset charset (String charset) { + return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * + * @return 转换后的字符集 + */ + public static String convert (String source, String srcCharset, String destCharset) { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * + * @return 转换后的字符集 + */ + public static String convert (String source, Charset srcCharset, Charset destCharset) { + if (null == srcCharset) { + srcCharset = StandardCharsets.ISO_8859_1; + } + + if (null == destCharset) { + destCharset = StandardCharsets.UTF_8; + } + + if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset () { + return Charset.defaultCharset().name(); + } +} diff --git a/src/main/java/com/muyu/common/core/text/Convert.java b/src/main/java/com/muyu/common/core/text/Convert.java new file mode 100644 index 0000000..fb57cb9 --- /dev/null +++ b/src/main/java/com/muyu/common/core/text/Convert.java @@ -0,0 +1,903 @@ +package com.muyu.common.core.text; + +import com.muyu.common.core.utils.StringUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; + +/** + * 类型转换器 + * + * @author muyu + */ +public class Convert { + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static String toStr (Object value, String defaultValue) { + if (null == value) { + return defaultValue; + } + if (value instanceof String) { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static String toStr (Object value) { + return toStr(value, null); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Character toChar (Object value, Character defaultValue) { + if (null == value) { + return defaultValue; + } + if (value instanceof Character) { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Character toChar (Object value) { + return toChar(value, null); + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Byte toByte (Object value, Byte defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Byte) { + return (Byte) value; + } + if (value instanceof Number) { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Byte.parseByte(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为byte
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Byte toByte (Object value) { + return toByte(value, null); + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Short toShort (Object value, Short defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Short) { + return (Short) value; + } + if (value instanceof Number) { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Short.parseShort(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Short
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Short toShort (Object value) { + return toShort(value, null); + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Number toNumber (Object value, Number defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Number) { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return NumberFormat.getInstance().parse(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Number
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Number toNumber (Object value) { + return toNumber(value, null); + } + + /** + * 转换为int
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Integer toInt (Object value, Integer defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Integer) { + return (Integer) value; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Integer.parseInt(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为int
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Integer toInt (Object value) { + return toInt(value, null); + } + + /** + * 转换为Integer数组
+ * + * @param str 被转换的值 + * + * @return 结果 + */ + public static Integer[] toIntArray (String str) { + return toIntArray(",", str); + } + + /** + * 转换为Long数组
+ * + * @param str 被转换的值 + * + * @return 结果 + */ + public static Long[] toLongArray (String str) { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * + * @return 结果 + */ + public static Integer[] toIntArray (String split, String str) { + if (StringUtils.isEmpty(str)) { + return new Integer[]{}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0 ; i < arr.length ; i++) { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * + * @return 结果 + */ + public static Long[] toLongArray (String split, String str) { + if (StringUtils.isEmpty(str)) { + return new Long[]{}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0 ; i < arr.length ; i++) { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组
+ * + * @param str 被转换的值 + * + * @return 结果 + */ + public static String[] toStrArray (String str) { + return toStrArray(",", str); + } + + /** + * 转换为String数组
+ * + * @param split 分隔符 + * @param str 被转换的值 + * + * @return 结果 + */ + public static String[] toStrArray (String split, String str) { + return str.split(split); + } + + /** + * 转换为long
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Long toLong (Object value, Long defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Long) { + return (Long) value; + } + if (value instanceof Number) { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为long
+ * 如果给定的值为null,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Long toLong (Object value) { + return toLong(value, null); + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Double toDouble (Object value, Double defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Double) { + return (Double) value; + } + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为double
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Double toDouble (Object value) { + return toDouble(value, null); + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Float toFloat (Object value, Float defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Float) { + return (Float) value; + } + if (value instanceof Number) { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Float.parseFloat(valueStr.trim()); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Float
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Float toFloat (Object value) { + return toFloat(value, null); + } + + /** + * 转换为boolean
+ * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static Boolean toBool (Object value, Boolean defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof Boolean) { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) { + case "true": + case "yes": + case "ok": + case "1": + return true; + case "false": + case "no": + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static Boolean toBool (Object value) { + return toBool(value, null); + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * + * @return Enum + */ + public static > E toEnum (Class clazz, Object value, E defaultValue) { + if (value == null) { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return Enum.valueOf(clazz, valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为Enum对象
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * + * @param clazz Enum的Class + * @param value 值 + * + * @return Enum + */ + public static > E toEnum (Class clazz, Object value) { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static BigInteger toBigInteger (Object value, BigInteger defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof BigInteger) { + return (BigInteger) value; + } + if (value instanceof Long) { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return new BigInteger(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为BigInteger
+ * 如果给定的值为空,或者转换失败,返回默认值null
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static BigInteger toBigInteger (Object value) { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * + * @return 结果 + */ + public static BigDecimal toBigDecimal (Object value, BigDecimal defaultValue) { + if (value == null) { + return defaultValue; + } + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + if (value instanceof Long) { + return new BigDecimal((Long) value); + } + if (value instanceof Double) { + return BigDecimal.valueOf((Double) value); + } + if (value instanceof Integer) { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) { + return defaultValue; + } + try { + return new BigDecimal(valueStr); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * 转换为BigDecimal
+ * 如果给定的值为空,或者转换失败,返回默认值
+ * 转换失败不会报错 + * + * @param value 被转换的值 + * + * @return 结果 + */ + public static BigDecimal toBigDecimal (Object value) { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * + * @return 字符串 + */ + public static String utf8Str (Object obj) { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * + * @return 字符串 + */ + public static String str (Object obj, String charsetName) { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串
+ * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * + * @return 字符串 + */ + public static String str (Object obj, Charset charset) { + if (null == obj) { + return null; + } + + if (obj instanceof String) { + return (String) obj; + } else if (obj instanceof byte[] || obj instanceof Byte[]) { + if (obj instanceof byte[]) { + return str((byte[]) obj, charset); + } else { + Byte[] bytes = (Byte[]) obj; + int length = bytes.length; + byte[] dest = new byte[length]; + for (int i = 0 ; i < length ; i++) { + dest[i] = bytes[i]; + } + return str(dest, charset); + } + } else if (obj instanceof ByteBuffer) { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * + * @return 字符串 + */ + public static String str (byte[] bytes, String charset) { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * + * @return 解码后的字符串 + */ + public static String str (byte[] data, Charset charset) { + if (data == null) { + return null; + } + + if (null == charset) { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * + * @return 字符串 + */ + public static String str (ByteBuffer data, String charset) { + if (data == null) { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * + * @return 字符串 + */ + public static String str (ByteBuffer data, Charset charset) { + if (null == charset) { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + + /** + * 半角转全角 + * + * @param input String. + * + * @return 全角字符串. + */ + public static String toSBC (String input) { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * + * @return 全角字符串. + */ + public static String toSBC (String input, Set notConvertSet) { + char[] c = input.toCharArray(); + for (int i = 0 ; i < c.length ; i++) { + if (null != notConvertSet && notConvertSet.contains(c[i])) { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') { + c[i] = '\u3000'; + } else if (c[i] < '\177') { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * + * @return 半角字符串 + */ + public static String toDBC (String input) { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * + * @return 替换后的字符 + */ + public static String toDBC (String text, Set notConvertSet) { + char[] c = text.toCharArray(); + for (int i = 0 ; i < c.length ; i++) { + if (null != notConvertSet && notConvertSet.contains(c[i])) { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') { + c[i] = ' '; + } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') { + c[i] = (char) (c[i] - 65248); + } + } + return new String(c); + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * + * @return 中文大写数字 + */ + public static String digitUppercase (double n) { + String[] fraction = {"角", "分"}; + String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; + String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}}; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0 ; i < fraction.length ; i++) { + // 优化double计算精度丢失问题 + BigDecimal nNum = new BigDecimal(n); + BigDecimal decimal = new BigDecimal(10); + BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN); + double d = scale.doubleValue(); + s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0 ; i < unit[0].length && integerPart > 0 ; i++) { + String p = ""; + for (int j = 0 ; j < unit[1].length && n > 0 ; j++) { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} diff --git a/src/main/java/com/muyu/common/core/text/StrFormatter.java b/src/main/java/com/muyu/common/core/text/StrFormatter.java new file mode 100644 index 0000000..0c07cf5 --- /dev/null +++ b/src/main/java/com/muyu/common/core/text/StrFormatter.java @@ -0,0 +1,77 @@ +package com.muyu.common.core.text; + +import com.muyu.common.core.utils.StringUtils; + +/** + * 字符串格式化 + * + * @author muyu + */ +public class StrFormatter { + public static final String EMPTY_JSON = "{}"; + public static final char C_BACKSLASH = '\\'; + public static final char C_DELIM_START = '{'; + public static final char C_DELIM_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 strPattern 字符串模板 + * @param argArray 参数列表 + * + * @return 结果 + */ + public static String format (final String strPattern, final Object... argArray) { + if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) { + return strPattern; + } + final int strPatternLength = strPattern.length(); + + // 初始化定义好的长度以获得更好的性能 + StringBuilder sbuf = new StringBuilder(strPatternLength + 50); + + int handledPosition = 0; + int delimIndex;// 占位符所在位置 + for (int argIndex = 0 ; argIndex < argArray.length ; argIndex++) { + delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); + if (delimIndex == -1) { + if (handledPosition == 0) { + return strPattern; + } else { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 + sbuf.append(strPattern, handledPosition, strPatternLength); + return sbuf.toString(); + } + } else { + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) { + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) { + // 转义符之前还有一个转义符,占位符依旧有效 + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } else { + // 占位符被转义 + argIndex--; + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(C_DELIM_START); + handledPosition = delimIndex + 1; + } + } else { + // 正常占位符 + sbuf.append(strPattern, handledPosition, delimIndex); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + } + } + // 加入最后一个占位符后所有的字符 + sbuf.append(strPattern, handledPosition, strPattern.length()); + + return sbuf.toString(); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/DateUtils.java b/src/main/java/com/muyu/common/core/utils/DateUtils.java new file mode 100644 index 0000000..fb15c59 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/DateUtils.java @@ -0,0 +1,158 @@ +package com.muyu.common.core.utils; + +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.*; +import java.util.Date; + +/** + * 时间工具类 + * + * @author muyu + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + public static String YYYY = "yyyy"; + + public static String YYYY_MM = "yyyy-MM"; + + public static String YYYY_MM_DD = "yyyy-MM-dd"; + + public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static String[] parsePatterns = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate () { + return new Date(); + } + + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate () { + return dateTimeNow(YYYY_MM_DD); + } + + public static final String getTime () { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static final String dateTimeNow () { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static final String dateTimeNow (final String format) { + return parseDateToStr(format, new Date()); + } + + public static final String dateTime (final Date date) { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static final String parseDateToStr (final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + public static final Date dateTime (final String format, final String ts) { + try { + return new SimpleDateFormat(format).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static final String datePath () { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static final String dateTime () { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate (Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), parsePatterns); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate () { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算时间差 + * + * @param endDate 最后时间 + * @param startTime 开始时间 + * + * @return 时间差(天/小时/分钟) + */ + public static String timeDistance (Date endDate, Date startTime) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - startTime.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } + + /** + * 增加 LocalDateTime ==> Date + */ + public static Date toDate (LocalDateTime temporalAccessor) { + ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 增加 LocalDate ==> Date + */ + public static Date toDate (LocalDate temporalAccessor) { + LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); + ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/ExceptionUtil.java b/src/main/java/com/muyu/common/core/utils/ExceptionUtil.java new file mode 100644 index 0000000..e6abdf9 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/ExceptionUtil.java @@ -0,0 +1,35 @@ +package com.muyu.common.core.utils; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 错误信息处理类。 + * + * @author muyu + */ +public class ExceptionUtil { + /** + * 获取exception的详细错误信息。 + */ + public static String getExceptionMessage (Throwable e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw, true)); + return sw.toString(); + } + + public static String getRootErrorMessage (Exception e) { + Throwable root = ExceptionUtils.getRootCause(e); + root = (root == null ? e : root); + if (root == null) { + return ""; + } + String msg = root.getMessage(); + if (msg == null) { + return "null"; + } + return StringUtils.defaultString(msg); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/JwtUtils.java b/src/main/java/com/muyu/common/core/utils/JwtUtils.java new file mode 100644 index 0000000..62816cb --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/JwtUtils.java @@ -0,0 +1,165 @@ +package com.muyu.common.core.utils; + +import com.muyu.common.core.constant.SecurityConstants; +import com.muyu.common.core.constant.TokenConstants; +import com.muyu.common.core.text.Convert; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.security.SecureDigestAlgorithm; + +import javax.crypto.SecretKey; +import java.util.Date; +import java.util.Map; + +/** + * Jwt工具类 + * + * @author muyu + */ +public class JwtUtils { + + /** + * 加密算法 + */ + private final static SecureDigestAlgorithm ALGORITHM = Jwts.SIG.HS256; + /** + * 私钥 / 生成签名的时候使用的秘钥secret,一般可以从本地配置文件中读取,切记这个秘钥不能外露,只在服务端使用,在任何场景都不应该流露出去。 + * 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。 + * 应该大于等于 256位(长度32及以上的字符串),并且是随机的字符串 + */ + private final static String secret = TokenConstants.SECRET; + /** + * 秘钥实例 + */ + public static final SecretKey KEY = Keys.hmacShaKeyFor(secret.getBytes()); + /** + * jwt签发者 + */ + private final static String JWT_ISS = "MUYU"; + /** + * jwt主题 + */ + private final static String SUBJECT = "Peripherals"; + + + /** + * 从数据声明生成令牌 + * + * @param claims 数据声明 + * + * @return 令牌 + */ + public static String createToken (Map claims) { + return Jwts.builder() + // 设置头部信息header + .header().add("typ", "JWT").add("alg", "HS256").and() + // 设置自定义负载信息payload + .claims(claims) + // 签发时间 + .issuedAt(new Date()) + // 主题 + .subject(SUBJECT) + // 签发者 + .issuer(JWT_ISS) + // 签名 + .signWith(KEY, ALGORITHM) + .compact(); + } + + /** + * 从令牌中获取数据声明 + * + * @param token 令牌 + * + * @return 数据声明 + */ + public static Claims parseToken (String token) { + return Jwts.parser() + .verifyWith(KEY) + .build() + .parseSignedClaims(token) + .getPayload(); + } + + /** + * 根据令牌获取用户标识 + * + * @param token 令牌 + * + * @return 用户ID + */ + public static String getUserKey (String token) { + Claims claims = parseToken(token); + return getValue(claims, SecurityConstants.USER_KEY); + } + + /** + * 根据令牌获取用户标识 + * + * @param claims 身份信息 + * + * @return 用户ID + */ + public static String getUserKey (Claims claims) { + return getValue(claims, SecurityConstants.USER_KEY); + } + + /** + * 根据令牌获取用户ID + * + * @param token 令牌 + * + * @return 用户ID + */ + public static String getUserId (String token) { + Claims claims = parseToken(token); + return getValue(claims, SecurityConstants.DETAILS_USER_ID); + } + + /** + * 根据身份信息获取用户ID + * + * @param claims 身份信息 + * + * @return 用户ID + */ + public static String getUserId (Claims claims) { + return getValue(claims, SecurityConstants.DETAILS_USER_ID); + } + + /** + * 根据令牌获取用户名 + * + * @param token 令牌 + * + * @return 用户名 + */ + public static String getUserName (String token) { + Claims claims = parseToken(token); + return getValue(claims, SecurityConstants.DETAILS_USERNAME); + } + + /** + * 根据身份信息获取用户名 + * + * @param claims 身份信息 + * + * @return 用户名 + */ + public static String getUserName (Claims claims) { + return getValue(claims, SecurityConstants.DETAILS_USERNAME); + } + + /** + * 根据身份信息获取键值 + * + * @param claims 身份信息 + * @param key 键 + * + * @return 值 + */ + public static String getValue (Claims claims, String key) { + return Convert.toStr(claims.get(key), ""); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/PageUtils.java b/src/main/java/com/muyu/common/core/utils/PageUtils.java new file mode 100644 index 0000000..d4b0554 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/PageUtils.java @@ -0,0 +1,32 @@ +package com.muyu.common.core.utils; + +import com.github.pagehelper.PageHelper; +import com.muyu.common.core.utils.sql.SqlUtil; +import com.muyu.common.core.web.page.PageDomain; +import com.muyu.common.core.web.page.TableSupport; + +/** + * 分页工具类 + * + * @author muyu + */ +public class PageUtils extends PageHelper { + /** + * 设置请求分页数据 + */ + public static void startPage () { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Integer pageNum = pageDomain.getPageNum(); + Integer pageSize = pageDomain.getPageSize(); + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + Boolean reasonable = pageDomain.getReasonable(); + PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable); + } + + /** + * 清理分页的线程变量 + */ + public static void clearPage () { + PageHelper.clearPage(); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/ServletUtils.java b/src/main/java/com/muyu/common/core/utils/ServletUtils.java new file mode 100644 index 0000000..9a50531 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/ServletUtils.java @@ -0,0 +1,289 @@ +package com.muyu.common.core.utils; + +import com.alibaba.fastjson2.JSON; +import com.muyu.common.core.constant.Constants; +import com.muyu.common.core.domain.Result; +import com.muyu.common.core.text.Convert; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import reactor.core.publisher.Mono; + + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 客户端工具类 + * + * @author muyu + */ +public class ServletUtils { + /** + * 获取String参数 + */ + public static String getParameter (String name) { + return getRequest().getParameter(name); + } + + /** + * 获取String参数 + */ + public static String getParameter (String name, String defaultValue) { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt (String name) { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt (String name, Integer defaultValue) { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool (String name) { + return Convert.toBool(getRequest().getParameter(name)); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool (String name, Boolean defaultValue) { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * + * @return Map + */ + public static Map getParams (ServletRequest request) { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * + * @return Map + */ + public static Map getParamMap (ServletRequest request) { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), ",")); + } + return params; + } + + /** + * 获取request + */ + public static HttpServletRequest getRequest () { + try { + return Objects.requireNonNull(getRequestAttributes()).getRequest(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取response + */ + public static HttpServletResponse getResponse () { + try { + return Objects.requireNonNull(getRequestAttributes()).getResponse(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取session + */ + public static HttpSession getSession () { + return Objects.requireNonNull(getRequest()).getSession(); + } + + public static ServletRequestAttributes getRequestAttributes () { + try { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } catch (Exception e) { + return null; + } + } + + public static String getHeader (HttpServletRequest request, String name) { + String value = request.getHeader(name); + if (StringUtils.isEmpty(value)) { + return StringUtils.EMPTY; + } + return urlDecode(value); + } + + public static Map getHeaders (HttpServletRequest request) { + Map map = new LinkedCaseInsensitiveMap<>(); + Enumeration enumeration = request.getHeaderNames(); + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + String key = enumeration.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + } + return map; + } + + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString (HttpServletResponse response, String string) { + try { + response.setStatus(200); + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 是否是Ajax异步请求 + * + * @param request + */ + public static boolean isAjaxRequest (HttpServletRequest request) { + String accept = request.getHeader("accept"); + if (accept != null && accept.contains("application/json")) { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) { + return true; + } + + String ajax = request.getParameter("__ajax"); + return StringUtils.inStringIgnoreCase(ajax, "json", "xml"); + } + + /** + * 内容编码 + * + * @param str 内容 + * + * @return 编码后的内容 + */ + public static String urlEncode (String str) { + try { + return URLEncoder.encode(str, Constants.UTF8); + } catch (UnsupportedEncodingException e) { + return StringUtils.EMPTY; + } + } + + /** + * 内容解码 + * + * @param str 内容 + * + * @return 解码后的内容 + */ + public static String urlDecode (String str) { + return URLDecoder.decode(str, StandardCharsets.UTF_8); + } + + /** + * 设置webflux模型响应 + * + * @param response ServerHttpResponse + * @param value 响应内容 + * + * @return Mono + */ + public static Mono webFluxResponseWriter (ServerHttpResponse response, Object value) { + return webFluxResponseWriter(response, HttpStatus.OK, value, Result.FAIL); + } + + /** + * 设置webflux模型响应 + * + * @param response ServerHttpResponse + * @param code 响应状态码 + * @param value 响应内容 + * + * @return Mono + */ + public static Mono webFluxResponseWriter (ServerHttpResponse response, Object value, int code) { + return webFluxResponseWriter(response, HttpStatus.OK, value, code); + } + + /** + * 设置webflux模型响应 + * + * @param response ServerHttpResponse + * @param status http状态码 + * @param code 响应状态码 + * @param value 响应内容 + * + * @return Mono + */ + public static Mono webFluxResponseWriter (ServerHttpResponse response, HttpStatus status, Object value, int code) { + return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code); + } + + /** + * 设置webflux模型响应 + * + * @param response ServerHttpResponse + * @param contentType content-type + * @param status http状态码 + * @param code 响应状态码 + * @param value 响应内容 + * + * @return Mono + */ + public static Mono webFluxResponseWriter (ServerHttpResponse response, String contentType, HttpStatus status, Object value, int code) { + response.setStatusCode(status); + response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType); + Result result = Result.error(code, value.toString()); + DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes()); + return response.writeWith(Mono.just(dataBuffer)); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/SpringUtils.java b/src/main/java/com/muyu/common/core/utils/SpringUtils.java new file mode 100644 index 0000000..c37a65c --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/SpringUtils.java @@ -0,0 +1,114 @@ +package com.muyu.common.core.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.stereotype.Component; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author muyu + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor { + /** + * Spring应用上下文环境 + */ + private static ConfigurableListableBeanFactory beanFactory; + + /** + * 获取对象 + * + * @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(); + } + + @Override + public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException { + SpringUtils.beanFactory = beanFactory; + } +} diff --git a/src/main/java/com/muyu/common/core/utils/StringUtils.java b/src/main/java/com/muyu/common/core/utils/StringUtils.java new file mode 100644 index 0000000..ec8f557 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/StringUtils.java @@ -0,0 +1,504 @@ +package com.muyu.common.core.utils; + +import com.muyu.common.core.constant.Constants; +import com.muyu.common.core.text.StrFormatter; +import org.springframework.util.AntPathMatcher; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 字符串工具类 + * + * @author muyu + */ +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); + } + + /** + * 判断是否为空,并且不是空白字符 + * + * @param str 要判断的value + * + * @return 结果 + */ + public static boolean hasText (String str) { + return (str != null && !str.isEmpty() && containsText(str)); + } + + private static boolean containsText (CharSequence str) { + int strLen = str.length(); + for (int i = 0 ; i < strLen ; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用: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); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * + * @return 结果 + */ + public static boolean ishttp (String link) { + return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS); + } + + /** + * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value + * + * @param collection 给定的集合 + * @param array 给定的数组 + * + * @return boolean 结果 + */ + public static boolean containsAny (Collection collection, String... array) { + if (isEmpty(collection) || isEmpty(array)) { + return false; + } else { + for (String str : array) { + if (collection.contains(str)) { + return true; + } + } + return false; + } + } + + /** + * 驼峰转下划线命名 + */ + 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; + } + if (s.indexOf(SEPARATOR) == -1) { + return s; + } + 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 str 指定字符串 + * @param strs 需要检查的字符串数组 + * + * @return 是否匹配 + */ + public static boolean matches (String str, List strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * + * @return + */ + public static boolean isMatch (String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast (Object obj) { + return (T) obj; + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static final String padl (final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static final String padl (final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + for (int i = size - len ; i > 0 ; i--) { + sb.append(c); + } + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + for (int i = size ; i > 0 ; i--) { + sb.append(c); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/bean/BeanUtils.java b/src/main/java/com/muyu/common/core/utils/bean/BeanUtils.java new file mode 100644 index 0000000..d44b351 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/bean/BeanUtils.java @@ -0,0 +1,107 @@ +package com.muyu.common.core.utils.bean; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Bean 工具类 + * + * @author muyu + */ +public class BeanUtils extends org.springframework.beans.BeanUtils { + /** + * Bean方法名中属性名开始的下标 + */ + private static final int BEAN_METHOD_PROP_INDEX = 3; + + /** + * 匹配getter方法的正则表达式 + */ + private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)"); + + /** + * 匹配setter方法的正则表达式 + */ + private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)"); + + /** + * Bean属性复制工具方法。 + * + * @param dest 目标对象 + * @param src 源对象 + */ + public static void copyBeanProp (Object dest, Object src) { + try { + copyProperties(src, dest); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取对象的setter方法。 + * + * @param obj 对象 + * + * @return 对象的setter方法列表 + */ + public static List getSetterMethods (Object obj) { + // setter方法列表 + List setterMethods = new ArrayList(); + + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + + // 查找setter方法 + + for (Method method : methods) { + Matcher m = SET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 1)) { + setterMethods.add(method); + } + } + // 返回setter方法列表 + return setterMethods; + } + + /** + * 获取对象的getter方法。 + * + * @param obj 对象 + * + * @return 对象的getter方法列表 + */ + + public static List getGetterMethods (Object obj) { + // getter方法列表 + List getterMethods = new ArrayList(); + // 获取所有方法 + Method[] methods = obj.getClass().getMethods(); + // 查找getter方法 + for (Method method : methods) { + Matcher m = GET_PATTERN.matcher(method.getName()); + if (m.matches() && (method.getParameterTypes().length == 0)) { + getterMethods.add(method); + } + } + // 返回getter方法列表 + return getterMethods; + } + + /** + * 检查Bean方法名中的属性名是否相等。
+ * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。 + * + * @param m1 方法名1 + * @param m2 方法名2 + * + * @return 属性名一样返回true,否则返回false + */ + + public static boolean isMethodPropEquals (String m1, String m2) { + return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX)); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/bean/BeanValidators.java b/src/main/java/com/muyu/common/core/utils/bean/BeanValidators.java new file mode 100644 index 0000000..b904747 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/bean/BeanValidators.java @@ -0,0 +1,22 @@ +package com.muyu.common.core.utils.bean; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; + +import java.util.Set; + +/** + * bean对象属性验证 + * + * @author muyu + */ +public class BeanValidators { + public static void validateWithException (Validator validator, Object object, Class... groups) + throws ConstraintViolationException { + Set> constraintViolations = validator.validate(object, groups); + if (!constraintViolations.isEmpty()) { + throw new ConstraintViolationException(constraintViolations); + } + } +} diff --git a/src/main/java/com/muyu/common/core/utils/file/FileTypeUtils.java b/src/main/java/com/muyu/common/core/utils/file/FileTypeUtils.java new file mode 100644 index 0000000..dde7e85 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/file/FileTypeUtils.java @@ -0,0 +1,85 @@ +package com.muyu.common.core.utils.file; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.util.Objects; + +/** + * 文件类型工具类 + * + * @author muyu + */ +public class FileTypeUtils { + /** + * 获取文件类型 + *

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

+ * 例如: muyu.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(); + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * + * @return 后缀名 + */ + public static final String getExtension (MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (StringUtils.isEmpty(extension)) { + extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); + } + return extension; + } + + /** + * 获取文件类型 + * + * @param photoByte 文件字节码 + * + * @return 后缀(不含".") + */ + public static String getFileExtendName (byte[] photoByte) { + String strFileExtendName = "JPG"; + if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) + && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { + strFileExtendName = "GIF"; + } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { + strFileExtendName = "JPG"; + } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { + strFileExtendName = "BMP"; + } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { + strFileExtendName = "PNG"; + } + return strFileExtendName; + } +} diff --git a/src/main/java/com/muyu/common/core/utils/file/FileUtils.java b/src/main/java/com/muyu/common/core/utils/file/FileUtils.java new file mode 100644 index 0000000..5766365 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/file/FileUtils.java @@ -0,0 +1,223 @@ +package com.muyu.common.core.utils.file; + +import com.muyu.common.core.utils.StringUtils; +import org.apache.commons.lang3.ArrayUtils; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * 文件处理工具类 + * + * @author muyu + */ +public class FileUtils { + /** + * 字符常量:斜杠 {@code '/'} + */ + public static final char SLASH = '/'; + + /** + * 字符常量:反斜杠 {@code '\\'} + */ + public static final char BACKSLASH = '\\'; + + 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) { + e1.printStackTrace(); + } + } + if (fis != null) { + try { + fis.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + } + + /** + * 删除文件 + * + * @param filePath 文件 + * + * @return + */ + public static boolean deleteFile (String filePath) { + boolean flag = false; + File file = new File(filePath); + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + flag = file.delete(); + } + 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; + } + // 判断是否在允许下载的文件规则内 + return ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)); + } + + /** + * 下载文件名重新编码 + * + * @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 filePath 文件 + * + * @return 文件名 + */ + public static String getName (String filePath) { + if (null == filePath) { + return null; + } + int len = filePath.length(); + if (0 == len) { + return filePath; + } + if (isFileSeparator(filePath.charAt(len - 1))) { + // 以分隔符结尾的去掉结尾分隔符 + len--; + } + + int begin = 0; + char c; + for (int i = len - 1 ; i > -1 ; i--) { + c = filePath.charAt(i); + if (isFileSeparator(c)) { + // 查找最后一个路径分隔符(/或者\) + begin = i + 1; + break; + } + } + + return filePath.substring(begin, len); + } + + /** + * 是否为Windows或者Linux(Unix)文件分隔符
+ * Windows平台下分隔符为\,Linux(Unix)为/ + * + * @param c 字符 + * + * @return 是否为Windows或者Linux(Unix)文件分隔符 + */ + public static boolean isFileSeparator (char c) { + return SLASH == c || BACKSLASH == c; + } + + /** + * 下载文件名重新编码 + * + * @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()); + response.setHeader("download-filename", percentEncodedFileName); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * + * @return 百分号编码后的字符串 + */ + public static String percentEncode (String s) throws UnsupportedEncodingException { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); + return encode.replaceAll("\\+", "%20"); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/file/ImageUtils.java b/src/main/java/com/muyu/common/core/utils/file/ImageUtils.java new file mode 100644 index 0000000..7e23345 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/file/ImageUtils.java @@ -0,0 +1,69 @@ +package com.muyu.common.core.utils.file; + +import org.apache.poi.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; + +/** + * 图片处理工具类 + * + * @author muyu + */ +public class ImageUtils { + private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); + + public static byte[] getImage (String imagePath) { + InputStream is = getFile(imagePath); + try { + return IOUtils.toByteArray(is); + } catch (Exception e) { + log.error("图片加载异常 {}", e); + return null; + } finally { + IOUtils.closeQuietly(is); + } + } + + public static InputStream getFile (String imagePath) { + try { + byte[] result = readFile(imagePath); + result = Arrays.copyOf(result, result.length); + return new ByteArrayInputStream(result); + } catch (Exception e) { + log.error("获取图片异常 {}", e); + } + return null; + } + + /** + * 读取文件为字节数据 + * + * @param url 地址 + * + * @return 字节数据 + */ + public static byte[] readFile (String url) { + InputStream in = null; + try { + // 网络地址 + URL urlObj = new URL(url); + URLConnection urlConnection = urlObj.openConnection(); + urlConnection.setConnectTimeout(30 * 1000); + urlConnection.setReadTimeout(60 * 1000); + urlConnection.setDoInput(true); + in = urlConnection.getInputStream(); + return IOUtils.toByteArray(in); + } catch (Exception e) { + log.error("访问文件异常 {}", e); + return null; + } finally { + IOUtils.closeQuietly(in); + } + } +} diff --git a/src/main/java/com/muyu/common/core/utils/file/MimeTypeUtils.java b/src/main/java/com/muyu/common/core/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000..9eb1d84 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/file/MimeTypeUtils.java @@ -0,0 +1,56 @@ +package com.muyu.common.core.utils.file; + +/** + * 媒体类型工具类 + * + * @author muyu + */ +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[] VIDEO_EXTENSION = {"mp4", "avi", "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", + // 视频格式 + "mp4", "avi", "rmvb", + // 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/muyu/common/core/utils/html/EscapeUtil.java b/src/main/java/com/muyu/common/core/utils/html/EscapeUtil.java new file mode 100644 index 0000000..7dba9be --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/html/EscapeUtil.java @@ -0,0 +1,145 @@ +package com.muyu.common.core.utils.html; + +import com.muyu.common.core.utils.StringUtils; + +/** + * 转义和反转义工具类 + * + * @author muyu + */ +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) { + if (StringUtils.isEmpty(text)) { + return StringUtils.EMPTY; + } + + final StringBuilder tmp = new StringBuilder(text.length() * 6); + char c; + for (int i = 0 ; i < text.length() ; i++) { + c = text.charAt(i); + if (c < 256) { + tmp.append("%"); + if (c < 16) { + tmp.append("0"); + } + tmp.append(Integer.toString(c, 16)); + } else { + tmp.append("%u"); + if (c <= 0xfff) { + // issue#I49JU8@Gitee + tmp.append("0"); + } + tmp.append(Integer.toString(c, 16)); + } + } + return tmp.toString(); + } + + /** + * Escape解码 + * + * @param content 被转义的内容 + * + * @return 解码后的字符串 + */ + public static String decode (String content) { + if (StringUtils.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(); + } + + public static void main (String[] args) { + String html = ""; + String escape = EscapeUtil.escape(html); + // String html = "ipt>alert(\"XSS\")ipt>"; + // String html = "<123"; + // String html = "123>"; + System.out.println("clean: " + EscapeUtil.clean(html)); + System.out.println("escape: " + escape); + System.out.println("unescape: " + EscapeUtil.unescape(escape)); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/html/HTMLFilter.java b/src/main/java/com/muyu/common/core/utils/html/HTMLFilter.java new file mode 100644 index 0000000..68221f3 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/html/HTMLFilter.java @@ -0,0 +1,498 @@ +package com.muyu.common.core.utils.html; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * HTML过滤器,用于去除XSS漏洞隐患。 + * + * @author muyu + */ +public final class HTMLFilter { + /** + * regex flag union representing /si modifiers in php + **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("\""); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>(); + + /** + * set of allowed html elements, along with allowed attributes for each element + **/ + private final Map> vAllowed; + /** + * counts of open tags for each (allowable) html element + **/ + private final Map vTagCounts = new HashMap<>(); + + /** + * html elements which must always be self-closing (e.g. "") + **/ + private final String[] vSelfClosingTags; + /** + * html elements which must always have separate opening and closing tags (e.g. "") + **/ + private final String[] vNeedClosingTags; + /** + * set of disallowed html elements + **/ + private final String[] vDisallowed; + /** + * attributes which should be checked for valid protocols + **/ + private final String[] vProtocolAtts; + /** + * allowed protocols + **/ + private final String[] vAllowedProtocols; + /** + * tags which should be removed if they contain no content (e.g. "" or "") + **/ + private final String[] vRemoveBlanks; + /** + * entities allowed within html markup + **/ + private final String[] vAllowedEntities; + /** + * flag determining whether comments are allowed in input String. + */ + private final boolean stripComment; + private final boolean encodeQuotes; + /** + * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "" + * becomes " text "). If set to false, unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** + * Default constructor. + */ + public HTMLFilter () { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList<>(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList<>(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList<>(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = false; + } + + /** + * Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + @SuppressWarnings("unchecked") + public HTMLFilter (final Map conf) { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + // --------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr (final int decimal) { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars (final String s) { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + private static String regexReplace (final Pattern regex_pattern, final String replacement, final String s) { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + // --------------------------------------------------------------- + + private static boolean inArray (final String s, final String[] array) { + for (String item : array) { + if (item != null && item.equals(s)) { + return true; + } + } + return false; + } + + private void reset () { + vTagCounts.clear(); + } + + /** + * given a user submitted input String, filter out any invalid or restricted html. + * + * @param input text (i.e. submitted by a user) than may contain html + * + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter (final String input) { + reset(); + String s = input; + + s = escapeComments(s); + + s = balanceHTML(s); + + s = checkTags(s); + + s = processRemoveBlanks(s); + + // s = validateEntities(s); + + return s; + } + + public boolean isAlwaysMakeTags () { + return alwaysMakeTags; + } + + public boolean isStripComments () { + return stripComment; + } + + private String escapeComments (final String s) { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) { + final String match = m.group(1); // (.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML (String s) { + if (alwaysMakeTags) { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + // 不追加结束标签 + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } else { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags (String s) { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + final StringBuilder sBuilder = new StringBuilder(buf.toString()); + for (String key : vTagCounts.keySet()) { + for (int ii = 0 ; ii < vTagCounts.get(key) ; ii++) { + sBuilder.append(""); + } + } + s = sBuilder.toString(); + + return s; + } + + private String processRemoveBlanks (final String s) { + String result = s; + for (String tag : vRemoveBlanks) { + if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) { + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) { + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private String processTag (final String s) { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) { + if (!inArray(name, vSelfClosingTags)) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) { + final StringBuilder params = new StringBuilder(); + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList<>(); + final List paramValues = new ArrayList<>(); + while (m2.find()) { + paramNames.add(m2.group(1)); // ([a-z0-9]+) + paramValues.add(m2.group(3)); // (.*?) + } + while (m3.find()) { + paramNames.add(m3.group(1)); // ([a-z0-9]+) + paramValues.add(m3.group(3)); // ([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0 ; ii < paramNames.size() ; ii++) { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + + // debug( "paramName='" + paramName + "'" ); + // debug( "paramValue='" + paramValue + "'" ); + // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) { + if (inArray(paramName, vProtocolAtts)) { + paramValue = processParamProtocol(paramValue); + } + params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\""); + } + } + + if (inArray(name, vSelfClosingTags)) { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) { + ending = ""; + } + + if (ending == null || ending.length() < 1) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } else { + vTagCounts.put(name, 1); + } + } else { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } else { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol (String s) { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1); + if (s.startsWith("#//")) { + s = "#" + s.substring(3); + } + } + } + + return s; + } + + private String decodeEntities (String s) { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities (final String s) { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) { + final String one = m.group(1); // ([^&;]*) + final String two = m.group(2); // (?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes (final String s) { + if (encodeQuotes) { + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) { + final String one = m.group(1); // (>|^) + final String two = m.group(2); // ([^<]+?) + final String three = m.group(3); // (<|$) + // 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two) + m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three)); + } + m.appendTail(buf); + return buf.toString(); + } else { + return s; + } + } + + private String checkEntity (final String preamble, final String term) { + + return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble; + } + + private boolean isValidEntity (final String entity) { + return inArray(entity, vAllowedEntities); + } + + private boolean allowed (final String name) { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute (final String name, final String paramName) { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/ip/IpUtils.java b/src/main/java/com/muyu/common/core/utils/ip/IpUtils.java new file mode 100644 index 0000000..e750583 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/ip/IpUtils.java @@ -0,0 +1,331 @@ +package com.muyu.common.core.utils.ip; + +import com.muyu.common.core.utils.ServletUtils; +import com.muyu.common.core.utils.StringUtils; + +import jakarta.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * 获取IP方法 + * + * @author muyu + */ +public class IpUtils { + public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)"; + // 匹配 ip + public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")"; + // 匹配网段 + public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")"; + public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))"; + + /** + * 获取客户端IP + * + * @return IP地址 + */ + public static String getIpAddr () { + return getIpAddr(ServletUtils.getRequest()); + } + + /** + * 获取客户端IP + * + * @param request 请求对象 + * + * @return IP地址 + */ + public static String getIpAddr (HttpServletRequest request) { + if (request == null) { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param ip IP地址 + * + * @return 结果 + */ + public static boolean internalIp (String ip) { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + /** + * 检查是否为内部IP地址 + * + * @param addr byte地址 + * + * @return 结果 + */ + private static boolean internalIp (byte[] addr) { + if (StringUtils.isNull(addr) || addr.length < 2) { + return true; + } + final byte b0 = addr[0]; + final byte b1 = addr[1]; + // 10.x.x.x/8 + final byte SECTION_1 = 0x0A; + // 172.16.x.x/12 + final byte SECTION_2 = (byte) 0xAC; + final byte SECTION_3 = (byte) 0x10; + final byte SECTION_4 = (byte) 0x1F; + // 192.168.x.x/16 + final byte SECTION_5 = (byte) 0xC0; + final byte SECTION_6 = (byte) 0xA8; + switch (b0) { + case SECTION_1: + return true; + case SECTION_2: + if (b1 >= SECTION_3 && b1 <= SECTION_4) { + return true; + } + case SECTION_5: + switch (b1) { + case SECTION_6: + return true; + } + default: + return false; + } + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4 (String text) { + if (text.length() == 0) { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try { + long l; + int i; + switch (elements.length) { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2 ; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4 ; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } catch (NumberFormatException e) { + return null; + } + return bytes; + } + + /** + * 获取IP地址 + * + * @return 本地IP地址 + */ + public static String getHostIp () { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + } + return "127.0.0.1"; + } + + /** + * 获取主机名 + * + * @return 本地主机名 + */ + public static String getHostName () { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + } + return "未知"; + } + + /** + * 从多级反向代理中获得第一个非unknown IP地址 + * + * @param ip 获得的IP地址 + * + * @return 第一个非unknown IP地址 + */ + public static String getMultistageReverseProxyIp (String ip) { + // 多级反向代理检测 + if (ip != null && ip.indexOf(",") > 0) { + final String[] ips = ip.trim().split(","); + for (String subIp : ips) { + if (false == isUnknown(subIp)) { + ip = subIp; + break; + } + } + } + return StringUtils.substring(ip, 0, 255); + } + + /** + * 检测给定字符串是否为未知,多用于检测HTTP请求相关 + * + * @param checkString 被检测的字符串 + * + * @return 是否未知 + */ + public static boolean isUnknown (String checkString) { + return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); + } + + /** + * 是否为IP + */ + public static boolean isIP (String ip) { + return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP); + } + + /** + * 是否为IP,或 *为间隔的通配符地址 + */ + public static boolean isIpWildCard (String ip) { + return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD); + } + + /** + * 检测参数是否在ip通配符里 + */ + public static boolean ipIsInWildCardNoCheck (String ipWildCard, String ip) { + String[] s1 = ipWildCard.split("\\."); + String[] s2 = ip.split("\\."); + boolean isMatchedSeg = true; + for (int i = 0 ; i < s1.length && !s1[i].equals("*") ; i++) { + if (!s1[i].equals(s2[i])) { + isMatchedSeg = false; + break; + } + } + return isMatchedSeg; + } + + /** + * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串 + */ + public static boolean isIPSegment (String ipSeg) { + return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG); + } + + /** + * 判断ip是否在指定网段中 + */ + public static boolean ipIsInNetNoCheck (String iparea, String ip) { + int idx = iparea.indexOf('-'); + String[] sips = iparea.substring(0, idx).split("\\."); + String[] sipe = iparea.substring(idx + 1).split("\\."); + String[] sipt = ip.split("\\."); + long ips = 0L, ipe = 0L, ipt = 0L; + for (int i = 0 ; i < 4 ; ++i) { + ips = ips << 8 | Integer.parseInt(sips[i]); + ipe = ipe << 8 | Integer.parseInt(sipe[i]); + ipt = ipt << 8 | Integer.parseInt(sipt[i]); + } + if (ips > ipe) { + long t = ips; + ips = ipe; + ipe = t; + } + return ips <= ipt && ipt <= ipe; + } + + /** + * 校验ip是否符合过滤串规则 + * + * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99` + * @param ip 校验IP地址 + * + * @return boolean 结果 + */ + public static boolean isMatchedIp (String filter, String ip) { + if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip)) { + return false; + } + String[] ips = filter.split(";"); + for (String iStr : ips) { + if (isIP(iStr) && iStr.equals(ip)) { + return true; + } else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip)) { + return true; + } else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.java b/src/main/java/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.java new file mode 100644 index 0000000..e2041fc --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.java @@ -0,0 +1,23 @@ +package com.muyu.common.core.utils.poi; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * Excel数据格式处理适配器 + * + * @author muyu + */ +public interface ExcelHandlerAdapter { + /** + * 格式化 + * + * @param value 单元格数据值 + * @param args excel注解args参数组 + * @param cell 单元格对象 + * @param wb 工作簿对象 + * + * @return 处理后的值 + */ + Object format (Object value, String[] args, Cell cell, Workbook wb); +} diff --git a/src/main/java/com/muyu/common/core/utils/poi/ExcelUtil.java b/src/main/java/com/muyu/common/core/utils/poi/ExcelUtil.java new file mode 100644 index 0000000..16f2c39 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/poi/ExcelUtil.java @@ -0,0 +1,1230 @@ +package com.muyu.common.core.utils.poi; + +import com.muyu.common.core.annotation.Excel; +import com.muyu.common.core.annotation.Excel.ColumnType; +import com.muyu.common.core.annotation.Excel.Type; +import com.muyu.common.core.annotation.Excels; +import com.muyu.common.core.exception.UtilException; +import com.muyu.common.core.text.Convert; +import com.muyu.common.core.utils.DateUtils; +import com.muyu.common.core.utils.StringUtils; +import com.muyu.common.core.utils.file.FileTypeUtils; +import com.muyu.common.core.utils.file.ImageUtils; +import com.muyu.common.core.utils.reflect.ReflectUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.RegExUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Excel相关处理 + * + * @author muyu + */ +public class ExcelUtil { + public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; + public static final String[] FORMULA_STR = {"=", "-", "+", "@"}; + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + /** + * 实体对象 + */ + public Class clazz; + /** + * 需要排除列属性 + */ + public String[] excludeFields; + /** + * 工作表名称 + */ + private String sheetName; + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + /** + * 工作薄对象 + */ + private Workbook wb; + /** + * 工作表对象 + */ + private Sheet sheet; + /** + * 样式列表 + */ + private Map styles; + /** + * 导入导出数据列表 + */ + private List list; + /** + * 注解列表 + */ + private List fields; + /** + * 当前行号 + */ + private int rownum; + /** + * 标题 + */ + private String title; + /** + * 最大高度 + */ + private short maxHeight; + /** + * 合并后最后行数 + */ + private int subMergedLastRowNum = 0; + /** + * 合并后开始行数 + */ + private int subMergedFirstRowNum = 1; + /** + * 对象的子列表方法 + */ + private Method subMethod; + /** + * 对象的子列表属性 + */ + private List subFields; + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + public ExcelUtil (Class clazz) { + this.clazz = clazz; + } + + /** + * 获取画布 + */ + public static Drawing getDrawingPatriarch (Sheet sheet) { + if (sheet.getDrawingPatriarch() == null) { + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } + + /** + * 解析导出值 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(propertyValue, separator)) { + 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(propertyValue, separator)) { + 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); + } + + /** + * 隐藏Excel中列属性 + * + * @param fields 列属性名 示例[单个"name"/多个"id","name"] + * + * @throws Exception + */ + public void hideColumn (String... fields) { + this.excludeFields = fields; + } + + public void init (List list, String sheetName, String title, Type type) { + if (list == null) { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + this.title = title; + createExcelField(); + createWorkbook(); + createTitle(); + createSubHead(); + } + + /** + * 创建excel第一行标题 + */ + public void createTitle () { + if (StringUtils.isNotEmpty(title)) { + subMergedFirstRowNum++; + subMergedLastRowNum++; + int titleLastCol = this.fields.size() - 1; + if (isSubList()) { + titleLastCol = titleLastCol + subFields.size() - 1; + } + Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); + titleRow.setHeightInPoints(30); + Cell titleCell = titleRow.createCell(0); + titleCell.setCellStyle(styles.get("title")); + titleCell.setCellValue(title); + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); + } + } + + /** + * 创建对象的子列表名称 + */ + public void createSubHead () { + if (isSubList()) { + subMergedFirstRowNum++; + subMergedLastRowNum++; + Row subRow = sheet.createRow(rownum); + int excelNum = 0; + for (Object[] objects : fields) { + Excel attr = (Excel) objects[1]; + Cell headCell1 = subRow.createCell(excelNum); + headCell1.setCellValue(attr.name()); + headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + excelNum++; + } + int headFirstRow = excelNum - 1; + int headLastRow = headFirstRow + subFields.size() - 1; + if (headLastRow > headFirstRow) { + sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); + } + rownum++; + } + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * + * @return 转换后集合 + */ + public List importExcel (InputStream is) { + List list = null; + try { + list = importExcel(is, 0); + } catch (Exception e) { + log.error("导入Excel异常{}", e.getMessage()); + throw new UtilException(e.getMessage()); + } finally { + IOUtils.closeQuietly(is); + } + return list; + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @param titleNum 标题占用行数 + * + * @return 转换后集合 + */ + public List importExcel (InputStream is, int titleNum) throws Exception { + return importExcel(StringUtils.EMPTY, is, titleNum); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param titleNum 标题占用行数 + * @param is 输入流 + * + * @return 转换后集合 + */ + public List importExcel (String sheetName, InputStream is, int titleNum) throws Exception { + this.type = Type.IMPORT; + this.wb = WorkbookFactory.create(is); + List list = new ArrayList(); + // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet + Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); + if (sheet == null) { + throw new IOException("文件sheet不存在"); + } + + // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 + int rows = sheet.getLastRowNum(); + if (rows > 0) { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(titleNum); + 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. + List fields = this.getFields(); + Map fieldsMap = new HashMap(); + for (Object[] objects : fields) { + Excel attr = (Excel) objects[1]; + Integer column = cellMap.get(attr.name()); + if (column != null) { + fieldsMap.put(column, objects); + } + } + for (int i = titleNum + 1 ; i <= rows ; i++) { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + // 判断当前行是否是空行 + if (isRowEmpty(row)) { + continue; + } + 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 = (Field) entry.getValue()[0]; + Excel attr = (Excel) entry.getValue()[1]; + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) { + val = StringUtils.substringBefore(s, ".0"); + } else { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) { + val = parseDateToStr(dateFormat, val); + } 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) && StringUtils.isNumeric(Convert.toStr(val))) { + 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 = DateUtils.parseDate(val); + } 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)) { + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) { + propertyName = field.getName() + "." + attr.targetAttr(); + } + if (StringUtils.isNotEmpty(attr.readConverterExp())) { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { + val = dataFormatHandlerAdapter(val, attr, null); + } + ReflectUtils.invokeSetter(entity, propertyName, val); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * + * @return 结果 + */ + public void exportExcel (HttpServletResponse response, List list, String sheetName) { + exportExcel(response, list, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param response 返回数据 + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param title 标题 + * + * @return 结果 + */ + public void exportExcel (HttpServletResponse response, List list, String sheetName, String title) { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(list, sheetName, title, Type.EXPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * + * @return 结果 + */ + public void importTemplateExcel (HttpServletResponse response, String sheetName) { + importTemplateExcel(response, sheetName, StringUtils.EMPTY); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @param title 标题 + * + * @return 结果 + */ + public void importTemplateExcel (HttpServletResponse response, String sheetName, String title) { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + this.init(null, sheetName, title, Type.IMPORT); + exportExcel(response); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public void exportExcel (HttpServletResponse response) { + try { + writeSheet(); + wb.write(response.getOutputStream()); + } catch (Exception e) { + log.error("导出Excel异常{}", e.getMessage()); + } finally { + IOUtils.closeQuietly(wb); + } + } + + /** + * 创建写入数据到Sheet + */ + public void writeSheet () { + // 取出一共有多少个sheet. + int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize)); + for (int index = 0 ; index < sheetNo ; index++) { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(rownum); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType())) { + for (Field subField : subFields) { + Excel subExcel = subField.getAnnotation(Excel.class); + this.createHeadCell(subExcel, row, column++); + } + } else { + this.createHeadCell(excel, row, column++); + } + } + if (Type.EXPORT.equals(type)) { + fillExcelData(index, row); + addStatisticsRow(); + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + */ + @SuppressWarnings("unchecked") + public void fillExcelData (int index, Row row) { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + int rowNo = (1 + rownum) - startNo; + for (int i = startNo ; i < endNo ; i++) { + rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; + row = sheet.createRow(rowNo); + // 得到导出对象. + T vo = (T) list.get(i); + Collection subList = null; + if (isSubList()) { + if (isSubListValue(vo)) { + subList = getListCellValue(vo); + subMergedLastRowNum = subMergedLastRowNum + subList.size(); + } else { + subMergedFirstRowNum++; + subMergedLastRowNum++; + } + } + int column = 0; + for (Object[] os : fields) { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) { + boolean subFirst = false; + for (Object obj : subList) { + if (subFirst) { + rowNo++; + row = sheet.createRow(rowNo); + } + List subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class); + int subIndex = 0; + for (Field subField : subFields) { + if (subField.isAnnotationPresent(Excel.class)) { + subField.setAccessible(true); + Excel attr = subField.getAnnotation(Excel.class); + this.addCell(attr, row, (T) obj, subField, column + subIndex); + } + subIndex++; + } + subFirst = true; + } + this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); + } else { + 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); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBold(true); + style.setFont(titleFont); + styles.put("title", style); + + 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.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); + + styles.putAll(annotationHeaderStyles(wb, styles)); + + styles.putAll(annotationDataStyles(wb)); + + return styles; + } + + /** + * 根据Excel注解创建表格头样式 + * + * @param wb 工作薄对象 + * + * @return 自定义样式列表 + */ + private Map annotationHeaderStyles (Workbook wb, Map styles) { + Map headerStyles = new HashMap(); + for (Object[] os : fields) { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor()); + if (!headerStyles.containsKey(key)) { + CellStyle style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(excel.headerBackgroundColor().index); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + headerFont.setColor(excel.headerColor().index); + style.setFont(headerFont); + headerStyles.put(key, style); + } + } + return headerStyles; + } + + /** + * 根据Excel注解创建表格列样式 + * + * @param wb 工作薄对象 + * + * @return 自定义样式列表 + */ + private Map annotationDataStyles (Workbook wb) { + Map styles = new HashMap(); + for (Object[] os : fields) { + Excel excel = (Excel) os[1]; + String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor()); + if (!styles.containsKey(key)) { + CellStyle style = wb.createCellStyle(); + style.setAlignment(excel.align()); + 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()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setFillForegroundColor(excel.backgroundColor().getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + dataFont.setColor(excel.color().index); + style.setFont(dataFont); + styles.put(key, style); + } + } + return styles; + } + + /** + * 创建单元格 + */ + public Cell createHeadCell (Excel attr, Row row, int column) { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); + if (isSubList()) { + // 填充默认样式,防止合并单元格样式失效 + sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); + if (attr.needMerge()) { + sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); + } + } + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo (Object value, Excel attr, Cell cell) { + if (ColumnType.STRING == attr.cellType()) { + String cellValue = Convert.toStr(value); + // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。 + if (StringUtils.startsWithAny(cellValue, FORMULA_STR)) { + cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); + } + if (value instanceof Collection && StringUtils.equals("[]", cellValue)) { + cellValue = StringUtils.EMPTY; + } + cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); + } else if (ColumnType.NUMERIC == attr.cellType()) { + if (StringUtils.isNotNull(value)) { + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); + } + } else if (ColumnType.IMAGE == attr.cellType()) { + ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); + String imagePath = Convert.toStr(value); + if (StringUtils.isNotEmpty(imagePath)) { + byte[] data = ImageUtils.getImage(imagePath); + getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + } + + /** + * 获取图片类型,设置图片插入类型 + */ + public int getImageType (byte[] value) { + String type = FileTypeUtils.getFileExtendName(value); + if ("JPG".equalsIgnoreCase(type)) { + return Workbook.PICTURE_TYPE_JPEG; + } else if ("PNG".equalsIgnoreCase(type)) { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + /** + * 创建表格样式 + */ + 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)); + } + if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0) { + if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255) { + // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到 + setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); + } else { + // 提示信息或只能选择不能输入的列内容. + setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); + } + } + } + + /** + * 添加单元格 + */ + public Cell addCell (Excel attr, Row row, T vo, Field field, int column) { + Cell cell = null; + try { + // 设置行高 + row.setHeight(maxHeight); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) { + // 创建cell + cell = row.createCell(column); + if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) { + CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); + sheet.addMergedRegion(cellAddress); + } + cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + String separator = attr.separator(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) { + cell.setCellValue(parseDateToStr(dateFormat, value)); + } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } else if (value instanceof BigDecimal && -1 != attr.scale()) { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); + } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { + cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell)); + } 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 textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setPromptOrValidation (Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param promptContent 提示内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + */ + public void setXSSFValidationWithHidden (Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) { + String hideSheetName = "combo_" + firstCol + "_" + endCol; + Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 + for (int i = 0 ; i < textlist.length ; i++) { + hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); + } + // 创建名称,可被其他单元格引用 + Name name = wb.createName(); + name.setNameName(hideSheetName + "_data"); + name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + if (StringUtils.isNotEmpty(promptContent)) { + // 如果设置了提示信息则鼠标放上去提示 + dataValidation.createPromptBox("", promptContent); + dataValidation.setShowPromptBox(true); + } + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + // 设置hiddenSheet隐藏 + wb.setSheetHidden(wb.getSheetIndex(hideSheet), true); + } + + /** + * 数据处理器 + * + * @param value 数据值 + * @param excel 数据注解 + * + * @return + */ + public String dataFormatHandlerAdapter (Object value, Excel excel, Cell cell) { + try { + Object instance = excel.handler().newInstance(); + Method formatMethod = excel.handler().getMethod("format", new Class[]{Object.class, String[].class, Cell.class, Workbook.class}); + value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb); + } catch (Exception e) { + log.error("不能格式化数据 " + excel.handler(), e.getMessage()); + } + return Convert.toStr(value); + } + + /** + * 合计统计信息 + */ + 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) { + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + Cell 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(); + } + } + + /** + * 获取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.contains(".")) { + 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.isNotNull(o) && 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 = getFields(); + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); + this.maxHeight = getRowHeight(); + } + + /** + * 获取字段注解信息 + */ + public List getFields () { + List 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 (!ArrayUtils.contains(this.excludeFields, field.getName())) { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) { + Excel attr = field.getAnnotation(Excel.class); + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) { + field.setAccessible(true); + fields.add(new Object[]{field, attr}); + } + if (Collection.class.isAssignableFrom(field.getType())) { + subMethod = getSubMethod(field.getName(), clazz); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class subClass = (Class) pt.getActualTypeArguments()[0]; + this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); + } + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + for (Excel attr : excels) { + if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) + && (attr != null && (attr.type() == Type.ALL || attr.type() == type))) { + field.setAccessible(true); + fields.add(new Object[]{field, attr}); + } + } + } + } + } + return fields; + } + + /** + * 根据注解获取最大行高 + */ + public short getRowHeight () { + double maxHeight = 0; + for (Object[] os : this.fields) { + Excel excel = (Excel) os[1]; + maxHeight = Math.max(maxHeight, excel.height()); + } + return (short) (maxHeight * 20); + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook () { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet(); + wb.setSheetName(0, sheetName); + this.styles = createStyles(wb); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet (int sheetNo, int index) { + // 设置工作表的名称. + if (sheetNo > 1 && index > 0) { + this.sheet = wb.createSheet(); + this.createTitle(); + 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.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) { + val = cell.getNumericCellValue(); + if (DateUtil.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.getCellType() == CellType.STRING) { + val = cell.getStringCellValue(); + } else if (cell.getCellType() == CellType.BOOLEAN) { + val = cell.getBooleanCellValue(); + } else if (cell.getCellType() == CellType.ERROR) { + val = cell.getErrorCellValue(); + } + + } + } catch (Exception e) { + return val; + } + return val; + } + + /** + * 判断是否是空行 + * + * @param row 判断的行 + * + * @return + */ + private boolean isRowEmpty (Row row) { + if (row == null) { + return true; + } + for (int i = row.getFirstCellNum() ; i < row.getLastCellNum() ; i++) { + Cell cell = row.getCell(i); + if (cell != null && cell.getCellType() != CellType.BLANK) { + return false; + } + } + return true; + } + + /** + * 格式化不同类型的日期对象 + * + * @param dateFormat 日期格式 + * @param val 被格式化的日期对象 + * + * @return 格式化后的日期字符 + */ + public String parseDateToStr (String dateFormat, Object val) { + if (val == null) { + return ""; + } + String str; + if (val instanceof Date) { + str = DateUtils.parseDateToStr(dateFormat, (Date) val); + } else if (val instanceof LocalDateTime) { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val)); + } else if (val instanceof LocalDate) { + str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val)); + } else { + str = val.toString(); + } + return str; + } + + /** + * 是否有对象的子列表 + */ + public boolean isSubList () { + return StringUtils.isNotNull(subFields) && subFields.size() > 0; + } + + /** + * 是否有对象的子列表,集合不为空 + */ + public boolean isSubListValue (T vo) { + return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; + } + + /** + * 获取集合的值 + */ + public Collection getListCellValue (Object obj) { + Object value; + try { + value = subMethod.invoke(obj, new Object[]{}); + } catch (Exception e) { + return new ArrayList(); + } + return (Collection) value; + } + + /** + * 获取对象的子列表方法 + * + * @param name 名称 + * @param pojoClass 类对象 + * + * @return 子列表方法 + */ + public Method getSubMethod (String name, Class pojoClass) { + StringBuffer getMethodName = new StringBuffer("get"); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try { + method = pojoClass.getMethod(getMethodName.toString(), new Class[]{}); + } catch (Exception e) { + log.error("获取对象异常{}", e.getMessage()); + } + return method; + } +} diff --git a/src/main/java/com/muyu/common/core/utils/reflect/ReflectUtils.java b/src/main/java/com/muyu/common/core/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..2ec7e4f --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/reflect/ReflectUtils.java @@ -0,0 +1,324 @@ +package com.muyu.common.core.utils.reflect; + +import com.muyu.common.core.text.Convert; +import com.muyu.common.core.utils.DateUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.poi.ss.usermodel.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.*; +import java.util.Date; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author muyu + */ +@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 = "$$"; + + private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class); + + /** + * 调用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) { + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return null; + } + E result = null; + try { + result = (E) field.get(obj); + } catch (IllegalAccessException e) { + logger.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 + "] 字段 "); + logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); + return; + } + try { + field.set(obj, value); + } catch (IllegalAccessException e) { + logger.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) { + logger.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) { + // 如果为空不报错,直接返回空。 + logger.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]); + } 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)) { + logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) { + logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) { + logger.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/muyu/common/core/utils/sign/Base64.java b/src/main/java/com/muyu/common/core/utils/sign/Base64.java new file mode 100644 index 0000000..038933f --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/sign/Base64.java @@ -0,0 +1,256 @@ +package com.muyu.common.core.utils.sign; + +/** + * Base64工具类 + * + * @author muyu + */ +public final class Base64 { + static private final int BASELENGTH = 128; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final char PAD = '='; + static final private byte[] base64Alphabet = new byte[BASELENGTH]; + static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; + + static { + for (int i = 0 ; i < BASELENGTH ; ++i) { + base64Alphabet[i] = -1; + } + for (int i = 'Z' ; i >= 'A' ; i--) { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z' ; i >= 'a' ; i--) { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + + for (int i = '9' ; i >= '0' ; i--) { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0 ; i <= 25 ; i++) { + lookUpBase64Alphabet[i] = (char) ('A' + i); + } + + for (int i = 26, j = 0 ; i <= 51 ; i++, j++) { + lookUpBase64Alphabet[i] = (char) ('a' + j); + } + + for (int i = 52, j = 0 ; i <= 61 ; i++, j++) { + lookUpBase64Alphabet[i] = (char) ('0' + j); + } + lookUpBase64Alphabet[62] = (char) '+'; + lookUpBase64Alphabet[63] = (char) '/'; + } + + private static boolean isWhiteSpace (char octect) { + return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); + } + + private static boolean isPad (char octect) { + return (octect == PAD); + } + + private static boolean isData (char octect) { + return (octect < BASELENGTH && base64Alphabet[octect] != -1); + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * + * @return Encoded Base64 array + */ + public static String encode (byte[] binaryData) { + if (binaryData == null) { + return null; + } + + int lengthDataBits = binaryData.length * EIGHTBIT; + if (lengthDataBits == 0) { + return ""; + } + + int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; + int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; + char encodedData[] = null; + + encodedData = new char[numberQuartet * 4]; + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + + for (int i = 0 ; i < numberTriplets ; i++) { + b1 = binaryData[dataIndex++]; + b2 = binaryData[dataIndex++]; + b3 = binaryData[dataIndex++]; + + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; + } + + // form integral number of 6-bit groups + if (fewerThan24bits == EIGHTBIT) { + b1 = binaryData[dataIndex]; + k = (byte) (b1 & 0x03); + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; + encodedData[encodedIndex++] = PAD; + encodedData[encodedIndex++] = PAD; + } else if (fewerThan24bits == SIXTEENBIT) { + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex + 1]; + l = (byte) (b2 & 0x0f); + k = (byte) (b1 & 0x03); + + byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); + byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); + + encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; + encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; + encodedData[encodedIndex++] = PAD; + } + return new String(encodedData); + } + + /** + * Decodes Base64 data into octects + * + * @param encoded string containing Base64 data + * + * @return Array containind decoded data. + */ + public static byte[] decode (String encoded) { + if (encoded == null) { + return null; + } + + char[] base64Data = encoded.toCharArray(); + // remove white spaces + int len = removeWhiteSpace(base64Data); + + if (len % FOURBYTE != 0) { + return null;// should be divisible by four + } + + int numberQuadruple = (len / FOURBYTE); + + if (numberQuadruple == 0) { + return new byte[0]; + } + + byte decodedData[] = null; + byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; + char d1 = 0, d2 = 0, d3 = 0, d4 = 0; + + int i = 0; + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[(numberQuadruple) * 3]; + + for ( ; i < numberQuadruple - 1 ; i++) { + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) + || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++]))) { + return null; + } // if found "no data" just return null + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + } + + if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { + return null;// if found "no data" just return null + } + + b1 = base64Alphabet[d1]; + b2 = base64Alphabet[d2]; + + d3 = base64Data[dataIndex++]; + d4 = base64Data[dataIndex++]; + if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters + if (isPad(d3) && isPad(d4)) { + if ((b2 & 0xf) != 0)// last 4 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 1]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); + return tmp; + } else if (!isPad(d3) && isPad(d4)) { + b3 = base64Alphabet[d3]; + if ((b3 & 0x3) != 0)// last 2 bits should be zero + { + return null; + } + byte[] tmp = new byte[i * 3 + 2]; + System.arraycopy(decodedData, 0, tmp, 0, i * 3); + tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + return tmp; + } else { + return null; + } + } else { // No PAD e.g 3cQl + b3 = base64Alphabet[d3]; + b4 = base64Alphabet[d4]; + decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); + decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); + decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); + + } + return decodedData; + } + + /** + * remove WhiteSpace from MIME containing encoded Base64 data. + * + * @param data the byte array of base64 data (with WS) + * + * @return the new length + */ + private static int removeWhiteSpace (char[] data) { + if (data == null) { + return 0; + } + + // count characters that's not whitespace + int newSize = 0; + int len = data.length; + for (int i = 0 ; i < len ; i++) { + if (!isWhiteSpace(data[i])) { + data[newSize++] = data[i]; + } + } + return newSize; + } +} diff --git a/src/main/java/com/muyu/common/core/utils/sql/SqlUtil.java b/src/main/java/com/muyu/common/core/utils/sql/SqlUtil.java new file mode 100644 index 0000000..3f418e7 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/sql/SqlUtil.java @@ -0,0 +1,59 @@ +package com.muyu.common.core.utils.sql; + +import com.muyu.common.core.exception.UtilException; +import com.muyu.common.core.utils.StringUtils; + +/** + * sql操作工具类 + * + * @author muyu + */ +public class SqlUtil { + /** + * 限制orderBy最大长度 + */ + private static final int ORDER_BY_MAX_LENGTH = 500; + /** + * 定义常用的 sql关键字 + */ + public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql (String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new UtilException("参数不符合规范,不能进行查询"); + } + if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH) { + throw new UtilException("参数已超过最大限制,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql (String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword (String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new UtilException("参数存在SQL注入风险"); + } + } + } +} diff --git a/src/main/java/com/muyu/common/core/utils/uuid/IdUtils.java b/src/main/java/com/muyu/common/core/utils/uuid/IdUtils.java new file mode 100644 index 0000000..375b034 --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/uuid/IdUtils.java @@ -0,0 +1,44 @@ +package com.muyu.common.core.utils.uuid; + +/** + * ID生成器工具类 + * + * @author muyu + */ +public class IdUtils { + /** + * 获取随机UUID + * + * @return 随机UUID + */ + public static String randomUUID () { + return UUID.randomUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线 + * + * @return 简化的UUID,去掉了横线 + */ + public static String simpleUUID () { + return UUID.randomUUID().toString(true); + } + + /** + * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 随机UUID + */ + public static String fastUUID () { + return UUID.fastUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 简化的UUID,去掉了横线 + */ + public static String fastSimpleUUID () { + return UUID.fastUUID().toString(true); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/uuid/Seq.java b/src/main/java/com/muyu/common/core/utils/uuid/Seq.java new file mode 100644 index 0000000..b72e3dd --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/uuid/Seq.java @@ -0,0 +1,78 @@ +package com.muyu.common.core.utils.uuid; + +import com.muyu.common.core.utils.DateUtils; +import com.muyu.common.core.utils.StringUtils; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author muyu 序列生成类 + */ +public class Seq { + // 通用序列类型 + public static final String commSeqType = "COMMON"; + + // 上传序列类型 + public static final String uploadSeqType = "UPLOAD"; + // 机器标识 + private static final String machineCode = "A"; + // 通用接口序列数 + private static AtomicInteger commSeq = new AtomicInteger(1); + // 上传接口序列数 + private static AtomicInteger uploadSeq = new AtomicInteger(1); + + /** + * 获取通用序列号 + * + * @return 序列值 + */ + public static String getId () { + return getId(commSeqType); + } + + /** + * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串 + * + * @return 序列值 + */ + public static String getId (String type) { + AtomicInteger atomicInt = commSeq; + if (uploadSeqType.equals(type)) { + atomicInt = uploadSeq; + } + return getId(atomicInt, 3); + } + + /** + * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串 + * + * @param atomicInt 序列数 + * @param length 数值长度 + * + * @return 序列值 + */ + public static String getId (AtomicInteger atomicInt, int length) { + String result = DateUtils.dateTimeNow(); + result += machineCode; + result += getSeq(atomicInt, length); + return result; + } + + /** + * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数 + * + * @return 序列值 + */ + private synchronized static String getSeq (AtomicInteger atomicInt, int length) { + // 先取值再+1 + int value = atomicInt.getAndIncrement(); + + // 如果更新后值>=10 的 (length)幂次方则重置为1 + int maxSeq = (int) Math.pow(10, length); + if (atomicInt.get() >= maxSeq) { + atomicInt.set(1); + } + // 转字符串,用0左补齐 + return StringUtils.padl(value, length); + } +} diff --git a/src/main/java/com/muyu/common/core/utils/uuid/UUID.java b/src/main/java/com/muyu/common/core/utils/uuid/UUID.java new file mode 100644 index 0000000..37c3c9e --- /dev/null +++ b/src/main/java/com/muyu/common/core/utils/uuid/UUID.java @@ -0,0 +1,450 @@ +package com.muyu.common.core.utils.uuid; + +import com.muyu.common.core.exception.UtilException; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +/** + * 提供通用唯一识别码(universally unique identifier)(UUID)实现 + * + * @author muyu + */ +public final class UUID implements java.io.Serializable, Comparable { + private static final long serialVersionUID = -1185015143654744140L; + /** + * 此UUID的最高64有效位 + */ + private final long mostSigBits; + /** + * 此UUID的最低64有效位 + */ + private final long leastSigBits; + + /** + * 私有构造 + * + * @param data 数据 + */ + private UUID (byte[] data) { + long msb = 0; + long lsb = 0; + assert data.length == 16 : "data must be 16 bytes in length"; + for (int i = 0 ; i < 8 ; i++) { + msb = (msb << 8) | (data[i] & 0xff); + } + for (int i = 8 ; i < 16 ; i++) { + lsb = (lsb << 8) | (data[i] & 0xff); + } + this.mostSigBits = msb; + this.leastSigBits = lsb; + } + + /** + * 使用指定的数据构造新的 UUID。 + * + * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位 + * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位 + */ + public UUID (long mostSigBits, long leastSigBits) { + this.mostSigBits = mostSigBits; + this.leastSigBits = leastSigBits; + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID fastUUID () { + return randomUUID(false); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID () { + return randomUUID(true); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID (boolean isSecure) { + final Random ng = isSecure ? Holder.numberGenerator : getRandom(); + + byte[] randomBytes = new byte[16]; + ng.nextBytes(randomBytes); + randomBytes[6] &= 0x0f; /* clear version */ + randomBytes[6] |= 0x40; /* set to version 4 */ + randomBytes[8] &= 0x3f; /* clear variant */ + randomBytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(randomBytes); + } + + /** + * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。 + * + * @param name 用于构造 UUID 的字节数组。 + * + * @return 根据指定数组生成的 {@code UUID} + */ + public static UUID nameUUIDFromBytes (byte[] name) { + MessageDigest md; + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException nsae) { + throw new InternalError("MD5 not supported"); + } + byte[] md5Bytes = md.digest(name); + md5Bytes[6] &= 0x0f; /* clear version */ + md5Bytes[6] |= 0x30; /* set to version 3 */ + md5Bytes[8] &= 0x3f; /* clear variant */ + md5Bytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(md5Bytes); + } + + /** + * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。 + * + * @param name 指定 {@code UUID} 字符串 + * + * @return 具有指定值的 {@code UUID} + * + * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常 + */ + public static UUID fromString (String name) { + String[] components = name.split("-"); + if (components.length != 5) { + throw new IllegalArgumentException("Invalid UUID string: " + name); + } + for (int i = 0 ; i < 5 ; i++) { + components[i] = "0x" + components[i]; + } + + long mostSigBits = Long.decode(components[0]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[1]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[2]).longValue(); + + long leastSigBits = Long.decode(components[3]).longValue(); + leastSigBits <<= 48; + leastSigBits |= Long.decode(components[4]).longValue(); + + return new UUID(mostSigBits, leastSigBits); + } + + /** + * 返回指定数字对应的hex值 + * + * @param val 值 + * @param digits 位 + * + * @return 值 + */ + private static String digits (long val, int digits) { + long hi = 1L << (digits * 4); + return Long.toHexString(hi | (val & (hi - 1))).substring(1); + } + + /** + * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) + * + * @return {@link SecureRandom} + */ + public static SecureRandom getSecureRandom () { + try { + return SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + throw new UtilException(e); + } + } + + /** + * 获取随机数生成器对象
+ * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 + * + * @return {@link ThreadLocalRandom} + */ + public static ThreadLocalRandom getRandom () { + return ThreadLocalRandom.current(); + } + + /** + * 返回此 UUID 的 128 位值中的最低有效 64 位。 + * + * @return 此 UUID 的 128 位值中的最低有效 64 位。 + */ + public long getLeastSignificantBits () { + return leastSigBits; + } + + /** + * 返回此 UUID 的 128 位值中的最高有效 64 位。 + * + * @return 此 UUID 的 128 位值中最高有效 64 位。 + */ + public long getMostSignificantBits () { + return mostSigBits; + } + + /** + * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 + *

+ * 版本号具有以下含意: + *

    + *
  • 1 基于时间的 UUID + *
  • 2 DCE 安全 UUID + *
  • 3 基于名称的 UUID + *
  • 4 随机生成的 UUID + *
+ * + * @return 此 {@code UUID} 的版本号 + */ + public int version () { + // Version is bits masked by 0x000000000000F000 in MS long + return (int) ((mostSigBits >> 12) & 0x0f); + } + + /** + * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 + *

+ * 变体号具有以下含意: + *

    + *
  • 0 为 NCS 向后兼容保留 + *
  • 2 IETF RFC 4122(Leach-Salz), 用于此类 + *
  • 6 保留,微软向后兼容 + *
  • 7 保留供以后定义使用 + *
+ * + * @return 此 {@code UUID} 相关联的变体号 + */ + public int variant () { + // This field is composed of a varying number of bits. + // 0 - - Reserved for NCS backward compatibility + // 1 0 - The IETF aka Leach-Salz variant (used by this class) + // 1 1 0 Reserved, Microsoft backward compatibility + // 1 1 1 Reserved for future definition. + return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); + } + + /** + * 与此 UUID 相关联的时间戳值。 + * + *

+ * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。
+ * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 + * + *

+ * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。
+ * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 + */ + public long timestamp () throws UnsupportedOperationException { + checkTimeBase(); + return (mostSigBits & 0x0FFFL) << 48// + | ((mostSigBits >> 16) & 0x0FFFFL) << 32// + | mostSigBits >>> 32; + } + + /** + * 与此 UUID 相关联的时钟序列值。 + * + *

+ * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 + *

+ * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 + * UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的时钟序列 + * + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public int clockSequence () throws UnsupportedOperationException { + checkTimeBase(); + return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); + } + + /** + * 与此 UUID 相关的节点值。 + * + *

+ * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 + *

+ * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。
+ * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的节点值 + * + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public long node () throws UnsupportedOperationException { + checkTimeBase(); + return leastSigBits & 0x0000FFFFFFFFFFFFL; + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

+ * UUID 的字符串表示形式由此 BNF 描述: + * + *

+     * {@code
+     * UUID                   = ----
+     * time_low               = 4*
+     * time_mid               = 2*
+     * time_high_and_version  = 2*
+     * variant_and_sequence   = 2*
+     * node                   = 6*
+     * hexOctet               = 
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * 
+ * + * + * + * @return 此{@code UUID} 的字符串表现形式 + * + * @see #toString(boolean) + */ + @Override + public String toString () { + return toString(false); + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

+ * UUID 的字符串表示形式由此 BNF 描述: + * + *

+     * {@code
+     * UUID                   = ----
+     * time_low               = 4*
+     * time_mid               = 2*
+     * time_high_and_version  = 2*
+     * variant_and_sequence   = 2*
+     * node                   = 6*
+     * hexOctet               = 
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * 
+ * + * + * + * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 + * + * @return 此{@code UUID} 的字符串表现形式 + */ + public String toString (boolean isSimple) { + final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); + // time_low + builder.append(digits(mostSigBits >> 32, 8)); + if (false == isSimple) { + builder.append('-'); + } + // time_mid + builder.append(digits(mostSigBits >> 16, 4)); + if (false == isSimple) { + builder.append('-'); + } + // time_high_and_version + builder.append(digits(mostSigBits, 4)); + if (false == isSimple) { + builder.append('-'); + } + // variant_and_sequence + builder.append(digits(leastSigBits >> 48, 4)); + if (false == isSimple) { + builder.append('-'); + } + // node + builder.append(digits(leastSigBits, 12)); + + return builder.toString(); + } + + // Comparison Operations + + /** + * 返回此 UUID 的哈希码。 + * + * @return UUID 的哈希码值。 + */ + @Override + public int hashCode () { + long hilo = mostSigBits ^ leastSigBits; + return ((int) (hilo >> 32)) ^ (int) hilo; + } + + // ------------------------------------------------------------------------------------------------------------------- + // Private method start + + /** + * 将此对象与指定对象比较。 + *

+ * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 + * + * @param obj 要与之比较的对象 + * + * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} + */ + @Override + public boolean equals (Object obj) { + if ((null == obj) || (obj.getClass() != UUID.class)) { + return false; + } + UUID id = (UUID) obj; + return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); + } + + /** + * 将此 UUID 与指定的 UUID 比较。 + * + *

+ * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 + * + * @param val 与此 UUID 比较的 UUID + * + * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 + */ + @Override + public int compareTo (UUID val) { + // The ordering is intentionally set up so that the UUIDs + // can simply be numerically compared as two numbers + return (this.mostSigBits < val.mostSigBits ? -1 : // + (this.mostSigBits > val.mostSigBits ? 1 : // + (this.leastSigBits < val.leastSigBits ? -1 : // + (this.leastSigBits > val.leastSigBits ? 1 : // + 0)))); + } + + /** + * 检查是否为time-based版本UUID + */ + private void checkTimeBase () { + if (version() != 1) { + throw new UnsupportedOperationException("Not a time-based UUID"); + } + } + + /** + * SecureRandom 的单例 + */ + private static class Holder { + static final SecureRandom numberGenerator = getSecureRandom(); + } +} diff --git a/src/main/java/com/muyu/common/core/validation/ValidationConfig.java b/src/main/java/com/muyu/common/core/validation/ValidationConfig.java new file mode 100644 index 0000000..0540064 --- /dev/null +++ b/src/main/java/com/muyu/common/core/validation/ValidationConfig.java @@ -0,0 +1,14 @@ +package com.muyu.common.core.validation; + +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ValidationConfig { + @Bean + public Validator validator() { + return Validation.byDefaultProvider().configure().buildValidatorFactory().getValidator(); + } +} diff --git a/src/main/java/com/muyu/common/core/validation/custom/IsSystemPayType.java b/src/main/java/com/muyu/common/core/validation/custom/IsSystemPayType.java new file mode 100644 index 0000000..f1772d3 --- /dev/null +++ b/src/main/java/com/muyu/common/core/validation/custom/IsSystemPayType.java @@ -0,0 +1,21 @@ +package com.muyu.common.core.validation.custom; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target(ElementType.FIELD) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = SystemPayTypeValidator.class) +public @interface IsSystemPayType { + String message() default "数据字典:[支付渠道]-参数不合法"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/muyu/common/core/validation/custom/IsSystemYesNo.java b/src/main/java/com/muyu/common/core/validation/custom/IsSystemYesNo.java new file mode 100644 index 0000000..207c33b --- /dev/null +++ b/src/main/java/com/muyu/common/core/validation/custom/IsSystemYesNo.java @@ -0,0 +1,18 @@ +package com.muyu.common.core.validation.custom; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target(ElementType.FIELD) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {SystemYesNoValidator.class}) +public @interface IsSystemYesNo { + String message() default "数据字典:[系统是否]-参数不合法"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/muyu/common/core/validation/custom/SystemPayTypeValidator.java b/src/main/java/com/muyu/common/core/validation/custom/SystemPayTypeValidator.java new file mode 100644 index 0000000..cb3d694 --- /dev/null +++ b/src/main/java/com/muyu/common/core/validation/custom/SystemPayTypeValidator.java @@ -0,0 +1,12 @@ +package com.muyu.common.core.validation.custom; + +import com.muyu.common.core.enums.SysPayType; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class SystemPayTypeValidator implements ConstraintValidator { + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return SysPayType.isCode(value); + } +} diff --git a/src/main/java/com/muyu/common/core/validation/custom/SystemYesNoValidator.java b/src/main/java/com/muyu/common/core/validation/custom/SystemYesNoValidator.java new file mode 100644 index 0000000..4f69f48 --- /dev/null +++ b/src/main/java/com/muyu/common/core/validation/custom/SystemYesNoValidator.java @@ -0,0 +1,13 @@ +package com.muyu.common.core.validation.custom; + +import com.muyu.common.core.enums.SystemYesNo; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class SystemYesNoValidator implements ConstraintValidator { + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return SystemYesNo.isCode(value); + } +} diff --git a/src/main/java/com/muyu/common/core/web/controller/BaseController.java b/src/main/java/com/muyu/common/core/web/controller/BaseController.java new file mode 100644 index 0000000..3789a82 --- /dev/null +++ b/src/main/java/com/muyu/common/core/web/controller/BaseController.java @@ -0,0 +1,129 @@ +package com.muyu.common.core.web.controller; + +import com.github.pagehelper.PageInfo; +import com.muyu.common.core.utils.DateUtils; +import com.muyu.common.core.utils.PageUtils; +import com.muyu.common.core.domain.Result; +import com.muyu.common.core.web.page.TableDataInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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层通用数据处理 + * + * @author muyu + */ +public class BaseController { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** + * 将前台传递过来的日期格式的字符串,自动转化为Date类型 + */ + @InitBinder + public void initBinder (WebDataBinder binder) { + // Date 类型转换 + binder.registerCustomEditor(Date.class, new PropertyEditorSupport() { + @Override + public void setAsText (String text) { + setValue(DateUtils.parseDate(text)); + } + }); + } + + /** + * 设置请求分页数据 + */ + protected void startPage () { + PageUtils.startPage(); + } + + /** + * 清理分页的线程变量 + */ + protected void clearPage () { + PageUtils.clearPage(); + } + + /** + * 响应请求分页数据 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + protected Result> getDataTable (List list) { + return Result.success( + TableDataInfo.builder() + .total(new PageInfo(list).getTotal()) + .rows(list) + .build() + ); + } + + /** + * 返回成功 + */ + public Result success () { + return Result.success(); + } + + /** + * 返回成功消息 + */ + public Result success (String message) { + return Result.success(message); + } + + /** + * 返回成功消息 + */ + public Result success (Object data) { + return Result.success(data); + } + + /** + * 返回失败消息 + */ + public Result error () { + return Result.error(); + } + + /** + * 返回失败消息 + */ + public Result error (String message) { + return Result.error(message); + } + + /** + * 返回警告消息 + */ + public Result warn (String message) { + return Result.warn(message); + } + + /** + * 响应返回结果 + * + * @param rows 影响行数 + * + * @return 操作结果 + */ + protected Result toAjax (int rows) { + return rows > 0 ? Result.success() : Result.error(); + } + + /** + * 响应返回结果 + * + * @param result 结果 + * + * @return 操作结果 + */ + protected Result toAjax (boolean result) { + return result ? success() : error(); + } +} diff --git a/src/main/java/com/muyu/common/core/web/domain/BaseEntity.java b/src/main/java/com/muyu/common/core/web/domain/BaseEntity.java new file mode 100644 index 0000000..28c4927 --- /dev/null +++ b/src/main/java/com/muyu/common/core/web/domain/BaseEntity.java @@ -0,0 +1,85 @@ +package com.muyu.common.core.web.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Entity基类 + * + * @author muyu + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class BaseEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 搜索值 + */ + @JsonIgnore + @TableField(exist = false) + private String searchValue; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.UPDATE) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; + + /** + * 备注 + */ + private String remark; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @TableField(exist = false) + private Map params; + + public Map getParams () { + if (params == null) { + params = new HashMap<>(); + } + return params; + } + + public void setParams (Map params) { + this.params = params; + } +} diff --git a/src/main/java/com/muyu/common/core/web/domain/TreeEntity.java b/src/main/java/com/muyu/common/core/web/domain/TreeEntity.java new file mode 100644 index 0000000..85ea8df --- /dev/null +++ b/src/main/java/com/muyu/common/core/web/domain/TreeEntity.java @@ -0,0 +1,47 @@ +package com.muyu.common.core.web.domain; + +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author muyu + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class TreeEntity extends BaseEntity { + private static final long serialVersionUID = 1L; + + /** + * 父菜单名称 + */ + private String parentName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 子部门 + */ + private List children = new ArrayList<>(); + +} diff --git a/src/main/java/com/muyu/common/core/web/page/PageDomain.java b/src/main/java/com/muyu/common/core/web/page/PageDomain.java new file mode 100644 index 0000000..b9c5e45 --- /dev/null +++ b/src/main/java/com/muyu/common/core/web/page/PageDomain.java @@ -0,0 +1,93 @@ +package com.muyu.common.core.web.page; + +import com.muyu.common.core.utils.StringUtils; + +/** + * 分页数据 + * + * @author muyu + */ +public class PageDomain { + /** + * 当前记录起始索引 + */ + private Integer pageNum; + + /** + * 每页显示记录数 + */ + private Integer pageSize; + + /** + * 排序列 + */ + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + private String isAsc = "asc"; + + /** + * 分页参数合理化 + */ + private Boolean reasonable = true; + + public String getOrderBy () { + if (StringUtils.isEmpty(orderByColumn)) { + return ""; + } + return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc; + } + + public Integer getPageNum () { + return pageNum; + } + + public void setPageNum (Integer pageNum) { + this.pageNum = pageNum; + } + + public Integer getPageSize () { + return pageSize; + } + + public void setPageSize (Integer pageSize) { + this.pageSize = pageSize; + } + + public String getOrderByColumn () { + return orderByColumn; + } + + public void setOrderByColumn (String orderByColumn) { + this.orderByColumn = orderByColumn; + } + + public String getIsAsc () { + return isAsc; + } + + public void setIsAsc (String isAsc) { + if (StringUtils.isNotEmpty(isAsc)) { + // 兼容前端排序类型 + if ("ascending".equals(isAsc)) { + isAsc = "asc"; + } else if ("descending".equals(isAsc)) { + isAsc = "desc"; + } + this.isAsc = isAsc; + } + } + + public Boolean getReasonable () { + if (StringUtils.isNull(reasonable)) { + return Boolean.TRUE; + } + return reasonable; + } + + public void setReasonable (Boolean reasonable) { + this.reasonable = reasonable; + } +} diff --git a/src/main/java/com/muyu/common/core/web/page/TableDataInfo.java b/src/main/java/com/muyu/common/core/web/page/TableDataInfo.java new file mode 100644 index 0000000..d677cce --- /dev/null +++ b/src/main/java/com/muyu/common/core/web/page/TableDataInfo.java @@ -0,0 +1,45 @@ +package com.muyu.common.core.web.page; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.poi.ss.formula.functions.T; + +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author muyu + */ + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TableDataInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 总记录数 + */ + private long total; + + /** + * 列表数据 + */ + private List rows; + + /** + * 消息状态码 + */ + private int code; + + /** + * 消息内容 + */ + private String msg; + +} diff --git a/src/main/java/com/muyu/common/core/web/page/TableSupport.java b/src/main/java/com/muyu/common/core/web/page/TableSupport.java new file mode 100644 index 0000000..ce0328d --- /dev/null +++ b/src/main/java/com/muyu/common/core/web/page/TableSupport.java @@ -0,0 +1,53 @@ +package com.muyu.common.core.web.page; + +import com.muyu.common.core.text.Convert; +import com.muyu.common.core.utils.ServletUtils; + +/** + * 表格数据处理 + * + * @author muyu + */ +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 final String REASONABLE = "reasonable"; + + /** + * 封装分页对象 + */ + public static PageDomain getPageDomain () { + PageDomain pageDomain = new PageDomain(); + pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1)); + pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10)); + pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN)); + pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC)); + pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE)); + return pageDomain; + } + + public static PageDomain buildPageRequest () { + return getPageDomain(); + } +} diff --git a/src/main/java/com/muyu/common/core/xss/Xss.java b/src/main/java/com/muyu/common/core/xss/Xss.java new file mode 100644 index 0000000..fa31755 --- /dev/null +++ b/src/main/java/com/muyu/common/core/xss/Xss.java @@ -0,0 +1,27 @@ +package com.muyu.common.core.xss; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义xss校验注解 + * + * @author muyu + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) +@Constraint(validatedBy = {XssValidator.class}) +public @interface Xss { + String message () + + default "不允许任何脚本运行"; + + Class[] groups () default {}; + + Class[] payload () default {}; +} diff --git a/src/main/java/com/muyu/common/core/xss/XssValidator.java b/src/main/java/com/muyu/common/core/xss/XssValidator.java new file mode 100644 index 0000000..3a03eab --- /dev/null +++ b/src/main/java/com/muyu/common/core/xss/XssValidator.java @@ -0,0 +1,31 @@ +package com.muyu.common.core.xss; + +import com.muyu.common.core.utils.StringUtils; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 自定义xss校验注解实现 + * + * @author muyu + */ +public class XssValidator implements ConstraintValidator { + private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />"; + + public static boolean containsHtml (String value) { + Pattern pattern = Pattern.compile(HTML_PATTERN); + Matcher matcher = pattern.matcher(value); + return matcher.matches(); + } + + @Override + public boolean isValid (String value, ConstraintValidatorContext constraintValidatorContext) { + if (StringUtils.isBlank(value)) { + return true; + } + return !containsHtml(value); + } +} diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..17f73ec --- /dev/null +++ b/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.muyu.common.core.utils.SpringUtils +com.muyu.common.core.feign.FeginConfig diff --git a/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..17f73ec --- /dev/null +++ b/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +com.muyu.common.core.utils.SpringUtils +com.muyu.common.core.feign.FeginConfig diff --git a/target/classes/com/muyu/common/core/annotation/Excel$ColumnType.class b/target/classes/com/muyu/common/core/annotation/Excel$ColumnType.class new file mode 100644 index 0000000000000000000000000000000000000000..6658d785d67090c84b911796ec9b1f9fb7acd060 GIT binary patch literal 1474 zcmbVMTTc^F5dKcvZOgJitw;qy5kcD`R6xA7a3KJ4t=zL{^%nf>we%Xa|xkq*EkaHHsy5~b>HH9;RG$0kuW z61r_WuI`$oXI>NyYdGy#)snrs``l=QfKP)0zd#_rwv<`PrUfQ*t>PpZD5#;0f&7Kl zm2CbIo7y#KY*MmI^N%uY>D17L5LFvqpU~jI#lRG<4$}!51yZHUzq( zvD~)4qbDrg-byTQZW~26sUm{&0rYCQ5)}#mJ!iU@?lY69wH3@QTX(Bvit|Nj4g%h2EKBz- zRkRx8CIgutHlgs*q*`xtCMlp6oNBpfESOARl`AvOmxe0ljf%VIRNMgO1V;X8O9Zs6 zZ5w5IpA6!o9w>8>u~%{c%)Sgi})dWjvzSRb0U6{ELuGZQ+PVxe;sP=2L;|&Tn^I7vWDbHwHxf-yk-;HFygfz8V6B4W&kh%1lpA zCWyPZ*GOKX`SUaJm2$(wUhe@$_TiOU)aR30Kx#2Xk(zpl_&z$Ad>vMmL|-C~JsMG+ ZUJ@ztd*}~6BjqgSN%9U0%;LdZ?=LVcLJa@_ literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/annotation/Excel$Type.class b/target/classes/com/muyu/common/core/annotation/Excel$Type.class new file mode 100644 index 0000000000000000000000000000000000000000..4db0780c16bf426552966660d99959f783f0f4de GIT binary patch literal 1429 zcmb7E+fEZv6kVsC>17z8R-}TUh@fq`R8+jRmLjR4NdaS#NPHUVh(o3`rkxV`5=_*@ z5AZ>YiqU9z_M?n@pB5>R2bhOBvoCAy%h`K=|M~t4z&*?b;S)%f-Abxb->RqRqvASr zRLzv(IId@S7RmWnWz!y6-g;?*msPf$4Y~dd@a#wRD@J4FG z2_*lZj`O%cRc9>6^0ETG?NlvfA+f^kxTs?omndl&S3nd(P&G1KW|Aucv7@jA4j~+Z z&YojB#xcR|lN>dHR6KE_22!f~P-V`2M!oAUT8_C`udJEXWn;}IP40+15+}JOfoRb! z8}^D(wV1NSt2jo5=%fGlmZr~pVNp5ZlC|y_UcE|wN}Ot^d5k9tG+vpq-D)u@NS$qC z;p@npB*AQ2Kr6ZRYT0~Xamkw8g-IR}inVCgym`0g1(6dNJ=P)!=mp0yt8#iwszl+v z%1zOw#b_thTpw>2Kqsw`V(7Ol0{=P&0*GQu`y>OinY^V97H#5w`4~0FFV*|Sw zNDh9%&?o7`F}uhLyrI}{(Sdhhu3kbiyq9#%)YK+jMB{<~2j;|pSl}nbs=on$X;o<;SXxyZbe&x3;m(9`2X|ZG1?oRP zQ$GkB9r62jF}ef4l;VmarJ$4&swySz8vOnk@7+lGvseHOosQLv|nibhGlD P!7QD;s{%8)pX>VzdL=Ki literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/annotation/Excel.class b/target/classes/com/muyu/common/core/annotation/Excel.class new file mode 100644 index 0000000000000000000000000000000000000000..e53645722ba08c7d5af189cd444db36f498d4f3b GIT binary patch literal 2053 zcmbVN+ji4N6g`7)B&1Eawt+>V6hab06d?2lrFLv35!fcRO}a`RSYv5oi%J@=(I`#& z(*Np1KcFAgbW66eV!TSIU#!{MXV0E<&K&*y&!2x0(GRp+pfil_*wQ!r=qNJq;L8Ai zN*Fu{q~_Yi+B~#{SD-ATxwrg)8y*ij#>@6wVe10r8QmD6si@LB0Y=$SD$OXfxMVRp zKYCLU`#kb==8xm!W3U453r3d~m#QPhrdDpydBTVoO*>qRO{shiu{kBUQmuPoZE*Y7PLfM#$CZfWy~XHU-^XD0+|S!q%Vad$9`}WkB>r+6)l&HdO2j?4 z6EJ%80l(W)xxdRmbFUN!_#)77{op@cPmamQhRp_}LYD`QCy=a*Cz`wL@i0!w`sBhy z+V#RDp~)58?u(Qh-b2SDY^n)=Tt^BmapisCr_0Yk%A%vtJz1S}&MIi9>zqN)tb80j zQ>s?c#!VS1TWq=>oJ}X@SK}+qXuc5z+V#b*8@g>zj79-0-b`Jb)F5dHjS^rG;V`*_ z{=HlH0Ch)tu6=}nLgQ7vW!2Ci*C&Uxk_!jst;z3APsANC$VP6{GOHEzU|oc|Cj7Qg zVS#oSt(`8ZXxhPbED-u)`E*h7<`@T75D1mDj6k-gM_Qpp zR#RAIESd&zj%J2HNS^@sbR3u+2j8s zf(%*%^x!1)5YVIdq4kr{W3axaZ$?_*(szKqrzdo#UlN<1;u}m@KEsP2$In-!(kOU? z%9N!_!Zv9W|JM+=1;VxS5Xb*hjnUSR>PMO=g@qA8Ul8~(ug!9w0as01-148$qsLPCp+DK;ady0!i zE5d$KTc>k=(v_YVUbd(b_#1@eZYD842fx5EiLVP!dj z27e&;h0$3fpr1V6rlXrEAP`pMc=8J*TlKLnQ3o4ewu_$l1JRqp_+t=b3)|RPC`KQ< EpA+GNlK=n! literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/CacheConstants.class b/target/classes/com/muyu/common/core/constant/CacheConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..8fbbbccee4ce763b74eb5352e15db83c67f00ad6 GIT binary patch literal 878 zcmb7?OLNmO5XV=|vmrE)(xK(q@@z|q;YxuS<2bE}YiDeeHYbgun8d9kcWejf$Ku2c z2R;BNJ`uwz3Bf($!&*P>e^rn2^3!kB1qp7$ZhX*2~_lxj^U`D zVOs>qdjePg=IXL=;uo+G{FZ(Zs5*Mf(cMGp8AtkjAHEP+@2IYOY&%VQq@GYm_naQp z><^ZQ`HUO}7YNiB8q?O=moiic)J*%pu&8IZb&Iz39_r11g}Z4Sh~a)2Zeej@GzSn}Q*ky4bdA^xX zM?pfMVgAo(?Bip*(In=6E0CF2FHcTG-Z*Rl)`D+Vfelzji}xg-AF9YJ8LlB;hx)?5 zihLvEUqikL>kIz|^6d=YLB5ya`^Z}vet`Ta!;g`lW_TMj6FK8(cdIA-~a#s literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/Constants.class b/target/classes/com/muyu/common/core/constant/Constants.class new file mode 100644 index 0000000000000000000000000000000000000000..b6a66d752983ca62f64ac8e6c16dc19397a62ed2 GIT binary patch literal 1774 zcma)-;Zqw$7{;H4ge){|A+2bwT5HupwU<^~ZGl!pIN;#m;#~ryRpSwka3#5mcNZxA zpkMrloPMa|jDB|fd;IM9Y(nvvjx)l{?f%~P-QDNieRuQc-@pD2-~kTCFofY8GI?Y% zA~62MJ#dR{H)s{D?I&I{5g3{C13!5vFg!KAF$Rgz9LDlEgS^1Rzu`uZcr7my$Q`)t zo@ea}Oimfo<|`4iqd152IgIBqfr7yGX4olqdPlt?JDo6K6M6guapDF^v3%T#IkQtM zmvzSxxbPp-Ud-b)HD_kAWSBX;ekvg+iTt1?af#!@sHMeS#k-N)@eadiU*fWWqy|li zQ6k^Y;~iWPD6BZvdSi3hsOqNSR2xp!<`j=p8U|DMGrO9{duq_ciZy?FjKuo_d9@!} z;3ZnkHYGk3xU4KswZQFAjb?DKeYef56YpsvF~#MT*dw>o*5bh3_f${fhQOGzyIr@r z=Sh4laOI_TZLpDSB2VijemmB7{kEr4(())Ob!U}2-L@@zkWHpmUA)JoUd@TIFOOhD z9jwG1fh@ysGJbezepTWwJDZ!E68E|Dhlht6wV9T+TB|hdHA7;K=BVS(2%I@Kn+v6i z#21{Xz2kQ2$fq2R#5~JRd1AUU%hf7_b)NrTl5}T^MGjLo#x3*2lripGFPhepvEDeY z5++uv))=%ZAa3zM23}PeC$4q6ZZpGE10}vvwbpAky_i)uLZ?-$N>o)pY=u2u3Tf+0 zECt<`*i_`T{5Vn7&%~7mwTi?eD%GPXq+M1@OL}9ywkGinXYaZ#Z@t$M8135~mntG^*mZR?Izv&(v;V(W{>mIRf^VmAs^op8&`;f_*Z z`hilp?L}30TR945*mT<)ZsaRIHfEANpZhdzvh4oPMV{qabItbgt1{+q AhyVZp literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/GenConstants.class b/target/classes/com/muyu/common/core/constant/GenConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..10ae21ef1b0a2726a1cafcd2428e65c503009f42 GIT binary patch literal 2727 zcma);`F9gl6vywBws~y>gn$cz8z=%I6+{F9HOo*&CP|x_R03+8Cew5vnbb*w)P3I- z_kG`YMN||8cRk0S{DV9mzxTbAj-u!IOWymud*Aonx7<7V?a#wUiD(P`+D~0HD?;5- z>Y-kZV!NHa&S1^)tAn|*-EO(1QSWBY_ga@|G;8^a(FlpZIa#g1^Q(gTHR>);IDw$3 zMv=WvpkR(h!aqhaPzTobQJm&SXhD=tpc6G(S#Hz^>+PxbAUgGik0x;O<2PH5-x?fp z{Zyyl)M!pBXBIM9yEv?uEIY5!{9Wcu+$y9^f=!HwVI^0P*D*|T!*ulo%Og4zg-`5an2hs9fNL_ z;bIuZysC8CtWnQ+t>Hiwm)2Wpw8v_Q>@xUQ+_Hy7IId)rQXJR3&?d8mOj6Ga(lzSx zDuRX(Mmcb?vC`O-AVZ^p4ytW$=i_i|rSY0mWz9^KvaC5@X=W1{y_C(_B|UB6@P?t* zp5$YaYPhz64ze20x1&_}xA~@FVg41^OyJg?U=RBiqqLKK7yM(bk%FEt3c3=ZsaTVU z{A%2|B3s_qHL$9+**XTRBDS)4B}y)f4{Z`iD`}d%t*uY`! z0X2e(8)VycL3M1_@ymDzjiAYrjVMh@NjtAkOJasSY?e~_LRzEv@lRNz+0(Cn)TyD+rl#H~Xdo+rw1If64+d!1Du#3{T9}{Ps zlv4jTJ7boN>~I11{1D!+=TEj#dS=UU&OJn#5cCMIk1R!a4sJ(UE#1^pnD#iHN7Jpz zlBM+WiL{Xu^c3_0r{XoH^-|mP)b?aJ}!EV!T7?wACxdJ@2k!z>(%1&+62|VV`V0UZ6Ls?&C{{N4_ zCd9G1jA|*rO#N1)9hBXzICNZF_+zn}zY8emaeU^8meNAHmIBhK3F@L2cyEZW15btc zdhm@Qz6pFwh;Ieo9^yN|cZK+F@Vz0v4~)+p)?Ub;7}?_MAX`*p*`k8V7L`!8sB*GJ zL6R-1h-@DS={^X(heNy{{Ah?D13wYsC&5pL_!;nXAzlK0KEyA8UkdTd;8#QZ8u*P6 zzX^Uj#P5LL3-SBl4@3MB_>&MH03QtTXW%bFdEZ zqKIE)6=S{ejrfhkH{n;rx8S!geko=rI>Kq5yp<=U8|IURLbC z6lT15`BC`p5K3?tFLo6#R^r7Rj+E`?j?_5YC)mE5?KPNuK5tE)_cH23e;qBNjkKOF fp%MHA*-r+ZMwWgjoBp7k+F~lf`)Bxd(Jy}iAhJ`M literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/HttpStatus.class b/target/classes/com/muyu/common/core/constant/HttpStatus.class new file mode 100644 index 0000000000000000000000000000000000000000..ca14d556a094d0993a092b35dd61d4316b2caba2 GIT binary patch literal 905 zcma*lNpI6Y6bJA(S(-GYq%CXN%bEsSm*vJHrOrgL6nl)9pmMRCV1cW|L8*ov;4zCZB>QQYq*^acU%F|S zX8VjPuCMFdbr~^((ULyT8HD33Dq;uUk)k`i?eUJ}4@T8CCfIWyFsfN1(1qo3%aa*D z5i!MpcLJL`CL(N;(W1+FAiN%TWI$t7w}cm%qGNQ8yfE8lbY!R92^{{|=dP^8-XP7l z+P>Elj`8#`?Ja6`g|lOHI^2>;?+}o+y27{Q4%vIGFAJF*^YX|C>=_&E_6ocN~%L@fV|ptZSHdpPM+_;rhQBm7cU6xpZL{@A~vvgv@@N zL{>H#Ml&xQjuBbyPe#!C0WXe*v>MlKKDu literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/ScheduleConstants$Status.class b/target/classes/com/muyu/common/core/constant/ScheduleConstants$Status.class new file mode 100644 index 0000000000000000000000000000000000000000..2e9838bf83856dd9898f6cc3963055cfbee6107d GIT binary patch literal 1555 zcmbVM?N8HS5dS?}_g2c=gdqs1ICLE^0|W$zu(`~DnP99eA$}^Oj*_lR)|SNoNU@?zww@{r>h7z%vvg2nZ}!>a|SG``~5hr&hN~Gz|LK zj;q^lMynhe2cBgVS_&trxw`8)F$hQsLI?|lw|CyW%9jLIN}Yja87-)F#y}(kc&AVXfj+1RuXl}!_tJ!u22JrDm6x_im z)o#tSO?O=&(GJz}+)~S2hj9gWagT!bc?IIvIid(f@jyV#$>cD};12~-H(_3PR?AVu zqEN|wp53PuOk;-Y?h`r!*_7IG|;Uba=2&w8!XB-XP6vR3yR72}1;B}!bI#98i3iecMu+|9b`kF*k)qi@*XOOpK%7@zGI36DMGxJaMl)&&IH2QJw!kVa`*;W2a5J~cRf8DSGa zNNkaw8a=~sdgcqpKKVAx*+aV^v@kJtVS!#CL7t4b=;yxV z#}`U}#@N-+mVCHoXrU%tpUlJ4a#sDofd0@Ah`rzmg4&*Rf{4aImunKmDxS97id1oa zCcl$c{C+S#afak6g8uT66i@lf$T`xdkU7;RR5R5S-E`9!N0PXk31zWHHUYZw*L}Hx OJV~B(fek#*4gUe$S!DG9 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/ScheduleConstants.class b/target/classes/com/muyu/common/core/constant/ScheduleConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..b8bb4ca07bea54ec95f0f0255c280e196b33750e GIT binary patch literal 755 zcmb7?%Wl&^6o&sv(!>o3EdknwJG5LEn1aNHi?AH0SU7eSn`|w|9ks3;Tk-{o$6|%V zf(PKC5Whn#BC+b`%zWqk=Q2n0>-UeJ0N&wo7Y#H!X!Wpxw!rpz@Fh^=AURc?`MC@W zf%e-diHi3E%_mQ19Vh~7m@d>s`L(Pri!|YpNtz@tf}~L0@JybRvD8W z6kHJyF9de$fO%v)jIWSc*C;p?*sBH0bj=?5EUg>HNWm@@FF9DP7&*S}cppvsNWl%p zUJ11H^hC0~6(!Ox7jv0;!91pCV5MOY&w?zfc;##rXA$3iXkBn!TtwGR%Pf@Rs4Bkm z-$I{PyA!x%%e~!E3K~ZwXo|z;v)8in|C9(b2kNfEGdjM?=v579& zlGH$t++X9%Y$!&qqA^F#H3^^QJ!l literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/SecurityConstants.class b/target/classes/com/muyu/common/core/constant/SecurityConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..206f8bd3547593ff3fbe83aee5130357fa9bf349 GIT binary patch literal 750 zcmb7?+iuf95QhIvb1)$#C6sbLlon_!fyFfkDN0;w;n>JdBEgNdahG(9y+&&rDZCX| zNL=s$JQQMV1!0LRZf573)z17gvp;`*{{i47j=E@Iql0D-EwmZ7&iQ9<##}8;Z*eZ7 zoT2?fDw)4x*f=QJR=Zu_{U@NfjMhkWpFARc;0%Dzwa3qjex-=#Q=G&~}1w z7Fd30j~NEe-%3HQrCL5`*!=Tk&f`KD*ktGwnb4s;C292>?r>rm*kUlsd&LvMusxhj zPdwj#Kb+d08=hFhvE>`MLV0t5DWR!MCH#%`&cN+;(eR^KF?1d8we41Y8MsFrr%S2AQWdrBdyW;pwfu=4 z1f*Rtewu$iAp8tF6V zKes^h?FLnc$FfYm^Ut21mMg(7I`k(1>K_--1x<&jfgbUt8uy7W*LXm@UE{07*J^y7 z_-2i75#OotUE=#S-lfX40JO>Okpi<~pmp>O>}w@ypKN(uihW47SNSbG!eb(a1F{Vq F{s!KpqUQhr literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/constant/ServiceNameConstants.class b/target/classes/com/muyu/common/core/constant/ServiceNameConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..fde0b1c9bba3efd03574ed477f00f8f0aca57073 GIT binary patch literal 527 zcmb7>OH0E*5Xb*(U$LeS>$7_Drh*2Dq3|1CmXlAIp>A!4Kev z5+|{>J$UglJHMIP|Lo3ue!YJHxWaxJE6A0Q*HJ)`p+4plZg@Nx8u$INa1}%GQU+38 zGvp4BoDwvKGdJ`NKba;5Ier+>5eYIutazXdTSOD-iZ1s>YZi+c^qa@t?Xzt@IGvWs z(6APrY!%61c)?Ja*E`%xgoX-3+4aI?aKaNcVyN0rcF(+%}xR_5Xb+OuN4s${Pv_BZ5qATwdhS(wAbiV^K9Ne=Gls-| zsg;4laOmsM4Wmiqk`ro0hY@7d&~jy6Pu~kw`Jy31zI^LlRvTWeQubyB1z@Q_O+2yZlzZAlk1!6MeWYPGDGHEa3jnvsm*HTrs_E;GL(4R z?}%=%F9-KQsD?a{LO<|Mmp}5c=#GUM+GsR>noJpz72OdGOLeJ4BMRHXc)T5uQmAX6 z2Q6-7%wJ;C_9gXlRR2%!)K<2sBjbw;8D}p39nDcZ2J9h2I{*^c!aTBISRk51jyV5| wmxxz>ae-d4cxz-=DZ-sGkUDq)d!D6OBO6}>4%W%$W_}7A*d$_lr*OnbaT<>A zIl9fLWcJHDX%fW;>x{aiUoo z!4MNo(+rJL9xW({t5Oj>Ch-OEgv1xYljnHq9AA=H7!Jw&hR4TzBjJ3!li0jq|=A^-pY literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/context/SecurityContextHolder.class b/target/classes/com/muyu/common/core/context/SecurityContextHolder.class new file mode 100644 index 0000000000000000000000000000000000000000..d4e0c246e38ba5e594819fc2ca57b0394bb1823a GIT binary patch literal 3440 zcmb7H`%@EV6g?jaY>10MRBW}r>Wc(5)%p(7Qq+P3uoAJ>wsZ+AtR@?}*-)|1zoz}Q zj~T@})9G){^l$3ap1b>nZ0NQ{GP94n_q*rZd(ZdakH3EX4ZszAmqrH?29hQ^(WTJ$ zz*@EP70X@9&n!H!%f3R_u;V)Zh(cm8JC{ZZ-3HPow!u_5Q?6C>)y7&Q&xdNw<;}Bs zaee!dpP#kM4bSn{#=`gUT4mAp6t*qdez8`zDpS^qLjPd47=Si>r;?|sU|_q#vDnDs zQ_s)(p5rdvmgf}u6v!om9R_xq*o6Uwp0;=-zS3YG7Y9R}NOFaLS~QuclSF^b#Oo5; zB=;Hbs(s&TRQxpd;td1)Ozg)2g+sBFgG#UhtF}iHoqmn%nO+Q;D0G-&A&nj!GVvx3 zDC*VEYok}^i!)=RMTJ~Zh*}kA!CJ8LzF*0gJj<&N6OY;_iwo-<*N-3ZleVN!ERf2oX&N1}f;Hg3+kk-n_FY z^1dv|7B&@H_anANS1@AW9TV?jRAGB-0u^iS5<{n z#);ltzd0gV8bD+=G51( zfmr^P_DErb-ARts775i`bXw>?M38)&Dvwqk4U=h|JjSPm|Dv%Xb+$mtTqF|gRS zkcVUyF8sGD#wu35UWn>yBazN>#d`dhYjvaqp}Qp0DobD+E|r1~jSZJBN51J`BU>O5 zM#wUbkk*V|Q6t=DxKgyXnT*D5hACv{I9dJHTF2_O_K2p}7CRuZy1C%p=1iJk@iR@* zfs%vyN(b_3I<&1{T1*neu*&6H!{rJmo1}P8b7F2@M>o_bDYl%_ddQ@xHLX7dFTwH_ zJoV7$=EiiUa_AO)-`1MzoG+>2az$_c>DgMtE8Eu{nPYn*tElX6;m&?agn&a_LOXc2 zpqK1EywCEj110qFnTHHsZ_|?Jom)3Lb5Egu3S8!RmCryw?(k}c4)_pv`PMCK8!a;U zdnEV+cCW*jI*}WCfmEjV2PB7{p+A8;5-te|w>@y%#kT?eb_Zb(hC}fY?$Lum@G(AN z;3Rh7Q_Pd=XS51;eJ{=`0MN=WAc={!V5(;3%vQW{tU5-s^j7(8e+u_Rix4J)(=Rv6u7^cq%} zq7?jSP;Q_nb738qy4Nwhj`t)r6?8R}^l1+H9G)I>P7^XR7jo;k-qL?4fpeS(=OcU! z)B~}0!$(7h*w4HCb!8@qx*6^g;Z|edCgR|(5N@Om?uLf@A_i_U25yvak7D2^rN9v6#j++Ewu`ii+4o?+=5!~7g|uM5{LzjG!Wyjq20jBc9-lF;XMX^>!we#u0c9)L@RruC|>^; zphLrI9I2BOCvUL2$4{scN7uT(e*zOmI~d%IskR&&@CoGxr&(Z-3nSN<*DYU~ZnB4^ zn2nkQk}Gb_E1UC{KJcf4_HkQ73M7_IUoE&k+fv`0>ndM)a(l^Cn{LJL?Z%TNo?<$V zoW8Dkfw6-?Ea#KEWoCmYgBv_A%gXh31U@%!dFU8`E=Z?hoBmkQb+>BUxu$5t%iCmW zSyh}$lmDO75DBs%ZF|L1W-bA?-KnqwEq&C`U35m=9AV?sLbt{lkr7BOI*#cT zZ0Y+Zd&23KRdLJ-j7Rtm%QcRd0$2X+%C{jX46d!_~*kwtwT5Vx@7MLq3Zfo zbW`%Bp=E^H3re9allu@~sl*6{`ZTy~lzJ*~z;%pqG~QyF;D|>AH%K=^eThkP=nMyNl@vifH>usi?U3v(cSG;M;CBqYpWJ2DcA3^L`uB16@cIQc z8jNg+wj5L~OVm5K%l`<`m$?s`CEd*M4Htlaaik+0+M+qS!d&j*K1UsRfQNNCgh!MK Zay{lZgJ&G2IiKLe{~SF$Zw0)<`QN9tEn)xw literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/domain/Result.class b/target/classes/com/muyu/common/core/domain/Result.class new file mode 100644 index 0000000000000000000000000000000000000000..3976bce828f359700072387f0a103198ffc20551 GIT binary patch literal 7130 zcmbtZeSZ|y6@G4ZHk*WrguI{uq`{&rNnla274o7n2_=|-urX9@tHWkY7B;)-&Mb&+ zEm*M@tFcvEMJo7;wNwx_M8LPcXn*}2B;h0Uk6QcOxii_>Fp&lGBbk|d&wb80&pG$p zGsD0CclHwiZTMFNB?8ezW+XO}+n0;+W+ap5C2R6e+Omzb9ouNzqjB4?b5=Ptgd-@` z5kZ;24T0+hGb2Va9ouGFxs)vsiQn7V*&UAyh@J|ruh20Mx6Ka+=%_{wt=XANrUuQd zz}jdrXv>v_cd1n^6{y3)2(Hy}9qI+vT;7~Q09usD44MMBMSHGN{bC(Ua6N$r4cidd z5Ww73B7a9m1C|MdMy#P(z*oS3p~DVi-_@}kHwuIu@&#@xih3^9utG-^D+S7vRy>zT zn3g55E?P_)tn{VNU71YEG}1(DLURPGbgV{9U_n0TTnPbvr;;5oQaQ#c6kWMPuDV&r zEx48Wvqz3^c}QSkbVslX4Y%p|9==cEA=B=3!c7<^e;wB8SdSKg($-`;X}3H012SRT zWJZ7N==r8+@>Rre&u?Xlc0r|Gp6=o zK*x5;QrWO!4NID;S(5J4u>;X8 z9*E#US;Dw|Rs`#!S+j<=+51LmVr0g*d4r~v$RowB&pmPR~-2O_1x1JK0cyWGs#ps3S2i!&-CHPr^d!EetL>kBAy&d^PtMg zo!j3p9Z|wlFPxfs`d!*?c|}B18*_edGHq_ojqEhD{VD<-t^MnLp?1@$y{MAaN}cW0 zdVA28E2e14eVs`dsR4sY!5F$WEi4>l7~F}jIgF(p#T){jy_*8;^>J_o)t}A}%x%-v zVR}}E&1^Qqle>W3E3+*=hi%`^uyxUZl2i=;WUGG;i>?yU<4W6WWVt7|&wycBiY?6m)pGLMpQ}UU`lN zZ3f@|@;Ol-B*AI5TL?FU8pkoWuDDK9=p!C){26rYo7= zli6*?6y0nS*dc8&5_TrLPvAv=9d`v4=td(wm@=*9y_wAJ+-QrBJ2&loBLxfldDsMq z-|v(6BI+A*Av%pzDxS2>mNI-MaJ^!lZ<~W=n`mxeqRNZRpf0j zR2IB?Meq-S8!w?D$h!!>5Lo)nqD*B)1(vaE?Snv)4Pm`}uVph;FW(-W>uz2JQoJw0 z2o@oY%*^vB$Jn&*g{! zTi)nf7V<5-4F@@`DbXs}DjQwfN_=j26u8~MV0ljd*3lot-;930lidYC zGNj+k-ysC?R~f`#&$r<3X_tr=H%Jk&$W!5`q0grx;-odr=XQ{U2$$JsNXS?~Ko;=r zBp?stzJQDc1cb|i0GucZ{sN%O2V^WDAcXeV@J0@=H<7TBRt{*;|V-F;_p`|KiI>n8snX%#;P@$Ugjckn7%2{(R#))Tz(CsovE zR~RqO;z5o`9)$d669CtqkFh!inu>(u_ZrtHzjYn6;Z_#~r;dl0Xy0MH>{{7Ncu7`i zr3myQl|6^ zR3ArWeYn2V6VhZ7`ZuEr$3|t)OgM6Q)p4y358^c@W(k{&F1*gM5Ocd7Z}3iI9xcP0 zybH5wU5vMQSL!1p=LS$=94Cg{(#ud0Df=(3i9pl8lHb<*_^(WSh3nL9IU8^JNmFs< zWWLO$uq0{r2J)wpw}E8Qc#W2*u&C}Pzm@m_(gpqx?UCQox~f`QwYDWyEyI%T2iqK; zx^$*ugQse&7CQe+;eJ4FsEx3zRPKdwcu^1c?{zY{F!$psKpw* zLt8^wg=_H_-f6x<*yZvkS=$8dYuUMyH6ch8KmUErW%=h4IZ!A6vqlMcGS2_szjf;e2&DgCEV_QFTRC z7s0RRe#%paO;hf6S*vul(xGG@3E_BcvmAq>#SI!)5wP;{Xka<<>9DE^P z+Sa26_fve%r)o;parSRS{5$@MFH!%0 DGi6pb literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/enums/SysPayType.class b/target/classes/com/muyu/common/core/enums/SysPayType.class new file mode 100644 index 0000000000000000000000000000000000000000..c26d0eec92818d5e98d6b9e94f5b6e463fd920f9 GIT binary patch literal 3821 zcma)9`*#yX6#gbnvPrtw5TMwCf)JnyN(Avms!~b|#q!WVk*er6-L?yxP2FtJ_(l=M zw*ra^3cer6qe!Xci2UsF&j6186CUr(PMeJcOnXju_s;#k`<|Kp@z3}L0QX@`fsbK9 zHlIu7ilt(TUUGSh9=4v+tzxc_%9IM5w9@9%upS13Uqt{xhCo~QrnYSii@Ixqra3mG zBFwSjtsU)a+cp!POY2prf^pqyDY-#K1ELH{yr->uOGk#G<zX!KG^WLKhxC*l?r^Dv)MoXz)> z&#|jbaIFO@778uH8puaT(4r!NB$*KI78sH(iQ3b3D{fP;L`4d>GekuSijHBX+H6}Z z5m~U{*t$m9SVA=@XGo?{#w-x7Vv1rS{dA1FYnh5Wu$-!(4G)_ohB*^e5c&f}E9)54 zYn}2XU5~qPw}N|A+=~?qGt1soa5L29v|)yOWGb)0c0J!1T2*R(s)ygv3l77wDrNB! zOgg*C*87dD=IFxPl`7h>iaJ}fO6xTzJ498i>Qxz*=#9aLRvv4IicYMd91j?#quUJk z{vXz@K$UcJx-J##@F0!XfMNA_8a9usu_EOghk3#^ld4mPWf5$^Mg^OAx*wu`E2n!x zkKvB09!*xvo1zI2k^7NRu^C&aQiD2qagD-fiqsc|ZquY}z*ZHHfHstH-tI69`WlW~ zTGjd_Oj`HOw1P(`+E|FG8)-H}c%0(9GIH$7;eCId{N~Eo(Z6@^zkF~nAD<^wJPD1a zojh$9gIBp(xD4cCFS087L6aHOpDJo54aW@WpVxy#ZwP@9s1t&kY0%CY!VZe+%7K%Y z&L6sb;t02C@?C*uYK0ds4Rv{@Op30SBzi&!hd@IRep=5CX^yZ%9i(2qaN^SM$6RY6 zs38<-{&w_>^`~k5()jU9V~5>!?n+6;vwZhZ;uG74-_1fpw_)iUin%`B-mLYR6n46b zw}~3}Wxk!|vzpnX*#>8mlzvOg5wqVJGANzlj4^0wPSGaOqAJF!<$=;{6kLxhsv%RC z=w+BfmF=R&-lp@R zKIi@V)0;sFat*B2tbS83#JltPoyFlQN3kc?3LwA4c-3oPbWL6#>+K=Q+^(5s#-PI@ zio*;QjaPYsdUue90JcZ*g&4TnE>~X5vU{V@sSIE85&ufX+ju96JtX*+3%*ma4{t{C z1HUWO*awMTa_c9KKCa?*Xi>}{x|3XRO2r#oK&_y5S(a{#8UxogQBvD;0 zyd-?^@x7k3xW&il+zrq(mRvmh9A+nPJBzu=CjVK)Pfs%O;}e)h9!y6)W?(8B!CB`L zmPhuoh;SlCSH`3CW4GXVg?xS$d!)|~OP^`6v zZ8wqKX0keqew&1CH=@}xt6{u`y^?=O@>4=MKe4uR*3~}xvzB2T-M}c;kK!V)u+-=( z$rwo;Z}HwEDw3iV@&t)zzTlzbUGk(vX8|*VzkzM58$n%Wn|}mK zW?Nu{Hu?X?qacKL@ty>4mudM>ANIY5p78IIs{@pcr)@U?vV a2H(roALZ)LIDyj`Atc|K&fqN0q3K^*CBm@) literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/enums/SystemYesNo.class b/target/classes/com/muyu/common/core/enums/SystemYesNo.class new file mode 100644 index 0000000000000000000000000000000000000000..ce2320d8a405bdb76a254f0ecbfe9b6cccdedebc GIT binary patch literal 2801 zcmb7GZF3V<6n<`Ay6JWyA=1`j5sI}WsSrR=Yzns2R;p=>1gb46-lp4jVY3@{H`V%v zuiyRXFYuEyDhSj%I(&Bg8~QUG&%JxwZfRsG}+Vx&NbA9t9192A;z)hK$sp5m9eYcpj%UoH6hMUS#OrX0rpE zhOEZx3}=;=|AF>6ZVWFO7($8E4op8_IMt*tQGhM7mppUPs`9{;Y|j}ukC$nLxwAIK zgX#)HUsG1wVflF-qqv}9%)l!c-xOU=CTT~bM53Fw8r&xJJEOEVHJ?u*nZiW|HkZO{ zq{iRh{valyEQW20VJI3DLY5{Yy;G*$mi%lA?I~O$EcYw{r!W%^uMu=2Sg}Zx_KLOa z@Sx$5>1dN|&FUgaEkC5ZLsBJ0ex7PuHiOV(=Wd}~LWfCObPQ>m*A^Cee+b!sqGcYG zhEWBn;i|3ngLp1KOC5`F7JJ8VtAd@U3Dzra!>gJTmXJRa*_Mxs^+To$t{eD)$LmvO zu;MQI={D4KIB+%84cvl9yUOh)t-@tp|8IUqG^evuuQ4(shG8m_hd@LY8F;K-~2G<#kNyjlgdDxh~hRyW``G&s=^yEd;Z6E&lkYV0@5Woo|1@IKs%KeY9Zx(26aKLs{&Qq8 zLNClq4l%K>k(bE$HsZvT_!S0wAE2jj>>dsldJ^~0_tO?q774mf6N3yo=$`=n7l1%L zOtGS}YqG-48bh0?GC}Bq%{#>TU0he3FDuTy>*!xcZUe`GUvMgh!UoQY+u<0#mvN%% zFn1^A?V@itG4GVQ!-{&9s!WWI!Y|TQsF*DLjDwHLVMKzHia5hU)8M{GgZJzX&gf#o zROTV7EJm5z1`GEwvRy;ixo#QV6?!P%qN^q;#R!K^1cj5AdIS5CztNc#zk_&XE^!B1 zW%n?ou!Ln5Hm=%`|COS$6Y=b;*~tfZ{Vw9tFrCQGWZ#emZ5@@n&_##C+0rE|o#s#5 p>e>n{dLP3L+@!1EZBxH}H1L7E`w$=DQ{1L^VyS(GFYpz5{skKarP=@h literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/enums/UserStatus.class b/target/classes/com/muyu/common/core/enums/UserStatus.class new file mode 100644 index 0000000000000000000000000000000000000000..63279d09db4a0d6708c9e6d8dadf06f7b8b3df69 GIT binary patch literal 1579 zcma)5OHUI~7(KV0w$ov-Wkg=0B7(Fx60SfJ+Z8G=HneRL2d;a?O?I(a4th!)h=uc)d!A$Xa zF-Vt8)}SM&1vR6X$p<&`S}tBt3&p$}41x>?oD87ur_%`oY!@?K1<`FyAfh!=9Y zkqT8SZ~~M6ij1qc#^4O=hF+LuXsf2OJfr>uPy4!zUfiJiCbLf|W~EkwTlLGhX`VwA{7MT`^q(Tg{KUVRWD zi?~hbn25U^efjq9>-Su8T1E(A-Zryvd4_<`-)Q5A>DWtHH1qewbVFM$X1284y1JF7 ziiGOq;%{&;cs;X8HJwm%I%l&e1w+jcvru@ZQ@rlDo-%06a|8|45vx}v$~UDIDj}a8 zGpoB5gD7>2HXxi#TZ3Tt`4bFNRg`>a!VRV~8)A^+*$U1T?dF!|5YTQ8mbCza6r6)lHQKG7S) zJ$gFLZ!{;gL35V<1Z*ZMDJ)P%+aVaYx1F({Cq%ATVZn^S#;296xZ)GoDPoE*FxY*7 z?!eGKdIFuoKKeeNFewn|et{zJpoyYxp+9HsAzz-^qM6}wjunh&DPYOuh>-d+?$eVi z2I=HkIs#wNb3WWwleiMD!y;yQP}jNdymLpbvsdD4a-z)h0NR~Dz&7nA*yEc*39k62 zqeKnnbZ1K~B8rEWbHYk;`aAh519ruy1P*X(4|Wp>3d)EwW&$n~m~beQ${iDs%9z?i aGcRa`U!vlJ8aWP;Zj~afAV!!CkNyJ^>`6HQ literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/CaptchaException.class b/target/classes/com/muyu/common/core/exception/CaptchaException.class new file mode 100644 index 0000000000000000000000000000000000000000..d54a8d469322dec9241097926641073553d76536 GIT binary patch literal 469 zcmb7B%TB{E5S&e$6iQ1=p+)MA8xM(ybD@_45-8$8p?5b}sZnBAiG$#?I3aQ11NbP! zx`04%!iV+FXgvGy>)Z1SfFo?y;h|DPwE-Uip?@pxM3@SlgqNkZDw8Mov7B3FG$A-t zTG=6?yB&S&#x_?v8SG4ISR#b6$-=CBC|!~n%~vi%`DGH0#N5U+@x!%U$XtnZBJ+Z) zT%R2i=$z0T8C_VR?L?%d^toGih)^Aw8%bzIO3RBfo67u3OjBk$k%`$yup8q~vTA3l zARI*h>}x=%WJTg!|BOngk4>4!@>IFH-QP3qyBF9(jd#l}qmO0O`CehUHfOyL71q#U#Coh_W8u|hB&CM5P+I;;G_A0ZxD|Q{AQeR%NXQ{4w(crf8n2_ZP2sUP zMdH8%@KA_Z$Arif32ezbyZg=0-^}j!A78%#c#elIN?3DHuAzb|Vf%ylDEz6=WB+Zc z6BWvrp8`2cRHO;jXG*K&nBYC?{nqspqxAS_e`rxxEN7k2UR4YxCb|%(Q<;mdT2YPA zSrz4&6>u@_noVmE4*xZ6G}<3JXc7D%3jHwsoZ29aG!I7l@>gYkcOrvxdA3q&GnPh) z=}?-OOMiFrf>9TA*R#<3V@n;8aW$4Vo%d0|wN z?Ia>N9~coZ#O+6^3FIqf3-O9gdTf7>yJ+&Ua}ThM4P57OlV>G(D09qrioZ8`<(Sv3 zuG%@6gT7>%Hh=A<0qn`vvBlAig^Fpnc*c6%#tt(qYyC2oQ)D$++4>9X4t8@^EoYrz zjbFg&930N!7Gaxgz{_BJ3)#|`lN;kySZpb?*vPT(*@V3wE@OAR@*MRdxy|KlW#p#| d<&x|!$!<=zZQA2jTca-Sab%l&pJydJ_zBsc{B+~AVa~!{l%Q%kbQ^jI|QFag+##z@KK1p z2qYvbw%DCr?TkkA@%i=+-~cNrT4*PTx`@#s4DaQm6s0t`;=&uJD|Pf#s0XL5A$0b& z(e9AYUf;+Q%n-HWxhDWW0`k{!is_dD)`7P3KRIO#1tGZ#)>yt5oP6_iP zYZ@nw%Vp_R%;rK7AsR8C(95(@=f0Y#`bthpz6>&3u#RLk-oKBLyVDI}C;P9lJwkeE zeO;(y9n@F^Wn!E*g|h2w`^2UwNP_VM?;|VPJWQCCxfZ`Dh(3t zt0x~P>V2ZaK%ntJ2ReBqQ0?|cOsXtcHYdQ9^yy1jCl5UJ=A8W~59SiIa&sWcZ zz*={)j^0S1Jyprz?-EwKy+tjR@q%(tW_o@$n+&H1XfsU_9EWK%QAgUG$m%~`+B1#8 zHk(o5Sys_O8!KSP7*%kYFMFS@*(uHq{^K>`xW?!{XTiDN{|@mbldW?!Hx9I_VFOpV za&i%_;u<4k(BWtdj;J(R+Zgoke1lcEED;CTq{|I7v6VTk=jxf0$z<>h#0IXp$?3U|zJI*F0XRmdf&!KT6sstqOz7T;2N5PhPs1y(ol51|V=V8TGMZ36 zQd+q_p|u_T>PF5gJ?-s`11u8`Vv~lcfAS$GsnL8{8Ok4%aHzGkC*IBe_%jQ-tOj}W9X%fxiKyYw0;@}?p}|@EONDhb8L=K4*qnQ{7!}a|1eNG@g8%>k literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/PreAuthorizeException.class b/target/classes/com/muyu/common/core/exception/PreAuthorizeException.class new file mode 100644 index 0000000000000000000000000000000000000000..1f0963af79c27ec2739e8ee9b49656b65662ceec GIT binary patch literal 428 zcmbVIyH3ME5S(@F7)&4`K;w=MC~yHv!$U#=Bv6D95BC>yB8TidbiPBtUr`}Z@Bw@j zVjY1*LB$ojv#Xuiz4`cjdk3(Gl>`A=F~SZavJ=P_mo+l8sJ%0KyxL1i>2D>L~+$2NN6r7u-Zi2HkZHfq6D5W@|!bC_s5TFlTq@t7u0+D!h)2m>V*vLx-e+3d1 z5)XU;ABC7}XK`Ee0FiQ!uRV9p%=q}%?;k$_JV(2T46+(>I`UW&Xne3vEpu!+BlC6W z1olMke;UeSE$LES@yw?6BFF z-l;uIvS}0P`_@Pb)Ow4q{lK%GQCG2-byQFl$PL{SqE-{ALnn|U=|!-bj#Z_gbRq-G z9v{tEtG@JXYdnyiPxWsP_XNaC!ggK94=g7bSmRLUnS%NWw%Lu^RC=}}Uxkxn>AkUz z$B{gDNFIx9+)r=jg7>yB(CPi7@2)`INI04LZ4CsBl=}(f%(H@4M>5zuZ+FdTCBRc! zBK=Fq{gghf|L{?yh#&B-fMa#BTUWZ0mIJJU8MYwZ0SR=$uh!w?Zg z18k@I-k_6M;||fvx28O=v=_(Y=pNBdCt+BdYtq!07FzrYyAN@sO?h# literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/UtilException.class b/target/classes/com/muyu/common/core/exception/UtilException.class new file mode 100644 index 0000000000000000000000000000000000000000..b81448c64a486c290b01bdf66bec5de40c109132 GIT binary patch literal 824 zcmb7?&u-H|5XQerQoC^-lBNk1D5X#&nxv|)NP!;OQmH8P&_B6v!z$g%UL$+WpU2_? z5(gfD124gQAZ8mkH8huAygRes{^r{m|NQg)2Y^?2=AneLi;9mqIE1AO@j(Qk(Bt6b zJc&PwvrrPeu{3XGnu;+8t&Ps$T6Js^rN?~_^QgM;d@R5xJh&DdW!k7nzWy|l?~RHz z!Fj2)GTVgi#!XNmGd0lf3@!hTh1Ut~8P_^P7mI|=Q5*$P_Bji96UCaBLW;O zS{`Q6nM_V5y=xBQ5tk5Lh!yU)kX{|7psWogAK^!3_s^l4xRy*A_=5v{B~$0`Bp5nKL^amw5HMy|19&H@IIe zb@y%V^2A3KHKqV}CrUiT3P<+*5muRFdG(yP%^J&dy3DHm&uZ{Lx>#U2Q*fO0`iG#d`0+{@Z5HM_0ZZH@jcPbMDx0sbiC zENV32W)Cy-Ca5IQ^IFK_HJZQ}m!B)~G^FtVvg{gW45q}FiClu$n+LV7n7BkMvNYx76Dm8(q4 zWTLX1-@3UtCD0|IF|;Ok(zuCCysEJ0;t-)cw6}`T47E`spH5YFEvE^0+M$hDN3t5@ z?`GM}bWS)5|K+Yv2vU{jGM?)%j83SHtT7j*%dU<;;Q?_!aCZFn2!x?&b2y>O6Yz9EbMq7 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/auth/NotPermissionException.class b/target/classes/com/muyu/common/core/exception/auth/NotPermissionException.class new file mode 100644 index 0000000000000000000000000000000000000000..7c35b19cf059b2746a28a206dc316c6e328d7df4 GIT binary patch literal 772 zcmbV~&rcdb6vw{<2$ls=s942TZ9GtEItNb*dZ9LHL#U~Ri>F~bfg!s)WOue{|13`$ z5B>rEQBB_<=r(fdBs;V3?RP%!$G-bNw|4+e@HUSW(m7-bSVERzYb<^W?ulT?zr}%3 zzC8Qo%85}rV92&qpv)=5dcE_cyD*^&hRt{VWh^tW_j%;u8y~I!b^IXoh90<aquoYp|=SW`lM+cfblMOL#?Z)dv+eiDy?9HEa{ZvR=j>HW8RAb zqkQ@4%9WQ!>43rcpaNxD4Aq0qeO}*$Di}9k57)59z}{q$MJ|JU9tEs3ywc&Ai%a27 zBzLv%>tHtLzvFio2S#}_hSXFml6Ze`5ksGkrqVUdSY#=-8p@!=a6}5+kFKMI6fL3T za%q8!$V_-wo1XUK#!538D&Y-fI3uHjvlH_1nW508VvPvQP z3S>9(M>6~(Mjl1V9qkfF5RLYWV9HDsIXv$CPjO9B3#nSmUg(MNnZG}kE7qP@*?4jVtf zzRz=>(`;WBuuhppY|vlrE(@E)v%|qQc8FnFy9-tu$$3`puu;zZ#FIyWWdc`Xz}#P8 O4ll4b2ksL-f%+eR`>;6x literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/base/BaseException.class b/target/classes/com/muyu/common/core/exception/base/BaseException.class new file mode 100644 index 0000000000000000000000000000000000000000..5d8e2d83d45c8ab9c6cac6db4430800fd554a218 GIT binary patch literal 1604 zcmbVMYfsZ)6n@U=n4RN(QKm)^l&u>S1Br=v34$i-&_rZk{M3!tS+cceZH<2OCu!nB z;s<|#KgxK{+X92tMBTFY*5`80c~AHA*Y_U)?qe;F42E(r3dmxZP&{-#ICk6dTK22R z3*C--{IRLthpz7thVQwa8$KWmmCAJ!7hvX)FW@2ygxgKOV|SuYkadrKHkg5 zp=ySjH&ei@@J0{RTPJFVyDA8rmddljWyy1nP%HIO6U)Jq6#YR^xlR}lRM&Odb=3{H zQu|ML2=t6Fvh908=y+k>X-6u{6_*cj0^6JsVXWqQ>P6IPsP1d05m&-*vW~-QyiX2| z@SV%)uGjv##+!t@|C_1gwft9PL6%aGDdiLBObS%a&6Wyxla81!l?N+L$T1`?ovgNW z7tEB(DMo||M(mtv078DxkGf6u#MQMv(~hgsf>_`l$?zRzQRMFx5U%nrgKPZbKG$pR zNj-Bb>Y00uXOpqqT0CCo-Dk$jeHX1GkX7j+XH|O`u~vE*x8{rIA zXO#tv;sz@(vepvsfQ?v*PZxP7c!`AcN@9_Ci}GS%NUtOwLr1feM6=Hd20t^cN_B;f zaOu=s-hW`3(=KTnyyXg=dqrk8i+~{}-0w zwnsUUv-O@k$NGlc7uL=2b%L)}{O@R)IF@XZIKfIKkDMoOrjjdM&A8Y4oyX6UAEuI5 QQk|#IlebgJt2#ORH^q<@E&u=k literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/FileException.class b/target/classes/com/muyu/common/core/exception/file/FileException.class new file mode 100644 index 0000000000000000000000000000000000000000..f9cd22f60b8e394450210da0dad8ba9e4f0cf045 GIT binary patch literal 679 zcma)4$xZ@66s%@v1VK=7J$O@GCdQkn2T>EvL=PwzPtDlkkXg(uMnB7wi3dNxk22OE zCKyPt53k>=uI^V|-Jf6Y9{>)qnnOY$b#K{9Lkj6EG6iIj6WBF9M|Yx^NN3`BE+=2< z>e*C}p~bQz1En7`oc=-rnFGtU!Xp7=-RQ|DsoT=+>aEbX+-_qOxgCP8Iz45EV@MnA zEVRjT;v48^3`26tf$}YBx0N4I@y+>(fVdDSHa#~8r5m=T9jP>Zh=&l^AEWx88tGxv zyHf%s!*bPSiTN_6fgc5Pg%TbubA{LmMhe!37Qthge(*a48^CS?wVZ331xklVmGFDI1k>pFhORNng;+ z%{|l!?GtsT!c>`Acsx1b*!ft4=b_QWHTZ;$tNWpGJmZ|;ovF0s<0+xLKkP++cnlh7 z61Lr(gUiZ+E&^w5kXkeIaRcif+D&YrLwFq9EX>M}WhjTt8ZkMCRi~#;3#?LvuVj09 zNfFkbYNOqA!jt`_@*|gPGaI~LqR!tmSYj@mdSefpgxCLC{7B@B7P3V;)2`};6Hb1Dh~mJ<^7c%51{<8#PIV z=|nb`bV`y6z98#vt_#9p^uPKZ5VjJYsxozz##hgj?uP__WXn9}>Wa|&-Q({<^s8~e z9&XAn%R6x!Tj+|tC8&mNImu87OV|-6l4+}n-F(!c`Zuh+TiN-7)lujAXS6;oBJRlU eFMOJkvxQy3-SZgS#XUh1jX)|^nePj#;lVFiiqu8` literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/FileSizeLimitExceededException.class b/target/classes/com/muyu/common/core/exception/file/FileSizeLimitExceededException.class new file mode 100644 index 0000000000000000000000000000000000000000..f4aedc8e64078d59007652697d86e2e8f71d9d21 GIT binary patch literal 734 zcmbtSTTc@~6#fn^Y+YL@rJ&-4RbGIHZhW=sgP@6Im4|8*!_##4v<%tZA-l5#{Z~Fg zOyCFjql{+?#`<7l;yj$oH*?N+F7y4zw<`cIu-U*IVYNC*jY@ia7BeTkOq~t%7xqvm zw2#%P3R9I&!h_K<$JWOJJP(Z~Zowxk{=Sb)J|TFgDy{fnOjz04-;Vyg?l;gR+_Og< zjCIPTumrjctT92ViV6Ez#FB@06U*ojp2j8%v+8pdijkRIRKcOE^2BO!U5@aLh}XX$ z!oqW%Yx|P$Y-@&mU<;j3`iC>nbvykTR-v-tRkIh>#E>{lbLGTB^O$y zLoP}w_~Y9>0__u8yCyHK%I(k%YhG624iV}yv!SS6lQ3Z^(mB7cvJn>_)F>6C6PZ}j zDM>2+4Oq8Fx+LsH|6g%mHk$BQRjGY<{R;^Gz*I%dZq9^Fr~ck?&+QwJu_B9rHYK%_5`KvQzI@KCI^ Uso%vTY=|e(2&Nn)ypH9`Pvl_5J^%m! literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/FileUploadException.class b/target/classes/com/muyu/common/core/exception/file/FileUploadException.class new file mode 100644 index 0000000000000000000000000000000000000000..c54837eb6fef355a0e209a975d3615e0b155045c GIT binary patch literal 1389 zcmbW0NmCO+7>3_Y$igJ-5|E$-aLIy<8=}PJfLf&$EiE9PhoKFl$xLc85&2hIrBLO; zqX&PK<=dUfg5=~Jdb(%6?|HwifB*UM6Tl;s4MY%4U?hzg;sTqt*DxFH*piqPFt!!>Ah&6kjC9otg*^<6v)vMBPu{(P& zo(hPU0%O~r+X^f5jIq<|5dzVCp(-%4?Hw@niHhUO*X_o>^mkQ51g0yVO`1g} z&*8_B;LvFaJgEHVXp|}2Xw?+G-`{X9I5w?76};EHZkjYuePAxSTd%BU7*701SLmEW zSU7=XO$NGc0(1GofM&1$q#8S3+qb2fWcFalK(DJFl6Kc;d0Yk}rj#eJswzh( zmuycqi`%$Ek-OSkENIo-FxAV0s>`A3m48(WR4r1qMAbE_t`AgjP;~?M&Z=(WeyD2l cty&vX8eh1H=&V$w!D#zUjfGk8%4n;tzgQLzF#rGn literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidFlashExtensionException.class b/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidFlashExtensionException.class new file mode 100644 index 0000000000000000000000000000000000000000..c45fc5c158062abd78611a1d1d5540be98627dfe GIT binary patch literal 803 zcmcIiOHUL*5dLae*oOqZkvc4ze^!%kO1ECCxlV zu8E!w^lPv*zgVY9*Pj??57tkE`hw{C@L4eS-g+B82;M#4=^dLBlQ`oKldX_jf4K55 z$Wp(Cx?uOe3R%1^al@J7=%zZ`h33|{zUHxk&)qeFd=iXzGG7GaL*KYkM>(SSiJ;oa z4pcDNvtBpLbYJsrv+syZ^|Ar;7-pk=4OYXEEd+bLyKG`b&^FFx-}Da?g6SK^E@1VD%rHyTX7S+4yN)?(BRmg@SMZ2`kFtU%l(C9f)jS%%01KtwyZ`_I literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidImageExtensionException.class b/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidImageExtensionException.class new file mode 100644 index 0000000000000000000000000000000000000000..e027f8d03908d3252ff81f2ca91016bff4bb5b77 GIT binary patch literal 803 zcmcIiOD_aL5dLZ{`>Ti&_dJcKQ@t+Er z`6#g(swRI|XF1_mD^us#H*i?pB+xFQs}kA7DeLOWq}(ne@*fehmFSEKJvD84FAYyQ zK2WDdkiJ^fkUUDViTwd)-GxpFC$;}<5|qcm>twg7~wAGu!kStM|e6Sos3j!>#v%W=i1Bw^{k75W1Qm_|-^Po|486i^h| zDOLt0(a3M3+}(m4AS(yR&o3-4J%H}tyn5vJy9>-po;j37n}7F1FZ#ri2=rq>vUqI} eLvP-B42#w#XGHJ}M&<8bW-u<&SK+IgK;aeETi%NR literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidMediaExtensionException.class b/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidMediaExtensionException.class new file mode 100644 index 0000000000000000000000000000000000000000..48704bb734a7a3b535c1947ade9aae72b4be98a7 GIT binary patch literal 803 zcmcIiOK%fF4E~(vP1>XnDA0$5#DSL5y%s{agdkFdT-xT+s?sDe>7dzJv^!hcpT!A@ z13!Qth47?_dLWT1RqRM(`y1P9`}6NVKYsyeV5^J_77EB#kVBr(7(`(Zrq^j8N*GxY zF$a7#;IB@L`B@td+V)ZzJ#1Y$wuzvv=`$h!R$J}f5#GEw?R-&}Dlp29f+H7eJF4FW z+36KfB%Ix=kmr*UKk-njS#{PDjb}%Pnnc+G9v#GA=`|G zOsICWBgjf88b}@`*~FfJS$Clm!g=R^Hc=L7E z75~Evq3DUVDwK}OM^PFN_=5n1?YUg<`z#XJ<-~oA5=W@Ct>w6BRFbfCKMkG30iK~C zyC>7dQ)+CG99^%p1yNGqs7UVn@JcB3lcP}&85b3M%Rc)g57t`n7q5uE@ literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidVideoExtensionException.class b/target/classes/com/muyu/common/core/exception/file/InvalidExtensionException$InvalidVideoExtensionException.class new file mode 100644 index 0000000000000000000000000000000000000000..89dcf9fd961f37426b0708922c55bde4fe23e517 GIT binary patch literal 803 zcmcIiOHUg?4E`Jv@*qHXw52a3Bo2@QdoQJGl?IV2$|WI}BBUWPVXD~~v^xv*XK||3 zLw`VjR810cC>pR zWV2sHiE#9wLe|G6_Vtk6ZFSaCPP8(8PC^5Rtxp8{Oqgvrn|ft^Uzv;xGNSMiA>VLA zCd{|BcgDmRvH~+r zxv$EeTbKG*Tkr7{Xz6M?ev%)w{1iz7U=}9M88~kuhjD?`y4SRt?ZdXkL(_9fd}XQE zb=A@~**|PYS(|)3Z#kZ9JnFs>7`7pMq0y52Rxg zL@PHSdLP=jbR6%M>b(<~?9Xr~ogwNMCT4L-U`%!W2uuuSD^&f`#FbDr6JFDmO~tYX z%D1IcQ+^o1^U6a3@kHQUw;DC+wABc!7Jh`l+DC=%gfWOVC@Itg(q*qf%v{xW)zfx! zNBPg>jzh^r)vGfI$xz65glWBJvl;GJKP#6dW^PyMje&el=L-oL6)>rNToQq)d_q?V zoTXOSCvg_D+g{tRt56^?H?*!d!V#hEQx)hf72ZEE@U6gapLN5<4qnY}DDOD(<7P7O z-Dx3gsfI0+5WYVxgiS{Vdr1g)P79&Zl)GvWfs^pS^K_tn+1gTi&uav^QIxW{i**C{ z!j*MjV6nI3Z1=$1S5`a$@fO>Zb?y0w0&n_PL`N}p`dGRRM+J*j&)aXeN`qt4C;7LqG@)2f= zD@VBeE^=^<&x`z<1wnI|#1y}?gqfrCYf6i;D_lpO9GylXi0Bjsk%~@X7-tAypne>L zMH*_26#vA9w>+c}LXAek*~qmSD|B27EMb|F@CN)4UtVOT0w%CU0eb0bE7$`zMH)sESp ziuQ-PL+W8=KbEy>@AV7IWTNuM4uZj_!jAw$S5`B33;L_1nKc=fQyme;Iisv1$Qf@K z=|USRcXg>yxvNjuwNysew(|uut7WqKHV52L(Zd1Kp0R7BUmDzYQ$?8D)I{3YNj@*= znM^vv9epbLxnoeU8R>1kV5GAJEvF?@+Ez;Em_Ze{FhqotIW4uPQ)w%&JFHE?2u39g zskn_h4E|!N;@Xr&B$_(3j;vV8at~tZ{X@H0k1H6%JqhC~CNN25T>^BsQKoc`tWv{H zzonatw4F|rtXeJJW-#kj$32L*N8kj4e@evzL>K~Vj_cGn7zWy@S|^jyoD9E0otTml zl%dM#kr9^B&u#N69%F%bN90puSdBzG?GI&g!Q$i7#n6*-T-#`r_w8!d+Aoo1_a7-n zJG>8uaH>+YN;#|QaQ0RRpKFyVQuuloY1r%U94azsItQ**Z&V5AjYM-avunjttBc9D zgS^*k9j3PtXHd*aqgu3g9A10)$^y>vk)XhaU8}#S)anwp8Rq_X>u4*Iu4`At;Mldz zdAigwdKaY4A->iCNm@oBY4e1n1rw5%N=VuvAT-SPgiiVizla6mSt4zmB>yN)41B}z z8AiU4#_)uG1Hv~<_z5hx@Qd&Ws}g3@r?`6t#_^sj_!Y9K=O{eIs_@ew6N*QihnK!o z!Su}N3GROt?)Gq($0fvh>R1z)^^n4cxs}Kkd}IZtLxG=Qd2bV5Gw*9cGV}f>-Ag{u zM7Nojnh2SBxrtu$dSNm)=z%?N#K#uj-Vb66N4+PQK89B)Gd`h6LV4&HiXxOp0ikpY zWmXbONGLH`D7~kcJH`Mn^1P=CbpiCw7#OC2=Y>7PCfPjDuq9*yI!V613<)f44*dmW C0AREL literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/job/TaskException.class b/target/classes/com/muyu/common/core/exception/job/TaskException.class new file mode 100644 index 0000000000000000000000000000000000000000..6c8df4f7e4df4467feb15344d93fd8b274a48f29 GIT binary patch literal 1152 zcmbVL+iuf95IvJPvFo@O8d@l~aw*Wb1tTPcPyiu?BDD&AX~+{Vn{<`BIBVo}p!^j` zph`UO0elo<)(%dQ`jYI!?#%4$nKNg1fB*UU3&0E9cTqywhUKAxD&bK-9tOkFmr=mR zFjl-IGLR>I`7sUIJ&t=pN9Yeb|00Cy^H7E9OM=*JAB#^Sh=dvh2Wb+jL9;zA-bO1v zl+80hMWtq=>%zgD4cCyZ5$cn2MHaz7kH#dkbCkrNMK6+!H^jeWoRt9Q)&-l^%tf@ObKOn}qUE4-D)?)A3~!93^!s4|h%oD`)nL+u_sp zK&Cm>XPb?w%jeI7;2y-Iq%YruS%?3<$cKg(p|;Od-by2cwsDv6WF~D1-mX$IX+=V7 zsd0;+jKddL!WAsx0$7O5t8;|k5!+>sRj|VIDtmjdI088S);67jzGc~$cs4%|e8%Qe zm)W|R=V6VJ&2VrP*BHfE2Dy~sR>!#SIoskr&)<4*3ftfQ0dIo6kYO#OiaKhznBn_* zeu3{5_}LH0*m$^(8+?|q&V2F?0$vS^ivJznS2jv8^bHZPWvF|3!Wg>DBAKk)xWlW( QdmFgNmYZ26tiD?N3)%1)8UO$Q literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/user/CaptchaExpireException.class b/target/classes/com/muyu/common/core/exception/user/CaptchaExpireException.class new file mode 100644 index 0000000000000000000000000000000000000000..c48bfde395b8196ebb5c56d44a65576f33e0751b GIT binary patch literal 536 zcmbVJyG{a85Iw`g#T670AJNJVEZEps2-+YfnvE97HddGG4P3GhvU}IyXIYt8_yK;D zady>&!oqlqnKLKzICJOyTJ%z z@B4JJZ^I#0`4}u0`&dJjeT}06))^6>r_OehnG+Nl0hOZ$(F=;tc~*n1&Dr2eiz~Ns Ql;@#|ZH@>#Yzx@^1dCjaD*ylh literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/user/UserException.class b/target/classes/com/muyu/common/core/exception/user/UserException.class new file mode 100644 index 0000000000000000000000000000000000000000..24edc6d8d1d7c512965b340045ea70b1b5984d58 GIT binary patch literal 645 zcmah{%TB{E5FGd2(9)9fh6CJMKtzaRfdd63Py~n4TsS$wDz5TCiG$#?I3aQ11NbP! zx)iCXk;q}aJKlI^$Nv0!{{V1|%?ff1g)|YdfdYzUlxirW!f@b4ffb}LsYOW;g|x)N z63?D^RFX=UC&D_VaQ+K1l#XO5)d_>$wnzMlTRsnmR$s+39Cl}syD8|#9SKimGC!~0AdB(u580x(!OcW25!~Ikg$p`&0hIWSP42>O!9P35* zf}vr{P+X^hE8<)3`h=KvpVWWV?Ip q4f)q`pQ$nG2mMh+11-w7emb#;C93rPGFIpuovmVxx;2|-+4u%hH>ni> literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/exception/user/UserPasswordNotMatchException.class b/target/classes/com/muyu/common/core/exception/user/UserPasswordNotMatchException.class new file mode 100644 index 0000000000000000000000000000000000000000..f5c7b0f7ff3b3552234105b9ed0ba1ed5de7d4f4 GIT binary patch literal 560 zcmbtR%TB^j5Iw`gVg*HfVBF~nT(oiH1~oCLi3ZUG>BiNi+(1ctFKKUme3mN{7k+>r zWtwk1RQ2v+&-I&ABwPa9H_vY5*m%pL_7*N6l&!5OdP0D z>tTVq9ZaNeT20S_O*s4OsJpr7t~NKB&kIJwlu8_53GT`9oGh4ekPzCPf9q`#?4C|z zUtR{;xczLAzy8k2c8NVK^MzPEcCmso`wB-ntTH0LS(WWNGe^iX0!jxpqBrDUXIVA2 YHfMt?Ew0>{p;;a_vBeQ#n{5vDZ&UA=L;wH) literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/feign/FeginConfig.class b/target/classes/com/muyu/common/core/feign/FeginConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..3d466820b66cf79863933d47227010a3dbb2ec56 GIT binary patch literal 647 zcma)3%SuBr5IyPJT5YZGr5mY&23)w&3M#m|DyS4(rq}eE+MAR#*T-M!s-WNp_)+5I z*7^V!W-*hQoO5O-^Y;Gy3ZRLlGBU^(k*gq&0z<7UZUyfN9r4q4SB8$Eu&cCkdkope zTC0c>L(|xZ5BgT=sAEMe?~J|SVb3I2-1MdHNEK;5Ncw$a9Y0TT$G733(aws{l~ME+ zCmB{l6Z1HENH|?$qsdvxNAx2ZDNU4)iWqW-=1MYD1Eu9j61Szj5bYji>VXMGuO+PV z@nJ*Cf6Wc@QRfoZap5dc-xC}NmFokTo&D-{DuFDPCPG4V*b48Hj@Klr6j{w!g< P`do^gPwfK6*+t+3BMGCW literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/text/CharsetKit.class b/target/classes/com/muyu/common/core/text/CharsetKit.class new file mode 100644 index 0000000000000000000000000000000000000000..88817c1e7cc48838dfca7e6c7eb2efff939b401f GIT binary patch literal 1822 zcma)7?NZxD6g_JUvW;x0n-54S1d zv`ts5_@h9oZa&pJ4Y#{6k;(duJ>ZLy_neCJxIhh0Th5l=GzI2+Y4|UaF^ns?q~a4y z2wd%%v}^vl&H^pe#FHMKDM?J3Ve_Q{ZAWyG4fpc+8VoJef71NjznEt@GnycG& z-Kht5u@s5*+V*~_baP?9C~&F&ZIb$`iffX0aCc{Iza-7Pt|EghyTbgjqsz*^S5LoZ zSWgA{_nOIm<;^sRlw}yvOHCk{rQ=|ROWHHzhv2;DSV;g zCTgt?MLex>4T ziA^aGvNwz$HuV<))BV0}8rJ(^ z20hx6{n2i99D|}0ZO7=o)#19?K6|;z_EFn4o88^mlF?^wQ`fudE&*hI%D7?XqvvejY8N7Os zcEp)NimKDRY8o|M!EQ)Yu`8-bQ8SbP6p5UnD4F^YqVZTtkfnxOfxsybMO*0PF+P{q zija#>_?NWPE!{!@9#7w&J{r@XW$d3*+=nC0p&_afMP2RSj3 AA^-pY literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/text/Convert.class b/target/classes/com/muyu/common/core/text/Convert.class new file mode 100644 index 0000000000000000000000000000000000000000..a0b003274d494051fb3c70d558c7341025d96608 GIT binary patch literal 14494 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 I*yi~D5Bo@NaR2}S literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/text/StrFormatter.class b/target/classes/com/muyu/common/core/text/StrFormatter.class new file mode 100644 index 0000000000000000000000000000000000000000..f1d4c94839ee4fb02f59966d0a9e768f2d4d34ca GIT binary patch literal 1851 zcmZ`(&r=g;7=Avo$zlu`&_$^zVyPrSNTm|7sBH+LM8gjahSEBNOR~V)WJ5O_2Z!;- zrMF&nI*#LX#@@8knaH#=9(w7Fhn_k;^bhF8YcHM7ls;b)FgCD<-F@Hh{qeld`@Y|+ ze}8-l;4(h*q6sb)iVtph1pIgOyLvdMTPxw2r8`E(5%63xEz`Lo;0grOUNqx?3a<|b z;S)HMDdfZX(!ElcKly^ik8OlYj+rZlQ;uy~D>vo8fNB=w`8DUBfEGx;$x*c#4H8B( zT4m5f0v&rARJDkg1cS8>>fBhcPLT8%=aIm23URx3yoDvk;q{eP;ll9|gIwig}f zlqJ6-pac@Zw2H3%s&R~UM;0?tu=Bd(79fIvZJ!%m>2KkoQfeIKEQc_o;^ERsXbP(?ix1z)RMD2!gOS+ z9{5g&8UR<2Mr6?!1P1C|YP>W8uCMW;^!!kuD-he?P{13Xnw?u%yqcPs7HDq-A<)7K zijHnMX+2jm1P;a)$D*-osbn-YDIj7luEH&8wm2S7CZ-lsbI}`fQn^vFtt#Ww<5G2> z^u-EUMmdx;En~WrUoz}DeJMvxd$N$xb7|c+rCd`g&Z@};2qgC>m~8A0*C_k6T$wb1 zi+fPE*J|ulvo~wx%zQ#lB}+_jQgnNzCVGpGJzE)NtE!LMw$9Z&yhm^@+8gU+ZNHS_ zQi-G9*^qdrePm}O*+@x6tx{p`M4z@L&E39SdFl zq1!KTY}yr3ToI4v>3{hI&qD1dG^LF0h+A_vJ;pIjc_^I*LYmT5#=G+aW%NDQ+>ek6 zX>KK3M!)~oW2E{2EzVKp-cj{Rm#PW9`Zdqc7Q$r=&(r31M0tuUo1X2rZ2TK#jPO{g z9CugGDmfdxH$CF%_N=s!)$HP8xh_bGEOrFwMk`LikJHe&qCMzCFR!CPgfN1BcIGVE zA0Sy_O!JmW@rE&Q9_xr;6BqC`tsbzS->{?Kv7^uEv4t`GOs`)tj^7yT57Pc8DVMF7 zB;6x;f+VI$eII^c)G0QLEx-(8$mca?ah(m)@H=ksw27!*G4mX8_u?1aq)tJamcuyE pDzzUhoR*k#7`don`s3;rE?P&{sVg*vKjyY literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/DateUtils.class b/target/classes/com/muyu/common/core/utils/DateUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..692f4a0979a86701aec8677529d72457112d81e9 GIT binary patch literal 4847 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 Jj9dv+{{r1GP$K{U literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/JwtUtils.class b/target/classes/com/muyu/common/core/utils/JwtUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..9e9366cfb7c430a960782ae8f34d6f2e6627057b GIT binary patch literal 4023 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/ServletUtils.class b/target/classes/com/muyu/common/core/utils/ServletUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..45095667b382097e2857934f4c9b6a740b3185a3 GIT binary patch literal 10517 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/SpringUtils.class b/target/classes/com/muyu/common/core/utils/SpringUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..9586955bfe1a4ffbecd0718aecef48b456bd6e53 GIT binary patch literal 2375 zcmb_eS$o?=6g^`*6}AOUOA{zdp_I0^(^eG9mbGr$biob%YLf?e07XpPX>5(rQWAa> z4=fKX5Bvar6dz|KxmIGO@X!ZqMl<)GIrrY9JO2BhKmP)-g3TIAC|ju5n87iD*~jh^ z*BQ8e-}!v|vGgK=W6R1{(W*eX(cG%y1yn86Y}8>3T=4YJ8OHmu!^u$l90KXYks5?f zcN8eU|AmO1Sn5C`t| zKz39ZneoO1YpITxaNNSIjT1O2aOZge3s`*_nUff0qccfMH!@)@HFHa8rV=Wr439a1 z^Ldx`fg6TLdAwrdRh$;E8F1t(KTOY@%L9zh{L)1Gx{WuCLtTYkG8xE7`)2)&jkoZ2 z%DcBel7~o)F><_9UdHzw8|Uz@K#eiC2g(g4Yj&}S!dE%}46=p`xM-naqluQlrJ@qJ zdgM$h-PR-4HIjRjm+i$tApPh;p!X<^Q;mYmTDT<8F2XI;OimvUbZC%08HPF#sI2R6 znV91p<;%@@xGjU85tP8mj`rNamK!MZo-J0QM~Zo9bpD^pmx%9E%m!^rFU;+&Jx`7z zrTx&tM}$2(9uq+L)Lfw2Rej%$;(*wfmwSsj_)L4NMYZbnNU7`%eh@g3b4kn24?B=y zJYWg(bTd4G`GXmupt7vYABI}yIjiQR!6_wrgeI2=p2nAY&RKiFG zQb#N}o9}R>eSVxvxXQ*~g1`cQHPifgeN;K;t-v~9sNsEl!2N6dRfzc^K2EGZNigR! z%x~yl;<}w;zFb0Q!Jw8CUgqKhXEov)Zu6-vKE)#6%r&R&MYtsm~3lPSv+GN8Up*X{DPG|VxGqKVPuM?9u zMKQm#)0kgB6SIn&xRqgDXV#25D!=3Wq)MrJc5^5dY_Klozsp!pW@U|UDZ|@Dxr4hI v>I&aXoo5z)g*6dnTKo~k^IZa+7JnuaCe0It=L=lIJ;Idm89E#dt^2^gw=*g_ literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/StringUtils.class b/target/classes/com/muyu/common/core/utils/StringUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..cb1077a950437396e441deca8d0e439f2f597f5c GIT binary patch literal 8432 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 C5|^z2 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/bean/BeanUtils.class b/target/classes/com/muyu/common/core/utils/bean/BeanUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..2fb1041c0351cdaebfc8961d259f994f09bca73b GIT binary patch literal 2746 zcma)8TXz#x6#h<b$=G^w#dw<`)oc#Ikug?LT$5&za;8ze( z(T1SF5z|_WSIU-ATDxs&Mg6{M-HEU0TB#DB;&;I|3KfCixKT3f2?2jJwireT?Fzyw zc0d(~<;`NeSlz6~IVqYY4wfFT%8QO7ubxQWEN^Bkv#eXTp;Pfdbaq3#r^O3eX)Qjt zvZ3egMC(p$Q9(ptcSAJ!Ag`Bg!z_i-fld{>B$k~LhMl#w{GFVo<#h$Sw=YR|;**x8 zZO$4MJB%*)!|1_Y1^ZO=qEDc+p}gjYKxj?3rwdwze(sLOJZ?Fgi7@u#fP!~ayo-ah z-caCP3iEzSx7W>8YB&&$-Snui^xFl3jn~c-?d0^ZiX%8Gup^tyEoUZkx#WCWptp9( z0buEC`h$2zvu)if(f%+>T zu-8%4YLI%0nw?+QErC&Q+@{wxE34nF>ZQD%aC!1vPt`8b%t?$YIHlq=#$I8@m8+W} zX-u~z3G=Lq4{%Ok7lC9nnWtnRw^^1cL`Ys@Yq8mZahz8$q2dBA3Pc)^Wc;aETU{0C z_M&jJFSaCOF{NVKiN)ncEW$|Ql7h=BuHb4@!qj*aXs=XPDh{Vo_f>Do)TvJ5BNemK zsURuS3Y8FKlnE?)tNc**l+?3^`9db(O%VK}rE=~>sTnb!)7nq|nfyBV<84TfrH_N{wGLO_+xLN+1UFz5=E zcY7+R-U28ZSk+}zyFABkI2r1Sl_vrp2O&+4*}>J@s_%jtGDc&blk4sD6z ztBP_v$r)BACre(S&*M#VMN*63T-l&kjEUEU&Q^0uO&!_m_ojJ^!k%W{SsO0W;g@ud zzuv8hgaVUkoHf=;nq9TX_{Fy%<$pD@P)POVW}F?|^5X6?Dzz}kP$!+Tc0$9dp4uA+W ztWa87&vPcQ%DDpH6$Kpuit4ycL23SPjv_Ip|5#gh zTX*1loEhnEJ9#en6AtwTxA5K;hR!Ly$`($1gC4na=6T>ds6)NMUy$(O+ShI3@r&Pw zex&ArqXyGD5Z|8|2N0bZ1yoed*TZ-!}nP_m)SLb4&&c#BV zixlp;TqIk#kY{h=Vzily`*=X|WMWJ)r(`ii1{vL%A^F+Dhd(&1HL}}q9POz|ViTY9 yTxQ)v&SW^gs29ly*Ya;ySLzw&e#T^1))^1Uf)P%R$e*UbUS8YJokyJe@a2Eo_>3$7 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/bean/BeanValidators.class b/target/classes/com/muyu/common/core/utils/bean/BeanValidators.class new file mode 100644 index 0000000000000000000000000000000000000000..e378429e90cc7989c12c12bd52b24e2ebe78e15e GIT binary patch literal 1244 zcmbtTU2hUm5Iq-Y7bul>DfI)a-wL#JtBFrrd5~ayp!ETRQJ*f`4ZU>PCClALeu96Y z|H7xHn&`W~$r$JE0x5zfMo8|*%y=FEKm`S~k=XLyoE3~>#K43@CWu-46=WESJ$}M{$&FL)h$AkA=Nj$k==luEvDs#L zT5A3dZN9%`sylo*G|Q1Ckis!qwlr681z8Pi8LUHRSPda2UItAJ8~uSCg}J@cu)$y~ z$f)kQL+Nwj%C_*FFw4dV%O0q7)5u{{k-y5Ik8_+nV3yk&t~2afUf<{kqrjj;pD0?M zZyPFVXmo7u8qaB&(jGD->fRA?&NhW>9|rx7?Z4(7hb(&2v$)gdzEJnEF(HoyeYDs7 zw`WX-{G`5bggl;7VrVELe-_5PRQE{bMN+gGQe%9j<<{RJsZYFd!|3zyt#pb`Z=O{iy|8l3OPS zd@vR-JuN%sn`()!%Vpq`)Gz;E1I3_BGNfBx;9K?!p;{<6+ibfkPu#&Znq&2gfvHKR z^#*rih}B)S)#9{&OzGf0~N literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/file/FileTypeUtils.class b/target/classes/com/muyu/common/core/utils/file/FileTypeUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..7b71c9127143225e3cd5acbdf2e743e2cc3cc394 GIT binary patch literal 2017 zcmb7FT~`}b6x|mBlaGN8p`d_PDOi)iGGeMN4XqXg3{3(GMJ-w#!T?i}nRGIdvV8Jq zblFw&WMAtGq7N>g{Y_mi_njF&+VUWIn0x2UIeXu;&p9{${QKu$0B+#BB-+rfAf}=N zodVi@^9R$Yn$DK7xPITN_yV0%wqyG@1==&&RRwW@QP+paNZS1kc$%ks-+jl1)iZ1I>ngvlq7Mz4bN zD*DhbaG6|2t-05XNV#~H(UfGyCh-E$mA$$Z@C&4fE_tL$;8NyQf>Su-cwIn@Coza2 z1#hT$6Bk~PB|IC^t7gM5I2+c(#Z7^})6feN7# zD&@OHch~Y}%!ZZ1yT~ZWs?g;pL#p4XOQAPCinr@}JI1cHPHC#XT{k`7C>`!XnR_Y3 zqGxZ}j#-r!hfztqhsz4aRTxs+kyA<imC*fedt?G!*-n{6ilf2067-YZp_x| z{+__lNg-yoO>fzH(6pS2mCxRliF~NyBbh}vp=Ml%SiY=J64x-P;JS)DrUZI|UXZ1Y z+OWY0k4Uy>m0hRYtX5yDXxOd!ld?vpByP$~KmH#LRI+P9w*=|Naf>~_urwdX3^((I zxj1IInJz8GG0)9Xna|jayTR@{SF|0g+^nrz-io;{dplipD`s`o^lbSa8Dsvo%~Xuy znOZq7a50iKs>us^M$^Kx$SI&uVWS_q3Un>|W@V>j)}vFzrC&IA=~st>01b<6Wcscb z^f%|BATXOLp0V*xKjg%jVK_V1VbifSqNxu0a3jp3KeIM{vhqiYB5*e3$$oWn4mXyB^2zgKP`5E5~uDs*Wq5lr?8#iqz z@F_oo_uT@YYUqI5DDo}Ai>yS848Bco>8A<(S9GQm&-8ty4$$+Aw)Oz0n=5!HbYKW^ z-b2TD8p>GYx23>W!~@{|2-sqnJnev>~BgYJB#OSDVkjIeX zh0u-hfTceKz~}ga-xa36j1|I5K4$kE-2wwl|4u~tfUBe&(f`0Dfdh;c#}4rRBlOa6 zMH;UDjll!lD2}~MKFPm`>*(Rw5A*LxrWlfsFvV5AB}w!pj}el`CHb&IQ4;tHUx)O} zzb&ADlK!Nqx97C^7AEyrPAjx9p?Bo8xfZf|XHL7;!mzI7w5z`$CD+Lodh~csGh0Zc zr;ATjn9?)Iz^xEw|7u zS$Uey^xVnJb!G)Nfh=>Ljc|+2VX-lGnDdV;>`xT>5ygK@*^d=@g1cB_TswZoH%E%_ VfBQLdRHQ50H%L9crAHg?{Ri7~*)RYA literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/file/FileUtils.class b/target/classes/com/muyu/common/core/utils/file/FileUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..f7952fe704170f555be2f16ef0e47b542e48949c GIT binary patch literal 5216 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 CKNjWy literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/file/ImageUtils.class b/target/classes/com/muyu/common/core/utils/file/ImageUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..c10a6dc286bac3f66319bbbba27297199f2ab4f6 GIT binary patch literal 2296 zcma)7TUQfT7~LlqCWHaGC|B>GCO{l*@fy4ZrC zDhR0vqd}l`RezvsmY&aQGfS&R#uaE7HS?x>Q6LzLFGLYRqk^c4Ca3~~89S%tN^2#J zFF89;;}}}WHLaqyY+8mknbWhzE%_~=WDR$mivsajx|(OsbtQcCsHoZ*RWfzUvl4-aWojR*dV{$`ZvW#SWK|!}bN44f_pJt4LYufon;?b+34||D^ zWoHH2)3U~*wLG$_rR{9iaFP-17ud7??TbGjKidBCyI0SjZ~yYe_SV+H&pvO$K^#(W zSVcbu2!Fk=K-h2`+ac6%z^n$v`4z{0=vOOAI;!FrVgeDuc(06lr8ke=3hEM#K@2Gv zR*}H*iUK5sng=9_YslDzwV7oy7+XwD5#TOzt zMG#(nwYmNE6Ca8S2nx=S2rpdTaJ5@E(@~tpIq80$K5uAT3h^{XRVtXmY_SVQe$3A2 zsaJ9$&>QpBu@g zj*1BxqJ<}K5@i3F+`6vfU8Dt~+`4Leut@Javh2&4RxyJcbmV=gflQ#QQg)qWBe*G{ zd;0RPZ=U|~N#WI}!|1*I(A`%2SBm@M1 zduk-TbIEwD(UfOy=Y4jfdciAI0k3JzpetVm1!m=n zzwWQ#er3Z;xpUKaF&v{4N@v-`5?$nB_`?Ukr9UcwxsO*L+ zj*Mn3fAmJ@?2?l)%J+Czb*LVfNZ=6fdw}Dd!k3eXZ(+W3p7VK|UmC5DtAm>m-}5Da zJABG*pdE{Rs^tUt03Y(J5g#GO73usNf(!*D2DhN3hqll>#Ye~R`qU5TY2P>e6AlC+ zrsY~<{d`E;p3qB#=oCdOx;#6;0Ik>$X$NrBvq7(j7&m+9Ht$h9pslR_8?1YLkB*_U9ay1bS!Z_%%U^6$HEOSX5e3j3Mg1sumYi=Yfix` zo8w=X-`rzHlF0S5xg+VJp%+_-r=LN)J+z6F>uK5H$WXb%b-Dn%`LEGMCy8G#5u_{A z4lv*m?i^(!$4Ezfr_3-bu#lr~C)3J;Wt4uuU|A+v;05ktS)AA9vcv&qkg;b4i#dIp zw4I$A-av9X(N;RKflG<@Ya19(gf=jl*ua#>N(K5dFSB*Lggsuul9vGI{0I|DJHaF) zNO^Vw*F9TqZk!0qy#UUz@Uv{=9DUA{g(UeHWw96NpTbGn5nRM6T;gcE%#{?zX(wo> zIb$VXBZR1lpyXjQUMt}$;1jlZs)oZ^I39-q&c@>F9I}Xd4kK_q`AUHv@*t&X+ap_; U`w=}-;i5+29sDYBEr19A0boH91poj5 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/file/MimeTypeUtils.class b/target/classes/com/muyu/common/core/utils/file/MimeTypeUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..d653de350c9af09bdc694490041176e8cbf94f11 GIT binary patch literal 1898 zcmb7ETTdHD6#mv=doW9IhFeI;g@z`8OPqwHO$(&qVu(|7X%`4i+N5i!V5H0lT@|TN=4V2IGZcLPa~c|Jp07~l`}9%ptuJUm6Z$a_ z#-NTEUehp?Ex2*F@}v@{;1=>^B`aR>Y^NMwvmGlwYrEFslcKexR2o{7v*R;~hl!QN z#GH|wpVQEGziwZ({)`A*V$SjwE4)l$&Dm6Guj&|9Ia{YwFyg^~h z+!T0I39czH;tSM_DI0rL;B5-#rY$h8G^%HlN>gUCgoZ%L6_{ZYO73PxWlie1<7b^s zOeM$bv!;CiYszR&$GmT}oSaI`*BiY{qt!xIz+g-Y+X72eZ98RwyHru2Dos_f=n34X ziUL(1P+Ip~N8lkBDG8Vqylq-#DU{5TfSR8jo9D`z3gmVKY$`H4R|OtXD6X!l;#?hh zRb2N}VtRZjwfJy6m72esn0i?zhoW{a3v=AM{O5saXqhbJ%buC{mQAO^vNOt@M9GzOcXh;5YII`@4^$E`KT>KbSx&jeH09j^*m=Fe#13} zM)E%X7x@qJSNSf>Q&oAoD$iDBZ&jYJ%2%t@Hu$xkL74IYzGVxa(fT>t@;$Dg%7`y; zy{-#;c*>>&pYU&o{yRp)5LyerNMAsG?AfP(HCMakR|4&X_!%PIAbX8;qdaeipN@9O4c6wUdDHw8=;TNOZ8(Px_PvWU Qb`oErhpV4aAHe5-0z$5U`~Uy| literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/html/EscapeUtil.class b/target/classes/com/muyu/common/core/utils/html/EscapeUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..a95f8c31251609b3e0945cf100716565477bef06 GIT binary patch literal 3371 zcma)8`*#z^75+w&wX(9rvcPuiSOmw|NHSOsq$I(%0yd^7NI-03112$Rd1DE$c2#Lb za05*rq;2|2OWNkuhilr9zDatH@gZ$bf9{{s|DcZp{bpB+ZLD&7bToVC&Ye5=e)lo+ z_j`B$3Sbx?2jPKNfloyP`~sm%+GQMIXnOsa3A>ax z7Y1WnS@Nt$RW!+i{PViptDyP+IP~~rCVeb#*m^055WI5Op`yjn^GcQ9hQ}1NtLVVv zH0U92xb{g8$^uHhJXR>$O9CzRd^jIKL;wn&5NLbQ#gR(hn3pDX;YkJEDt4o16X5Pi z^wrSK1v}>eo(f_o_Q>Ew1$@zzj6fISD*CXOlG&VAI>H#qmC*qD1w@bBF`(ip?5BWM zEb8XGz`lCsZh^dN;$Q$zQ`0~Y2l0%8XH`6hLjuj~9;HlMU(ibe0o$sX-5O1$>O?Vs zApuWMMVghAnw}Tf5v?OA9Xq081fvpXb6&r4>J@?3I)npAFWO1X&`Wmo zso3C9qRNpOJE3CI$u!+b{YFe-TESTr=Wu>=xR=VdUSO213M1I!1|x4JPO~0tf~sqU zL8Mv=y{Pebh3unmwJjbEL|)X4>T-=8#n|uR;eQ-0s9} zvt~kEl;;@c|48MjFa&1h`FRzWADnV%a~O_(>*hzjg+ud6!8US;pEuaNjfw$ z!(3#w_MZ8LtXFVq2p!XGld-ELFO*3p zHgcTBgu9T8(X>&gRW+sarhc+gnA1y>+ML1W6;4}O&6v_kc{#5#eReKShxeu*(nucY zhqTjY>sJ_hC2O&qOj07tKXX^)`A-o^yHFHp-{NB}W9jOItz{Q8TCr+~C(FK}7+Tpr zZP6faQI5WXmS>z>qcdAH4aTOpu9X%jw!O|W7p2{d{!rGa-UGo2t5VA9?68ERX}!bu z%RFO>k64z?den*;-OgF_#ZbjUbYtXgxf{jWIm>4ZL7qr zcz0v*R|Q?A$2D`_(965imbF+Z4sP{p18395$)%!RM|`8}?!~w1Myje9)eK`IZ|h9S z4+)7=kcW1O06tJT$yoK(*@Sr2n+;snD zJ(25PaqIqveXAIjMtdF9M)*Vl#`tnLM&MJ7-wAXhjTkZ*z)3uVQ+%wQ#!-y(H_5x? z3=3%*3#3Yvy@Csl!*MzlqwII^U4ryDFOKiwEuKL~;YOhy^Y}h~Kp1Y2y9-M29zqJQ zNO2!g_!M+;!i>eX9l?JxR~qH}s|wlzwKs6rM=od$@y{@G02}ruJ6*`$h==!euHtYq z(z%Qm;}PFQA{eSHqbD9|xEKlfIX@~f`}~cAzP=XUDqfhD+~HgI|0bm)bp@RD<%nk) zEq!sS&q$c%f!y{cISkWL$%=5kv>D%V?4aEX#5YHe7Wo!5h_T6vv4~d@{j82dL^6Xi z(Y1-@Wv;%83X#2v*O-D=nMBv{HeSciSX(!7-N8G_V#yGpw~4opJ07i4#HgBdE#$a( zw-NOpG8(cv-@=caxX2hZ!{2xhO%Ck;#>f+`O*HYxc*g~uwZ;cJ#SVl|r~B40p7{i4 z_?@|nmw{DiobJ6#*J|_{a(C&WoUWI22kiul*vm2w(AGBQMK>+jPupaf?{bg8yLgW? zFLUmFr+)lnAWfe1C2@=k2(0X5u=S z=l>upv?p9zg*_q3C&O22WN-M3HF79?wMHhxUy`IW-7Sqc3xe55148^YBf_zp0qjRB zACqk?iN~1m?KsaSSL;|o&Sm1mN%BT`{)3?S7X`ie37H=Jlu-n8!i%31=3hDEEob~S Qe#@00xxd37a2xIa1?*P`4FCWD literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/html/HTMLFilter.class b/target/classes/com/muyu/common/core/utils/html/HTMLFilter.class new file mode 100644 index 0000000000000000000000000000000000000000..afc89bba6866562517dd01753b7ed84e07c73d6f GIT binary patch literal 13885 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 Vq`m`M1Z&`jD_T?=)V5I0{{gKP>7M`q literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/ip/IpUtils.class b/target/classes/com/muyu/common/core/utils/ip/IpUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..4fe1e170a198c9c36650ab8db202433514e3145c GIT binary patch literal 6726 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 bvj$v)qw;?_Oz?gT@4sb6#6QU`3;+5r{(cY3 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.class b/target/classes/com/muyu/common/core/utils/poi/ExcelHandlerAdapter.class new file mode 100644 index 0000000000000000000000000000000000000000..46727c6e53bcd72f711824659db36b8febe97bad GIT binary patch literal 299 zcmaKou};H442J(JB>^Tz9-&>Z)HPy2h>D>SLx&Db*NaKh-o=rVLoo7M3_Ji2g}BnC zs;VybC)=|B-#@=!-vI7#nPXruaS|xRk4OoEG$|=l>}%gqD>Xg7JN8euDLw0bY1^JP z$I#$Js( C!d(9V literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/poi/ExcelUtil.class b/target/classes/com/muyu/common/core/utils/poi/ExcelUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..fdb0ab7a1d2bdf7980706e46bf0ff0426fe9f0d9 GIT binary patch literal 39722 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

2Z%ZiPMAXOsn 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/reflect/ReflectUtils.class b/target/classes/com/muyu/common/core/utils/reflect/ReflectUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..17f400eb81f65343c11728cec31807fa313cc6a7 GIT binary patch literal 11066 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 Q39bur&BOAj97V++0WLonfB*mh literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/sign/Base64.class b/target/classes/com/muyu/common/core/utils/sign/Base64.class new file mode 100644 index 0000000000000000000000000000000000000000..145b4cdfcdc3fbc3edda364185460162055bec56 GIT binary patch literal 4504 zcmb_gYiu0V75?tb?#@1DcgJ?d*lU{vNQu26aS}TV#BVz$G1yMPc0vdbkG)I0$$D+p z>yU&7Qfh=$sg**dLR__Z&=R0jHPAu|QHoj>3aFG)A)u(J6xynhP${%3Bq8p1XV#ky zBx--umgkB!Sw9r08eBTu@CX=Nt?gEA%1UpkT{pBfF`O0f zG$zx@Y_ot`U9&-hSK!j&vC-Pm$(@t6Bu2;595RX8$!sz;Q9F^`lCEvHCK9oFA2j%N z1fUCqhHOz=YJ9{RO3MAR61+ z&W>>BL^d%h;IpLv;jwYX5UuY1e103c&LQfO8_}>-N3C?FCnpM{^tZS5b#{05uIXPZ zAi4yC9b@T2 zuwH7)1iYPHYu5HtD0v>Szpv~1{?5+coW$S^d)21?PC3KHg!FZ-=~ZWEXX#5_-?o~e zbVyYbRUKn-W;5KKOecCLM~4!berqU2Npbhsu$9_iWs;K530>Kd~s!1luD$xWJe^^p3E}9@U4m4xswqqy`p}|mW0yI<}%6gR6CvV&=$fnwPdqWVt1oV;W;3^b zw45QC=QGzVzjeP;f=(*3%ry~dt9rx7r{?p=EiLziO_ zp1XT*EX0|P%BMLhjz##8s<7#|RXRtH)CFy#2&bqt%H3vQDj=Rf*bLPV6mVhFqwUyp zmPm8&FpaZCexv2i`hlsSI6S+u((oR@AY~&o5=^Cty`Tpk|1<#+O(0QW?oih!E0X~b8P37*VVb0|1;23L2-gy^qkOw`iuwEEg z$9MX5C_^8rSXogFU=1WgrA#aZ>EV8Q z@Cw!wnu7GV!k!nT#SJ;?4K&y*Lb7UbtqoDSVlV>|EXx!Zce7v_0Rv4#5#B|@~)=|Y4w=8iuaZjpoh0b16IQz#PhSW4!Nly@+eLNm32MkR)VCcvJ!&4~hUVH?VO_kdCJ_!|-TB^Bf8k&04J0n)P)Yy5^ zK#hgeSh&hFa@4!ZMQCuv58NmxFN3dWY>hiqb<}bs>@d9) z*mZw>-lY@bnGj@%=L{jYA{LkTW& z*60seIX}WzFoXN?IQHSkT=5gmc#7Q9_$hy1#xr;i&*Gn)djiKq1V0m%__@_ zOR*Bqi)Oqadhsi9GhP(8;$<;{UyBT05qIG?;v0BX?8R@1C9jD`@H;Vs*ZC%SgDCK( zcoA>0I)5)d#M|Oy{6YK+e`M{wtGMwerKdX&YBUSSwE2xDvK; zr4eDzXDE^watZL%>O7_9W*>D~8J_(=Eder?S!fJ!lf`wUj5v6|$4EIChhK7jIb`T{} zNGeVU!R+DL4~$(@SO-z+D6F^<8O-U98&^`dEU#M@H|p~`PB#`C&HZw$HCp=V)hK^Z z+Gm^E78$&6z;^tB5ou5xBSzhW(gRgig`;9J56>Pq>TPY)oOan+S}rh}jm5-|u+d`F z4#+0jX?HU$M6fONGI?Q`EX`6Lr^!^8@zq|=Yh1>EO;oV4uH?(Ef)`U>@dZrrd`z-u z-OZWzuo?b3i}-$y-{Ap0%n$Gx7o*hEH8U5FOvtp5+V5#Jb~g*&5gVg87@{Z@gIP1U6=p> literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/sql/SqlUtil.class b/target/classes/com/muyu/common/core/utils/sql/SqlUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..9955e3dd4cb26b7c60a1047a4962cc999984fd24 GIT binary patch literal 1847 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 TdKiBLL_8}}-oPV#kHh~159t%7 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/utils/uuid/UUID$Holder.class b/target/classes/com/muyu/common/core/utils/uuid/UUID$Holder.class new file mode 100644 index 0000000000000000000000000000000000000000..f96cf7e95c78f45452a2e00aff1a0cfc06d926d3 GIT binary patch literal 600 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/validation/custom/IsSystemPayType.class b/target/classes/com/muyu/common/core/validation/custom/IsSystemPayType.class new file mode 100644 index 0000000000000000000000000000000000000000..da9635e8aa3047cd1586966608799b434366c0f3 GIT binary patch literal 887 zcma))OKVd>6oAj9k84}CtyXK*8tbC82E7Zxh4FzlDFmXHBz6;AOmD`^)O%;bJPLQI zAh;4mxd=SjeenbtI91ZI|&t9`s~6c=HUz;vH3u}9QKhCm_R`IK&d=)Ql`eb%|w zOkaQ8{rWcTy!-Lw)x%5O7f;c=+u82Ee4c*ZAut*$Y1?`)LvtX-N<_8B3}ba33Tmvv zB4(GC47i zYE~E?vvscdM#TD^WAXC?l@H9aK~=~M#vj3dvKab8Hdl^V%!G0O<>1vyxmqG{J{ztv zgDn0yqKp4P)?~zk1VOL%;9jG0w@hFm+odD}>uO*vr1QuenAeIF+9=9}YiQ#4;<479 zgut!pe=g^~)m-oGu2jWE0tANejNrl#;lg@w2&FM6X&6Vv1RRE3Ptio}5j;6KiiXK7 s!xS2)_mE?79Pa`Q!wd#I(FDTaB+SAoCo!0V({KiXvnbA^F@STw0EoB_)Bpeg literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/validation/custom/IsSystemYesNo.class b/target/classes/com/muyu/common/core/validation/custom/IsSystemYesNo.class new file mode 100644 index 0000000000000000000000000000000000000000..a4f34939c3f2d65d4a41f332f724b5f8785b3d79 GIT binary patch literal 881 zcma))&1(}u6u{r4A8T7b+FGquYpjRT8gvhOGFH$gg+Qz&i3JHgOgGPE>h4U~nJMg5 z5WEz7DSGqf%@63MSnv<T~HY(zy& zFD#xw?%#Ysl+)&Mpm>YHoh+t6fnV^*@cwD7bzO?7|7cy=$io#8P@2iV26#Jdo54)Y zN+UvC7g}rv*z220pY5x=Z;}lj`DiHm5dD#*z&EnFa)2R9(}>%c!Yh?>wZ!0hHe5qP zEd4g2^Z!8BR3N;VK&SR}wNZIoW-yoSQc|8xYrq!Kd16jXYgtKcA}(aw(Ae*#!`7pi z!BX`<7qf3I*SlM*qT)OQ1_N}4Xw?U3Ssge<(nu<47$wCRoQ7Oi(Io8|IypE?hI3hl qaWYOEBa?8R?g9+L6a~D{1cq=Crr}a5A=;*cWaK7_-KNWTPfa_Q0)o=&X%9J*KCJxPQQ3 z8%2+)!;x1yshD%k~bk%!RHLp*8{rCxB8><04RD4uJ)G)JHzy?814-} zNWxHQD>1^E|_oi&ZgHi}7dM zO3T+-+>>Tc^aiw$xpoqXL01^%;__qFzEdf~^Y*1iZZgzpnk;AeXX^|L(SPS-;1e$7 z%vKBWG$#aU>@!SvR9_358EX5}h*%~=+`8!McGEGvxQ_okfKr}2w8x;6WG0fYl>23i zV-=^;c;+hcfJEzogig<^LY`g~+1nIx@{D|K{TtX9I(WE4)?EWW?vf3Q1T0{YBIa~Y z))lwNSIE~kzQg}ahtc97FJ37U%3?~zJ=`w=m#_@4{(=BkO2AFZc7Vb9#xbrv{fgPM UsG}_fC8|gBIqrvel>5iO0cfBre*gdg literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/validation/custom/SystemYesNoValidator.class b/target/classes/com/muyu/common/core/validation/custom/SystemYesNoValidator.class new file mode 100644 index 0000000000000000000000000000000000000000..fa3876466167af397809e27a9e19aefb4f2025f6 GIT binary patch literal 1090 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 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/domain/BaseEntity$BaseEntityBuilder.class b/target/classes/com/muyu/common/core/web/domain/BaseEntity$BaseEntityBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..7e76ea62a8f652ee74ef8fcb18647e597f9e3ee6 GIT binary patch literal 3335 zcmbtW>r&fB6#f2@OLS zW*9x?FS%}V`&i#SIu$j^FkCcjL#{ClW^;!lNMR(2w1#WY7>YH=(k;K~>ol<(n}{p) zAH|VgcPwt$dWn1Di7gG;Tx?HEzG2pd%W%yT+^wA)a?=+K4xi z%8>Ac`GVn5HdpBfwV+%W*Kl3gpQ^cnOHpbn<_!&#xXF+XnN`Cgqeercd})~aV-gLv zPiwdpZ1)@W*7kQa+zGaaOtoEUeOJS*k{x!1#oaT-n%A&^MPfC$%Po%~69d`ijlwwH z&3hW&N0#BH#m_|9v1?pDH{=P;JjrcIyMD=b9@u4^w*7rdDD!fiIv7R{jANTi-=#x) z7zzZSw4vB3ALE2^R#+?06_=elZO>E;TkQDOk#MX0$P7Zmsd4j=yM|gv%!E8K=or@e z3kQbD$_3@k#yP-7Uz&^6a-muZ{MzqwQ+-A;1x7ce1jsPG?^DWI;?VF6I<9rwb|jYu zMGnJK;L{84N#XuvnffWOoq3eFyd|VRqxIIYO_@x(_9B#a0QGJ7jZT$;*;h1e!*MMx z$+TpHOY*{IxZb2^X?uIAUZ36ET(PVbk6hi2P&I*QHFwfI&${P&R`yO%Di87)?`MimWQ*F|7vh1RDW;iY=lk a!hS|$5Bszlr|&5|#X({ORUG0QO#cU1-Vk~K literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/domain/BaseEntity$BaseEntityBuilderImpl.class b/target/classes/com/muyu/common/core/web/domain/BaseEntity$BaseEntityBuilderImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..81b1c22b6255a3c7e5f55345a7d71b8eb657bba6 GIT binary patch literal 1228 zcmb_c%T60X5UgIWS$0`4kU$8}B;sIOh>et^4FUsEkSs1BOB~1cBpI|1w2vTu3MH3B z3KAcXkBZW>w(!9OVVTR+Ona)j+TF8%{{FrLu!DCF3=}MwE{d2S)H_k&1=)4x@g|5u zhFE%6vh8)FK&a4bh(sQRsY8f9@uepI?mrNQ`bUx;slFnJ=A^i!0i1ot=$Wqja^B$3>< zxxwB0r?M~<(|Pco$JXGd37CxhCczWICy$XBi`8GCAG|T}f>-@Bu!NVqy1ffnz#^Ya zJ@*{ZwlO=pGkPdiaq8B6mq703+tRy+m8v@J%QOnPW`$sF!22o?qlTQ iz3=7R;|f-DT*G>f7B(2?*}cKvi8rRrf0Tu{SpElN5kpu2 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/domain/BaseEntity.class b/target/classes/com/muyu/common/core/web/domain/BaseEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..7e2b55d4ca972417accfb055b6600c1dfe53efb1 GIT binary patch literal 7046 zcmc&(*?Sw+75`mZ(n#`HmJM+tlahouCEgIFta9uoPMq3F?4-663iK`u?vrE<1dI6ZkpK^^0v z_*-$`oG`a6|CB;%rov>9x6fqDSt>YGC=?ybp(yt}bV9=PtW|dG(u4V2`kb|}Qf5lA zs!Zu)oKG$lm}7<&ZglzQtztgASgfS;YxC4pUd>g?L6JEz^k~-3Em9%i-n<3RkW1-_X?5(Bk6miHS@; zpDEJ=k<+J+9GV+vbj@a$3YJqT(Z#m}PMIfk;Bto?NP@$oT-C0=3RTjmc;qyAp z-FiiWy^~c1vFVf3_l{4Un!8IOq$9rLM7Cg0SMu|A$vp^3qQwO(cgA8A@nAe;$XU*E z|AX$z&6N`x+&=3tMCcPw%WWIq!=`-|E8C9$Hg|ciUbQ;)@lEZnw|Z^WxBT`E+)XYi zIuGr?g6(duPQ#)@%`1#ofd7N7*Tr}#)7FBqA zOE5g@3Rqpu^U|{z&wim=q!^#onJ!IN1!KjnOumd?k+e*$4lxr@hps+6>|%Wn;uTxI zxkYDL+LffdM!j`COQ%b!$F;j`ext(rta)mPjsSx;JsD)tD6OU9)zYe#8bWK)^Exd- zRGYh$?phQ~y^KHAM89kFi2gKuYG!hZxl&EKZBMz9bEu$xr?KAJrrJDMn-c4-8QSK- znqu_&%NxD^T2ZH{Pg&ui_pCBAzMguI7Qce57N0FvN(-#G(jIiwdg>dbf#4f5ZI_)X zTM7abesZi>bjnW2TAi|;<>F$wBZ6n*coxqYcwU;M7ZiGHEq=CezPMti^-<`)>8Q2f z6id8ZJP~w_$EcM~ScS!$UG6`xX7cIj}=Dwl2gwzIZm z^**z06HdB&1AkJuxw+;`7kj_x8+e6P`${C4;Jt>yz-tQoHXUxGGc)kI!nNv+gLBQ~&6*PDTzJJbRhGe)b(P#RXyqK(-v1)hTS)Z30^_ci5L<^5%yT5Q;(q=nI07ely`DlBPNKw_ zsYOwS!&!w7m34VmoG0-CJm{@+ien2IBK-qY{k+R6YUO?e%<{{?oU2l-CYPsDAlaG1 z8nJpg!K@IY_xcb*yzGC1QnH(eIg0#9|4V4^A9xYTb#%+PeH}eAUbBu}GVWf-UKxAW zalMTD*D)aDV4ZQYFt8(F*htl|5quJ#sxwS5pROAA8N~2ee9kj$w`&#rfpE`8;l75#yc{!hXd)y4*1->jZmhTCA^BaIClXjZYLMR|AlWr)A4Jjw}rvXh6iXQ2OSghLkx-ayNf z2)AAwcpWWMgZ-CqqdO&V^YkEpGNGZj(3T3liOvf!hf<+SxZUR%&V(rzJ z|DtxDpZ?SyJc_T;wcC`5uQUC(pcilB8^pEptKz@$O+q1lCi@2-BNS%Q_&dHuD8ibw zj&Bn(_(DC4?+}WT@)*8LD2B)J2);)sj!Vq)-zU_DS6NISCuHKEIEp6-wc}qnh#wG2 zFhB0WlY}}{1lQn)gpzJ4x)VE$=zowf(DF9A4FM8S^)|6C82f)gZi}BYbyVRFj*>IN z5>Dc|%cTrILz9*M63;35)Th<7yg<1)rQb*n9|(=OA-FR+yvzWMCI>FS7`lX$_X&PD z6B0ryUkfAqcO0d$A7c8IcPmP_{GQJrm_+Gra(0q>DHJ0|3*Vt0{1GqX O)q^Sg8GpeWNc|5aIWSNF literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/domain/TreeEntity$TreeEntityBuilder.class b/target/classes/com/muyu/common/core/web/domain/TreeEntity$TreeEntityBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..f8fbcab320b3a6cdc1f1f0de06e626d5547d5e70 GIT binary patch literal 3373 zcmb_eZFAd15Pr_FrmXwi_*ke9Ow|83YbG!T8?)~%ctJeTFahO2@Q)wg>q%h4; zZkxSQZ*V#&k@8Z2J=mA6VAv#04ssiN6@#}K+W%>`m*pm#gmVwf)LhAy@krt*b@ zS{o8h;7^v?@d9EU?1 zL&ri(UPj!NVDmA1lu0WnC}N!<)sie?*cdBoDuuD39~qh$SVRmjt~VkYW>~U5&MR#y6ii>i>r3o0McMIB2PS zFjgtDqi{YbxAem(r7id&TB^y!>vHwp7(`Sn<7h{VsZZO>&(%d6_suY58s@-i^Ict@ zLqS>z-+gG6s@Cl`bivgbJYwjCq85l=`^(#dKDRd6otr`H4Q92Dl!whu%6>PK zlVKCvWCaGLW*FS6b~W4Pb{bDcNJqc{hJ|3_Uk4T<+fCzu;daE~xL~L8BSZFLRl3Z$ znMvNFCY7LOnxZ$|WJpTLD}ggo%XdcV=gvqS91M3H`7UWwTf;QHH)v&>Mn+?*_&3;} zBut@1Z}}N?Z~2hkimQN+@G;FkIkWO9%@~>djNqlY$27`qWs2*6AzgflH~*kn)aHt- z<=G^C#|aj)o}q8jy1VVq31tai#Gx#VgCaw8KFXK$Z53a|p)8MsA`@^v%02paJw9S< zDKB2zs8AddsN#V$?%*35X9#GIo_#t=z%@EK34D)6 RQr^XP(4_GPJjG8~`wvH5KWhL0 literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/domain/TreeEntity$TreeEntityBuilderImpl.class b/target/classes/com/muyu/common/core/web/domain/TreeEntity$TreeEntityBuilderImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..1b5c0be1e0dc2e1999bb8d3b52d2a844bf259e0b GIT binary patch literal 1618 zcmbtU%We}f6g{3yGM!-{ZJ|8MqdWp60d5(7r_K=T0grx0vF z0*MdcqY&3q3ojC?iL#k%-|;#3_}JIK|NQs`;29oyuuyYg`>3PA(4Qnx5EUmyK!YfW zDWoF!B*wusiMWh|<5Y+jaW3Zg`r!W(1Qa{={U!* z+a6X2&MN73Mjp=Nf`g`yRje^QUxw}=`VcbMnF!x7?6*5hX;Wl9rS77SOW0tjkClB4 z+Y1r*NYGv~6%5UxjKyIQjYWFQ$023bhslJ8Bc4h%*GW5nCo_h@^5V(Og{00opK7}u z@JwGe+HIAZ2GBA?eLIQ5J(6!@o);;3^m!>C`U{|Y3#^^Bs=O{cB;GqpigY4gN_E0b z(|p_S`A5#MawxL=Rg&cl{y`jzbT8ytCg{Z1%-VmAx-pYebsRjb@B|oVXH9m{snGL= zfz+9aR);6l92PxKK!YN^OJKN6vw$L_SnqxZ`$_`~SIR{y*~C@)`lkzU4VyHxRqt!? zV-2>tU+B;Okd{U=)tVal6t$Ao{R!tam3Ge}a8C(V_o?)CO<;6?gMSvduED!h{l*;d xdKIv$d~*)CN@a5FR_V?bZkO>6?v~NPJ&K#;ghj7(%XaCA9NeeO1GLe#-M{Vqqxk>; literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/domain/TreeEntity.class b/target/classes/com/muyu/common/core/web/domain/TreeEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..3daee9715d8f22fcbabd2d92a6e29e42dd965669 GIT binary patch literal 5462 zcmcIoZF5^!5q^#>=}Pid>^N}}g(OW=H#m}AK~o5o9n;uJh+Er9<1|fE3cZ#uwqjXw zrK^e@1AG( z?C#mKXRrVI?>GMh;3$5RMHjj)By1#+QYcg!E2Wk8m3E25N~6x9>6V^#=SvHX6{lJ+ zO*k$0MBS@;R}@lX)q2$%S2#8_y?MF8NX10ET3c|NqleC0NGoi+$K3=snvB|Pdxas3>7J^4?joZp%I^~VppARQnT%7fxGk^I zY{}H1OfiIq6dt-0FQ-;kYgr5-o2AlW8zZ<+A-CvyXJWo@A37AX(Dz;hK4jy=xL=_s z6cFG0*TA*+0)D{8NAOVtJ{|f#um&7>FZhqycu=gdsr*>ryG)GQ7{gJcXfjNOa8;dp zIvx6XIzDdWAskcKx#BFllZ|@C@gA>wOQc$!Q}5l7|V}{;Y7=K z3|f~7^>G^~aFSV2aq1_YX*)HAfw&!~=P$VxZ}iYbIohXeObIyU3bK{OBRFMYnpvjv zUniLn5cI5#(>O!bOHPY^E--m{=B7kymLe^;S#@gX-Da!Ws6RG!TtPj|Ee`^6-l?_S zBm*b^6w_|5x>$F-c9UxSJPkb@D~ykBs%}JwYvVa%-B3svJA0?Ab(cqC-ff<9=4<-c zH7c~$q0M~vnF(*H%8eVoZM}-trJZVCVf=p(>0qkDj_Eb_Tv-ilnz$p)V+9?`6SptH zkxLux(^@2)*1W07EDk(gcTyi1x8rxH!uKsa=WQk8bAx>({w)kPu zM>N1hrDaDP6C7KC*;Ex)6r(w+BZ217Or4;Cu8=FaFS^oR!x*V>F}~iKnh;$Bv8oYR z6l1Ls3YXIBJoSH49{8aeYwtL}04XFJ-jds7g^)ux7~ODNG(W~Lfaq590TH7&romjQ zeQ_OzwMB!%yH26kU}7AzP}Bza3q_3Foaa=QXPi~PUL?<)otinp3NXbQ+H_m(n#aNx zGd(jHS=rbaw7{6t|Y3dB&< zJsnlU`-8+0ItaGVVR+>w2=7tFzQ&%a*WKo1&1tpVmW7{fqMwVJ(vAJ8!q#Xy?D4in z28XbtQqrGx5Z=39cwa|h_NyI)53Coyr=u{N*ABu5*9#AI6lR0#M=I{K zy1z4@zfN5#VvFl^>2xU!OOY6n3XxApeaI&}REMp4nO+tosSe{t zU6@QoKbg3Md@F0iijWPJ%2Je1T*?b2K~2W0h;S~DV}k0@Wqu2p5U9UVPmWUW6brva zGI6c=XXIW*vin-`ZRBQ#8QMwxDi!b(hGOJrhxt=ZjQj;X`NS=3y$X9IpSXdC1H|ES zl90pYR6Z$~)GhR1MJ}Jrr(&RD*&?V|PUkHFrG1cYJNClw8H9BcZvB}7O9pvYY^I?$RK^vDDngRSB&$29cG5h|A&yv@T z2k<*wA(gIZ`&hO4}x|%}W1E{veUdyo((c9^wDAdKbG4nYlel%lJiXHkOx((kYUZ9Tn%} z<;pm3%2iP4c_+|iabC&SuTi7^Nx3woU+NnjV`k4BWk!@{_w8U-PH}kBq z)Zff*yoj&idHRvYH}G{*lIhQpmd!lK(*6Re1dd?_-z1e}LfnsUkxDTRJGrs4nX)zi zK=wU$771>RQrrzF^&VA3?_I(eKr#RX81@ozmJdtCcoA|v*9Ti`!4ba0gfEibAQDM+ zo}(ZG@uE(W@8G)}Qw-J+|33B-=`=(5Jw89iPx*F$$X7V~YC`^gmcwfthdBP65&8vw I#Z1rt2SO6i^8f$< literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/page/PageDomain.class b/target/classes/com/muyu/common/core/web/page/PageDomain.class new file mode 100644 index 0000000000000000000000000000000000000000..872c92a844cb7ebf75ef355c536204e6023086df GIT binary patch literal 2627 zcmaJ@?N%FA6y2A6OcI7dLrFy~Z7I+Yu%TL&8j6JgLK{dWd|0R-m*h4KOlIQD1Q-7C zHRK8WTU|w2{ow=nP%h8SOvnTVe{er$owM&g=j?OBKmWe_8^9CP6X-%nL0CluQHH() ze#EmnH>%m<-hn7P4AB|Q(41L@PDy(MCAFB9RTE?VhN&8vI7$2$lRHiSX*=wfL zOiT=)GsHEYk+!^9p_KO)G(!fsC#(%uFUf*g=K2=5Gaj>uJoQ*^b(a3dX%X%b(_;pM|sUiaRSKC)?=DIe(YX(gS2ZJ$xf zU*?w0_!dLA2PJDlH_ykt^|h(FvZo4=fycJ>sUz_%B@=RtyjR?2j**vl?4hsgzP{^Z z-)d6|nOyvK9Rak=WB`eh*|5rDNt0dN+a4tkvHBL&kuY}9j?`^WdC!*S!d zE&|MVefBLW`#yOPd9Ldv%@Mg6G#b0?4r5SP3`1CXo!hps73d73mx2r8tbnHH(EpoK zpSS_yF7t@iK)EFbz7-+9;_8uWFWtHE8O^U6m#dQLei|7RkM5WXi0 ZUHAc<_85KHqrZI|&@DlyL)2hm@IRE}BMJZj literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/page/TableDataInfo$TableDataInfoBuilder.class b/target/classes/com/muyu/common/core/web/page/TableDataInfo$TableDataInfoBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..fdead68cfa8cf5209a00ac3ea5c2aa3967f6b9a8 GIT binary patch literal 2827 zcmcImYfl?T6g|Vs#&v7zfPtpXqan@Oq}ilR+cXA};6SizQmI%(QKU#?vo#ymyJ&Zu zh=0?k@n#sHQN2(FDfQ7{`Rb z)GPT~nvQgv=Fjz4RznF)EZMHDRs=?k{PrZ0m`os*#z#mCJZyL^v(-Lmn>1RU%gMLQ zH&)%;mrcv8$+}}bmP(f0U%iE%)oR;zb}V0DTzN`50-~a^KS?8lDSP|la8+QoCHJh7=QgBzW~*IVfs(GGSNBeaHb@{axn(z9 zsoFjrpXrmdRI3$Nii}Gsj7z3!yVlcot8V#W2Z|l6on`3I%rl!^EDMB+e zm1NHK5*+MzNS>S-z2n@PQOTbfj8ZG-fzuIHGx}0dJQs~G`(Y!#vtxI3uNmdDgN4C7 z2b_+m?bz$?AMd%SeDS{kcVv&(bwv{}jZ=wb^zNSSMTan{yr{GZOcUX_aK{Btz*wr? z@7j+FdU0iNOCYu7wf%;*ZaXY2*`7*$OCt*;pIU+1@B(&(sa4NYf%4`4rloehogg!T zl@uP}VFHhI^;;EKIM!pkuf09XjATUxaa}f)=N}0C)}531Vg$M&-5tjY7OI}N*WNF7 ziH`m2+Ua>%W7!#U{YBUPI1=4Kiy=zVakgw_6_a?(qSzaVo>knyjIezziSOTXR~*yP1>Ata zRlaAZz?C5JB55?-Cf|>8P82R5arm9)AYhJ{wT=i-TUxp3g4SmmI`ZKr&ocNrrg+9V zd|y~R!pA43h=QWkAJc0JO`pLvQbc68XkCCAlWqP-cJT$LKI(kV{fYVKg+nIhkdZs2Lx-4oi;Kh46y<$xAn$tTI62=D z`Fs4pQRn{`ezi1HuAk){E&(6n$qn%69nCWyXXYM$Q4HsKEOAbfZ<(JG*0{>@ RJjwrc>zKq7l<^bh{{?|@zk>h( literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/page/TableDataInfo.class b/target/classes/com/muyu/common/core/web/page/TableDataInfo.class new file mode 100644 index 0000000000000000000000000000000000000000..7acf30eae4afa321e85306e141a94619969a8f73 GIT binary patch literal 3966 zcmb_f-BTM?6#re=O#)pCO$%+LwneFi08Op+ivUt+YlA?wP_%xvOW4Aeu#3s2wK_ia zMc;i;UwpGKbw+1wovAa9zSJ52Ccl1X?pql6AFd} z6ETI@xa+yWq(XaoXt@Ikbi~nVVGk^Y;awO~FatlZiwbI1)aiyq&`=)y|wIOP;$MsTqlK| zu+Wdg3WUJ1bjHS$G6;d0q2m0jPvoIk73RW-b97b}iQ z2jx#GbS%1So*h(5JlEUg&-l_(Zjxr=E4mOB&Ju%NR9VY%rb0s}uY1n*oQ2Bfic<>f zUg7Ha(pVh^QC&>_4_2$OBqpWa*_`$kUVhss=gL-mwhP-Hz2sgsX(4qMueR5auWTXVU76ZGmF>h~088hFw zl%GFG=SxnxQVd88M)S;!Y#W22twiAKP!yisS;H~nk;f!8ey#eG;*+hb_VGg2oTh$d zbe)TSrBravyVAYMhCASdw79~a1*aU$JJKpLo~M03CJp5T;i z!z4evqC=Y3EcsI*eTIBqsUgiY;zpXKTppYoUZ8S2VUX#bwH!a07&_yo^R z@w*M@x#FG4Z#gAeW!KF7i1>FT+Ut%S#%tt=YZSl*P^My=nR--TwXIyuNGvC5A z?hXHj#Mdy}?+yQo#QaF+0aD?T#FHcZeDRfRay7u!z&Fw2_ySkQ$Bfb6u_t9b!oIt( zMpMQE3{?-G7&9qyVl0+2MJDzL$-C%EnWUu|~{epI{mi9YX##?m0m-F{+ z_EQ^PWr1HIPa0(s?~pRE!twAfDHH2_7k-aaEG!hA&O1?|XdUlU#|O0i6!ydue`0SO zi7x9e^u>|ke?t9*Lz?X1tCYN1M@e~|Pbn=^Fl%n9`kJjazKnpk=}LW0WKY*DUuv~t z)lWIe$(5emxG^EfPap2dtq=4Z`*h&WXV)fVAsM(Pd&kF2SqrR*p5ePlq|6666>bsj za4S~ZBG}wI+#2agVnm}6((T0gYFL^kmT-+!8#-|jHk+=U^Xe2a7JR4qgQQTyS5G?8 zAwdbM3o!n{3owbQQhbl*$X5Rl$2vxvaC#A|iEK+X@+e4%R%=t}679>Z>=TRx3qggS z6Ax(-&0|TYM0?m5MY%nTg`*R}Uw%3fVWaC={1aYj?z#gzoN^`{LMJo$a{?z2_h+as zoOGE{4y8=5!EupEnJrqoH#BmZaq?K?vru~U2_>USMrVI`wHYBLjc?Y~yPVYHOXSZ` veu{E!xK1fet+7vp=$WI9YS4m3nhZicmHgDo1e2mn;h0qQr literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/web/page/TableSupport.class b/target/classes/com/muyu/common/core/web/page/TableSupport.class new file mode 100644 index 0000000000000000000000000000000000000000..3a4da38a6ee9f720ae6cf42fa56380c9924836fd GIT binary patch literal 1534 zcmah}?NZZF5IwhmX+sdGilT_32yH~-2YyjN+fuYr+S)*8@DG!gYYmeom?kJbfsdnq zfYBKrz=v|&n^MSVNB`VpH+#<6-MgEgzrOtdun1j71U(XZ74+c@!_bbgXK0pTH?&f1 zhu1xZGYh6|dP@vFiDXqmlp#@fnp)G}_ceNHIyOCAu6^J&ZP#dUtxU(V(=<$5h9t=Q z8PtD6){UCQb$@r)alI%87$m_|^qVpUF(hGFK^*58rn}Pko@uo-ox6J$_cnyVpftEw zHe930J?=70B?_mN>7Hxaja2e)my8P-k#JGLC5$o*pJMX1#~Xr4+A}Plm)bJAXETIK&>#pJbP2{}~rO>0}YD*V0ATQuad?)YwVJfOPJI|f23asHlNEtNb}nR3lD!hLlVraL*&5j|L-rhch>QMmbmoasqbCzO z>LJ+IK;jjh;xo{XRXUY+018+mD<)=wJOcbVAOlvuL)ttyMig!4zZe1Pj} ze3I-Tx#O5p<4JNH;Ixlqfca@<~=>LB0T`u_QQIz}c?o0a>rf7eVDWykU7P literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/xss/Xss.class b/target/classes/com/muyu/common/core/xss/Xss.class new file mode 100644 index 0000000000000000000000000000000000000000..a7ef1bf346b7e7affdd5a08c043adf93c967a40a GIT binary patch literal 819 zcmah{%}*0S6n|5o3)Bx#6cMoKfe%gGgNc`_Ni9nxDYV%x#H6QTJ8TALXPTK=;vP-( zrim9X#*263nMl;Te@8X_D~xZcu}x^?Fz>y2@ArQ1Bk#xWFW&&*A>4EzM_?gTu^T68 z;-V2NiApo~xiRijV;mSIFm*r=sVk_A+}hp&3#|ir0>!?UN~tWh9FxocOae~KjG+-D zFtfT=?ZX>Za~YKgO!v|2Y@a5=5}5BCz4`g-MfdYj=lHnu^25Y0fjK{smd9+D8@?x4e>!Yq_u2&F1iTwu8+rkHF&alz{4pSw!9%9`^)`v3!uW8G`a#Uht&0j*V<= zdR5egN^QFl_&b%L=HqVbWxtFN5A7oIomx>vNnKR}LRk6(vsdXf literal 0 HcmV?d00001 diff --git a/target/classes/com/muyu/common/core/xss/XssValidator.class b/target/classes/com/muyu/common/core/xss/XssValidator.class new file mode 100644 index 0000000000000000000000000000000000000000..04c5a557563ad4d9b36f1fb3b45c417b49b5a177 GIT binary patch literal 1593 zcmb7F%Tg0T6g{1XL&ES15Fm(x3giKd3O*A9h*~TXq)bE$U)6-EWFVQ~Ob>-s{)qm7 z8#Zo`a$&jlqbzSv5(pA3S)^~z?Y`&SSKs{l{rv}k2UrZk1Fr&~3O_C|bZ_xpu9dl2 z)Shl^=>@@XA!V3`NHch&u{8y44C94rMXNX;9E~=Ws!77qwLRO`UfT8=FB_X&RIN4y z83t3)*SYw7?A6=!n|OLAKL0UA%czzPLPdvyP8D6~W*BgJ9buF;OE2ns+A0@9w@e0w zIChM(&M+O#9DA1&mSGl?v6||%VNw!=RP>^cFe+RWO1i}`+l;YP;#N+7@91VhZ-JDp z84*$#0}2LJ3?b6O)%v|78rx0PdJq>eqTrH>%NS*tXqhzWxUJQKc`o;aV%QI<0NV`1 zXFE&i3a+TQifasNp=t_lnD(-$lo|S)%^G=HS1@s+ytM-f6IBsI+$DC4$MC2H0wsEz zTY_u5wE`Pd_ob?73yYY=QPoK$^gWS`5#ba?{eM;z!*V{GdAGWl&p&>)!Vo%LYK9J% zkGpIRHH2@ex=ErdW0?AiQ`yk1Jl~L=63SEyyu8LOLw?tlK2b6#y_1=ih4{OBlMH@} zRMIFrjb0o&v)dR>pEdf2AwmT@BT)?6IWtRn$O&H9&hnjlWGBj1d$!4Qg2vVv0y(2- za^YAMbGa%1=R-{WGr!WW#(=4}W|~qR%vBw$pg(cnc~A2cnUVJ~Ms4Z=LxO%0Ok;+m zMgz=)0DQEk*+uJh(r6?ZNq_ts*jM+;4O-3ZM| s1Q%HMBE9QWopp{-C2KIA_=$0fY4SLx)5!_e89ekCAtO&?-jxe~0GOGSg#Z8m literal 0 HcmV?d00001 diff --git a/target/cloud-common-core-3.6.3.jar b/target/cloud-common-core-3.6.3.jar new file mode 100644 index 0000000000000000000000000000000000000000..3f87f684ab3a84f269cb4f1b9c48ab294a5cdb3e GIT binary patch literal 146314 zcmbrm19+urvo@NfW81cE+qOHlZFFqgww-ir+w9orI34`?_Izi5GqeAh+2@>G*SgkP zN!<_YuBxY=dLu9O1sDt&Hfc%*42~6b&Vd81qztu$ z%&c>HqvEv;wbZ22wF9&w_y~o}^n?=q5)){dJ>}$t#O%G~=n@RAxD2QT^U=ZX0T95y zM)2D}b^bI^;Li~l+FJkD82|4Q|C-9bB&?m?o&QD*{`X>^^47LCzmxv+`k?$@qz!Ey zjDH9D^GNak3ZidgW9y{vWd4T^|BS}{E3~1ljiZykjnm)sjPo~GCu6t2gJS;`)X3Ia z-~9J0^ydL%{T0&K#@X8OZ$^vvmq0f|W4nJ?CgOhv>pMG{{Z04(ixv#@9sh2l{}(No zm|Oi_3q=1s3kzF=|9_Kkb~JYQn->0Z`%H|@P5*A+G5>1p|Db7q*`c$Oxz*q43;thq z_#4o`SpV;a`w!@U*rkrq{mmNxC8vKIxw+lnVE>XOzhUic&Ho1cm-_V^*umJu z%GmJl%)&p++wt#JtMUIQO8*P?=>(h{Y^|*RKrpR|995&n##{2P>^m94W8&2LKa`S$Nn;J2{pU%pW%idcIQ2mqiD1OR~bvz<@L z-$Ih#>(TE*0g+E{XGJVzYvpWhqwH>HOlxSR@93DNtRsh{0MCL`R+vA?jG6maK_pWOB#ImSgTATh;Y6C_ z(N;&dkMA!CJ?ImFQ{YSF4TJCMtCa&M1;?C5k|rB=*vm}Z5w8;!-^?G2bvhKCP}#nw z6M&O*DnEe$IZ8F81zBn8vAe2f10#Vr2d0kXeAOPAl5s564VfZf;o{=R`XOErP0Fm) zvUM=Jp-4(c|MTwrf;rHh!OsMTrd9Y3WZhZXKUti)#l{NVe%)?q_qO89q?gDFixzCA zy5NhNcn<>po^p7hQGYGf;j5$nthkKx8td4BunhiH616Ff!n!{Mv2RLrMXRWkoM!Yv z6jY-0z5D#iu$+y}*LYpE^nt6lkaoJk2&k z^t?9tp7cG=z{n%zL5@ze=Q1!%b^`iB)qRg>ISqBb&U8AD%!+I5(Aakh@oY&|tBx`3 zm1@KJ-h_L#l2u$PmEdxho<<}bOj(>Wwew*oJk*J%d+;w;-iWYMs~QEce!zvIY_obj zqZniPzlOKVWOz6*3UCh;Slm!6{A9Yzvgq&R-KKqU*-6k9RwzV^)m2t0D!CwN4hXIi z(v+dSgE0`UQcg+XS6pL=l;ZN22-`Q7-LWr!gZt0<;$K9;MG({+`y@)zCsFAC*F^ab zMUs?sl;-6>DMI`P4rn1l2_6o9fp5(IibM|t*9^CQb<=U`a_ju(?}W`VmZIVDv)mx)FL+ZXT||69O20S-AZiUQMs>140*= z%m|bdc!8WOP6U1M*t%0FIr~!3d()a_g@oY^0>aErd)NVr%{s$I$I)crXG6hx>%k4h zbk)@v#xb=FnQ-}PLU^?DC%%5)m1^YSu!42i(7w`34`!@1G%HjTr2~=FSa4XD9YSjJ zAH$iohDtFTtT|BA_0J&jO;HmkKcAvVbp*dx&6$B5L46D%I#}qmzri~K<56QLP zFAZjhyxl{>WC7*LHah_*Tl`Yaea2hD+8&;4NV`B)Vd6Zh-b4}4lNTdwDUvVJVzn|Z zy0{zPReg?*l5iAVrZnYgt|0d#zUdHMw{z@=eR|ddLpJ%0N6~n*?*MYH-QmcUc*~q# zFl9MOi!MzD9L-ibWjvC0yai1vi|tgEyMPgfsBF=AE(-Q=W%va`$vBiT*-6RZu`K1P zu1^O*z5cev#vJdwB0wCk55owYybsXc!2Bo{;W%ECf3z)oL&&k|PxNXi;^|HTFFaE3 zSDMDKQcUAfox5{?d#`ohC#<`r2ZdG%=wu_!JVZ%Q8HtH z*TQ?;izoa>5AtD@k^%152sz>(&3c=8l0vO#k0l8QNlE)?&_0}VYs1A$iQa9YV`%TO z)Db{+J#w`uWq@UkglzECRpc-)S;KOqfu5~b2}cs~dRIh`eAS+E+Klm>RC8B2_=$A0PRI@2IR%j*$zvT#m7P z8u2hvpY;6%AOpYzO50rOSRbu^ppcK7z3^-w1P=#9-{imPuC(*Ji?Rhf4OHCOkC9gh zmSGql9@2;&1=~^@gotHNy*k_30aWU&jUC<*?sd*dC&0c+W5eDhLHK;i_rXqZ&08Lf7argd0@sV!*`l`R3;RMFemO1G*vT*69xk>T>S3x{J7 zA9zoJfdD%DF*YrjimvDa=Quk8wYE1gvQd(WUFq$BRQdb|9vj!7StuPL3L-_pmyt$O zb$_A<;cZQVolPW-939(K+bteVpB8i0F_X^0W9hHMKQ7yru~f$cb-1daNKRrZ78Rd4 zL@(QLnD_dpk2k@Kewm`1T_zcTeFetky!7>#<3+V%MMr7pw&Mn5K#OK}UEQPP-5-1E z6JEPluGdgZiSmh!@Ao`@YAs7&i8vF_C!zJld^+i4LN}gOIL@w=&GC{o8RNE1aiTSn8Wc396w*9D1nYv6n!GzX7zG6=qI+kAIr z`-L$-IpcWY&5n#&b4pVY4BE!KRg~mqSNomiz4IijH9cf_yh_8Q=^Jh(RFP$$EmRp~ z|e1LnZSW?~klrt+a3b0tf)m`}v~& z-?G~AH(E!7kqMSJ1#qA%zqSxTd(V ztw&@uD5^dmMXeG?pSh$@Rnb%l>~D3>R8CTInR_UF<7Lcja5lf40CMkFK>mspz5XLG zt2Q4P=AHi%s-QuXpU?ffj2N2&KYr!N&wVs;-NoVdQdrim2U-tAIALqZy%>Q=8Y@H7 zIEI&%H{d@mCLY%Q2*zjVVDo7v8UJcA|2ttOq;F_uEcEa6*}s=GDPGEPo*sT!ZL)!Y zcxEo|VD+b!RM-zme~dl$sxV7as{~fEsQlD{Dk4`au;by~0cbE@05V>LeoBa59)s!1 zyY)9ql8e)$t1CW$9hmRby@>uixKT+r`v&4eJ+HV;Z<9%UY z{Z3l$BKQ|)wW2R^6{p$fj(na3^*RgMFY7LtPvSfTaW)-2lpFZeaSxdsN-5ygHO!>7 zEWeJ)6Ueh&eCf~6-dv(tTk_75NEyRZ@l{$E9rF zUrd{l{DamX)AWb}k72C9pU#-2oK;xKg~~M5r>21Pl{2chhps_2bmwvn2hH9upI)OxEHQ zvpb=oX?Yalm89>%Vo6EhfwnS3-h2=0e0Rnqgj0RA5no0fO?h!ZApC=$`Q!}oGA=|D zQh!zPlWKHg+l++wqw2Y=qOABCH>#7Z`jiqbGir-3|uyEfb}!PpwYh_l7Mp!GeKCfX?5B%Fg%clm&=Voi zJ*I{;lwD?p;&5RyaRcUiN^Ll$?!Dp2v0u8bI~iP&#in-}drhI9NKWChDdvj#6y=QV zYtbH(ws!3D^d}+&!7IZ=(u#D_D9+3hv8y)avkT!IzFsgTj~EgLao8_q8;#Jic#Q4%)N%(iX9Pi&dzD{mBFdFM z%*V_@*P-e{bZe-{@>-4}FiI>VDf=$(J0Gg2PYgxTzFMS&fKfyQB!ZdG$n0n3okgPiReaBLbV3qLsz#L!LFIJ8HN4h?~pbcj3I z+2IRi=%-gq23uC0WM1}TKYrs7B@;C<%v;*I13`3d>Ey*$oYHqp7h8vr15(ppwTG|# z@$Nd`$X7zHPWq`ZLs1Zh@fy>Zhw-|uVmjaYEM$=cDk4{4v`1#BIQK?WLe5Ajxtn9> z)$*4?FPd|5&m`^AWkM2&4i(5ScZznBn*%Ku?aHvey~@TG=KrFqartovF4@E$t#=f) z7Js;uVVT(_@X)n?wZ_!ADj4nW~Z1Y^VXAL2?7`mqGx*74Mm&lM{6UI)qVd%pv zZdUQtr-SRIT>0D#zU6JuYEMZ_px#WlJun$3;PCdTTYxQWmMkCW1=)*hILDuF`UdA( zJNn8WZ~uwlX&igG$08c7CxSy4XwNW-f`bk7KGPS(YTpgU>aZ2C*}*CxgF_e0_OKPi zCv&f+cl&S!#FJwS$o6Oj%+>5M^vkvG)HcZ8eDb2bJ2T}fdocPd;ts|)8o{ zKGRF^X+@L$g<&O3(3wYM)8>7%8#v_=OdId;_otw->63lrUsM^H6z`(*RX3*@E*0|L z<36&sXu+TizP9zufmD6J{5L68Yu2jb!D-b@FHmcI0!z;XVa6Av6U;8Om<3$zS*DL6 z-@t$H^=6oagMIwhRn~v9LJIM2Fjb!i-IC9{tG_(#{gXJH7UIV;SkN|wAFF7b=7r6vn}=U^lJuza80}$ZiYD>H!qv~UNJ|oE^Eogvec%n zDNozIM8}+Jp{3V8>wz?=m`;NemEeXhZuSAYh185cFMBNT03w_cdDYq-Ftse!E+!vc z9$fWaDf3X+%qCGbPYFd+)togLGplS0o-?XAVyNN9o@_mN9T&5CQ+Xvv+02Bp1dUOn zfjvJNnyF?c6X)fIq6*E4v)GdBQh9xA9@Pny5!wR^8PjYLAlZVm|ehRcVHhyh3%|h6_e(=K1{ik(NJZ7=%WpG-o*0qF~SjP1O7u!bDRPr4a~g z@Pvcbp%r~90j5Itah9?b7~{o`^a3+rTp%$koo+2x{>rV> zJTF4%tbfRnKU@ughHo*v>TDN-@~Hl5}miN+}2LN~U2hPi~&4BcFr8w-jmsRY;@ z5+;~l{XumLwnG=QMvLWPLYQJa+YxBmitx*HriS7?CaW#5O_plYS+F4%G(m^`cZ{Mw z-@&tV|EG#N^l2OQE!rj2g2t>S$C&wO)CDhv85VJx5tgvF>i#gWkvpVrTq}CE2IE>l z#(v>)h5A)5`ZW55_;eN)q->UB&1BP#i^@S-SZ$z6{RS66md^4EV=fp080sYls#Y)= z+jyD`1&ilo6Wt3+$j%PPEvQyl5lAB?x0i}dlGz!yI}k5^e? zQ^BGH6=x<}853|SE4Op#lB9&(u+V@5%S=#qQ>P<|e~ObLZ}_hn^oDkq^P{3)zeBcj zG4I?9VGfxrSmhNKfozt@Gq1!(UbrwDVI+|F4+nsAlR{>KHm72A78;8|vLA`r`Qo%J z_Rcf);~lL9$Oz6Da`TlV|3Gb?Glfx6Qv&xyTsEAm{w1fnlOk8xl$mR~bEKhCvU)FN zt)Qfp&}RKD`$&sXU(F>c!?WFrQ@>n0mplr;LfSx`21WEv8%W9vV?IC7!X+;VaS!Ds ze=^-i`W6!r-St$AL?Bxmm;-q^V+5%v%Ck3xz^kwEyf)Xh2be6z`woM~vbrICb6;`xaqJ*VaLJCus^Lp3~)7$*t&ZYx{$ydU*Kx*q zKMCpuG1`0qh}efF@1@z`$ub+9=Ukn>G8*y)6)uP~eB1`t2dMnCLx<9b{1lodiDfPJmZWI0R^uJ2E z{?hZ*Cgh9zG4OQpvsNa^n$-$Qzk|o>qSiX-LMZ;Kzb8i04expn(Ff>>0)h|bwK6d0 zi;qAbl>gVnYpI?Z@h6p?Ws+CWYb`_{tS23aZm?JXKtAAi^}ZYcU(z3MJz&JIAlGV$ zyx^}scLA2?tMZd-!t1)8IK7B&?w`V+M7@6Pso`@XV3u&WF@f3s z*s0(@sq0Fxqo1m~Ay*bXH-a5j=6*wOTo=aQ?47gJ&@?C;R6L~0TV%gQnz%CRf*m_} zQ+<8Ym417wE`Dx|UYa4r94y)v!>krfekV?N&%YQ0q7-wOe5`hl!#7b9Y4HBUfZ3O6KfIyc5o;ky;rEQ8BGu);I0gLhHAlx}DuQ(yac+QWp$ zWt45a2_87;R{NX@;40jt+3UaiHJ`9vMqci#xPAcrQM(}N!DL20wF~LY`1iV&rED!XuZPS7=Sg>9-3Je>jJ+0>@(t)4R&CpaUz%PeHGvOhL3DhT zRCDrx?_dPvtl86f4CB_iN@hJ>HJ-<>jiU|6sZQ@TJicx(u-ag4a2=rWB2ASlPCV=+ z+;Wx(!Oh%^#aica)uy>T`yJ)T%oMW$7Oj>nQD7h+3_xIzZ|hvPy2emIR6$cCiW8{G z2>Q)EXXn+)N760O7(76EZVXy0la@dgSDY%bGa>Kr9!Ajkl7vN)lZ?QiNy0zG`IZ*L zZITwV-iQi}kX+z}2nLLx_nP^y@c6eJ%J+}dYuJaTJpDHWv~DEDB8%v{Xp884juQym%{s1)`&q(@pKJdM^CQ9`$bgAu^@{QXi>O7+4=@gT`B z*w@jigApKz1P-9Id1(wm8@OH7Y6)T$5pm?QJziz@rWavHe82WKMp~D&+b(RM{z4f; zUPG60qD7}!kn|`jU6v_+WPVN7J6!i}H&j@=T znpzg0_m^|`Qm;2|gAmK;^zcuhbw^wQa_hG_1cjTK66h6fhe-!vku_yC$|#*z5wg1Y zKCn3*Ui&eWmyAwf`y7SymgOcDkZ&g@^a6=KHF?N$HroB|SZuM*Vxv*kJMJd?Xn$mg zTzENP+h^A8_LC(n|L+;{TMF(oU-W5);fFug3+u2DUjWvEO|@PCU{k*h1clUMm#DM5 zB(b!KV!1B1J1oWHiF;AYieoC&c46A?UDJpvRfEJz`#tx zCeIqEcOZWaM1XR(d778PIE1chi3|Vv2pvTxH;m~7N+fMERQaTt*h{UjuP7mE+$P`F z+YjZgIxv?`#u&WVv!6qnZ0W#zGm$r0`{Vs=;FekO$QHdlg2)g7O>uZ^cmHIBuSv|` z&=E&R5*CNoPV}MB7H(qNCf6{_zf*5T6FC!Unv6}1(>Vip7V0*Y&);y#lu;_mt7yP%k}zs~&nlP^vslHZ>B z)P>9coh}#~Iy;ye$}qRH-JOcu8@ zl-?@DIfz?O7lphPPDM=X27n7`Z}qKq0ENx;@Ym7As)^6*>jO@Y6!u+h@I9@jcjK)7 z3in=4YnojX{o8X|C{*wiRGHCDxW2co?@~~&-jIex@j-nht9h~6?6=4aHeaTopk#}iO#Qv-Bn&x8eZ7D@twTYvpMjE=L)Vpc z)_MuOrBf(!ApOlOS=i71w^QltU1&I~OCzw*+WD>Dsb!gH_-+MF!hgK#@5B_$*Wi-sSzqO_K-0WwwY9Q2v8G1lNpH*zy?ZtJ$^R zlR-dBXbYBC+LL5J4dPeZYnWXvm@XNwmfns=!^Ik6&m80ilU(m>lyj+zpMF*)s4(2b z>mL_>Vs6q@{kj)TA5ecZ7dBr6m_p0v{kcU>@$(b%NZYVUZ- zbA)qweYyNNOy*~aT{=SWRa8I-fh71PRj&2Y!MBv}Zn!TDLsD%nRRE$}NA*NLSp>2@b31qM! z6}o(B+8o;Ez*$7?@UIi0erW8=HSR=;oQNPdV)Hww+YhLD)^Zf$Jfby?y~D4?4R>&M zp^P|yBL!hBrF!aQ$pNC@+xsjB*i_vD7?ZQ3>>`kP_V{o1an5NPtdNo!6?$RwSef+D zJdw@ICz?L~#9qzTHV6IBt%3dAntx9FE8ANBk2FeB+@vfJ!>1WX2}DtV@4nAxV+i&J z;6o%vmjK7q2wSd4CO>c1Y|rgVB13}X^@B6c6p8Y~EtyZ7TK_dp_P}4Ykdt$sHOP01`hIcVS6{*OsKI zK$fDm*svBAz%BHmY)3Q!TQ+HNP=3mxZbJUEc^hF<_bY6$K&dEqtl;)f*_7>@uw&Uk zj8!x4HeWX*aaAWV`u$VIFj3^@pc^+Xcze&aBY_AkjN6pdMsJCR#M6(otf4VxXCp6r z(mld)-x#SIHa#@+HNe;&(!*H5e(qW5`hkdUcCqhw5m3l=Zk9%B;`Sxb6PJ7eJTgkE zqs7Jf0W9^a)4-L60o(=O?3b3n{>UYM>{BPr&&`VYtlnn$M=q&+R;vEl)F!Sg&dVbQ zFBi+tDFOqEaPP$hz+YEpLX(&cIh7pBm$IeFGof3}r_G#RtLt*?1;OnIalCWstxjeo zq-DLmeP~+Z)suFAyuOMEV=2?l0UQLI*9r?Inlk$!d%-N2z~hxK^(w3!(~s4N*)Oab zC1zyQz$EmU)y>+JRb5J`4Hhm&-$)8Ve`c;ixyoI!Ne`IVO$ynahaa&wO_=qwQ(QSE zknyS+FyGL$pwc(x^MI1~lXYgLgND%SP((qzyDQan`gb8^_%)4{5mDZ7`e&PEaLlxd zeWHoDz#ru*dZZ;7qkgufRh&f&swp%@2LZfSSE;}k+f}eRpQ$Kpsve^PQGrV*g-`JW zUGh^FSW#MgR#P>*QvuGVve`UJk2|~p{sSrTi1e;~-V}g0t%`>Jp9h!pJ*}`JG8h;2*8wY! z%tl`fc~MZ-2GluWa%nsg9?FwNtv^8isHooXc%h!3=~+9Nzc>2-RokrepRnLx-^FdM zjEo)rU4Wr#t%Rh8>_Z!7g^21;zG8t=Wh)`CRCOh+8Lk-%K#5>!EtOK+cWNT!%BFmN zR%6~R$yK0k%K3IE?W6tHLb&QI@>Y(DBJO}?Qy!>_ZLnN$!n@0m;vT4 zXLFuX?qgS-#lCgF#@ICV2HSWSziF=nwXZOK^5|4iEWe_Vq!^l$ztVvP$=9-~#hXEt|Z2GlIHho7bEyzTolNLD8aPu^&7 zY^9bt+ooGnCOt(bACy)CT$#@o>)--_zz8WS#OZ-5ilq?OUny4|-4Tq^^8!d_`9uMzkW1Bi%5{3)#bdfPsAPIfa*k^`5VGrH|N~^+TJcLf{nUV%(fpMoTh$BjdIvZfYK`FU* z+_+9o`;IJ&PpXkQcf%_?UqklxAO@l@+pppO+MQH*ge5B_LkUQA{M}FWR@!w-Gx5M% zf!3v!W=5ZvP{|2`2$Of_hCmdgnGHEy#Wbv14W`3nY6EE{u5HPR&KGVR5p&)iL#=i8 z)k4qV4L)xN7b2HT*=C zdb*)JdSbvChs~(s*lAMIc`-3RmEU1W(*e5sFdb+p8LD!o{T@mykEbuBL%*_Jyfi!i zAa%ZJ?Au9lp{;+T1Gi~wavx-%z3=Kz^p)L@E46`e2JE>TQiqLc%8n{Nq3p(rk<0n{ zr7d7kO^WKO@A>YBQGLC^Y-d;pV2$!V%+$@yKYNsSHqI&xCRn-Y%9HGpjMv@nLOVSY z+O?%KD&;9D6b*ys2Ep64@Dbcb91;r~Y|#^GYo1djOxNaOv-V8xv5HC?r%boNrC%iL ze{AkSykl_=wxj9T3iJ6l{nV4*4!Opws1qNp*? zU(0woEuOl6aXH+u%yMOU;Cz(Imv8Rx=VQ^TYBRnqCpmL+-IwJcz}N-&B@cFmx)5Ii zx80EGoExa?a~t1#gG%Dw+JyDPtHMOj{6#opTajRtZD@L?(wr1w@A~DRqogUI$v(gE^k* zTB=}}b06wSl=Vc#6`2j5@DqMLc*dw(M*Qb6QlHK69C?1yCX!er&=NNAXmI<7mObb> zA73S5k28dmK^|&~4-X|_Al9GT4sSV;GO=GHu-(X@IVx{x64;)gV0i=%;R?wd>0*7N zkzBKPJ0&C?8z7i8Ap9b#ZBGPVoncB`Hhkcw^BsNB4>G-}`hi z-uM!pkSwF=F|jYLlfwU49JE8$R@C9 zOSn^9kcZpdgqu5M%A(i9jx6V@;xadke{Z6n+Xb zncxTm^KRb+Dt#7FKv{^2IXLXQjx?H-SP?Ua$U5O(s8cVkL%*aivdw6sP?rWdhKT?> zbd-AsKKe?1etQ)`Fl#<-I~Vj#lGMHP3Hp+(sQ)e|=Zpjsl=e@D#2iD?Z?wU^zDI~6 zK&}gtp6E{AZHm?LoNX8-g7+4!A-|wEMY`x5nv;$k#$!A7+v2t6j8n_vsu2ff>TS-| zwUe>SrTT|JMKB$8;|!>RNtPrBt$$cuTPu|guDjdVI1I~Q3DhcFVkY+OkIA?OB({%1 z#K2BTl-N!r7cCrxIY@q$T}l|U;<=p?LAxItTS^-2_z+ZPsfu8d7t_?pLO+`>FxTp2 ziac(zn+a5w>2Z89G5=L$aJ*2FZO_xeprsN1JO(f1v`Ne1UT0QnxN-^=MTLD*386;2 zO50S_46>eF?ex@J9^2v48x?dz7>+R^8mq9(GEVO_YNH_&TsaT|5(Jcs-)0X4A$h7SrBdKH^DHfE^OYXJL=e)@OD&+qI@qUY(iZp)tA}^wR zY;CTJ^#Kdw@&lOH;%A^m08zS|i+=;I2V9LsHls?IjDFkomls1OIK z@N1%wgNO?;!&{O2fMxw5cMR9`u))=kF=_HGBNmS9ajNskYx>tl$9VUL>n#)j%u@;& zEa+Eq)EhBGFeIOJVFLxsT}qz(_B>&j57B;faLn+ynOpqc1AnbxFx}u`>t_!`1d)iB zmNE}QD|)wY>lqnZ0Ro^)$#SpHj3xpmBQX{2afEBN)`7=TVypo8=SqK-^LUwJSN)W>!rkG(Z| z=C8Y9t{;u5`yD`2?0EZ;ING|RhpmI4@hH)MGV`Q@2Px~AsvnI9br1@@-PftBtK0c5B3I#c`r9vnTXSQ%~0PP{=@ReC=^I@5ZfpSZnfL?h6ziY&Q- zMtCd}Z2)KMZM2uGOi+m61a<91U5pg1n;k@I_BTyTnaG2VLZXQJ;X+GP)8tSqO82vBN-jqavN09s|J1y+UY6B}O{| zO5~FyHOH~fiXq^XUfdE2oE4g;%Hl_hvAH3&+Jr-p!-vg%~ro~Gd!fF3%YF(!_Qhl=mKdJN3aI0Jd$T4 zzAb@#gp*jyvG z?f4gpd+n$ZHnx^|$?c;cw=oQf)>6VSH2E&(?V@@zvu2U)ta0%VixdkD~h z;4ZVJyFPkXZhp-6iw#ZT5@dtn`7l1*OwKNEOXBh=Wpi_SeN1^CD*k+^7>$ej36?Sy zv&s3eGZ!_>bTlN}&ER2v{XSAsV4E!k>m$q=+2y_ao;6R(Mv{gh5)7i@FeKZ_%E|t; zb7_2vC{RTw38s>Hwy`=2!w@F6-Nx;)OL$UUk{)V=dYI`#Q|>}c$Yb$+K9XO_+w@}J z$zr0+crjr@H2&orI>P~{=1e`*pi;h20!OOE9SMyBdP#H~c`P1xe%3W1s*8!+8>78= z$=oEBf=0)J8#lt#-PNNVq-5q|7P-M%g2Q5gBS@4%7XieLxpNUZ zgsFNCqn4V@v4kk!k2WjM8_>8%@}W#SiK%eYeX{ld0n%sJnC!x<;A;Wu-cOZK-2GXl zWq>dnZ=HoPr?c-gO;X=!6Z*M%tl?~72_!Q~sYSmTh<3AEwr&{jJ|vSRSGK9M)@5Z9Fy`r?#xI8!tu@dM-=;ayH4rtO|6B^`Tf!-u<>gmu zs;p#6YMh1}LcED>7ueHa9&fZHDIu}$-qU7IhHl%I!XZ;YRd z`Btav9gW3yYY)}J)7oDn^i|$DYQ0?KarmJuxn%-t4wS@bU>6KyYjOfLVg`7#RM@k> zysMH2bv*^W)_g#T;b;F)u-9_Gtv0G~10pOKi%`|=u2k@_^z^SMwp>tE9a)S4uxtUC z$jc`OE#~r}jQ;TIiv5&t5KRZYeCWwXMpLA8;-HAUmf z7#|PhL*C4cf##R|z)%Px)Nj1}IUojnvR6gSr*?faaXmgbVAu800m6bU&!faOcJVn5 z@i_<(o5v^5j{Y9vu~UeJkw~vVQn4ZZ>arPPW|kBL*WKJMD6*{IzK_4Ygs7dI6eGCJ z3BDBRc}^NwlCXAVsHOEDPUvYx6x=1s5auD;S@n$(V9FeSg*aZOIi?BR6Bkfh<*z}S zxs@h_N}rZqmL}O>zVq2wItSuvz+#->jb@{6UZiN?&?*`{9MQ8(*JE8KC;4Cl8kzD1 zae24QD*lLGf2rx2^0kiH=|)P9<&+8yp{cC57s3|`6f0yIm_XJC>XPsaUZvNA#)zAr6pZz1|JeLEQXA zapQLpkZCbRB@XCORpAUr>2dLveF=KMcrV<&KqwL&b}pPh*hgR<2r4}oToKLKTu8g+t&LIn3yhxNLuG1bB6H92-I}M468?0 zML45h0jJcfkH>^<#!%AGqQbblTp2rE$#q&x&6`o^QdMh78h7*Vg;fsRTMP5bYw)wa zjdLj9lN9o^7&}I|9hl49e?N@8udfT(VqKDC`D&<|<^<GMRJ9 zh*o01Ei?;)oY*$DK|yFvUcoLs&zcTdBqOyWq_0WgviF%H&y^B|;>~9vJ8&W5Elv}5 zZ$v&aJIuGx4!mV{G-W5!=jb13<+uDkkW9F}_eN*pi9fo1y}k71ZhE|{7wEGP6wUTM zp%}$J`x$#;Fe_1qKTY4h$k{cn@el$KZ~E=h$@o2_^~u(pCdm0-v46L(-RJUh6Q*za zHR<~~O=UZP+$4Q-#66lNNtXht2AA%o=bEO~)jSJnS5Znr`2|wkE-iNm-~5CCk0A;# z3U5`f*Q>~rllB>^l;vfUOl;Qyo7zuILtGzU<88$Cr;Y%+#GfCP3}}kXa|0xVMCW-< zLMOFT3xqb@Y*`uZNPGbG>jL(oT;%Bsu;FvK)kTi99U7ZGa1B)D%)=%s5#5?7FN{%$ zQ6$*1PRU~y7C=cXtoNL9xoYWmCj;aXc-ACKvqPp4A^=14&BQwWB>BNvsxV)Px1`MX zUV+50`S>tJr&-u*^5vuTUO|&GW-b-&{SBb&0Ni{OQ4{zF*t2PM>8C7qEZxVAOB_bwbJA zQC{EuKhFwgsr^z@RzZHJy~V9&hz7b5mjOc$b^>ln6hJ~i7Rm!Bsw!-T+C_0f0+3NsQD<%IDDUU$8*PzkXBY-U ziy);So=U({J_?lVQLzqMq(53CsoCA#=_(IKi~Ql`}GOTH|jn}~A17-eglJs_{G^W_f@;0kMXqQ00WAZ=|!K{aJx zLuyhIhzZPP!+POabs>%s@Vp;PDdG%_O6Cx)W$mZJmHi%L-M>9_yfcT<(}!!9JJBoQ%GnuqAo&5 z^+||N7+YK_LPf0##*!QNZ6x4enL=vLiz z4D6~1U4B4V)bNTxwU9F$s?Ao$w!ks)OB8{p${!8jHm=X~_Pr4=YLVvnIkye7!)!$6 zhRU87N#BpZd=G;oEu}@~K-Eh=N4jA)%Vp26Ghv~<(sO9iXp)OCJ~797*rwZSR9?G* zer99wus_`x?XK2N$Lzj-tW$cN%GA5KtqeWFS7=EnlKFmP0tZ!qo_Q=FE{r~)mjp*f zoRnTLlTk$CabCM3kffKS9E3R;E%4Lg^e$<1-SkR_ciO4kic%hD*%S*jt&qBC)i|Ud z)&gi4frA