From be9c2993980fa2b34a775db49b7900016c00baf6 Mon Sep 17 00:00:00 2001 From: haown <454902499@qq.com> Date: Wed, 24 Dec 2025 14:56:35 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BE=E5=BA=A6=E5=A4=96=E5=91=BC=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=9B=9E=E8=B0=83=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/compiler.xml | 19 + .idea/encodings.xml | 7 + .idea/jarRepositories.xml | 20 + .idea/misc.xml | 14 + .idea/uiDesigner.xml | 124 ++++++ .idea/vcs.xml | 6 + pom.xml | 236 +++++++++++ .../org/example/AIOBCallbackApplication.java | 32 ++ .../ability/shiro/CNFilterFactoryBean.java | 28 ++ .../org/example/ability/shiro/ShiroRealm.java | 69 +++ .../example/ability/shiro/aop/JwtFilter.java | 49 +++ .../example/ability/shiro/jwt/JwtToken.java | 33 ++ .../example/ability/shiro/jwt/JwtUtils.java | 98 +++++ .../aspect/mybatis/QueryInterceptor.java | 75 ++++ .../aspect/mybatis/UpdateInterceptor.java | 79 ++++ .../org/example/aspect/utils/InjectUtils.java | 98 +++++ .../java/org/example/config/CorsConfig.java | 39 ++ .../org/example/config/MultipartConfig.java | 27 ++ .../org/example/config/MybatisConfig.java | 37 ++ .../org/example/config/ScheduledConfig.java | 76 ++++ .../java/org/example/config/ShiroConfig.java | 118 ++++++ .../org/example/config/SwaggerConfig.java | 65 +++ .../example/config/jackson/JacksonConfig.java | 21 + .../jackson/XssEscapeJsonDeserializer.java | 15 + .../controller/AIOBCallbackController.java | 43 ++ .../java/org/example/core/annon/Dict.java | 21 + .../java/org/example/core/api/ApiError.java | 65 +++ .../java/org/example/core/api/ApiRest.java | 62 +++ .../core/api/controller/BaseController.java | 164 +++++++ .../org/example/core/api/dto/BaseDTO.java | 14 + .../example/core/api/dto/BaseIdReqDTO.java | 27 ++ .../example/core/api/dto/BaseIdRespDTO.java | 25 ++ .../example/core/api/dto/BaseIdsReqDTO.java | 24 ++ .../example/core/api/dto/BaseStateReqDTO.java | 30 ++ .../example/core/api/dto/PagingReqDTO.java | 47 ++ .../example/core/api/dto/PagingRespDTO.java | 30 ++ .../example/core/api/utils/JsonConverter.java | 47 ++ .../org/example/core/domain/AjaxResult.java | 165 +++++++ .../org/example/core/enums/CommonState.java | 19 + .../core/enums/ConfirmRefundStatusEnum.java | 29 ++ .../core/enums/GooodsOrderStatusEnum.java | 69 +++ .../java/org/example/core/enums/OpenType.java | 18 + .../org/example/core/enums/PayTypeEnum.java | 30 ++ .../example/core/enums/RefundStatusEnum.java | 41 ++ .../core/enums/WeChatTradeStateEnum.java | 52 +++ .../core/exception/ServiceException.java | 51 +++ .../exception/ServiceExceptionHandler.java | 50 +++ .../org/example/core/utils/BeanMapper.java | 58 +++ .../org/example/core/utils/CronUtils.java | 31 ++ .../org/example/core/utils/DateUtils.java | 103 +++++ .../java/org/example/core/utils/IpUtils.java | 65 +++ .../org/example/core/utils/Reflections.java | 323 ++++++++++++++ .../org/example/core/utils/SpringUtils.java | 32 ++ .../org/example/core/utils/StringUtils.java | 39 ++ .../example/core/utils/excel/ExportExcel.java | 401 ++++++++++++++++++ .../example/core/utils/excel/ImportExcel.java | 302 +++++++++++++ .../utils/excel/annotation/ExcelField.java | 59 +++ .../core/utils/excel/fieldtype/ListType.java | 55 +++ .../org/example/core/utils/file/Md5Util.java | 37 ++ .../core/utils/jackson/JsonHelper.java | 116 +++++ .../core/utils/jackson/MyDateFormat.java | 36 ++ .../org/example/dto/TaskCallbackDataDto.java | 169 ++++++++ .../java/org/example/dto/TaskCallbackDto.java | 22 + .../example/entity/AIOBCallbackEntity.java | 49 +++ .../example/mapper/AIOBCallbackMapper.java | 8 + .../example/service/IAIOBCallbackService.java | 16 + .../service/impl/AIOBCallbackServiceImpl.java | 39 ++ src/main/resources/application-dev.yml | 36 ++ src/main/resources/application-local.yml | 93 ++++ src/main/resources/application.yml | 33 ++ .../resources/mapper/AIOBCallbackMapper.xml | 20 + target/classes/application-dev.yml | 36 ++ target/classes/application-local.yml | 93 ++++ target/classes/application.yml | 33 ++ target/classes/mapper/AIOBCallbackMapper.xml | 20 + .../org/example/AIOBCallbackApplication.class | Bin 0 -> 2143 bytes .../ability/shiro/CNFilterFactoryBean.class | Bin 0 -> 1363 bytes .../example/ability/shiro/ShiroRealm.class | Bin 0 -> 2129 bytes .../example/ability/shiro/aop/JwtFilter.class | Bin 0 -> 1528 bytes .../example/ability/shiro/jwt/JwtToken.class | Bin 0 -> 1801 bytes .../example/ability/shiro/jwt/JwtUtils.class | Bin 0 -> 3396 bytes .../aspect/mybatis/QueryInterceptor.class | Bin 0 -> 3627 bytes .../aspect/mybatis/UpdateInterceptor.class | Bin 0 -> 3329 bytes .../example/aspect/utils/InjectUtils.class | Bin 0 -> 3160 bytes .../org/example/config/CorsConfig.class | Bin 0 -> 1850 bytes .../org/example/config/MultipartConfig.class | Bin 0 -> 1048 bytes .../org/example/config/MybatisConfig.class | Bin 0 -> 1127 bytes .../org/example/config/ScheduledConfig.class | Bin 0 -> 4156 bytes .../org/example/config/ShiroConfig.class | Bin 0 -> 4708 bytes .../org/example/config/SwaggerConfig.class | Bin 0 -> 3128 bytes .../config/jackson/JacksonConfig.class | Bin 0 -> 1009 bytes .../jackson/XssEscapeJsonDeserializer.class | Bin 0 -> 1380 bytes .../controller/AIOBCallbackController.class | Bin 0 -> 2099 bytes .../classes/org/example/core/annon/Dict.class | Bin 0 -> 503 bytes .../org/example/core/api/ApiError.class | Bin 0 -> 3692 bytes .../org/example/core/api/ApiRest.class | Bin 0 -> 3872 bytes .../core/api/controller/BaseController.class | Bin 0 -> 4101 bytes .../org/example/core/api/dto/BaseDTO.class | Bin 0 -> 875 bytes .../example/core/api/dto/BaseIdReqDTO.class | Bin 0 -> 2199 bytes .../example/core/api/dto/BaseIdRespDTO.class | Bin 0 -> 1815 bytes .../example/core/api/dto/BaseIdsReqDTO.class | Bin 0 -> 2534 bytes .../core/api/dto/BaseStateReqDTO.class | Bin 0 -> 2813 bytes .../example/core/api/dto/PagingReqDTO.class | Bin 0 -> 4792 bytes .../example/core/api/dto/PagingRespDTO.class | Bin 0 -> 801 bytes .../core/api/utils/JsonConverter.class | Bin 0 -> 1968 bytes .../org/example/core/domain/AjaxResult.class | Bin 0 -> 2704 bytes .../org/example/core/enums/CommonState.class | Bin 0 -> 371 bytes .../core/enums/ConfirmRefundStatusEnum.class | Bin 0 -> 1413 bytes .../core/enums/GooodsOrderStatusEnum.class | Bin 0 -> 1891 bytes .../org/example/core/enums/OpenType.class | Bin 0 -> 364 bytes .../org/example/core/enums/PayTypeEnum.class | Bin 0 -> 1326 bytes .../example/core/enums/RefundStatusEnum.class | Bin 0 -> 1473 bytes .../core/enums/WeChatTradeStateEnum.class | Bin 0 -> 1670 bytes .../core/exception/ServiceException.class | Bin 0 -> 2844 bytes .../exception/ServiceExceptionHandler.class | Bin 0 -> 1523 bytes .../org/example/core/utils/BeanMapper.class | Bin 0 -> 2718 bytes .../org/example/core/utils/CronUtils.class | Bin 0 -> 819 bytes .../org/example/core/utils/DateUtils.class | Bin 0 -> 2178 bytes .../org/example/core/utils/IpUtils.class | Bin 0 -> 1284 bytes .../org/example/core/utils/Reflections.class | Bin 0 -> 10091 bytes .../org/example/core/utils/SpringUtils.class | Bin 0 -> 1449 bytes .../org/example/core/utils/StringUtils.class | Bin 0 -> 1609 bytes .../core/utils/excel/ExportExcel$1.class | Bin 0 -> 1281 bytes .../core/utils/excel/ExportExcel.class | Bin 0 -> 14903 bytes .../core/utils/excel/ImportExcel$1.class | Bin 0 -> 1291 bytes .../core/utils/excel/ImportExcel.class | Bin 0 -> 10692 bytes .../utils/excel/annotation/ExcelField.class | Bin 0 -> 778 bytes .../core/utils/excel/fieldtype/ListType.class | Bin 0 -> 1940 bytes .../org/example/core/utils/file/Md5Util.class | Bin 0 -> 1353 bytes .../core/utils/jackson/JsonHelper.class | Bin 0 -> 4607 bytes .../core/utils/jackson/MyDateFormat.class | Bin 0 -> 1083 bytes .../org/example/dto/TaskCallbackDataDto.class | Bin 0 -> 18013 bytes .../org/example/dto/TaskCallbackDto.class | Bin 0 -> 2135 bytes .../example/entity/AIOBCallbackEntity.class | Bin 0 -> 4395 bytes .../example/mapper/AIOBCallbackMapper.class | Bin 0 -> 322 bytes .../service/IAIOBCallbackService.class | Bin 0 -> 509 bytes .../impl/AIOBCallbackServiceImpl.class | Bin 0 -> 2153 bytes 138 files changed, 4840 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/compiler.xml create mode 100644 .idea/encodings.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/org/example/AIOBCallbackApplication.java create mode 100644 src/main/java/org/example/ability/shiro/CNFilterFactoryBean.java create mode 100644 src/main/java/org/example/ability/shiro/ShiroRealm.java create mode 100644 src/main/java/org/example/ability/shiro/aop/JwtFilter.java create mode 100644 src/main/java/org/example/ability/shiro/jwt/JwtToken.java create mode 100644 src/main/java/org/example/ability/shiro/jwt/JwtUtils.java create mode 100644 src/main/java/org/example/aspect/mybatis/QueryInterceptor.java create mode 100644 src/main/java/org/example/aspect/mybatis/UpdateInterceptor.java create mode 100644 src/main/java/org/example/aspect/utils/InjectUtils.java create mode 100644 src/main/java/org/example/config/CorsConfig.java create mode 100644 src/main/java/org/example/config/MultipartConfig.java create mode 100644 src/main/java/org/example/config/MybatisConfig.java create mode 100644 src/main/java/org/example/config/ScheduledConfig.java create mode 100644 src/main/java/org/example/config/ShiroConfig.java create mode 100644 src/main/java/org/example/config/SwaggerConfig.java create mode 100644 src/main/java/org/example/config/jackson/JacksonConfig.java create mode 100644 src/main/java/org/example/config/jackson/XssEscapeJsonDeserializer.java create mode 100644 src/main/java/org/example/controller/AIOBCallbackController.java create mode 100644 src/main/java/org/example/core/annon/Dict.java create mode 100644 src/main/java/org/example/core/api/ApiError.java create mode 100644 src/main/java/org/example/core/api/ApiRest.java create mode 100644 src/main/java/org/example/core/api/controller/BaseController.java create mode 100644 src/main/java/org/example/core/api/dto/BaseDTO.java create mode 100644 src/main/java/org/example/core/api/dto/BaseIdReqDTO.java create mode 100644 src/main/java/org/example/core/api/dto/BaseIdRespDTO.java create mode 100644 src/main/java/org/example/core/api/dto/BaseIdsReqDTO.java create mode 100644 src/main/java/org/example/core/api/dto/BaseStateReqDTO.java create mode 100644 src/main/java/org/example/core/api/dto/PagingReqDTO.java create mode 100644 src/main/java/org/example/core/api/dto/PagingRespDTO.java create mode 100644 src/main/java/org/example/core/api/utils/JsonConverter.java create mode 100644 src/main/java/org/example/core/domain/AjaxResult.java create mode 100644 src/main/java/org/example/core/enums/CommonState.java create mode 100644 src/main/java/org/example/core/enums/ConfirmRefundStatusEnum.java create mode 100644 src/main/java/org/example/core/enums/GooodsOrderStatusEnum.java create mode 100644 src/main/java/org/example/core/enums/OpenType.java create mode 100644 src/main/java/org/example/core/enums/PayTypeEnum.java create mode 100644 src/main/java/org/example/core/enums/RefundStatusEnum.java create mode 100644 src/main/java/org/example/core/enums/WeChatTradeStateEnum.java create mode 100644 src/main/java/org/example/core/exception/ServiceException.java create mode 100644 src/main/java/org/example/core/exception/ServiceExceptionHandler.java create mode 100644 src/main/java/org/example/core/utils/BeanMapper.java create mode 100644 src/main/java/org/example/core/utils/CronUtils.java create mode 100644 src/main/java/org/example/core/utils/DateUtils.java create mode 100644 src/main/java/org/example/core/utils/IpUtils.java create mode 100644 src/main/java/org/example/core/utils/Reflections.java create mode 100644 src/main/java/org/example/core/utils/SpringUtils.java create mode 100644 src/main/java/org/example/core/utils/StringUtils.java create mode 100644 src/main/java/org/example/core/utils/excel/ExportExcel.java create mode 100644 src/main/java/org/example/core/utils/excel/ImportExcel.java create mode 100644 src/main/java/org/example/core/utils/excel/annotation/ExcelField.java create mode 100644 src/main/java/org/example/core/utils/excel/fieldtype/ListType.java create mode 100644 src/main/java/org/example/core/utils/file/Md5Util.java create mode 100644 src/main/java/org/example/core/utils/jackson/JsonHelper.java create mode 100644 src/main/java/org/example/core/utils/jackson/MyDateFormat.java create mode 100644 src/main/java/org/example/dto/TaskCallbackDataDto.java create mode 100644 src/main/java/org/example/dto/TaskCallbackDto.java create mode 100644 src/main/java/org/example/entity/AIOBCallbackEntity.java create mode 100644 src/main/java/org/example/mapper/AIOBCallbackMapper.java create mode 100644 src/main/java/org/example/service/IAIOBCallbackService.java create mode 100644 src/main/java/org/example/service/impl/AIOBCallbackServiceImpl.java create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-local.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/mapper/AIOBCallbackMapper.xml create mode 100644 target/classes/application-dev.yml create mode 100644 target/classes/application-local.yml create mode 100644 target/classes/application.yml create mode 100644 target/classes/mapper/AIOBCallbackMapper.xml create mode 100644 target/classes/org/example/AIOBCallbackApplication.class create mode 100644 target/classes/org/example/ability/shiro/CNFilterFactoryBean.class create mode 100644 target/classes/org/example/ability/shiro/ShiroRealm.class create mode 100644 target/classes/org/example/ability/shiro/aop/JwtFilter.class create mode 100644 target/classes/org/example/ability/shiro/jwt/JwtToken.class create mode 100644 target/classes/org/example/ability/shiro/jwt/JwtUtils.class create mode 100644 target/classes/org/example/aspect/mybatis/QueryInterceptor.class create mode 100644 target/classes/org/example/aspect/mybatis/UpdateInterceptor.class create mode 100644 target/classes/org/example/aspect/utils/InjectUtils.class create mode 100644 target/classes/org/example/config/CorsConfig.class create mode 100644 target/classes/org/example/config/MultipartConfig.class create mode 100644 target/classes/org/example/config/MybatisConfig.class create mode 100644 target/classes/org/example/config/ScheduledConfig.class create mode 100644 target/classes/org/example/config/ShiroConfig.class create mode 100644 target/classes/org/example/config/SwaggerConfig.class create mode 100644 target/classes/org/example/config/jackson/JacksonConfig.class create mode 100644 target/classes/org/example/config/jackson/XssEscapeJsonDeserializer.class create mode 100644 target/classes/org/example/controller/AIOBCallbackController.class create mode 100644 target/classes/org/example/core/annon/Dict.class create mode 100644 target/classes/org/example/core/api/ApiError.class create mode 100644 target/classes/org/example/core/api/ApiRest.class create mode 100644 target/classes/org/example/core/api/controller/BaseController.class create mode 100644 target/classes/org/example/core/api/dto/BaseDTO.class create mode 100644 target/classes/org/example/core/api/dto/BaseIdReqDTO.class create mode 100644 target/classes/org/example/core/api/dto/BaseIdRespDTO.class create mode 100644 target/classes/org/example/core/api/dto/BaseIdsReqDTO.class create mode 100644 target/classes/org/example/core/api/dto/BaseStateReqDTO.class create mode 100644 target/classes/org/example/core/api/dto/PagingReqDTO.class create mode 100644 target/classes/org/example/core/api/dto/PagingRespDTO.class create mode 100644 target/classes/org/example/core/api/utils/JsonConverter.class create mode 100644 target/classes/org/example/core/domain/AjaxResult.class create mode 100644 target/classes/org/example/core/enums/CommonState.class create mode 100644 target/classes/org/example/core/enums/ConfirmRefundStatusEnum.class create mode 100644 target/classes/org/example/core/enums/GooodsOrderStatusEnum.class create mode 100644 target/classes/org/example/core/enums/OpenType.class create mode 100644 target/classes/org/example/core/enums/PayTypeEnum.class create mode 100644 target/classes/org/example/core/enums/RefundStatusEnum.class create mode 100644 target/classes/org/example/core/enums/WeChatTradeStateEnum.class create mode 100644 target/classes/org/example/core/exception/ServiceException.class create mode 100644 target/classes/org/example/core/exception/ServiceExceptionHandler.class create mode 100644 target/classes/org/example/core/utils/BeanMapper.class create mode 100644 target/classes/org/example/core/utils/CronUtils.class create mode 100644 target/classes/org/example/core/utils/DateUtils.class create mode 100644 target/classes/org/example/core/utils/IpUtils.class create mode 100644 target/classes/org/example/core/utils/Reflections.class create mode 100644 target/classes/org/example/core/utils/SpringUtils.class create mode 100644 target/classes/org/example/core/utils/StringUtils.class create mode 100644 target/classes/org/example/core/utils/excel/ExportExcel$1.class create mode 100644 target/classes/org/example/core/utils/excel/ExportExcel.class create mode 100644 target/classes/org/example/core/utils/excel/ImportExcel$1.class create mode 100644 target/classes/org/example/core/utils/excel/ImportExcel.class create mode 100644 target/classes/org/example/core/utils/excel/annotation/ExcelField.class create mode 100644 target/classes/org/example/core/utils/excel/fieldtype/ListType.class create mode 100644 target/classes/org/example/core/utils/file/Md5Util.class create mode 100644 target/classes/org/example/core/utils/jackson/JsonHelper.class create mode 100644 target/classes/org/example/core/utils/jackson/MyDateFormat.class create mode 100644 target/classes/org/example/dto/TaskCallbackDataDto.class create mode 100644 target/classes/org/example/dto/TaskCallbackDto.class create mode 100644 target/classes/org/example/entity/AIOBCallbackEntity.class create mode 100644 target/classes/org/example/mapper/AIOBCallbackMapper.class create mode 100644 target/classes/org/example/service/IAIOBCallbackService.class create mode 100644 target/classes/org/example/service/impl/AIOBCallbackServiceImpl.class 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..ac56891 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ 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/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..712ab9d --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..132404b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ 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..677e4c7 --- /dev/null +++ b/pom.xml @@ -0,0 +1,236 @@ + + + 4.0.0 + + org.example + aiobcallback + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + 2.0.24 + 3.7.0 + 4.1.1 + 2.9.2 + 5.5.1 + 3.8 + 8.0.11 + 3.4.1 + 1.18.4 + 3.0.11.RELEASE + 2.1.1.RELEASE + 3.9 + 2.17.2 + exam-admin + 0.4.4 + + + + org.springframework.boot + spring-boot-starter-parent + 2.5.14 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.aspectj + aspectjweaver + 1.9.5 + + + + com.alibaba + fastjson + ${fastjson.version} + + + + net.sf.dozer + dozer + ${dozer.version} + + + commons-collections + commons-collections + + + org.slf4j + slf4j-api + + + + + + com.baomidou + mybatis-plus + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + mysql + mysql-connector-java + ${mysql.driver.version} + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + org.dom4j + dom4j + 2.1.1 + + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + org.slf4j + slf4j-api + + + + + + com.github.xiaoymin + swagger-bootstrap-ui + 1.9.3 + + + org.apache.commons + commons-compress + 1.27.1 + + + + org.apache.poi + poi + ${poi.version} + + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + org.apache.poi + poi-ooxml-schemas + ${poi.version} + + + + + com.auth0 + java-jwt + 3.7.0 + + + + + org.apache.shiro + shiro-spring-boot-starter + 1.8.0 + + + + javax.servlet + javax.servlet-api + 4.0.1 + + + + javax.validation + validation-api + 2.0.1.Final + + + + + com.alibaba + druid-spring-boot-starter + 1.2.6 + + + + commons-io + commons-io + 2.11.0 + + + + + org.apache.commons + commons-pool2 + 2.11.1 + + + + + + ${project.name} + compile + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.1.RELEASE + + + + repackage + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + UTF-8 + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + false + + + + + \ No newline at end of file diff --git a/src/main/java/org/example/AIOBCallbackApplication.java b/src/main/java/org/example/AIOBCallbackApplication.java new file mode 100644 index 0000000..1e7def9 --- /dev/null +++ b/src/main/java/org/example/AIOBCallbackApplication.java @@ -0,0 +1,32 @@ +package org.example; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; + +@Slf4j +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class}) +public class AIOBCallbackApplication { + public static void main(String[] args) throws UnknownHostException { + ConfigurableApplicationContext application = SpringApplication.run(AIOBCallbackApplication.class, args); + Environment env = application.getEnvironment(); + String ip = InetAddress.getLocalHost().getHostAddress(); + String port = env.getProperty("server.port"); + String path = env.getProperty("server.servlet.context-path"); + + // 未配置默认空白 + if(path == null){ + path = ""; + } + + + log.info("\n----------------------------------------------------------\n\t" + + "百度外呼回调接口启动成功\n\t" + + "----------------------------------------------------------"); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/ability/shiro/CNFilterFactoryBean.java b/src/main/java/org/example/ability/shiro/CNFilterFactoryBean.java new file mode 100644 index 0000000..ce146c9 --- /dev/null +++ b/src/main/java/org/example/ability/shiro/CNFilterFactoryBean.java @@ -0,0 +1,28 @@ +package org.example.ability.shiro; + +import java.util.Map; +import javax.servlet.Filter; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.filter.InvalidRequestFilter; +import org.apache.shiro.web.filter.mgt.DefaultFilter; +import org.apache.shiro.web.filter.mgt.FilterChainManager; + +/** + * 自定义过滤器,用于处理中文URL问题 + * 如:下载文件中包含中文会返回400错误,https://youdomain.com/upload/file/云帆考试系统用户手册.pdf + * @author van + */ +public class CNFilterFactoryBean extends ShiroFilterFactoryBean { + + @Override + protected FilterChainManager createFilterChainManager() { + FilterChainManager manager = super.createFilterChainManager(); + // URL携带中文400,servletPath中文校验bug + Map filterMap = manager.getFilters(); + Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); + if (invalidRequestFilter instanceof InvalidRequestFilter) { + ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false); + } + return manager; + } +} diff --git a/src/main/java/org/example/ability/shiro/ShiroRealm.java b/src/main/java/org/example/ability/shiro/ShiroRealm.java new file mode 100644 index 0000000..82db3ec --- /dev/null +++ b/src/main/java/org/example/ability/shiro/ShiroRealm.java @@ -0,0 +1,69 @@ +package org.example.ability.shiro; + +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.example.ability.shiro.jwt.JwtToken; +import org.springframework.stereotype.Component; + +/** + * 用户登录鉴权和获取用户授权 + * @author bool + */ +@Component +@Slf4j +public class ShiroRealm extends AuthorizingRealm { + + @Override + public boolean supports(AuthenticationToken token) { + return token instanceof JwtToken; + } + + + /** + * 详细授权认证 + * @param principals + * @return + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); + + log.info("++++++++++校验详细权限完成"); + return info; + } + + /** + * 校验用户的账号密码是否正确 + * @param auth + * @return + * @throws AuthenticationException + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { + String token = (String) auth.getCredentials(); + if (token == null) { + throw new AuthenticationException("token为空!"); + } + + // 校验token有效性 + return new SimpleAuthenticationInfo(); + } + + /** + * 清除当前用户的权限认证缓存 + * @param principals + */ + @Override + public void clearCache(PrincipalCollection principals) { + super.clearCache(principals); + } + +} diff --git a/src/main/java/org/example/ability/shiro/aop/JwtFilter.java b/src/main/java/org/example/ability/shiro/aop/JwtFilter.java new file mode 100644 index 0000000..1702a32 --- /dev/null +++ b/src/main/java/org/example/ability/shiro/aop/JwtFilter.java @@ -0,0 +1,49 @@ +package org.example.ability.shiro.aop; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; +import org.example.aspect.utils.InjectUtils; + +/** + * 鉴权登录拦截器 + * @author bool + */ +@Slf4j +public class JwtFilter extends BasicHttpAuthenticationFilter { + + /** + * 执行登录认证 + * @param request + * @param response + * @param mappedValue + * @return + */ + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + try { + executeLogin(request, response); + return true; + } catch (Exception e) { + // 写出统一错误信息 + InjectUtils.restError((HttpServletResponse) response); + return false; + } + } + + + @Override + protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + //String token = httpServletRequest.getHeader(Constants.TOKEN); + // + //JwtToken jwtToken = new JwtToken(token); + //// 提交给realm进行登入,如果错误他会抛出异常并被捕获 + //getSubject(request, response).login(jwtToken); + // 如果没有抛出异常则代表登入成功,返回true + return true; + } +} diff --git a/src/main/java/org/example/ability/shiro/jwt/JwtToken.java b/src/main/java/org/example/ability/shiro/jwt/JwtToken.java new file mode 100644 index 0000000..7f857f4 --- /dev/null +++ b/src/main/java/org/example/ability/shiro/jwt/JwtToken.java @@ -0,0 +1,33 @@ +package org.example.ability.shiro.jwt; + +import lombok.Data; +import org.apache.shiro.authc.AuthenticationToken; + +/** + * @author bool + */ +@Data +public class JwtToken implements AuthenticationToken { + + private static final long serialVersionUID = 1L; + + /** + * JWT的字符token + */ + private String token; + + + public JwtToken(String token) { + this.token = token; + } + + @Override + public Object getPrincipal() { + return token; + } + + @Override + public Object getCredentials() { + return token; + } +} diff --git a/src/main/java/org/example/ability/shiro/jwt/JwtUtils.java b/src/main/java/org/example/ability/shiro/jwt/JwtUtils.java new file mode 100644 index 0000000..2b13276 --- /dev/null +++ b/src/main/java/org/example/ability/shiro/jwt/JwtUtils.java @@ -0,0 +1,98 @@ +package org.example.ability.shiro.jwt; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.DecodedJWT; +import java.util.Calendar; +import java.util.Date; +import org.example.core.utils.file.Md5Util; + +/** + * JWT工具类 + * @author bool + */ +public class JwtUtils { + + /** + * 有效期24小时 + */ + private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; + + + /** + * 校验是否正确 + * @param token + * @param username + * @return + */ + public static boolean verify(String token, String username) { + try { + // 根据密码生成JWT效验器 + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); + JWTVerifier verifier = JWT.require(algorithm) + .withClaim("username", username) + .build(); + // 效验TOKEN + verifier.verify(token); + return true; + } catch (Exception exception) { + return false; + } + } + + + + + + /** + * 从Token中解密获得用户名 + * @param token + * @return + */ + public static String getUsername(String token) { + try { + DecodedJWT jwt = JWT.decode(token); + return jwt.getClaim("username").asString(); + } catch (JWTDecodeException e) { + return null; + } + } + + /** + * 生成JWT Token字符串 + * @param username + * @return + */ + public static String sign(String username) { + Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); + // 附带username信息ExpiredJwtException + return JWT.create() + .withClaim("username", username) + .withExpiresAt(date).sign(algorithm); + + } + + /** + * 根据用户名和秘钥,生成一个新的秘钥,用于JWT加强一些安全性 + * @param userName + * @return + */ + private static String encryptSecret(String userName){ + + // 一个简单的登录规则,用户名+当前月份为加密串,意思每个月会变,要重新登录 + // 可自行修改此规则 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + StringBuffer sb = new StringBuffer(userName) + .append("&") + .append(cl.get(Calendar.MONTH)); + + // 获取MD5 + String secret = Md5Util.md5(sb.toString()); + + return Md5Util.md5(userName + "&" + secret); + } +} diff --git a/src/main/java/org/example/aspect/mybatis/QueryInterceptor.java b/src/main/java/org/example/aspect/mybatis/QueryInterceptor.java new file mode 100644 index 0000000..9199f1e --- /dev/null +++ b/src/main/java/org/example/aspect/mybatis/QueryInterceptor.java @@ -0,0 +1,75 @@ +package org.example.aspect.mybatis; + +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import java.sql.Connection; +import java.util.Properties; +import lombok.extern.log4j.Log4j2; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Plugin; +import org.apache.ibatis.plugin.Signature; +import org.apache.ibatis.reflection.DefaultReflectorFactory; +import org.apache.ibatis.reflection.MetaObject; +import org.apache.ibatis.reflection.SystemMetaObject; + +/** + * 查询拦截器,用于拦截处理通用的信息、如用户ID、多租户信息等; + * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确,分页计数大于实际数量等问题 + * @author bool + */ +@Log4j2 +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),}) +public class QueryInterceptor extends PaginationInterceptor implements Interceptor { + + /** + * 客户ID + */ + private static final String USER_FILTER = "{{userId}}"; + + + + @Override + public Object intercept(Invocation invocation) throws Throwable { + + StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); + MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); + MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); + + //sql语句类型 + SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); + + // 只过滤查询的 + if (SqlCommandType.SELECT == sqlCommandType) { + // 获得原始SQL + String sql = statementHandler.getBoundSql().getSql(); + + // 不处理 + if(!sql.contains(USER_FILTER)){ + return super.intercept(invocation); + } + // 处理SQL语句 + String outSql = ""; + // 设置SQL + metaObject.setValue("delegate.boundSql.sql", outSql); + // 再分页 + return super.intercept(invocation); + } + + return invocation.proceed(); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } + +} diff --git a/src/main/java/org/example/aspect/mybatis/UpdateInterceptor.java b/src/main/java/org/example/aspect/mybatis/UpdateInterceptor.java new file mode 100644 index 0000000..ace06a8 --- /dev/null +++ b/src/main/java/org/example/aspect/mybatis/UpdateInterceptor.java @@ -0,0 +1,79 @@ +package org.example.aspect.mybatis; + +import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; +import java.lang.reflect.Field; +import java.sql.Timestamp; +import java.util.Objects; +import java.util.Properties; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Plugin; +import org.apache.ibatis.plugin.Signature; + +/** + * 自动给创建时间个更新时间加值 + * @author bool + */ +@Intercepts(value = {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) +public class UpdateInterceptor extends AbstractSqlParserHandler implements Interceptor { + + /** + * 创建时间 + */ + private static final String CREATE_TIME = "createTime"; + /** + * 更新时间 + */ + private static final String UPDATE_TIME = "updateTime"; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; + // SQL操作命令 + SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); + // 获取新增或修改的对象参数 + Object parameter = invocation.getArgs()[1]; + // 获取对象中所有的私有成员变量(对应表字段) + Field[] declaredFields = parameter.getClass().getDeclaredFields(); + if (parameter.getClass().getSuperclass() != null) { + Field[] superField = parameter.getClass().getSuperclass().getDeclaredFields(); + declaredFields = ArrayUtils.addAll(declaredFields, superField); + } + + String fieldName = null; + for (Field field : declaredFields) { + fieldName = field.getName(); + if (Objects.equals(CREATE_TIME, fieldName)) { + if (SqlCommandType.INSERT.equals(sqlCommandType)) { + field.setAccessible(true); + field.set(parameter, new Timestamp(System.currentTimeMillis())); + } + } + if (Objects.equals(UPDATE_TIME, fieldName)) { + if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) { + field.setAccessible(true); + field.set(parameter, new Timestamp(System.currentTimeMillis())); + + } + } + } + return invocation.proceed(); + } + + @Override + public Object plugin(Object target) { + if (target instanceof Executor) { + return Plugin.wrap(target, this); + } + return target; + } + + @Override + public void setProperties(Properties properties) { + } +} diff --git a/src/main/java/org/example/aspect/utils/InjectUtils.java b/src/main/java/org/example/aspect/utils/InjectUtils.java new file mode 100644 index 0000000..8783757 --- /dev/null +++ b/src/main/java/org/example/aspect/utils/InjectUtils.java @@ -0,0 +1,98 @@ +package org.example.aspect.utils; + +import java.io.IOException; +import java.lang.reflect.Field; +import javax.servlet.http.HttpServletResponse; +import lombok.extern.log4j.Log4j2; +import org.example.core.api.ApiError; +import org.example.core.api.ApiRest; +import org.example.core.utils.jackson.JsonHelper; +import org.springframework.stereotype.Component; + +/** + * 注入工具类 + * @author bool + * @date 2019-07-17 09:32 + */ +@Log4j2 +@Component +public class InjectUtils { + + + + /** + * 给对象字段赋值 + * + * @param object 赋值的对象 + * @param value 值 + * @param fields 字段 + * @throws Exception 异常 + */ + public void setValue(Object object, Object value, String... fields) throws Exception { + + //设置同类的属性 + for (String fieldName : fields) { + + //获取当前 + Field field = this.getFiled(object.getClass(), fieldName); + if(field == null){ + continue; + } + + field.setAccessible(true); + field.set(object, value); + } + + } + + /** + * 获取字段名对应的字段 + * + * @param clazz 目标类 + * @param fieldName 字段名 + */ + private Field getFiled(Class clazz, String fieldName) { + + System.out.println("注入的类:"+clazz.toString()); + + //是否具有包含关系 + try { + //获取当前类的属性 + return clazz.getDeclaredField(fieldName); + }catch (Exception e){ + + log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); + + //如果为空且存在父类,则往上找 + if(clazz.getSuperclass()!=null){ + return this.getFiled(clazz.getSuperclass(), fieldName); + } + + return null; + } + } + + + /** + * 打印结果返回 + * @param response + * @throws IOException + */ + public static void restError(HttpServletResponse response) { + + try { + + //固定错误 + ApiRest apiRest = new ApiRest(ApiError.ERROR_10010002); + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + response.getWriter().write(JsonHelper.toJson(apiRest)); + response.getWriter().close(); + + }catch (IOException e){ + + } + + } + +} diff --git a/src/main/java/org/example/config/CorsConfig.java b/src/main/java/org/example/config/CorsConfig.java new file mode 100644 index 0000000..0987e8d --- /dev/null +++ b/src/main/java/org/example/config/CorsConfig.java @@ -0,0 +1,39 @@ +package org.example.config; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + + +/** + * 网关全局设置,允许跨域 + * @author bool + * @date 2019-08-13 17:28 + */ + +@Configuration +public class CorsConfig { + + @Bean + public FilterRegistrationBean corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + // 设置访问源地址 + config.addAllowedOriginPattern("*"); + // 设置访问源请求头 + config.addAllowedHeader("*"); + // 设置访问源请求方法 + config.addAllowedMethod("*"); + + source.registerCorsConfiguration("/**", config); + FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); + bean.setOrder(Ordered.HIGHEST_PRECEDENCE); + return bean; + } + +} diff --git a/src/main/java/org/example/config/MultipartConfig.java b/src/main/java/org/example/config/MultipartConfig.java new file mode 100644 index 0000000..6c4104c --- /dev/null +++ b/src/main/java/org/example/config/MultipartConfig.java @@ -0,0 +1,27 @@ +package org.example.config; + +import javax.servlet.MultipartConfigElement; +import org.springframework.boot.web.servlet.MultipartConfigFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.unit.DataSize; + +/** + * 文件上传配置 + * @author bool + * @date 2019-07-29 16:23 + */ +@Configuration +public class MultipartConfig { + + @Bean + public MultipartConfigElement multipartConfigElement() { + MultipartConfigFactory factory = new MultipartConfigFactory(); + // 单个数据大小 + factory.setMaxFileSize(DataSize.ofMegabytes(5000L)); + /// 总上传数据大小 + factory.setMaxRequestSize(DataSize.ofMegabytes(5000L)); + return factory.createMultipartConfig(); + } + +} diff --git a/src/main/java/org/example/config/MybatisConfig.java b/src/main/java/org/example/config/MybatisConfig.java new file mode 100644 index 0000000..41cf01d --- /dev/null +++ b/src/main/java/org/example/config/MybatisConfig.java @@ -0,0 +1,37 @@ +package org.example.config; + +import org.example.aspect.mybatis.QueryInterceptor; +import org.example.aspect.mybatis.UpdateInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Mybatis过滤器配置 + * 注意:必须按顺序进行配置,否则容易出现业务异常 + * @author bool + */ +@Configuration +@MapperScan(basePackages = "org.example.mapper") +public class MybatisConfig { + + /** + * 数据查询过滤器 + */ + @Bean + public QueryInterceptor queryInterceptor() { + QueryInterceptor query = new QueryInterceptor(); + query.setLimit(-1L); + return query; + } + + /** + * 插入数据过滤器 + */ + @Bean + public UpdateInterceptor updateInterceptor() { + return new UpdateInterceptor(); + } + + +} \ No newline at end of file diff --git a/src/main/java/org/example/config/ScheduledConfig.java b/src/main/java/org/example/config/ScheduledConfig.java new file mode 100644 index 0000000..498c4d6 --- /dev/null +++ b/src/main/java/org/example/config/ScheduledConfig.java @@ -0,0 +1,76 @@ +package org.example.config; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import lombok.extern.log4j.Log4j2; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +/** + * 任务调度配置 + * @author bool + */ +@Log4j2 +@Configuration +@EnableScheduling +@EnableAsync +public class ScheduledConfig implements SchedulingConfigurer, AsyncConfigurer { + + /** + * 定时任务使用的线程池 + * @return + */ + @Bean(destroyMethod = "shutdown", name = "taskScheduler") + public ThreadPoolTaskScheduler taskScheduler(){ + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(10); + scheduler.setThreadNamePrefix("task-"); + scheduler.setAwaitTerminationSeconds(600); + scheduler.setWaitForTasksToCompleteOnShutdown(true); + return scheduler; + } + + /** + * 异步任务执行线程池 + * @return + */ + @Bean(name = "asyncExecutor") + public ThreadPoolTaskExecutor asyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(10); + executor.setQueueCapacity(1000); + executor.setKeepAliveSeconds(600); + executor.setMaxPoolSize(20); + executor.setThreadNamePrefix("taskExecutor-"); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + + @Override + public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { + ThreadPoolTaskScheduler taskScheduler = taskScheduler(); + scheduledTaskRegistrar.setTaskScheduler(taskScheduler); + } + + @Override + public Executor getAsyncExecutor() { + return asyncExecutor(); + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + log.error("异步任务执行出现异常, message {}, emthod {}, params {}", throwable, method, objects); + }; + } + +} diff --git a/src/main/java/org/example/config/ShiroConfig.java b/src/main/java/org/example/config/ShiroConfig.java new file mode 100644 index 0000000..2607d32 --- /dev/null +++ b/src/main/java/org/example/config/ShiroConfig.java @@ -0,0 +1,118 @@ +package org.example.config; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.Filter; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; +import org.apache.shiro.mgt.DefaultSubjectDAO; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.example.ability.shiro.CNFilterFactoryBean; +import org.example.ability.shiro.ShiroRealm; +import org.example.ability.shiro.aop.JwtFilter; +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; + + +/** + * Shiro配置类 + * @author bool + */ +@Slf4j +@Configuration +public class ShiroConfig { + + /** + * Filter Chain定义说明 + * + * 1、一个URL可以配置多个Filter,使用逗号分隔 + * 2、当设置多个过滤器时,全部验证通过,才视为通过 + * 3、部分过滤器可指定参数,如perms,roles + */ + @Bean("shiroFilterFactoryBean") + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { + ShiroFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); + shiroFilterFactoryBean.setSecurityManager(securityManager); + // 拦截器 + Map map = new LinkedHashMap<>(); + + // 需要排除的一些接口 + map.put("/api/**", "anon"); + + map.put("/", "anon"); + map.put("/v2/**", "anon"); + map.put("/doc.html", "anon"); + map.put("/**/*.js", "anon"); + map.put("/**/*.css", "anon"); + map.put("/**/*.html", "anon"); + map.put("/**/*.svg", "anon"); + map.put("/**/*.pdf", "anon"); + map.put("/**/*.jpg", "anon"); + map.put("/**/*.png", "anon"); + map.put("/**/*.ico", "anon"); + + // 字体 + map.put("/**/*.ttf", "anon"); + map.put("/**/*.woff", "anon"); + map.put("/**/*.woff2", "anon"); + map.put("/druid/**", "anon"); + map.put("/swagger-ui.html", "anon"); + map.put("/swagger**/**", "anon"); + map.put("/webjars/**", "anon"); + + // 添加自己的过滤器并且取名为jwt + Map filterMap = new HashMap(1); + filterMap.put("jwt", new JwtFilter()); + shiroFilterFactoryBean.setFilters(filterMap); + map.put("/**", "jwt"); + + shiroFilterFactoryBean.setFilterChainDefinitionMap(map); + return shiroFilterFactoryBean; + } + + @Bean("securityManager") + public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + securityManager.setRealm(myRealm); + DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); + DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); + defaultSessionStorageEvaluator.setSessionStorageEnabled(false); + subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); + securityManager.setSubjectDAO(subjectDAO); + return securityManager; + } + + /** + * 下面的代码是添加注解支持 + * @return + */ + @Bean + @DependsOn("lifecycleBeanPostProcessor") + public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { + DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); + defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); + defaultAdvisorAutoProxyCreator.setUsePrefix(true); + defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor"); + return defaultAdvisorAutoProxyCreator; + } + + @Bean + public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } + + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); + advisor.setSecurityManager(securityManager); + return advisor; + } + +} diff --git a/src/main/java/org/example/config/SwaggerConfig.java b/src/main/java/org/example/config/SwaggerConfig.java new file mode 100644 index 0000000..c6ad186 --- /dev/null +++ b/src/main/java/org/example/config/SwaggerConfig.java @@ -0,0 +1,65 @@ +package org.example.config; + +import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; +import io.swagger.annotations.ApiOperation; +import java.util.Collections; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.service.Contact; +import springfox.documentation.service.SecurityScheme; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * Swagger配置 + * @author bool + * @date 2020/8/19 20:53 + */ +@Configuration +@EnableSwagger2 +@EnableSwaggerBootstrapUI +@ConfigurationProperties(prefix = "swagger") +public class SwaggerConfig { + + + @Bean + public Docket examApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .groupName("考试模块接口") + .select() + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + //.paths(PathSelectors.ant("/exam/api/**")) + .paths(PathSelectors.any()) + .build() + .securitySchemes(Collections.singletonList(securityScheme())); + } + + + + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("考试系统接口") + .description("考试系统接口") + .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) + .version("1.0.0") + .build(); + } + + + /** + * 授权头部 + * @return + */ + @Bean + SecurityScheme securityScheme() { + return new ApiKey("token", "token", "header"); + } + +} diff --git a/src/main/java/org/example/config/jackson/JacksonConfig.java b/src/main/java/org/example/config/jackson/JacksonConfig.java new file mode 100644 index 0000000..3b475fc --- /dev/null +++ b/src/main/java/org/example/config/jackson/JacksonConfig.java @@ -0,0 +1,21 @@ +package org.example.config.jackson; + +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * JSON序列化配置 + * @author van + */ +@Configuration +public class JacksonConfig { + + @Bean + public SimpleModule xssEscapeModule() { + SimpleModule module = new SimpleModule(); + // 注册反序列化器(处理输入) + module.addDeserializer(String.class, new XssEscapeJsonDeserializer()); + return module; + } +} diff --git a/src/main/java/org/example/config/jackson/XssEscapeJsonDeserializer.java b/src/main/java/org/example/config/jackson/XssEscapeJsonDeserializer.java new file mode 100644 index 0000000..50ccca3 --- /dev/null +++ b/src/main/java/org/example/config/jackson/XssEscapeJsonDeserializer.java @@ -0,0 +1,15 @@ +package org.example.config.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; +import org.owasp.encoder.Encode; + +public class XssEscapeJsonDeserializer extends JsonDeserializer { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getText(); // 获取原始字符串 + return Encode.forHtml(value); // 转义HTML特殊字符 + } +} \ No newline at end of file diff --git a/src/main/java/org/example/controller/AIOBCallbackController.java b/src/main/java/org/example/controller/AIOBCallbackController.java new file mode 100644 index 0000000..a7e5e34 --- /dev/null +++ b/src/main/java/org/example/controller/AIOBCallbackController.java @@ -0,0 +1,43 @@ +package org.example.controller; + +import com.alibaba.fastjson2.JSONObject; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import org.example.core.api.ApiRest; +import org.example.core.api.controller.BaseController; +import org.example.dto.TaskCallbackDto; +import org.example.service.IAIOBCallbackService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @description: 百度外呼回调接口 + * @author: haown + * @create: 2025-12-22 15:55 + **/ +@Api(tags={"百度外呼回调"}) +@RestController +@RequestMapping("/api") +public class AIOBCallbackController extends BaseController { + + @Resource + private IAIOBCallbackService aiobCallbackService; + + @ApiOperation("任务回调") + @PostMapping("/taskCallBack") + public JSONObject taskCallBack(@RequestBody TaskCallbackDto taskCallbackDto, HttpServletRequest request) { + return aiobCallbackService.taskCallBack(taskCallbackDto.getCallbackType(), taskCallbackDto.getData()); + } + + @ApiOperation("创建实时任务") + @GetMapping("/test") + public ApiRest createActualTimeTask() { + System.out.println("1111111111111111111111"); + return super.success(); + } +} diff --git a/src/main/java/org/example/core/annon/Dict.java b/src/main/java/org/example/core/annon/Dict.java new file mode 100644 index 0000000..c621f69 --- /dev/null +++ b/src/main/java/org/example/core/annon/Dict.java @@ -0,0 +1,21 @@ +package org.example.core.annon; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数据字典注解 + * @author bool + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Dict { + + String dicCode(); + + String dicText() default ""; + + String dictTable() default ""; +} diff --git a/src/main/java/org/example/core/api/ApiError.java b/src/main/java/org/example/core/api/ApiError.java new file mode 100644 index 0000000..4790256 --- /dev/null +++ b/src/main/java/org/example/core/api/ApiError.java @@ -0,0 +1,65 @@ +package org.example.core.api; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +/** + * 全局错误码定义,用于定义接口的响应数据, + * 枚举名称全部使用代码命名,在系统中调用,免去取名难的问题。 + * @author bool + * @date 2019-06-14 21:15 + */ +@NoArgsConstructor +@AllArgsConstructor +public enum ApiError implements Serializable { + + + /** + * 通用错误,接口参数不全 + */ + ERROR_10010001("参数不全或类型错误!"), + ERROR_10010002("您还未登录,请先登录!"), + ERROR_10010003("数据不存在!"), + ERROR_10010012("图形验证码错误!"), + ERROR_10010013("短信验证码错误!"), + ERROR_10010014("不允许重复评论!"), + + /** + * 考试相关错误 + */ + ERROR_20010001("试题被删除,无法继续考试!"), + ERROR_20010002("您有正在进行的考试!"), + + + ERROR_90010001("账号不存在,请确认!"), + ERROR_90010002("账号或密码错误!"), + ERROR_90010003("至少要包含一个角色!"), + ERROR_90010004("管理员账号无法修改!"), + ERROR_90010005("账号被禁用,请联系管理员!"), + ERROR_90010006("活动用户不足,无法开启竞拍!"), + ERROR_90010007("旧密码不正确,请确认!"), + + + ERROR_60000001("数据不存在!"); + + public String msg; + + /** + * 生成Markdown格式文档,用于更新文档用的 + * @param args + */ + public static void main(String[] args) { + for (ApiError e : ApiError.values()) { + System.out.println("'"+e.name().replace("ERROR_", "")+"':'"+e.msg+"',"); + } + } + + /** + * 获取错误码 + * @return + */ + public Integer getCode(){ + return Integer.parseInt(this.name().replace("ERROR_", "")); + } +} diff --git a/src/main/java/org/example/core/api/ApiRest.java b/src/main/java/org/example/core/api/ApiRest.java new file mode 100644 index 0000000..bc375bf --- /dev/null +++ b/src/main/java/org/example/core/api/ApiRest.java @@ -0,0 +1,62 @@ +package org.example.core.api; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.example.core.exception.ServiceException; + +/** + * 数据结果返回的封装 + * @author bool + * @date 2018/11/20 09:48 + */ +@Data +@NoArgsConstructor +@ApiModel(value="接口响应", description="接口响应") +public class ApiRest{ + + /** + * 响应消息 + */ + @ApiModelProperty(value = "响应消息") + private String msg; + /** + * 响应代码 + */ + @ApiModelProperty(value = "响应代码,0为成功,1为失败", required = true) + private Integer code; + + /** + * 请求或响应body + */ + @ApiModelProperty(value = "响应内容") + protected T data; + + + /** + * 是否成功 + * @return + */ + public boolean isSuccess(){ + return code.equals(0); + } + + /** + * 构造函数 + * @param error + */ + public ApiRest(ServiceException error){ + this.code = error.getCode(); + this.msg = error.getMsg(); + } + + /** + * 构造函数 + * @param error + */ + public ApiRest(ApiError error){ + this.code = error.getCode(); + this.msg = error.msg; + } +} diff --git a/src/main/java/org/example/core/api/controller/BaseController.java b/src/main/java/org/example/core/api/controller/BaseController.java new file mode 100644 index 0000000..147ec43 --- /dev/null +++ b/src/main/java/org/example/core/api/controller/BaseController.java @@ -0,0 +1,164 @@ +package org.example.core.api.controller; + +import org.example.core.api.ApiError; +import org.example.core.api.ApiRest; +import org.example.core.domain.AjaxResult; +import org.example.core.exception.ServiceException; + +/** + * 基础控制器 + * @author Dav + */ +public class BaseController { + + /** + * 成功默认消息 + */ + private static final Integer CODE_SUCCESS = 0; + private static final String MSG_SUCCESS = "操作成功!"; + + /** + * 失败默认消息 + */ + private static final Integer CODE_FAILURE = 1; + private static final String MSG_FAILURE = "请求失败!"; + + + /** + * 完成消息构造 + * @param code + * @param message + * @param data + * @param + * @return + */ + protected ApiRest message(Integer code, String message, T data){ + ApiRest response = new ApiRest<>(); + response.setCode(code); + response.setMsg(message); + if(data!=null) { + response.setData(data); + } + return response; + } + + /** + * 请求成功空数据 + * @param + * @return + */ + protected ApiRest success(){ + return message(0, "请求成功!", null); + } + + + + /** + * 请求成功,通用代码 + * @param message + * @param data + * @param + * @return + */ + protected ApiRest success(String message, T data){ + return message(CODE_SUCCESS, message, data); + } + + + /** + * 请求成功,仅内容 + * @param data + * @param + * @return + */ + protected ApiRest success(T data){ + return message(CODE_SUCCESS, MSG_SUCCESS, data); + } + + + /** + * 请求失败,完整构造 + * @param code + * @param message + * @param data + * @param + * @return + */ + protected ApiRest failure(Integer code, String message, T data){ + return message(code, message, data); + } + + /** + * 请求失败,消息和内容 + * @param message + * @param data + * @param + * @return + */ + protected ApiRest failure(String message, T data){ + return message(CODE_FAILURE, message, data); + } + + /** + * 请求失败,消息 + * @param message + * @return + */ + protected ApiRest failure(String message){ + return message(CODE_FAILURE, message, null); + } + + /** + * 请求失败,仅内容 + * @param data + * @param + * @return + */ + protected ApiRest failure(T data){ + return message(CODE_FAILURE, MSG_FAILURE, data); + } + + + /** + * 请求失败,仅内容 + * @param + * @return + */ + protected ApiRest failure(){ + return message(CODE_FAILURE, MSG_FAILURE, null); + } + + + + /** + * 请求失败,仅内容 + * @param + * @return + */ + protected ApiRest failure(ApiError error, T data){ + return message(error.getCode(), error.msg, data); + } + + + + /** + * 请求失败,仅内容 + * @param ex + * @param + * @return + */ + protected ApiRest failure(ServiceException ex){ + ApiRest apiRest = message(ex.getCode(), ex.getMsg(), null); + return apiRest; + } + + /** + * 响应返回结果 + * + * @param rows 影响行数 + * @return 操作结果 + */ + protected AjaxResult toAjax(int rows) { + return rows > 0 ? AjaxResult.success() : AjaxResult.error(); + } +} diff --git a/src/main/java/org/example/core/api/dto/BaseDTO.java b/src/main/java/org/example/core/api/dto/BaseDTO.java new file mode 100644 index 0000000..099a8b9 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/BaseDTO.java @@ -0,0 +1,14 @@ +package org.example.core.api.dto; + +import java.io.Serializable; +import lombok.Data; + +/** + * 请求和响应的基础类,用于处理序列化 + * @author dav + * @date 2019/3/16 15:56 + */ +@Data +public class BaseDTO implements Serializable { + +} diff --git a/src/main/java/org/example/core/api/dto/BaseIdReqDTO.java b/src/main/java/org/example/core/api/dto/BaseIdReqDTO.java new file mode 100644 index 0000000..b996953 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/BaseIdReqDTO.java @@ -0,0 +1,27 @@ +package org.example.core.api.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + *

+ * 主键通用请求类,用于根据ID查询 + *

+ * + * @author 聪明笨狗 + * @since 2019-04-20 12:15 + */ +@Data +@ApiModel(value="主键通用请求类", description="主键通用请求类") +public class BaseIdReqDTO extends BaseDTO { + + + @ApiModelProperty(value = "主键ID", required=true) + private String id; + + @JsonIgnore + private String userId; + +} diff --git a/src/main/java/org/example/core/api/dto/BaseIdRespDTO.java b/src/main/java/org/example/core/api/dto/BaseIdRespDTO.java new file mode 100644 index 0000000..04cfbc6 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/BaseIdRespDTO.java @@ -0,0 +1,25 @@ +package org.example.core.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 主键通用响应类,用于添加后返回内容 + *

+ * + * @author 聪明笨狗 + * @since 2019-04-20 12:15 + */ +@Data +@ApiModel(value="主键通用响应类", description="主键通用响应类") +@AllArgsConstructor +@NoArgsConstructor +public class BaseIdRespDTO extends BaseDTO { + + @ApiModelProperty(value = "主键ID", required=true) + private String id; +} diff --git a/src/main/java/org/example/core/api/dto/BaseIdsReqDTO.java b/src/main/java/org/example/core/api/dto/BaseIdsReqDTO.java new file mode 100644 index 0000000..9db5f97 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/BaseIdsReqDTO.java @@ -0,0 +1,24 @@ +package org.example.core.api.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.List; +import lombok.Data; + +/** + * 通用ID列表类操作,用于批量删除、修改状态等 + * @author bool + * @date 2019-08-01 19:07 + */ +@Data +@ApiModel(value="删除参数", description="删除参数") +public class BaseIdsReqDTO extends BaseDTO { + + + @JsonIgnore + private String userId; + + @ApiModelProperty(value = "要删除的ID列表", required = true) + private List ids; +} diff --git a/src/main/java/org/example/core/api/dto/BaseStateReqDTO.java b/src/main/java/org/example/core/api/dto/BaseStateReqDTO.java new file mode 100644 index 0000000..3038ea0 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/BaseStateReqDTO.java @@ -0,0 +1,30 @@ +package org.example.core.api.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 通用状态请求类,用于修改状态什么的 + *

+ * + * @author 聪明笨狗 + * @since 2019-04-20 12:15 + */ +@Data +@ApiModel(value="通用状态请求类", description="通用状态请求类") +@AllArgsConstructor +@NoArgsConstructor +public class BaseStateReqDTO extends BaseDTO { + + + @ApiModelProperty(value = "要修改对象的ID列表", required=true) + private List ids; + + @ApiModelProperty(value = "通用状态,0为正常,1为禁用", required=true) + private Integer state; +} diff --git a/src/main/java/org/example/core/api/dto/PagingReqDTO.java b/src/main/java/org/example/core/api/dto/PagingReqDTO.java new file mode 100644 index 0000000..7de79b9 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/PagingReqDTO.java @@ -0,0 +1,47 @@ +package org.example.core.api.dto; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 分页查询类 + * @param + * @author bool + */ +@ApiModel(value="分页参数", description="分页参数") +@Data +public class PagingReqDTO { + + + @ApiModelProperty(value = "当前页码", required = true, example = "1") + private Integer current; + + @ApiModelProperty(value = "每页数量", required = true, example = "10") + private Integer size; + + @ApiModelProperty(value = "查询参数") + private T params; + + @ApiModelProperty(value = "排序字符") + private String orderBy; + + @JsonIgnore + @ApiModelProperty(value = "当前用户的ID") + private String userId; + + /** + * 转换成MyBatis的简单分页对象 + * @return + */ + public Page toPage(){ + Page page = new Page(); + page.setCurrent(this.current); + page.setSize(this.size); + return page; + } + + +} diff --git a/src/main/java/org/example/core/api/dto/PagingRespDTO.java b/src/main/java/org/example/core/api/dto/PagingRespDTO.java new file mode 100644 index 0000000..df9a994 --- /dev/null +++ b/src/main/java/org/example/core/api/dto/PagingRespDTO.java @@ -0,0 +1,30 @@ +package org.example.core.api.dto; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +/** + * 分页响应类 + * @author bool + * @date 2019-07-20 15:17 + * @param + */ +public class PagingRespDTO extends Page { + + /** + * 获取页面总数量 + * @return + */ + @Override + public long getPages() { + if (this.getSize() == 0L) { + return 0L; + } else { + long pages = this.getTotal() / this.getSize(); + if (this.getTotal() % this.getSize() != 0L) { + ++pages; + } + return pages; + } + } + +} diff --git a/src/main/java/org/example/core/api/utils/JsonConverter.java b/src/main/java/org/example/core/api/utils/JsonConverter.java new file mode 100644 index 0000000..cead204 --- /dev/null +++ b/src/main/java/org/example/core/api/utils/JsonConverter.java @@ -0,0 +1,47 @@ +package org.example.core.api.utils; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; + +/** + * JSON数据转换器,用于转换返回消息的格式 + * @author dav + * @date 2018/9/11 19:30 + */ +public class JsonConverter { + + /** + * FastJson消息转换器 + * + * @return + */ + public static HttpMessageConverter fastConverter() { + // 定义一个convert转换消息的对象 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + // 添加FastJson的配置信息 + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + // 默认转换器 + fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, + SerializerFeature.WriteNullNumberAsZero, + SerializerFeature.MapSortField, + SerializerFeature.WriteNullStringAsEmpty, + SerializerFeature.DisableCircularReferenceDetect, + SerializerFeature.WriteDateUseDateFormat, + SerializerFeature.WriteNullListAsEmpty); + fastJsonConfig.setCharset(Charset.forName("UTF-8")); + // 处理中文乱码问题 + List fastMediaTypes = new ArrayList<>(); + fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); + fastConverter.setSupportedMediaTypes(fastMediaTypes); + // 在convert中添加配置信息 + fastConverter.setFastJsonConfig(fastJsonConfig); + + return fastConverter; + } +} diff --git a/src/main/java/org/example/core/domain/AjaxResult.java b/src/main/java/org/example/core/domain/AjaxResult.java new file mode 100644 index 0000000..867df3d --- /dev/null +++ b/src/main/java/org/example/core/domain/AjaxResult.java @@ -0,0 +1,165 @@ +package org.example.core.domain; + +import java.util.HashMap; + +/** + * 操作消息提醒 + * + * @author xinyilu + */ +public class AjaxResult extends HashMap { + private static final long serialVersionUID = 1L; + + /** + * 状态码 + */ + public static final String CODE_TAG = "code"; + + /** + * 返回内容 + */ + public static final String MSG_TAG = "msg"; + + /** + * 数据对象 + */ + public static final String DATA_TAG = "data"; + + /** + * 成功默认消息 + */ + private static final Integer CODE_SUCCESS = 0; + private static final String MSG_SUCCESS = "操作成功!"; + + /** + * 失败默认消息 + */ + private static final Integer CODE_FAILURE = 1; + private static final String MSG_FAILURE = "请求失败!"; + + /** + * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 + */ + public AjaxResult() { + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + */ + public AjaxResult(int code, String msg) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + /** + * 初始化一个新创建的 AjaxResult 对象 + * + * @param code 状态码 + * @param msg 返回内容 + * @param data 数据对象 + */ + public AjaxResult(int code, String msg, Object data) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (!(data == null)) { + super.put(DATA_TAG, data); + } + } + + /** + * 返回成功消息 + * + * @return 成功消息 + */ + public static AjaxResult success() { + return AjaxResult.success("操作成功"); + } + + /** + * 返回成功数据 + * + * @return 成功消息 + */ + public static AjaxResult success(Object data) { + return AjaxResult.success("操作成功", data); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @return 成功消息 + */ + public static AjaxResult success(String msg) { + return AjaxResult.success(msg, null); + } + + /** + * 返回成功消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 成功消息 + */ + public static AjaxResult success(String msg, Object data) { + return new AjaxResult(CODE_SUCCESS, msg, data); + } + + /** + * 返回错误消息 + * + * @return + */ + public static AjaxResult error() { + return AjaxResult.error("操作失败"); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(String msg) { + return AjaxResult.error(msg, null); + } + + /** + * 返回错误消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static AjaxResult error(String msg, Object data) { + return new AjaxResult(CODE_FAILURE, msg, data); + } + + /** + * 返回错误消息 + * + * @param code 状态码 + * @param msg 返回内容 + * @return 警告消息 + */ + public static AjaxResult error(int code, String msg) { + return new AjaxResult(code, msg, null); + } + + /** + * 方便链式调用 + * + * @param key 键 + * @param value 值 + * @return 数据对象 + */ + @Override + public AjaxResult put(String key, Object value) { + super.put(key, value); + return this; + } + +} diff --git a/src/main/java/org/example/core/enums/CommonState.java b/src/main/java/org/example/core/enums/CommonState.java new file mode 100644 index 0000000..8d177c1 --- /dev/null +++ b/src/main/java/org/example/core/enums/CommonState.java @@ -0,0 +1,19 @@ +package org.example.core.enums; + +/** + * 通用的状态枚举信息 + * + * @author bool + * @date 2019-09-17 17:57 + */ +public interface CommonState { + + /** + * 普通状态,正常的 + */ + Integer NORMAL = 0; + /** + * 非正常状态,禁用,下架等 + */ + Integer ABNORMAL = 1; +} diff --git a/src/main/java/org/example/core/enums/ConfirmRefundStatusEnum.java b/src/main/java/org/example/core/enums/ConfirmRefundStatusEnum.java new file mode 100644 index 0000000..9273eb0 --- /dev/null +++ b/src/main/java/org/example/core/enums/ConfirmRefundStatusEnum.java @@ -0,0 +1,29 @@ +package org.example.core.enums; + +import lombok.Getter; + +/** + * @Description 确认退款状态枚举 + * @Author 纪寒 + * @Date 2022-10-26 11:15:21 + * @Version 1.0 + */ +@Getter +public enum ConfirmRefundStatusEnum { + + /** + * 未确认 + */ + NOT_CONFIRM("NOT_CONFIRM"), + + /** + * 已确认 + */ + CONFIRMED("CONFIRMED"), + ; + final private String info; + + ConfirmRefundStatusEnum(String info) { + this.info = info; + } +} diff --git a/src/main/java/org/example/core/enums/GooodsOrderStatusEnum.java b/src/main/java/org/example/core/enums/GooodsOrderStatusEnum.java new file mode 100644 index 0000000..2dd2df7 --- /dev/null +++ b/src/main/java/org/example/core/enums/GooodsOrderStatusEnum.java @@ -0,0 +1,69 @@ +package org.example.core.enums; + +import lombok.Getter; + +/** + * @Description 商品订单状态枚举 + * @Author 纪寒 + * @Date 2022-10-19 09:15:38 + * @Version 1.0 + */ +@Getter +public enum GooodsOrderStatusEnum { + + /** + * 待付款 + */ + WAIT_PAY("WAIT_PAY"), + + /** + * 已付款 + */ + PAY("PAY"), + + /** + * 已取消 + */ + CANCEL("CANCEL"), + + /** + * 待收货 + */ + WAIT_RECEIVED_GOODS("WAIT_RECEIVED_GOODS"), + + /** + * 已收货 + */ + RECEIVED_GOODS("RECEIVED_GOODS"), + + /** + * 退款中 + */ + WAIT_REFUND("WAIT_REFUND"), + + /** + * 已退款 + */ + REFUNDED("REFUNDED"), + + /** + * 待退货 + */ + WAIT_RETURNED_GOODS("WAIT_RETURNED_GOODS"), + + /** + * 已退货 + */ + RETURNED_GOODS("RETURNED_GOODS"), + + /** + * 已评价 + */ + EVALUATED("EVALUATED"), + ; + final private String info; + + GooodsOrderStatusEnum(String info) { + this.info = info; + } +} diff --git a/src/main/java/org/example/core/enums/OpenType.java b/src/main/java/org/example/core/enums/OpenType.java new file mode 100644 index 0000000..504661c --- /dev/null +++ b/src/main/java/org/example/core/enums/OpenType.java @@ -0,0 +1,18 @@ +package org.example.core.enums; + +/** + * 开放方式 + * @author bool + */ +public interface OpenType { + + /** + * 完全开放 + */ + Integer OPEN = 1; + + /** + * 部门开放 + */ + Integer DEPT_OPEN = 2; +} diff --git a/src/main/java/org/example/core/enums/PayTypeEnum.java b/src/main/java/org/example/core/enums/PayTypeEnum.java new file mode 100644 index 0000000..71e629e --- /dev/null +++ b/src/main/java/org/example/core/enums/PayTypeEnum.java @@ -0,0 +1,30 @@ +package org.example.core.enums; + +import lombok.Getter; + +/** + * @Description 支付了类型枚举 + * @Author 纪寒 + * @Date 2022-10-18 15:16:02 + * @Version 1.0 + */ +@Getter +public enum PayTypeEnum { + + /** + * 微信 + */ + WECHAT_PAY("WECHAT_PAY"), + + /** + * 支付宝 + */ + ALI_PAY("ALI_PAY"), + ; + + final private String info; + + PayTypeEnum(String info) { + this.info = info; + } +} diff --git a/src/main/java/org/example/core/enums/RefundStatusEnum.java b/src/main/java/org/example/core/enums/RefundStatusEnum.java new file mode 100644 index 0000000..c75e93d --- /dev/null +++ b/src/main/java/org/example/core/enums/RefundStatusEnum.java @@ -0,0 +1,41 @@ +package org.example.core.enums; + +import lombok.Getter; + +/** + * @Description 微信退款通知枚举 + * @Author 纪寒 + * @Date 2022-10-25 13:12:03 + * @Version 1.0 + */ +@Getter +public enum RefundStatusEnum { + /** + * 退款成功 + */ + SUCCESS("SUCCESS"), + + /** + * 退款关闭 + */ + CLOSED("CLOSED"), + + /** + * 退款处理中 + */ + PROCESSING("PROCESSING"), + + /** + * 退款异常,退款到银行发现用户的卡作废或者冻结了, + * 导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款 + */ + ABNORMAL("ABNORMAL"), + + ; + + final private String info; + + RefundStatusEnum(String info) { + this.info = info; + } +} diff --git a/src/main/java/org/example/core/enums/WeChatTradeStateEnum.java b/src/main/java/org/example/core/enums/WeChatTradeStateEnum.java new file mode 100644 index 0000000..b68ec6e --- /dev/null +++ b/src/main/java/org/example/core/enums/WeChatTradeStateEnum.java @@ -0,0 +1,52 @@ +package org.example.core.enums; + +import lombok.Getter; + +/** + * 微信支付回调通知状态 + */ +@Getter +public enum WeChatTradeStateEnum { + + /** + * 支付成功 + */ + SUCCESS("SUCCESS"), + + /** + * 未支付 + */ + NOTPAY("NOTPAY"), + + /** + * 已关闭 + */ + CLOSED("CLOSED"), + + /** + * 转入退款 + */ + REFUND("REFUND"), + + /** + * 已撤销(付款码支付) + */ + REVOKED("REVOKED"), + + /** + * 用户支付中(付款码支付) + */ + USERPAYING("USERPAYING"), + + /** + * 支付失败(其他原因,如银行返回失败) + */ + PAYERROR("PAYERROR") + ; + + final private String info; + + WeChatTradeStateEnum(String info) { + this.info = info; + } +} diff --git a/src/main/java/org/example/core/exception/ServiceException.java b/src/main/java/org/example/core/exception/ServiceException.java new file mode 100644 index 0000000..6f11b6f --- /dev/null +++ b/src/main/java/org/example/core/exception/ServiceException.java @@ -0,0 +1,51 @@ +package org.example.core.exception; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.example.core.api.ApiError; +import org.example.core.api.ApiRest; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ServiceException extends RuntimeException{ + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误消息 + */ + private String msg; + + /** + * 从结果初始化 + * @param apiRest + */ + public ServiceException(ApiRest apiRest){ + this.code = apiRest.getCode(); + this.msg = apiRest.getMsg(); + } + + /** + * 从枚举中获取参数 + * @param apiError + */ + public ServiceException(ApiError apiError){ + this.code = apiError.getCode(); + this.msg = apiError.msg; + } + + /** + * 异常构造 + * @param msg + */ + public ServiceException(String msg){ + this.code = 1; + this.msg = msg; + } + +} diff --git a/src/main/java/org/example/core/exception/ServiceExceptionHandler.java b/src/main/java/org/example/core/exception/ServiceExceptionHandler.java new file mode 100644 index 0000000..9a23eef --- /dev/null +++ b/src/main/java/org/example/core/exception/ServiceExceptionHandler.java @@ -0,0 +1,50 @@ +package org.example.core.exception; + +import org.example.core.api.ApiRest; +import org.springframework.http.HttpStatus; +import org.springframework.ui.Model; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * 统一异常处理类 + * @author bool + * @date 2019-06-21 19:27 + */ +@RestControllerAdvice +public class ServiceExceptionHandler { + + /** + * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 + * @param binder + */ + @InitBinder + public void initWebBinder(WebDataBinder binder){ + + } + + /** + * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 + * @param model + */ + @ModelAttribute + public void addAttribute(Model model) { + + } + + /** + * 捕获ServiceException + * @param e + * @return + */ + @ExceptionHandler({org.example.core.exception.ServiceException.class}) + @ResponseStatus(HttpStatus.OK) + public ApiRest serviceExceptionHandler(ServiceException e) { + return new ApiRest(e); + } + +} \ No newline at end of file diff --git a/src/main/java/org/example/core/utils/BeanMapper.java b/src/main/java/org/example/core/utils/BeanMapper.java new file mode 100644 index 0000000..79ab6b9 --- /dev/null +++ b/src/main/java/org/example/core/utils/BeanMapper.java @@ -0,0 +1,58 @@ +package org.example.core.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.dozer.DozerBeanMapper; + + +/** + * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现: + * + * 1. 持有Mapper的单例. + * 2. 返回值类型转换. + * 3. 批量转换Collection中的所有对象. + * 4. 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数. + * + */ +public class BeanMapper { + + /** + * 持有Dozer单例, 避免重复创建DozerMapper消耗资源. + */ + private static DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); + + /** + * 基于Dozer转换对象的类型. + */ + public static T map(Object source, Class destinationClass) { + return dozerBeanMapper.map(source, destinationClass); + } + + /** + * 基于Dozer转换Collection中对象的类型. + */ + public static List mapList(Iterable sourceList, Class destinationClass) { + List destinationList = new ArrayList(); + for (Object sourceObject : sourceList) { + T destinationObject = dozerBeanMapper.map(sourceObject, destinationClass); + destinationList.add(destinationObject); + } + return destinationList; + } + + /** + * 基于Dozer将对象A的值拷贝到对象B中. + */ + public static void copy(Object source, Object destinationObject) { + if(source!=null) { + dozerBeanMapper.map(source, destinationObject); + } + } + + public static List mapList(Collection source, Function mapper) { + return source.stream().map(mapper).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/core/utils/CronUtils.java b/src/main/java/org/example/core/utils/CronUtils.java new file mode 100644 index 0000000..f99b21d --- /dev/null +++ b/src/main/java/org/example/core/utils/CronUtils.java @@ -0,0 +1,31 @@ +package org.example.core.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 时间转换quartz表达式 + * @author bool + * @date 2020/11/29 下午3:00 + */ +public class CronUtils { + + /** + * 格式化数据 + */ + private static final String DATE_FORMAT = "ss mm HH dd MM ? yyyy"; + + /** + * 准确的时间点到表达式 + * @param date + * @return + */ + public static String dateToCron(final Date date){ + SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT); + String formatTimeStr = ""; + if (date != null) { + formatTimeStr = fmt.format(date); + } + return formatTimeStr; + } +} diff --git a/src/main/java/org/example/core/utils/DateUtils.java b/src/main/java/org/example/core/utils/DateUtils.java new file mode 100644 index 0000000..6439dab --- /dev/null +++ b/src/main/java/org/example/core/utils/DateUtils.java @@ -0,0 +1,103 @@ +package org.example.core.utils; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * 日期处理工具类 + * ClassName: DateUtils
+ * date: 2018年12月13日 下午6:34:02
+ * + * @author Bool + * @version + */ +public class DateUtils { + + /** + * + * calcExpDays:计算某个日期与当前日期相差的天数,如果计算的日期大于现在时间,将返回负数;否则返回正数
+ * @author Bool + * @param userCreateTime + * @return + * @since JDK 1.6 + */ + public static int calcExpDays(Date userCreateTime){ + + Calendar start = Calendar.getInstance(); + start.setTime(userCreateTime); + + Calendar now = Calendar.getInstance(); + now.setTime(new Date()); + + long l = now.getTimeInMillis() - start.getTimeInMillis(); + int days = new Long(l / (1000 * 60 * 60 * 24)).intValue(); + return days; + } + + + /** + * + * dateNow:获取当前时间的字符串格式,根据传入的格式化来展示.
+ * @author Bool + * @param format 日期格式化 + * @return + */ + public static String dateNow(String format) { + SimpleDateFormat fmt = new SimpleDateFormat(format); + Calendar c = new GregorianCalendar(); + return fmt.format(c.getTime()); + } + + /** + * formatDate:格式化日期,返回指定的格式
+ * @author Bool + * @param time + * @param format + * @return + */ + public static String formatDate(Date time, String format) { + SimpleDateFormat fmt = new SimpleDateFormat(format); + return fmt.format(time.getTime()); + } + + + + /** + * parseDate:将字符串转换成日期,使用:yyyy-MM-dd HH:mm:ss 来格式化 + * @author Bool + * @param date + * @return + */ + public static Date parseDate(String date) { + return parseDate(date, "yyyy-MM-dd HH:mm:ss"); + } + + + /** + * + * parseDate:将字符串转换成日期,使用指定格式化来格式化 + * @author Bool + * @param date + * @param pattern + * @return + */ + public static Date parseDate(String date, String pattern) { + + if (pattern==null) { + pattern = "yyyy-MM-dd HH:mm:ss"; + } + + SimpleDateFormat fmt = new SimpleDateFormat(pattern); + + try { + + return fmt.parse(date); + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + + } +} diff --git a/src/main/java/org/example/core/utils/IpUtils.java b/src/main/java/org/example/core/utils/IpUtils.java new file mode 100644 index 0000000..ce346e3 --- /dev/null +++ b/src/main/java/org/example/core/utils/IpUtils.java @@ -0,0 +1,65 @@ +package org.example.core.utils; + + +import javax.servlet.http.HttpServletRequest; + +/** + * IP获取工具类,用户获取网络请求过来的真实IP + * ClassName: IpUtils
+ * date: 2018年2月13日 下午7:27:52
+ * + * @author Bool + * @version + */ +public class IpUtils { + + + /** + * + * getClientIp:通过请求获取客户端的真实IP地址 + * @author Bool + * @param request + * @return + */ + public static String extractClientIp(HttpServletRequest request) { + + String ip = null; + + //X-Forwarded-For:Squid 服务代理 + String ipAddresses = request.getHeader("X-Forwarded-For"); + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //Proxy-Client-IP:apache 服务代理 + ipAddresses = request.getHeader("Proxy-Client-IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //WL-Proxy-Client-IP:weblogic 服务代理 + ipAddresses = request.getHeader("WL-Proxy-Client-IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //HTTP_CLIENT_IP:有些代理服务器 + ipAddresses = request.getHeader("HTTP_CLIENT_IP"); + } + + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + //X-Real-IP:nginx服务代理 + ipAddresses = request.getHeader("X-Real-IP"); + } + + //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP + if (ipAddresses != null && ipAddresses.length() != 0) { + ip = ipAddresses.split(",")[0]; + } + + //还是不能获取到,最后再通过request.getRemoteAddr();获取 + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + ip = request.getRemoteAddr(); + } + + return ip; + } + + +} diff --git a/src/main/java/org/example/core/utils/Reflections.java b/src/main/java/org/example/core/utils/Reflections.java new file mode 100644 index 0000000..d05d74c --- /dev/null +++ b/src/main/java/org/example/core/utils/Reflections.java @@ -0,0 +1,323 @@ +/** + * Copyright (c) 2005-2012 springside.org.cn + */ +package org.example.core.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.springframework.util.Assert; + +/** + * 反射工具类. + * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * @author calvin + * @version 2016-01-15 + */ +@Log4j2 +public class Reflections { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + private static final String CGLIB_CLASS_SEPARATOR = "$$"; + + + /** + * 获取类的所有属性,包括父类 + * + * @param object + * @return + */ + public static Field[] getAllFields(Object object) { + Class clazz = object.getClass(); + List fieldList = new ArrayList<>(); + while (clazz != null) { + fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); + clazz = clazz.getSuperclass(); + } + Field[] fields = new Field[fieldList.size()]; + fieldList.toArray(fields); + return fields; + } + + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + public static Object 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 object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, Object value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i=0; i[] parameterTypes, + final Object[] args) { + Method method = getAccessibleMethod(obj, methodName, parameterTypes); + if (method == null) { + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + } + + try { + return method.invoke(obj, args); + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } + + /** + * 直接调用对象方法, 无视private/protected修饰符, + * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. + * 只匹配函数名,如果有多个同名函数调用第一个。 + */ + public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { + Method method = getAccessibleMethodByName(obj, methodName); + if (method == null) { + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + } + + try { + return method.invoke(obj, args); + } catch (Exception e) { + throw convertReflectionExceptionToUnchecked(e); + } + } + + /** + * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. + * + * 如向上转型到Object仍无法找到, 返回null. + */ + public static Field getAccessibleField(final Object obj, final String fieldName) { + Validate.notNull(obj, "object can't be 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) {//NOSONAR + // Field不在当前类定义,继续向上转型 + continue;// new add + } + } + 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) { + Validate.notNull(obj, "object can't be 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) { + // Method不在当前类定义,继续向上转型 + continue;// new add + } + } + return null; + } + + /** + * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. + * 如向上转型到Object仍无法找到, 返回null. + * 只匹配函数名。 + * + * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) + */ + public static Method getAccessibleMethodByName(final Object obj, final String methodName) { + Validate.notNull(obj, "object can't be 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)) { + 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. + * eg. + * public UserDao extends HibernateDao + * + * @param clazz The class to introspect + * @return the first generic declaration, or Object.class if cannot be determined + */ + @SuppressWarnings("unchecked") + public static Class getClassGenricType(final Class clazz) { + return getClassGenricType(clazz, 0); + } + + /** + * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. + * 如无法找到, 返回Object.class. + * + * 如public UserDao extends HibernateDao + * + * @param clazz clazz The class to introspect + * @param index the Index of the generic ddeclaration,start from 0. + * @return the index generic declaration, or Object.class if cannot be determined + */ + public static Class getClassGenricType(final Class clazz, final int index) { + + Type genType = clazz.getGenericSuperclass(); + + if (!(genType instanceof ParameterizedType)) { + log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); + return Object.class; + } + + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + + if (index >= params.length || index < 0) { + log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + + params.length); + return Object.class; + } + if (!(params[index] instanceof Class)) { + log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); + return Object.class; + } + + return (Class) params[index]; + } + + public static Class getUserClass(Object instance) { + Assert.notNull(instance, "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(Exception e) { + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException + || e instanceof NoSuchMethodException) { + return new IllegalArgumentException(e); + } else if (e instanceof InvocationTargetException) { + return new RuntimeException(((InvocationTargetException) e).getTargetException()); + } else if (e instanceof RuntimeException) { + return (RuntimeException) e; + } + return new RuntimeException("Unexpected Checked Exception.", e); + } +} diff --git a/src/main/java/org/example/core/utils/SpringUtils.java b/src/main/java/org/example/core/utils/SpringUtils.java new file mode 100644 index 0000000..b659ecb --- /dev/null +++ b/src/main/java/org/example/core/utils/SpringUtils.java @@ -0,0 +1,32 @@ +package org.example.core.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * Spring获取工具 + * + * @author bool + * @date 2019-12-09 15:55 + */ +@Component +public class SpringUtils implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext context) throws BeansException { + applicationContext = context; + } + + public static T getBean(Class tClass) { + return applicationContext.getBean(tClass); + } + + public static T getBean(String name, Class type) { + return applicationContext.getBean(name, type); + } + +} diff --git a/src/main/java/org/example/core/utils/StringUtils.java b/src/main/java/org/example/core/utils/StringUtils.java new file mode 100644 index 0000000..20ec321 --- /dev/null +++ b/src/main/java/org/example/core/utils/StringUtils.java @@ -0,0 +1,39 @@ +package org.example.core.utils; + +import java.util.Map; + +/** + * 字符串常用工具类 + * @author bool + * @date 2019-05-15 11:40 + */ +public class StringUtils { + + /** + * 判断是否为空字符 + * @param str + * @return + */ + public static boolean isBlank(String str){ + return str==null || "".equals(str); + } + + + /** + * 将MAP转换成一个xml格式,格式为value... + * @param params + * @return + */ + public static String mapToXml(Map params){ + StringBuffer sb = new StringBuffer(""); + for(String key:params.keySet()){ + sb.append("<") + .append(key).append(">") + .append(params.get(key)) + .append(""); + } + + sb.append(""); + return sb.toString(); + } +} diff --git a/src/main/java/org/example/core/utils/excel/ExportExcel.java b/src/main/java/org/example/core/utils/excel/ExportExcel.java new file mode 100644 index 0000000..c2ddba5 --- /dev/null +++ b/src/main/java/org/example/core/utils/excel/ExportExcel.java @@ -0,0 +1,401 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package org.example.core.utils.excel; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Comment; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.example.core.utils.Reflections; +import org.example.core.utils.excel.annotation.ExcelField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion) + * @author jeeplus + * @version 2016-04-21 + */ +public class ExportExcel { + + private static Logger log = LoggerFactory.getLogger(ExportExcel.class); + + /** + * 工作薄对象 + */ + private SXSSFWorkbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 当前行号 + */ + private int rownum; + + /** + * 注解列表(Object[]{ ExcelField, Field/Method }) + */ + List annotationList = Lists.newArrayList(); + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + */ + public ExportExcel(String title, Class cls){ + this(title, cls, 1); + } + + /** + * 构造函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param cls 实体对象,通过annotation.ExportField获取标题 + * @param type 导出类型(1:导出数据;2:导出模板) + * @param groups 导入分组 + */ + public ExportExcel(String title, Class cls, int type, int... groups){ + // Get annotation field + Field[] fs = cls.getDeclaredFields(); + for (Field f : fs){ + ExcelField ef = f.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==type)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, f}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, f}); + } + } + } + // Get annotation method + Method[] ms = cls.getDeclaredMethods(); + for (Method m : ms){ + ExcelField ef = m.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==type)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, m}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, m}); + } + } + } + // Field sorting + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return new Integer(((ExcelField)o1[0]).sort()).compareTo( + new Integer(((ExcelField)o2[0]).sort())); + } + }); + // Initialize + List headerList = Lists.newArrayList(); + for (Object[] os : annotationList){ + String t = ((ExcelField)os[0]).title(); + // 如果是导出,则去掉注释 + if (type==1){ + String[] ss = StringUtils.split(t, "**", 2); + if (ss.length==2){ + t = ss[0]; + } + } + headerList.add(t); + } + initialize(title, headerList); + } + /** + * 初始化函数 + * @param title 表格标题,传“空值”,表示无标题 + * @param headerList 表头列表 + */ + private void initialize(String title, List headerList) { + this.wb = new SXSSFWorkbook(500); + this.sheet = wb.createSheet("Export"); + this.styles = createStyles(wb); + // Create title + if (StringUtils.isNotBlank(title)){ + Row titleRow = sheet.createRow(rownum++); + 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(), headerList.size()-1)); + } + // Create header + if (headerList == null){ + throw new RuntimeException("headerList not null!"); + } + Row headerRow = sheet.createRow(rownum++); + headerRow.setHeightInPoints(16); + for (int i = 0; i < headerList.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellStyle(styles.get("header")); + String[] ss = StringUtils.split(headerList.get(i), "**", 2); + if (ss.length==2){ + cell.setCellValue(ss[0]); + Comment comment = this.sheet.createDrawingPatriarch().createCellComment( + new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6)); + comment.setString(new XSSFRichTextString(ss[1])); + cell.setCellComment(comment); + }else{ + cell.setCellValue(headerList.get(i)); + } + sheet.autoSizeColumn(i); + } + for (int i = 0; i < headerList.size(); i++) { + int colWidth = sheet.getColumnWidth(i)*2; + sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth); + } + log.debug("Initialize success."); + } + + /** + * 创建表格样式 + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) { + Map styles = new HashMap<>(16); + + CellStyle style = wb.createCellStyle(); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + Font titleFont = wb.createFont(); + titleFont.setFontName("Arial"); + titleFont.setFontHeightInPoints((short) 16); + titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + style.setFont(titleFont); + styles.put("title", style); + + style = wb.createCellStyle(); + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); + style.setBorderRight(CellStyle.BORDER_THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(CellStyle.BORDER_THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(CellStyle.BORDER_THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(CellStyle.BORDER_THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_LEFT); + styles.put("data1", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_CENTER); + styles.put("data2", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(CellStyle.ALIGN_RIGHT); + styles.put("data3", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); +// style.setWrapText(true); + style.setAlignment(CellStyle.ALIGN_CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(CellStyle.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); + headerFont.setColor(IndexedColors.WHITE.getIndex()); + style.setFont(headerFont); + styles.put("header", style); + + return styles; + } + + /** + * 添加一行 + * @return 行对象 + */ + public Row addRow(){ + return sheet.createRow(rownum++); + } + + + /** + * 添加一个单元格 + * @param row 添加的行 + * @param column 添加列号 + * @param val 添加值 + * @return 单元格对象 + */ + public Cell addCell(Row row, int column, Object val){ + return this.addCell(row, column, val, 0, Class.class); + } + + /** + * 添加一个单元格 + * @param row 添加的行 + * @param column 添加列号 + * @param val 添加值 + * @param align 对齐方式(1:靠左;2:居中;3:靠右) + * @return 单元格对象 + */ + public Cell addCell(Row row, int column, Object val, int align, Class fieldType){ + Cell cell = row.createCell(column); + CellStyle style = styles.get("data"+(align>=1&&align<=3?align:"")); + try { + if (val == null){ + cell.setCellValue(""); + } else if (val instanceof String) { + cell.setCellValue((String) val); + } else if (val instanceof Integer) { + cell.setCellValue((Integer) val); + } else if (val instanceof Long) { + cell.setCellValue((Long) val); + } else if (val instanceof Double) { + cell.setCellValue((Double) val); + } else if (val instanceof Float) { + cell.setCellValue((Float) val); + } else if (val instanceof Date) { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat("yyyy-MM-dd")); + cell.setCellValue((Date) val); + } else { + if (fieldType != Class.class){ + cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val)); + }else{ + cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), + "fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val)); + } + } + } catch (Exception ex) { + log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString()); + cell.setCellValue(val.toString()); + } + cell.setCellStyle(style); + return cell; + } + + /** + * 添加数据(通过annotation.ExportField添加数据) + * @return list 数据列表 + */ + public ExportExcel setDataList(List list){ + for (E e : list){ + int colunm = 0; + Row row = this.addRow(); + StringBuilder sb = new StringBuilder(); + for (Object[] os : annotationList){ + ExcelField ef = (ExcelField)os[0]; + Object val = null; + try{ + if (StringUtils.isNotBlank(ef.value())){ + val = Reflections.invokeGetter(e, ef.value()); + }else{ + if (os[1] instanceof Field){ + val = Reflections.invokeGetter(e, ((Field)os[1]).getName()); + }else if (os[1] instanceof Method){ + val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {}); + } + } + }catch(Exception ex) { + log.info(ex.toString()); + val = ""; + } + this.addCell(row, colunm++, val, ef.align(), ef.fieldType()); + sb.append(val + ", "); + } + log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); + } + return this; + } + + /** + * 输出数据流 + * @param os 输出数据流 + */ + public ExportExcel write(OutputStream os) throws IOException{ + wb.write(os); + return this; + } + + /** + * 输出到客户端 + * @param fileName 输出文件名 + */ + public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{ + response.reset(); + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setContentType("application/octet-stream; charset=utf-8"); + response.addHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName, "utf-8")); + write(response.getOutputStream()); + return this; + } + + /** + * 清理临时文件 + */ + public ExportExcel dispose(){ + wb.dispose(); + return this; + } + +} diff --git a/src/main/java/org/example/core/utils/excel/ImportExcel.java b/src/main/java/org/example/core/utils/excel/ImportExcel.java new file mode 100644 index 0000000..d6a4f3e --- /dev/null +++ b/src/main/java/org/example/core/utils/excel/ImportExcel.java @@ -0,0 +1,302 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package org.example.core.utils.excel; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.example.core.utils.Reflections; +import org.example.core.utils.excel.annotation.ExcelField; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +/** + * 导入Excel文件(支持“XLS”和“XLSX”格式) + * @author jeeplus + * @version 2016-03-10 + */ +public class ImportExcel { + + private static Logger log = LoggerFactory.getLogger(ImportExcel.class); + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 标题行号 + */ + private int headerNum; + + + + /** + * 构造函数 + * @param multipartFile 导入文件对象 + * @param headerNum 标题行号,数据行号=标题行号+1 + * @param sheetIndex 工作表编号 + * @throws InvalidFormatException + * @throws IOException + */ + public ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex) + throws InvalidFormatException, IOException { + this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex); + } + + /** + * 构造函数 + * @param is 导入文件对象 + * @param headerNum 标题行号,数据行号=标题行号+1 + * @param sheetIndex 工作表编号 + * @throws InvalidFormatException + * @throws IOException + */ + public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex) + throws IOException { + if (StringUtils.isBlank(fileName)){ + throw new RuntimeException("导入文档为空!"); + }else if(fileName.toLowerCase().endsWith("xls")){ + this.wb = new HSSFWorkbook(is); + }else if(fileName.toLowerCase().endsWith("xlsx")){ + this.wb = new XSSFWorkbook(is); + }else{ + throw new RuntimeException("文档格式不正确!"); + } + if (this.wb.getNumberOfSheets() List getDataList(Class cls, int... groups) throws InstantiationException, IllegalAccessException{ + List annotationList = Lists.newArrayList(); + // Get annotation field + Field[] fs = cls.getDeclaredFields(); + for (Field f : fs){ + ExcelField ef = f.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==2)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, f}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, f}); + } + } + } + // Get annotation method + Method[] ms = cls.getDeclaredMethods(); + for (Method m : ms){ + ExcelField ef = m.getAnnotation(ExcelField.class); + if (ef != null && (ef.type()==0 || ef.type()==2)){ + if (groups!=null && groups.length>0){ + boolean inGroup = false; + for (int g : groups){ + if (inGroup){ + break; + } + for (int efg : ef.groups()){ + if (g == efg){ + inGroup = true; + annotationList.add(new Object[]{ef, m}); + break; + } + } + } + }else{ + annotationList.add(new Object[]{ef, m}); + } + } + } + // Field sorting + Collections.sort(annotationList, new Comparator() { + @Override + public int compare(Object[] o1, Object[] o2) { + return new Integer(((ExcelField)o1[0]).sort()).compareTo( + new Integer(((ExcelField)o2[0]).sort())); + } + }); + // Get excel data + List dataList = Lists.newArrayList(); + for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { + E e = (E)cls.newInstance(); + int column = 0; + Row row = this.getRow(i); + StringBuilder sb = new StringBuilder(); + for (Object[] os : annotationList){ + Object val = this.getCellValue(row, column++); + if (val != null){ + ExcelField ef = (ExcelField)os[0]; + // Get param type and type cast + Class valType = Class.class; + if (os[1] instanceof Field){ + valType = ((Field)os[1]).getType(); + }else if (os[1] instanceof Method){ + Method method = ((Method)os[1]); + if ("get".equals(method.getName().substring(0, 3))){ + valType = method.getReturnType(); + }else if("set".equals(method.getName().substring(0, 3))){ + valType = ((Method)os[1]).getParameterTypes()[0]; + } + } + //log.debug("Import value type: ["+i+","+column+"] " + valType); + try { + //如果导入的java对象,需要在这里自己进行变换。 + if (valType == String.class){ + String s = String.valueOf(val.toString()); + if(StringUtils.endsWith(s, ".0")){ + val = StringUtils.substringBefore(s, ".0"); + }else{ + val = String.valueOf(val.toString()); + } + }else if (valType == Integer.class){ + val = Double.valueOf(val.toString()).intValue(); + }else if (valType == Long.class){ + val = Double.valueOf(val.toString()).longValue(); + }else if (valType == Double.class){ + val = Double.valueOf(val.toString()); + }else if (valType == Float.class){ + val = Float.valueOf(val.toString()); + }else if (valType == Date.class){ + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); + val=sdf.parse(val.toString()); + }else{ + if (ef.fieldType() != Class.class){ + val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); + }else{ + val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), + "fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); + } + } + } catch (Exception ex) { + log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); + val = null; + } + // set entity value + if (os[1] instanceof Field){ + Reflections.invokeSetter(e, ((Field)os[1]).getName(), val); + }else if (os[1] instanceof Method){ + String mthodName = ((Method)os[1]).getName(); + if ("get".equals(mthodName.substring(0, 3))){ + mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); + } + Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); + } + } + sb.append(val+", "); + } + dataList.add(e); + log.debug("Read success: ["+i+"] "+sb.toString()); + } + return dataList; + } + +} diff --git a/src/main/java/org/example/core/utils/excel/annotation/ExcelField.java b/src/main/java/org/example/core/utils/excel/annotation/ExcelField.java new file mode 100644 index 0000000..d553f23 --- /dev/null +++ b/src/main/java/org/example/core/utils/excel/annotation/ExcelField.java @@ -0,0 +1,59 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package org.example.core.utils.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel注解定义 + * @author jeeplus + * @version 2016-03-10 + */ +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelField { + + /** + * 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”) + */ + String value() default ""; + + /** + * 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效) + */ + String title(); + + /** + * 字段类型(0:导出导入;1:仅导出;2:仅导入) + */ + int type() default 0; + + /** + * 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右) + */ + int align() default 0; + + /** + * 导出字段字段排序(升序) + */ + int sort() default 0; + + /** + * 如果是字典类型,请设置字典的type值 + */ + String dictType() default ""; + + /** + * 反射类型 + */ + Class fieldType() default Class.class; + + /** + * 字段归属组(根据分组导出导入) + */ + int[] groups() default {}; +} diff --git a/src/main/java/org/example/core/utils/excel/fieldtype/ListType.java b/src/main/java/org/example/core/utils/excel/fieldtype/ListType.java new file mode 100644 index 0000000..864356c --- /dev/null +++ b/src/main/java/org/example/core/utils/excel/fieldtype/ListType.java @@ -0,0 +1,55 @@ +/** + * Copyright © 2015-2020 JeePlus All rights reserved. + */ +package org.example.core.utils.excel.fieldtype; + +import java.util.List; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang3.StringUtils; + +/** + * 字段类型转换 + * @author jeeplus + * @version 2016-5-29 + */ +public class ListType { + + /** + * 获取对象值(导入) + */ + public static Object getValue(String val) { + List list = Lists.newArrayList(); + if(!StringUtils.isBlank(val)) { + for (String s : val.split(",")) { + list.add(s); + } + } + return list; + } + + /** + * 设置对象值(导出) + */ + public static String setValue(Object val) { + if (val != null){ + List list = (List)val; + StringBuffer sb = null; + for (String item: list){ + if(StringUtils.isBlank(item)){ + continue; + } + if(sb == null){ + sb = new StringBuffer(item); + }else{ + sb.append(",").append(item); + } + } + + if(sb!=null) { + return sb.toString().replace("[]", ""); + } + } + return ""; + } + +} diff --git a/src/main/java/org/example/core/utils/file/Md5Util.java b/src/main/java/org/example/core/utils/file/Md5Util.java new file mode 100644 index 0000000..6a48103 --- /dev/null +++ b/src/main/java/org/example/core/utils/file/Md5Util.java @@ -0,0 +1,37 @@ +package org.example.core.utils.file; + +import java.security.MessageDigest; + + +/** + * MD5工具类 + * ClassName: MD5Util
+ * date: 2018年1月13日 下午6:54:53
+ * + * @author Bool + * @version + */ +public class Md5Util { + + + /** + * 简单MD5 + * @param str + * @return + */ + public static String md5(String str) { + + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] array = md.digest(str.getBytes("UTF-8")); + StringBuilder sb = new StringBuilder(); + for (byte item : array) { + sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + }catch(Exception e) { + return null; + } + } + +} diff --git a/src/main/java/org/example/core/utils/jackson/JsonHelper.java b/src/main/java/org/example/core/utils/jackson/JsonHelper.java new file mode 100644 index 0000000..539699a --- /dev/null +++ b/src/main/java/org/example/core/utils/jackson/JsonHelper.java @@ -0,0 +1,116 @@ +package org.example.core.utils.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import java.io.IOException; +import java.util.TimeZone; +import org.example.core.exception.ServiceException; + +/** + * JSON工具类 + * @author van + */ +public class JsonHelper { + + /** + * 转换为字符串 + * @param obj + * @return + */ + public static String toJson(Object obj) { + + ObjectMapper mapper = getMapper(); + + try { + return mapper.writeValueAsString(obj); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * 将字符转换为java对象 + * @param json + * @param clazz + * @return + */ + public static T parseObject(String json, Class clazz) { + ObjectMapper mapper = getMapper(); + try { + return mapper.readValue(json, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将对象转换为另外一个对象 + * @param object + * @param clazz + * @return + */ + public static T parseObject(Object object, Class clazz) { + ObjectMapper mapper = getMapper(); + try { + return mapper.readValue(toJson(object), clazz); + } catch (InvalidFormatException e){ + throw new ServiceException("数据格式存在错误!"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 复杂对象的转换 + * @param object + * @param typeReference + * @return + * @param + */ + public static T parseObject(Object object, TypeReference typeReference) { + ObjectMapper mapper = getMapper(); + try { + return mapper.readValue(toJson(object), typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 复杂对象的转换 + * @param json + * @param typeReference + * @return + * @param + */ + public static T parseObject(String json, TypeReference typeReference) { + ObjectMapper mapper = getMapper(); + try { + return mapper.readValue(json, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 获取转换配置 + * @return + */ + public static ObjectMapper getMapper(){ + ObjectMapper mapper = new ObjectMapper(); + mapper.setDateFormat(new MyDateFormat()); + mapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); + + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); + mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + return mapper; + } +} diff --git a/src/main/java/org/example/core/utils/jackson/MyDateFormat.java b/src/main/java/org/example/core/utils/jackson/MyDateFormat.java new file mode 100644 index 0000000..eab1902 --- /dev/null +++ b/src/main/java/org/example/core/utils/jackson/MyDateFormat.java @@ -0,0 +1,36 @@ +package org.example.core.utils.jackson; + +import com.fasterxml.jackson.databind.util.StdDateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * JSON时间格式类,用于兼容不同类型日期 + * @author van + */ +public class MyDateFormat extends SimpleDateFormat { + + private StdDateFormat stdDateFormat = new StdDateFormat(); + + public MyDateFormat() { + // 设置默认的日期格式 + super("yyyy-MM-dd HH:mm:ss"); + } + + @Override + public Date parse(String dateStr) throws ParseException { + if (dateStr != null && !dateStr.contains("T")) { + return super.parse(dateStr); + } + return stdDateFormat.parse(dateStr); + } + + @Override + public Object clone() { + MyDateFormat other = (MyDateFormat)super.clone(); + other.stdDateFormat = new StdDateFormat(); + return other; + } + +} diff --git a/src/main/java/org/example/dto/TaskCallbackDataDto.java b/src/main/java/org/example/dto/TaskCallbackDataDto.java new file mode 100644 index 0000000..7641210 --- /dev/null +++ b/src/main/java/org/example/dto/TaskCallbackDataDto.java @@ -0,0 +1,169 @@ +package org.example.dto; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import java.util.List; +import lombok.Data; + +/** + * @description: 任务单通电话回调传输data + * @author: haown + * @create: 2024-08-29 09:36 + **/ +@Data +public class TaskCallbackDataDto { + + /** + * 通话唯一标识 + */ + private String sessionId; + + /** + * 租户唯一标识 + */ + private Long tenantId; + + /** + * 任务标识 + */ + private String taskId; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 机器人ID + */ + private String robotId; + + /** + * 外呼机器人名称 + */ + private String robotName; + + /** + * 号码组唯一标识,导入名单后,返回的名单号码组对应标识 + */ + private Long memberId; + + /** + * 被叫号码 + */ + private String mobile; + + /** + * 拨打次数 + */ + private Integer callTimes; + + /** + * 主叫号码 + */ + private String callerNum; + + /** + * 接通状态,1-已接通 0-未接通 + */ + private Integer endType; + /** + * 呼叫类型,0-首次呼叫;1-重试;2-预约呼叫;3-实时呼叫 + */ + private Integer callType; + + /** + * 未接通原因 + */ + private String endTypeReason; + + /** + * 生成通话录音唯一标识,可通过该标识,获取录音 + */ + private String contactUUID; + + /** + * 文件id,名单导入任务时生成的文件ID + */ + private Long field; + + /** + * 信息收集内容 + */ + private JSONObject collectInfo; + + /** + * 会话还原记录 + */ + private JSONArray record; + + /** + * 拨号总时长,单位为秒 + */ + private Integer durationTimeLen; + + /** + * 振铃时长,单位为秒 + */ + private Integer ringingTimeLen; + + /** + * 对话时长,单位为秒 + */ + private Integer talkingTimeLen; + + /** + * 呼叫开始时间-Unix时间戳(单位:毫秒) + */ + private Long startTime; + + /** + * 振铃开始时间-Unix时间戳(单位:毫秒) + */ + private Long ringStartTime; + + /** + * 通话开始时间-Unix时间戳(单位:毫秒),未接通显示'-',已接通会有值 + */ + private Long talkingStartTime; + + /** + * 呼叫结束时间-Unix时间戳(单位:毫秒) + */ + private Long endTime; + + /** + * 意向,在外呼机器人-流程节点-信息收集,配置key为「意向」,对应的value值 + */ + private String intent; + + /** + * 动作,HUNGUP:挂机 + */ + private List action; + + /** + * 是否机器人主动挂机 + */ + private Boolean isRobotHangup; + + /** + * 变量,导入名单的变量 + */ + private JSONObject dialogVar; + + /** + * 短信变量 + */ + private JSONObject smsVar; + + /** + * 来自导入信息 + */ + private String extJson; + + /** + * 转接结果,字段为空或值为0未发起,1成功,-1失败 + */ + private Integer transResult; +} diff --git a/src/main/java/org/example/dto/TaskCallbackDto.java b/src/main/java/org/example/dto/TaskCallbackDto.java new file mode 100644 index 0000000..96617af --- /dev/null +++ b/src/main/java/org/example/dto/TaskCallbackDto.java @@ -0,0 +1,22 @@ +package org.example.dto; + +import lombok.Data; + +/** + * @description: 任务单通电话回调传输对象 + * @author: haown + * @create: 2024-08-29 14:06 + **/ +@Data +public class TaskCallbackDto { + + /** + * 回调数据类型, 0-任务呼叫单通电话回调 1-号码组终态回调 2-任务状态变更回调 3-实时呼叫单通电话回调 + */ + private Integer callbackType; + + /** + * 任务单通电话回调传输data + */ + private TaskCallbackDataDto data; +} diff --git a/src/main/java/org/example/entity/AIOBCallbackEntity.java b/src/main/java/org/example/entity/AIOBCallbackEntity.java new file mode 100644 index 0000000..739f28d --- /dev/null +++ b/src/main/java/org/example/entity/AIOBCallbackEntity.java @@ -0,0 +1,49 @@ +package org.example.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import java.util.Date; +import lombok.Data; + +/** + * @description: 百度外呼回调传输对象 + * @author: haown + * @create: 2025-12-22 15:11 + **/ +@Data +@TableName("aiob_callback_data") +public class AIOBCallbackEntity extends Model { + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 回调数据类型, 0-任务呼叫单通电话回调 1-号码组终态回调 2-任务状态变更回调 3-实时呼叫单通电话回调 + */ + private Integer callbackType; + + /** + * 回调数据 + */ + private String callbackData; + + /** + * 已读状态,0:未读,1:已读 + */ + private Integer readState; + + /** + * 创建时间 + */ + private Date createDate; + + /** + * 修改时间 + */ + private Date updateDate; +} diff --git a/src/main/java/org/example/mapper/AIOBCallbackMapper.java b/src/main/java/org/example/mapper/AIOBCallbackMapper.java new file mode 100644 index 0000000..3ba5836 --- /dev/null +++ b/src/main/java/org/example/mapper/AIOBCallbackMapper.java @@ -0,0 +1,8 @@ +package org.example.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.example.entity.AIOBCallbackEntity; + +public interface AIOBCallbackMapper extends BaseMapper { + +} diff --git a/src/main/java/org/example/service/IAIOBCallbackService.java b/src/main/java/org/example/service/IAIOBCallbackService.java new file mode 100644 index 0000000..c528b7c --- /dev/null +++ b/src/main/java/org/example/service/IAIOBCallbackService.java @@ -0,0 +1,16 @@ +package org.example.service; + +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.extension.service.IService; +import org.example.dto.TaskCallbackDataDto; +import org.example.entity.AIOBCallbackEntity; + +/** + * @description: 百度外呼回调service + * @author: haown + * @create: 2025-12-22 15:11 + **/ +public interface IAIOBCallbackService extends IService { + + JSONObject taskCallBack(Integer callbackType, TaskCallbackDataDto data); +} diff --git a/src/main/java/org/example/service/impl/AIOBCallbackServiceImpl.java b/src/main/java/org/example/service/impl/AIOBCallbackServiceImpl.java new file mode 100644 index 0000000..bdadea8 --- /dev/null +++ b/src/main/java/org/example/service/impl/AIOBCallbackServiceImpl.java @@ -0,0 +1,39 @@ +package org.example.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import java.util.Date; +import javax.annotation.Resource; +import org.example.dto.TaskCallbackDataDto; +import org.example.entity.AIOBCallbackEntity; +import org.example.mapper.AIOBCallbackMapper; +import org.example.service.IAIOBCallbackService; +import org.springframework.stereotype.Service; + +/** + * @description: 百度外呼回调service实现类 + * @author: haown + * @create: 2025-12-22 15:22 + **/ +@Service +public class AIOBCallbackServiceImpl extends ServiceImpl implements IAIOBCallbackService { + + @Resource + private AIOBCallbackMapper aiobCallbackMapper; + + @Override public JSONObject taskCallBack(Integer callbackType, TaskCallbackDataDto data) { + JSONObject retObj = new JSONObject(); + retObj.fluentPut("code", 200).fluentPut("msg", "success"); + if (callbackType == 0 || callbackType == 3) { + // 保存 + AIOBCallbackEntity aiobCallbackEntity = new AIOBCallbackEntity(); + aiobCallbackEntity.setCallbackType(callbackType); + aiobCallbackEntity.setCallbackData(JSON.toJSONString(data)); + aiobCallbackEntity.setReadState(0); + aiobCallbackEntity.setCreateDate(new Date()); + aiobCallbackMapper.insert(aiobCallbackEntity); + } + return retObj; + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..ee330e2 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,36 @@ +# 开发环境配置文件 +spring: + # 数据库配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://8.131.93.145:54081/aiob_callback?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: 1qaz!@#$ + # druid相关配置 + druid: + max-active: 5000 + initial-size: 20 + min-idle: 5 + async-init: true + # 监控统计 + filters: stat,wall + filter: + stat: + log-slow-sql: true + slow-sql-millis: 5000 + wall: + config: + create-table-allow: false + alter-table-allow: false + drop-table-allow: false + truncate-allow: false + +# 开启文档 +swagger: + enable: true + +logging: + level: + root: debug + path: logs/${spring.application.name}/ diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml new file mode 100644 index 0000000..c8befae --- /dev/null +++ b/src/main/resources/application-local.yml @@ -0,0 +1,93 @@ +# 独立配置文件,可以拿到jar外面跑 +spring: + application: + name: yf-exam-lite + profiles: + active: dev + main: + allow-bean-definition-overriding: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non_null + deserialization: + fail_on_unknown_properties: false + parser: + # 允许出现特殊字符和转义符 + allow_unquoted_control_chars: true + #允许出现单引号 + allow_single_quotes: true + serialization: + fail-on-empty-beans: false + mapper: + # 支持类型转换 + allow-coercion-of-scalars: true + + # 数据库配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/yf_exam_lite?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: root + # druid相关配置 + druid: + max-active: 5000 + initial-size: 20 + min-idle: 5 + async-init: true + # 监控统计 + filters: stat,wall + filter: + stat: + log-slow-sql: true + slow-sql-millis: 5000 + wall: + config: + create-table-allow: false + alter-table-allow: false + drop-table-allow: false + truncate-allow: false + +server: + port: 8101 + # 启用服务端压缩 + compression: + enabled: true + min-response-size: 10 + mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css + +# 文件上传配置 +conf: + upload: + # 物理文件存储位置,以/结束,windows已正斜杠,如:d:/exam-upload/ + dir: /data/upload/ + # 访问地址,注意不要去除/upload/file/,此节点为虚拟标识符 + # 如:http://localhost:8101/upload/file/exam.jpg,对应物理文件为:/data/upload/exam.jpg + url: http://8.131.93.145:54012/upload/file/ + # 允许上传的文件后缀 + allow-extensions: jpg,jpeg,png + folder: + # 身份证正面存储文件夹名称 + card_front_url: cardfront/ + # 身份证背面存储文件夹名称 + card_back_url: cardback/ + # 身份证正反面复印件 + card_copy_url: cardcopy/ + # 证件照 + photo_url: photo/ + # 学历证明 + certificate_url: certificate/ + # 体检报告 + physical_report_url: physicalreport/ + # 签名图片 + sign_picture_url: signpicture/ + +# 开启文档 +swagger: + enable: true + +logging: + level: + root: debug + path: logs/${spring.application.name}/ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..ef4e30b --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,33 @@ +spring: + application: + name: aiob-callback + profiles: + active: dev + main: + allow-bean-definition-overriding: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non_null + deserialization: + fail_on_unknown_properties: false + parser: + # 允许出现特殊字符和转义符 + allow_unquoted_control_chars: true + #允许出现单引号 + allow_single_quotes: true + serialization: + fail-on-empty-beans: false + mapper: + # 支持类型转换 + allow-coercion-of-scalars: true +server: + port: 8101 + servlet: + # 应用的访问路径 + context-path: / + # 启用服务端压缩 + compression: + enabled: true + min-response-size: 10 + mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css diff --git a/src/main/resources/mapper/AIOBCallbackMapper.xml b/src/main/resources/mapper/AIOBCallbackMapper.xml new file mode 100644 index 0000000..7af00e4 --- /dev/null +++ b/src/main/resources/mapper/AIOBCallbackMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + id, callback_type, callback_data, read_state, create_date, update_date + + + diff --git a/target/classes/application-dev.yml b/target/classes/application-dev.yml new file mode 100644 index 0000000..ee330e2 --- /dev/null +++ b/target/classes/application-dev.yml @@ -0,0 +1,36 @@ +# 开发环境配置文件 +spring: + # 数据库配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://8.131.93.145:54081/aiob_callback?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: 1qaz!@#$ + # druid相关配置 + druid: + max-active: 5000 + initial-size: 20 + min-idle: 5 + async-init: true + # 监控统计 + filters: stat,wall + filter: + stat: + log-slow-sql: true + slow-sql-millis: 5000 + wall: + config: + create-table-allow: false + alter-table-allow: false + drop-table-allow: false + truncate-allow: false + +# 开启文档 +swagger: + enable: true + +logging: + level: + root: debug + path: logs/${spring.application.name}/ diff --git a/target/classes/application-local.yml b/target/classes/application-local.yml new file mode 100644 index 0000000..c8befae --- /dev/null +++ b/target/classes/application-local.yml @@ -0,0 +1,93 @@ +# 独立配置文件,可以拿到jar外面跑 +spring: + application: + name: yf-exam-lite + profiles: + active: dev + main: + allow-bean-definition-overriding: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non_null + deserialization: + fail_on_unknown_properties: false + parser: + # 允许出现特殊字符和转义符 + allow_unquoted_control_chars: true + #允许出现单引号 + allow_single_quotes: true + serialization: + fail-on-empty-beans: false + mapper: + # 支持类型转换 + allow-coercion-of-scalars: true + + # 数据库配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/yf_exam_lite?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: root + # druid相关配置 + druid: + max-active: 5000 + initial-size: 20 + min-idle: 5 + async-init: true + # 监控统计 + filters: stat,wall + filter: + stat: + log-slow-sql: true + slow-sql-millis: 5000 + wall: + config: + create-table-allow: false + alter-table-allow: false + drop-table-allow: false + truncate-allow: false + +server: + port: 8101 + # 启用服务端压缩 + compression: + enabled: true + min-response-size: 10 + mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css + +# 文件上传配置 +conf: + upload: + # 物理文件存储位置,以/结束,windows已正斜杠,如:d:/exam-upload/ + dir: /data/upload/ + # 访问地址,注意不要去除/upload/file/,此节点为虚拟标识符 + # 如:http://localhost:8101/upload/file/exam.jpg,对应物理文件为:/data/upload/exam.jpg + url: http://8.131.93.145:54012/upload/file/ + # 允许上传的文件后缀 + allow-extensions: jpg,jpeg,png + folder: + # 身份证正面存储文件夹名称 + card_front_url: cardfront/ + # 身份证背面存储文件夹名称 + card_back_url: cardback/ + # 身份证正反面复印件 + card_copy_url: cardcopy/ + # 证件照 + photo_url: photo/ + # 学历证明 + certificate_url: certificate/ + # 体检报告 + physical_report_url: physicalreport/ + # 签名图片 + sign_picture_url: signpicture/ + +# 开启文档 +swagger: + enable: true + +logging: + level: + root: debug + path: logs/${spring.application.name}/ diff --git a/target/classes/application.yml b/target/classes/application.yml new file mode 100644 index 0000000..ef4e30b --- /dev/null +++ b/target/classes/application.yml @@ -0,0 +1,33 @@ +spring: + application: + name: aiob-callback + profiles: + active: dev + main: + allow-bean-definition-overriding: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non_null + deserialization: + fail_on_unknown_properties: false + parser: + # 允许出现特殊字符和转义符 + allow_unquoted_control_chars: true + #允许出现单引号 + allow_single_quotes: true + serialization: + fail-on-empty-beans: false + mapper: + # 支持类型转换 + allow-coercion-of-scalars: true +server: + port: 8101 + servlet: + # 应用的访问路径 + context-path: / + # 启用服务端压缩 + compression: + enabled: true + min-response-size: 10 + mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css diff --git a/target/classes/mapper/AIOBCallbackMapper.xml b/target/classes/mapper/AIOBCallbackMapper.xml new file mode 100644 index 0000000..7af00e4 --- /dev/null +++ b/target/classes/mapper/AIOBCallbackMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + id, callback_type, callback_data, read_state, create_date, update_date + + + diff --git a/target/classes/org/example/AIOBCallbackApplication.class b/target/classes/org/example/AIOBCallbackApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..91e10352ecb82a8d944b5e6ea9edae78b71cd3f3 GIT binary patch literal 2143 zcmbVN+fy4=82_DI*j%=urqC9lVy(qMfz^t&0!4v>MZ?9?;sr0W35T$-+0AS=6rX)@ z`k?itGmfJ^cp2Zk%_wx7zB=Qd;Crfnh59?2G>tY)9WvQ-zWvVmZoluczx{RVHh>Yl zlR!I0G(3~QIXs)hc|4cED8|$>9>awsCh&X=FT^kzM+j3fOeb*>GYQP%MGcn(!nRuw zNM~KIV3h6kkxe7(77EfE6KET^9Lt~JolO6VKxEoolLGBo%aIF}VorKj%$!XQh4ZGp zVtST(uQMb5hE*0g9VnJNX0c>TV{&eBYTC5zoSEO6ER}34Z~B(&&{m{qT8_Zc%xZSi z+%^r{bPC3@?^#Y^EHG|*1*$vJ;#eSQ-qR&8UW=uqWY;~jD6hHRmXUWIU+(zEwCk)} zg^H(KZE}HZbxcpf(%BXm*hh&c4W1h_&bH;bPEk5aBxIEo3imnAuu87ytIhN`1P(3x z41C@!1sG}Q(J-gsB@HhNBxZK{h(I zoV67GJ^R2qtQ->Px?FL5t0-5jvZaD{9M=zEr^<=91Zh27O+Slbu8f( z4VQH+pU)n-e7m{F?S57m+c9f$Fdz^93!1OF27 zKR&))z4dkV%bV4YeyM))*`MFNcjtqzsvmw)z42}J`ZsspzfryZc_Myb149~K*YO5c zHN2_gExgTwxmSLRxlNg8*^LHGeV|4V$g~!|zXASby4JD+CjxIA=^Iy_Eyum)Tyo2P zqr}-?t+WSqSF5z9Dq~A}70!lSrm4fGZL?e+YcUP_Tb5xx#SiZOR6+Vp%`I>~v!BK~ z5{=qrZ#7A>H#!;^%n^vmwKY$c*>gHg1QSz1B5<4rT3w_9<&3)25bd~ow|P9W%z1Cg zb4$|m-xcU<#_8?|ZGx`OV%mZnG|hYtD$7}S1v*=)U_TxEuf(jG_g#-h<3UjB!@-%~ zEL}@f9m6JDV>rnVQait50uQT>BNZmi*5}&6H-o$29v%1@;(HPybaHJAm?<13t=BH# z7>@HTjxMSS2g1Meb{lyY(xHJ}gtKS%5D}Q)Mf4}MEexi$J;Xv7jSQyaH7eQ_{S{g| zF&g~=$+W(QLm?=m;lOAgm4jYt^fN^tJLzRF4fWIXFpZx@55~z+PEFJdqnkWX;v7!k z5jvV;M7?-42qVMjAEWMGo}3~Tp{5QzPAZDil^l5lPLqaJc3`_(w_Ajt;;-=X zfWZfYul^|FncdbQXnP2q@&^ca@XnE+1Ig;kX;ly|bscLE$!Wpbf{Wua6-i+NW0=A? zvgFZ)XF~8+;W*M1m!i@p-DZs9B9t+VD-<2YHHz1bhQ0~%T_?)`*s1<6-Y{^}z%BAm Jk~Mw1pLAwXAe!@5r9juL?aG_w!ix0o zm@5t~1Y4%FX!^D~SB=qN-7X1S3VEF$41-j>CuoH`S1aW%H7Qp`J7EUR zsgFCW&}5COKuR_n=0~RCm~P%!2-tu;f9qHXOlxz_EQT_oh}oQL+m|1i$RwC{?QsaoqOQ7#|nNlmrMZ08E*HfVh@D2OC>~abqh8<;?Lb z#|G`6IK>2>M~}d{q1xy0i!UF4bNBD>zj}1=$>HZ8KmP3AU*Fw5{PdoN4-y!_jD{Nt ze27`<|M&n-Vn05}+C&5r;nn-|!TzJK_xn|?GrYh}OR(yM__W*-7=a;h;p7$_4M)RV z0yl9>;8FvNuilc{1>cZX%Uk7!~j`L5OR^a(N0&R>?d2a;<>Ql-&W~o$tMCvooqMuKFlK%n%FR0OT7vr89 z);;558SliOw|c=>*GFAabSQKc@lUDFVjnb$9Zbu+B)Kr5tq3}XzMvZWN8o4xgXJ*j6H>i ziN&QuqErP}BkI9h;6QlGBxxNae-gaHaGk`Iu4*O zCENFq_~if{Or=xNN5bYLi3eWiKjkPoF-F^XT?(mM3Mpj5T6K2&EC!jv5OHyce{e>_ zFka;;$`th{sby&3rQ%R3{hj2h`WqV@+C$gTbo9`AmCel6H91xzj#X<<5nHV|j?1-~ j_mf0@+LGN5@Z3*mRgp#A+TZxQ;sHVbuvdE?3 zCY!b{;*!A{q!O+WvpyRoj2K~Us;!~%j*RItqpA->=X1gdRX6b33Il^OlyCAmYEhTXW?Sp64% z_6OK6e5f;;&ghI|zvzs=Nv+S_UD7l%V;MN-+?#uz`<&;TOaA=l=U)M=Vkd(v*3yV$ zJ&AgTenXp0y?sra_mlV_gA~?MxUT(;6dKy!OyX7&TLQVB@@&~TR9??^olm!K3Wyzn z$%gCneChayveQ>4FVjCl!1Ud_$`Q!#p2)9cts|Y|+JW!c&T(BJv0*#5e@$Sz_}`C9 zhXO{!Z7G3EySAfl_fL2pfzKCRgBUeop4$`i=w zQkNoaCxXrM)#QOMn|JqQH&BIbX6wkWDVTHSpF0x9>I8maSVbd9LG%?yQAbd}v`BGXhthO@9kDT(R&f7A?G{qu23< z!0h;(-00h#mah5I`Gv)x?oA6Hfs94T!aG=GGoNIJdI^*@6WNu`wu%No_WgFVcAZwY zt|@&^anv`8!I4YIZdW-if$BvwIWh~OC=t6lUg0~+f-DikJaU*~oaY;e;W_?M7shGs z&Ek2k=eXLUkI`q!4YI6qIDB^q!U1~b#leSxc)@H7f|kt^l}r~)rBHu;9= z1Qzfzt%k4B3;j{~N5md5(7b>|usI(fTH%2RQLu(*N?y1ynSCVO|K2=xVe-;YmGwxK z#F!!>@AQZgiJ=mSaV2tO!jU4B=JSAF|4V9A%HP8@&MJ=({|;vStnwS;d&}hkj9|&Y zyuD1bZdCuk#GLUvrtZV4&KUzFf)mCWVd5h?hJ02-_#vMLuA)c^(^x@?-HKs}jVW_4 zPCJJRBLmCCnnog-`U}}4s()i9i532)hAq9yIWqJsi3(XGrk)s6SD>kkwsce)b4bM` z0Zknr{hV&@bfb8^&fJKp|Iev;0)9av#a+0Ld>l3m2DN4pXDM;`DFg zEdrYqXq8bc7}2+bvURbGh&|@~8!T1`7Rv93$5iCWI>s*yp&xU^PQMU6!i8Uu`s^Xn g`OE+lnj~G`q8VUve6m9s!pSZ~)CAroN(}G)3y|A2hyVZp literal 0 HcmV?d00001 diff --git a/target/classes/org/example/ability/shiro/jwt/JwtUtils.class b/target/classes/org/example/ability/shiro/jwt/JwtUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..5aaf1b66009630e239a43f93e9766e68d8ca54d7 GIT binary patch literal 3396 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 WZy&aS%qR2k6h{$sU{l_@8Tb#SEie!O literal 0 HcmV?d00001 diff --git a/target/classes/org/example/config/CorsConfig.class b/target/classes/org/example/config/CorsConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..cb6021ab78f42f5fadd739b2a19a6f7278839b86 GIT binary patch literal 1850 zcmb7F+g8&+6y4JnQey?If}(=pwJn8szm5eEowXtg7d(*>$Vv zNx!IH3k+tJW)E#A5Rzdglhq0S2Wh+YHObe-rYGN970(N-O;NFYAvYWmSYg7FsM~%Z zd0>0)oZv3Ob^BgJR*BVgB#^>T3tBIwGsk^VYjJ6WILkU;A%$!iuKXLR4S{kK6=K6M z6`9$2F@sADH?Y^mitXFf+F9520$nV1c03ZBI0s@Yu=rl6)ohFz7DkOzo7f^f@s4kB zhFhJ&g&WswRw0Fx7-X1KyS#tXI_)*X#6QzpT$`&Jm`!00#S|W3o`L03c!)sMhcFpNYkTJ@x` z%CaV;sHL!oGQ*IHJMe5V^r@}29PZYwa^;<<1`J1At~t+hv`UQ)?leSsjbR}3I$LUs zAUz-RMKJ3)-e!?j7og|p4DCSu8!@XFa8}zcaUBjPaoe#|M({Yj6spe(GLd1I!S!{i1A7C4ik+FL?K5N zUBx-f<2;^`M-k11WST^i^lg+PNE(=;s0)NTPgoam32|JecvWPE#u&2N=Jvc}z;D#k B7AXJ# literal 0 HcmV?d00001 diff --git a/target/classes/org/example/config/MultipartConfig.class b/target/classes/org/example/config/MultipartConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..00a1dbe01ba3df13d56a729b9f0747a7a583f9bd GIT binary patch literal 1048 zcmbVL-ELAr5dIb@AjQ%GrA6_FS}PQFZ;UsniB@}Is3xr;@p3sXxb<)r&)L&bpTNh_ zo7QOJ1NczJ*>ebqh_P`mW@lz+zM1)U_s7q#-vQji?Hm?S%iu~53Dg$IN2~NPhpV_| zUDvIsTd|SBjSMy!(hroU%p-q0mvDd=U6Nz@ue_w=6+Cz{Wf+bz%1P)m&oF@Gujun&%i!M#|4t<$XUQL>G?PSD=3o1 zP(qnNY_dR-G@$+siPvXHc3Nemz94;y%v8&^PI2KA1tnmCi%5|yA&XVg*HFWHRHPCE bO^ReurSl3ETcc>(%zA`SjpU`N_cHJcd`BCS literal 0 HcmV?d00001 diff --git a/target/classes/org/example/config/MybatisConfig.class b/target/classes/org/example/config/MybatisConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..b44881802c839a07b71ef1d19213db96ed48f87b GIT binary patch literal 1127 zcmb7D+invv5IxSF5ZW}9mT*nVEomS|2=P*c1Qkf2Z7CFj5Kqp=4Q{jEW!DSsU%?BN zsKf{GQNZk_kQ7v?A3PrKoa31@v){gd`3m4RT4j{cD56&Weyw#pSiolb$;ZB0&&kg{H zBp;J7+&Chx{yfx1IkKk$Md{zy+BKA&t10`0EAV`!ha0|dwKls}L{ zQw}qsHxNcnRC4q1N?smB5KVdA4M~YdDpq$wt?s6HFBtB`MgB)(iN>KHS47l{F>qhT zgkZdo72$c(U$^6ODt!^iHDPawp(HhG)XHw!%B~X!R&X2@hR%4C|Iw-nuHqWQ^+Od`*yvRU7N(5}G(hKTx!?U{Ue3pCFHuWn}Y69CJ!YIsP$^@H z5}U;-VxFVO=;e8`jNhJ%) z^)~=x_-zW0;&K94QfR|v8Rn9>D)YPy1sN6+cp-&u+3v>Z3lhn{O*gtoFb{B>_7H2h{|=nSh&sr=i_)${G&MIBq#- zRE^@Y%5kM^+GUx?R&q1^Qtr5ht_jmN{c~g)K6*_1`HmJl{AH8ch5|im-KbP8l`A^-l3C6bsI*kGR4E^PQ`Iit@Kzhku7>I1 zqXDB=bqQ?AH7aV&aaVI*$SGhct5|bgW&62>Wmg%cImfXU;$kSbJ7Q3jng72??4PgM zzFAS%OwZ(LCvDsD4c~NZ9`;yE4Fu||bw6j^AAJsyh;=T4LUbon!LSp<`<V;S znr~Y1aEl#$u)+3%T{LRtWq*3TsHzeU&l`5hlCZm9C>u^SXEHKeVQ}1Bp#6Sg=(D4i zQCTb*Ll4q8bX;_X$Ss43!t8L?Bs0fji>_L-RMF3cmKeVt+q$y2!kxec-F|~t!@d|v zQzWYdO&CP)K#brn@fs3NAeENh(?S;`a-wKO)h1PNYBb6PQ)6RhT zBGd9gg{iqgiqeV`Eg56s9?Q~cTdWoVV96o-ng5zSaO=2^BN$>@NYQ<$nx?}?O+%;8 zbUCKu2G(?}qo!j6uWESqf0f?|X&tYLuy4umx(weIZ9#QzkQ__k4GmAX%#3CsZcq>9 z4U1{OqUp^!mRa0js@=P!U$kxI<}JhXl&9l6_^ysOF{EPz*#y3)Wbi9lAG#nPIZr{QZcwff{_>lMl z!vu*JCKBt_1H2Loxn{660#{1N*_{gr!Y$6*<0)S{W5Ilt>C`cNQA+C`E{49k%nCTi zY&F-J;qj_b@TKzxRbYVBlWT_QFDSQS+CeH66qBvQbUwn(7rA%A;dOwuf5FK+((8S7 z#V$14+3+i(cQ=Xij;or0GF-V@Q#F;ByNKyCJ_Ot)rK*#bc|+aNljiEIvEJl-a)%M9 z;Q(3Zl@v8q3ga?fpHD`ozPrlbk0UTiN@|s9Sbi(^c5kq)lx<;j=!%sZ0 zeQseOq!fOHAIl~1CmJ4E4tmc$y+p%ff^?fp9}A0eUAbsnY7q;u`X2R&oveu8k8G!R z*07m})Y;9}7G6FzjK%c_g<(9r5pIKiJb|C;_!)kw<5^5HZ=0!T+Bck4m757#C<}+N zWE9zS8ErjmUyZK>e$9S1<2b9es)m2WAw&YgniKYRk9S+4jJMS&YhrfU!nm+e-O`13 zz8R{FtGbsrx~>GZC)$-#TQGe^)BHxm_PseX~Sa}goXhrxcujl z+CseY@+(WH-@E!oE88Wb4=)!}$dNxQTg^I8K}=un#9`&QnA^Mr>c;+i9HPuZj8W z9n2@Ve>%dP4lrvG+*ABIgQp|7S2?#+OV3Ch`)0GFb?k4tARTN?pc7w03g-evgCTjO zh>SRkFH&SDjXFXzwPBp%I@yXi@fJnayWL#JBTZ+7Zk}rC=5u%^Vm{7UVx;R9J_p>* z{alQ@D@2w_NoGffoFh6pWcp9&?;9A&j{XG)I?+6*{I3R{$1YrqoiU9m8F literal 0 HcmV?d00001 diff --git a/target/classes/org/example/config/ShiroConfig.class b/target/classes/org/example/config/ShiroConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..1a6a1e33e0abcef7b0eac7d4392f462d44d6a73b GIT binary patch literal 4708 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/config/jackson/JacksonConfig.class b/target/classes/org/example/config/jackson/JacksonConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..2caec8d650858c484ba04c5578f0bf879dccd0b0 GIT binary patch literal 1009 zcmbVLO>Yx15Pi;PNkbb_2yOX>OWF!7p^8fo5(GF@3rM62aCCN^;B?oH)(%AcD!5RI zO8fwR6k@zv0^v}gdzkTzXWq=4@qYXMRi0 z*BL7Jl~(QnL$STpXDD?|BpFr%rRDQ!GLY%M7{ugh1|}47U!=<0$Ig;_t1QEIVA2tn zGm%VU$wQ-uYQ)DPJg`Rdy__AMA7e{ z46}CdtHEw8tnK`5k$-m9In~o4I!p9(_^$xk9hOPf$>O9L>GJj=*r)9JEXhjdtYd}F z^*jKpXpqHl4ow2_$@?hL30OZu;msk6!A`Sugfbl~pHY3a^O5cf@OUdIl59{DO|-C< f;kNSJW85XWUBh|8zd(_`ek;qqn923IcLVqVCgd62 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/config/jackson/XssEscapeJsonDeserializer.class b/target/classes/org/example/config/jackson/XssEscapeJsonDeserializer.class new file mode 100644 index 0000000000000000000000000000000000000000..af6e8abd48c3b2f8686840a236e5b07e2dd15a8d GIT binary patch literal 1380 zcmcgsT~8B16g|_grArkA6#PO_fl@vu8ln#+BnE4gR4^$azD~EpGPvDoW~bQrtMmnp z5B>mul=1GiX$`b#;)B`j-np~)oO|cqv-|7!kDmax!CmC=z{Nu>xp;)fF0y#yVA;V6 zLvBZf%I-3xi)+UWnLXW*3{zDV%7b>ZF3pjs2edO&)t(5Bg;BBJ+sxQg6)`-oYU6X+ z5zSU0xu?SudCeLX`cwjIF|3Xt zyquTXNqedrbZXI*)Dvp;|LoCW z{Y-kc?4ZbyuPHwiwr!~P%DB^Cp7hSu#_v+=-I{J2Prg>Mz7|L7WGn7e0S+b{tQAng zx`T}ZHnCN}bxbjA|BLz z0i;2AOwcn=9w*DlW=r3|zS1HEm!7#~GmlAH7rFstuaU>%$q-2lJ|-_i)?L3q>R|Ib z(qG8yGPq=8Y?e?lOQ{>#V<8NtaU)@NF@sr(&eAo9o5X#K;xqJa9t*U}rzjK@gz1-* x{B|$-Q?hB=cS`FU7sw1UU#;EgWsP}rlxZG!`piTy>17J{a6hq&e*mrqbQJ&q literal 0 HcmV?d00001 diff --git a/target/classes/org/example/controller/AIOBCallbackController.class b/target/classes/org/example/controller/AIOBCallbackController.class new file mode 100644 index 0000000000000000000000000000000000000000..df207822767bf50d7085778d1c08df36ff8bc87d GIT binary patch literal 2099 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/ApiRest.class b/target/classes/org/example/core/api/ApiRest.class new file mode 100644 index 0000000000000000000000000000000000000000..7f9e5dc5b243f55ebae654f458ab2caacc399cb7 GIT binary patch literal 3872 zcmb7HYjYdb8Geqmt6j^RSTV7Kh#|zJjV#$HKw4VaaT5|l4R(^ojti8wtmQ@CAWO<> zl?&IVM?mRw_UuM0UqYCP_q^wv=e+NG zp7(N;fB)~==K%KOjUM#EP2&`vm7i)FJF${R4R!fx$lcRvc&PXAb6QTD2K+R~mi#m% zo`-rRz87cY^sIq%Y4l^o#CbVBXX1G|zF^`-6E8{eWdpwxNUk(10{t_m>@#+;YS${o zIp1?@m2rXWiB`>bSDXd6=`L2CL$zAnw|%!>YYL3axbf4uAuf21UwwM*`o*_a-~99FeH2&!`q6){zAs>U&gquxIZH{>D5!DC_U-P=99ul)lzl4f znR6>O+i!U^nVg^JO6bn&YpcAC6hGB@%h)g2BT?3;0G&e7J&qT|im z0`&Mx@}L zo1UDY&yzf!ns95bKPj*;w;u1DD?1Gtq2iq5opH;~RJ1TYvcNz%o>%t-#=h4{fy}Jq zFV~lj+n&AR_>RYG4sT#RyyuiO64=|d-cA>Wx2ZV(tW3b|xsg~N+(}U>p&diXh5Zmy*zyM5J;w76?pDyGo`u zL^8WXodK!)%MJr#%G}u#RANuC6w1M}DwDKYSCgJ#LuGrop(eXGWn5<8L|$glmO0-p zKRatTg2ZJb3HpFpwrf+;WqPx0H=a$5obsGztLn2ll#luz<&wTf zd0_f=6}_N}$VhHtz7!)o%kcD=e9NWoHuD{ap=5R`m5hzQ6jX z_f+c;=v{J}WzP)?!oo1_F>t}c@9_r4Kfx;JT6rn#32h$fZ^P+wt+s>a;r-+xY0#&j4y4xhS!;EqjyW%g6YLzD%m?gibpKi zppfb4Qnw#y$&*2EJ@yRyN^Uw{LQ&cZ6xQ8i^EM%H=Q?z}WEp?E(Qs-@Y$EX@ z2@5vvfLaP!U~szdQN_fvpc{|fe93mQttXL?VF5cUXT2PE@$c>?0SOt?a3d3JB;>{( z{NPFa5Sol4F(W*dKz{A<0=DwVD8~4`myn+mBsg06s}RXgk!T}%h4Une{HB7vJoZV1 z!r?yL&)EZAEBiSUOspSMo77t2nBX{&{{&jT(1!jogd9^J!}y3BN_{`Q1r=&kX;I~N z{wR>92G!xv6xHBC{DcNNMhCbjjsBE>y5P35U)s#R8Q8yyo(=4mXn&mcCusk`ruN6b z+dgZFAbI~o93`tdSvCGnAx`Ix7@hh$I^~L@ll8fQIH7?MHw7UDNa->MN=cPd9!{zf;EWwe)-D57lLOLL0AX)dxStGkJLjy)vs zQX&5VbnQyvpXhxTdh$x)3-r#8=G(A>DTOUZNBJpfWB)>LR{Ij$F2fqjYHe(d5Pc<` zkiJqXt4mDkOY~pHmaLvl#Xy;oK~Sb-W(^54Ly(a*BakMWffj29DvnPnM{mUO5@v$i z58xbTS9NkkKa<#_)}m9o~ES7TI|V?dP(?Mq`oCYBjG}jWd5(?TPo)TW1iPuQL2_9$J-=5)&Pk05( G{QMvCzv4~+ literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/controller/BaseController.class b/target/classes/org/example/core/api/controller/BaseController.class new file mode 100644 index 0000000000000000000000000000000000000000..f04f7c30aa72443b85667b9958c257aeef4ca671 GIT binary patch literal 4101 zcmb_fU2_vv7=AWMn`FC9OQFT`S&P!rv;+ZB+gj-tP-!TTQa%)Ln=a{=G>MyS!8`TJ z(Q(EZFZ9CE8Ar!UDKdre>(UE*vaW%@} znu_bVDu%aI=$IEnI*bJc+W5@GRp&75&&WqIDPX7%|jEp5~Jw4R;QEmO>0W5`}KiwX`+=dDb_xUDZ2vPL4Ew~T~d zF!>{ATls9(uo7c>(I6{#N{-=Wqgd241iskoi@}T2XL7^xS!U*!jI=#;pt9G|f_dI3 z+Vl}h%UD7Sx~+=6htheSfEaD$lK@3%)RC}Z6YQj(b-)Hx16%szJT=2R@IP7OuZrDU*?`;=f#n+E8A4&h=I;+sx+@DZ^Sd)5fG{c*^0S`T^s%f`Rg|YGAVYu{(+$rC_n{aBBe8m)Ax+ zKf0uoZBOr1g&hm|W!=mr#1c|l$;t+5(&)|Iym}k3RV1;fG)S`SW`k zp2PDRICrGw6iEC-_;W@yUEk`!1h7 zh8WkdMmg@~+XSBqpACKYp{&WRT^t*wQKK6WN-jV*_Hh;xHHo0ye3y9^$MyNKion1Oi^* zUjT=>^aww812VK@oQbftzTg9d+ak(3q9TX@x;Q%W9P!Dcxr8087bVs)SEehR1-VP@ zy9+f=X(Uq6hjd&bbvdg_p{p`r!9tY*2V|H|I)tU4Y(zNGz!RaoB;CL4x@l@-p-j#pvnr!K;40~;zIPQb6w$6%>0<~a-TU8FDG&-|CU zyCmI-yot;>btQgznU0h)9g!4*J_^Dj@>?^HgQ%o^b4Bgb|G)Nw7;?2AVT?k1k^1I% zr6S7uq*qH?c&T@V7M1DZA+_GQ5S1+|QWO(CR*L9d>Cr0~ zC%YTRVi2#o+FT=)I2N%!@@|RWLu;j@@sTe*v64P9UQDk^A~9JZ{-Yr*zN0Zh7aN6o zT)v$Wi zEp8IW2;}H6Nw+6(lCMMyp5b=kB)0QQL?2-5cW8WoZ5tGvX7jZ#kA59aVT$`jj|(H9 vj)n2M=kFA45u7fy`nc2!Xb~Ol2dE+WXkOzoMfM^m)-41Q4R@OM0FwUz3UPk1 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/dto/BaseDTO.class b/target/classes/org/example/core/api/dto/BaseDTO.class new file mode 100644 index 0000000000000000000000000000000000000000..d3c75cb06c3bd334a499978bd7db66fbb2425c27 GIT binary patch literal 875 zcmah`%Wl&^6g}fdou+A1LR%i?kra^f0K8!VYQ=(=gp^RER9&!}IHTCb$pptih)>}I zSY-hlkXRtt@=XYF#VBF;laatyv-KNsUZv!6U(b_3J&Mc%DutDsMqvdWN&@x&`L19GRe{xFw%MZO zKOK@jD@EGxE3P+=UYix8!9V4KqWJ?&BqPsNWkV9c(fI5!afd^ec`^bF*RqM7yx|v@ONN{)L#z=|;0(_4 wG|p}ph>mlx`!7JJ0JI2y4(B-~u!{=?%8e|i^_uhUud4FZ+69Qf#jNYnPa9E?lmGw# literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/dto/BaseIdReqDTO.class b/target/classes/org/example/core/api/dto/BaseIdReqDTO.class new file mode 100644 index 0000000000000000000000000000000000000000..9355eec832031c385c46918754fd8e87d166206e GIT binary patch literal 2199 zcma)7U2_vv7=BK&n{3i8q{SA3Rf`r$zgRy&r5|WZ3#2w}ZJ{bxF3B-jOtWFLLA-PP z4P5a9#0y60jJA%Qar6df{0&|@BKKa3_?+EMzsM-l&UxQ+&inDa&-cvorjN-HF>kVYCa1{RfEGVq>(Wu>kpaY-QNlmxox zuh}auQ@dQ2o@MXc zSW|VU;Fe@{$#d({^FL!8{f1p_N&(~d@3$V_`Z_;D)sxqojwefT)*}QG&4%>y1Ts2b zbl0qp?S?PCn`>3;nqB;);nsGgu;#eWmus#k89OoI)Exh;Ks-0NDxjTXZh?dIPE9T} z*RD$Ml1=EUK(}aDS8dNx`{+>fD-LTpG4Fb1OWw5C>Q!kK8Q8Mxj#ctqYuawed}&!; zpSiTCDk)1}p?oGc*p9FiuP;Z1=#9{{C-`>#^()d7NUGunRCA5sBv3no!xq_Qc+uK+uJ~lTVAlhB zI8#Ynrgzb<%_=ZdD|Vw2GEBPj%(b+fFU%4Q^@JxI&8p8%1euZpt+0mgh9f1AUU8dV zQJ!~HOS*QGds5Axz_I@uD>k7g9HWPy-+plGt3SWl{A2x#2kTn`9VOW)dQM$UsEIy2 zXQCU2OdQ1_f#XlrViRv**u+a1VCg1?)aEz_OuUJ=1PO-3l>r`TRfvYlB0sFa{ zp#hV=$emC`a^36vEn@e0x!bw7tuu*l;~d}boNep;GEOjs$~;CHqf879e}`Cm+`XYi zgj>}VQkA2h&UY5@HP}96{Aojm{6-;<1|d0M5z4CiGwhC)v{&TQb8z7^UwJr}-6X8ZOZORcbm49GlmuCGa}q z_al`w{>FhMPCY_z5~ulZh(|aQswshpj1iKdsizl_afT^X%XGzpLb`ic!buA|rf(zF ziBBPoBAyKB<*Vh98iL;#LZ=+dj8ABj0f~K?@d_z4GQ)R}9Nj?bBXw?!Y3d@YMK^{b zmREi42|E==jbOz2ojAjROwnj}pSTAYvJFea&K0XcKf9`isWIYN*S{t7;( z(at`m4tk)s3|cnY-XoeZA3rQnrOT{Tu+rQX(jRW3qubm-rz)7D`#`80Nz1swltBEq@An>We^Xpw>Z^}huCK~5QV`ryQ9+S7`qG(BNX&Vb6ga)? z*45S4)~52WOCr*^y^^eLNZ-}-_M#b7T|!JRdw#`HpUAC7O*tjcSB`ABPC4+LIoVXj z@|tQk7Or2@2%FLM{pqJ~&uj>!R#Z^+%B#|sTPjdKt9OxrtT8!q=Gx{>RSF838v?>R zDr@@_FY|(`@&#-S^MY1C9>P|6dKJ zZ2eI~AAffH(e~F5zx@2+gY8H6_5`}is#)^ghW1Jlr;!r4^#6L1L=G<`aTbH*oy2)P z8AD#+>~Vk2wcJ`+`ANKr34xv?6w+>aI*B6Qr7D>uUcsQixqk&f8?egK9~IpmbsJr3C3+$v7OwHFjmI0yNHETCg#;K4wGj77jzGqKcnXk zlKCNX7go5#++ms6AvO`7iKzTOo_UPo0$KHA92d#Z;A{k!IL44Aq!*c)NV8Tyy6pJx zIAtUA2L^0p`HQp5{6r$7Bw}hSwTWD2O|6Zk8E7c~B#pHX#UcO=rCsr2C=IR1B`wVt zEMYQ^qzY5!bSS`Zs!%2Ucq(@Xc77LKA50H-rk#zBw(p8Dj)%RsD9}sH3?xYK<&d@} zI|}0oZDNwF5G2Zf%qLXjU~UL)9QwSCZiywdk%sqRzkeU`-V?h>XpjuO-5hq2JnpZk zBay#`+t37G*Wdn{VNI=JB6}YvJ9_NQA&({Yg-mqv7$0pL>VfB3_PA^NI(Xi|YeZq- R_5COH24{RyZ{jkCzW{jdP|5%R literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/dto/BaseIdsReqDTO.class b/target/classes/org/example/core/api/dto/BaseIdsReqDTO.class new file mode 100644 index 0000000000000000000000000000000000000000..7e1c6b40e14678128fabd93d87735233b6c88379 GIT binary patch literal 2534 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 a@yBqIvk(@&&o}Yy^*Cqz5c?j!&*6W0Ot((} literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/dto/PagingRespDTO.class b/target/classes/org/example/core/api/dto/PagingRespDTO.class new file mode 100644 index 0000000000000000000000000000000000000000..9f3b368d748940bc0c7ae010e95bab538a2a992a GIT binary patch literal 801 zcmbVKO>fgc5Ph3CaqXlK`jM6th${0a`e zz<=n03rHOJ0sJO}m~|VWic7^|XWpCLoq02wpTEEV0Pp}q7cFeMuyEa&fsHL2HyGLz zm8x>e(A*gvGFXrFTrynsR4SiWNg#7y1TjTcJROSoP~^(+^Pp9}Rt3Y3r}K!*_aez+ z$wQq>E;7aErRFb0q|)f6EV9S`!I+_cG0kzdNOkX$IVQe8o>HQvNS2gbQh8GTl%bWK zF-CZKR*LY=Gm)L^bY?0_MOo$4$g7FJ=N*Z6g2y6__(5^SAT+reGIs*j?O2uZvsg zG2FS_*ckTyUmSx?lbWdy)Vi6OuS*eQn^vGjdjT{+I{=&P60wKm8Tr=kH?S`RnsCUr z>tF{i;qKW3bO-^<7a~`P(ej{2)};GLWt!wiyI;|8PCldMoDysrn(QyoTj%5x?4c|6 zho|(|s!I;2D6mR+jY{>gjt$(#ChlTT%jlExb-KHTm0Hl~A3-K!1g+As(dhibmPMb| Lh?=kc+Hd>;topZ8 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/api/utils/JsonConverter.class b/target/classes/org/example/core/api/utils/JsonConverter.class new file mode 100644 index 0000000000000000000000000000000000000000..e6fb9991ca0cabe27a3617d324b339c02ffe30d1 GIT binary patch literal 1968 zcmbtVZFdt@5PojowharUEv@(hBBCVe%L-JerdC2iq$O!9o3^G^Ik(AeyJeHjxw}E@ zuhM)dYLET^{sRBSl8Wahau&%EU6U%&qeU=H6W@HVCm%p}mq=WGH4 zd|D$I!Y3@QvAE9S28%fspR%~grniPMpTKAMoG)1e3ki&2dIVo!@f5zqZHCRUxMLu1 zpdc``;540JQJ_DS-Vhkbdvzsnw&XO`O1rV6bVcsCq!}xDHR*0h?eM*;90>LuUm#QR z^q!@Dl#Q0FteU5lC0mZw4jk9FmVK|8_nMED4wTLcoZgjw5Gw?-sdVV>x3tsT+tsq6 ze(>}oYd;8Dgw=Jl?$NcZd|&RV*qPAolxkkXlCHBOccjJ82lSrhw_7bw2UY}X6-m!= zoB(o${kn1PI(q_huScb*$Sg*sc<4&Ogg9kYcVy+TrHGhh=|Db~ArV%|@dL7%e3?hG z>vDPXU$zS;vl2g%T_nVW?X`7H6`in5FVQ{A&zpD$?+V=hzeEXKe=S5$Rs^o~c2d+x zuJe=9mK}dBDjBr3GI1A06JN2o$6|@aGK>2xN-WA)5g1&r6ldlQteRNE*Crmo78rlQ zc}{D2$iy3{m{`Y#flU+NplV_Z+a|uncLJ$5ZCyewNb^>NWrZk>83HnRgBmYjdL(FzU) zE*2c0$1?BeTHBTSf!bACHEXJ%f-uU+vmgVt?khf?$9pb@WSU~Y310=T)P)-QR%-h{ zB*=^9d`Ml>@vPdu)C6zkqf@}x_4Epjy})cL8iJ7FD93C%QuXlU-Y1|K=R()JmnnyE znG4->&BOymrO2(Vm6r0k%F^n}!)2QU_1L_?l{XnjS^+Pbj|ru7LJ_z0s zB;TW(MW>*1F!KcBm+Gcv&YxJ0)Rg1Sr^c7BFI^wat17=6_z=)ZrA z0XhduQ%U0w3|0F(Fzo6;2g7!Cu!9l1I@F;JRy8^}WmktgFzsrRRHyADoS7Os`zw-1 z7(K=qfsB`@J2>|nCi<|MnLff~X6guUWqzjT`oST7Ord}>8KzK@6leh-(Vngwv&W&l{iU}o)e8U>5!!i>H0ABH@CVnp8x;= literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/domain/AjaxResult.class b/target/classes/org/example/core/domain/AjaxResult.class new file mode 100644 index 0000000000000000000000000000000000000000..4fd5172bf6a2a263eb2a735445f7870e53775567 GIT binary patch literal 2704 zcmbVN-A^1<6#w1*n%NHuEESPz=?AULEOaThwa7x*?gCx9KxO%`e$`Yx?nR|ZccYf#G!=L~B z^c#Q+SP9`Mt|`c>7zkk+*ZDrDBB5eP#Y_ku%<^R}NXrd=;#Iz#SCQw>1->luZ%Yc6 z`Q|kRHyPThhGpudCBv$kmGWXX!@#B)TGEwr)z-`Ql3uDAeqz9X7=xOg%S_x_NKG+B zbL;vYJyFuj#YEn=%yMyrL7B-eqhOB+xK-WOA6Hg>rIO@r zy>NR*-xL{8BTyX`yh)N*YlVVQrATLEeTU2Ea;!=Gr*Pd<;&86h?x@oBsd@Mf%c@um z!_Cw^qzvB8noWhfZM?_ezr#D7p_w$zNH%)EULiGED9M%#=FMVRw`&$54m<8O+bkun z>D4tVVbX1OTT z|M;(8Ki~c6lZW@dh~P3t_>zp^IC>&@2Lkzg{oKQ^w;uiYO$4L-+$cYH3O&^74GEka zIC_$yUD(~}5_NaPzkm6FERVk3-rf4p!4?)5o+IfVl$bDbP*A&zLe0G^Ze^cK$i^s9 zO*y#4Y{=pyjk}{Xzf^SN8FYf-S=xEfh3Cj}tiJcs{(09vK>HV5dxcJuMC99z6E6En z+LI*0e%fX4#Sy}$BGLLHeSL|ZjGlgN8*GbSJc!ZCr!f$R5B=z)w}^8H8rf**5gi!hjSF{N zqzD9}>JEb6k%i_mtpQ=56=z?OS@LXom6WKe?I6StJ9TmnFS}}_2wF~bKckHkbwnZ! zN~D0sngHo8pn%A<4#b7$^pg@O13$e1Z9l_v^LvCJAfm;$(XyXgNkDcwXC)+g36^ZH zvK-uDI@&~^BRgo_uTPE0(B+q89?Pn2KZW<7lobt-=2^8Ll-0feo7I>Ma7D@%=CXCi zSrf%Rbzz4^WD3+?KPHSPipIEj6ox{+VSpcWTbPiqL_+~+T$;46Xd+__-A!Gm-e z_|V}sPElLe@7y?ZmNosSOZPB`>?i2fPkkRiJV6LeSkbLu}ZCi3zC literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/enums/CommonState.class b/target/classes/org/example/core/enums/CommonState.class new file mode 100644 index 0000000000000000000000000000000000000000..65b3d23cb4ca109821be11a68725cf3b28001aaf GIT binary patch literal 371 zcmZvY&q~8U5XQevVw1+$^p941_0%Gmi#J861)&fdu;P6a$B>fjN=%BcC0@jX58y+I z6H)5HJ|suCJz{z#v@7wG48p(qOJC zN~t^*aHbc(7o4*s&s0{O3z*}{t$;PtcO>A4nW9Bq#8lqMIA_OQ>bgwmGHZ(NOc#Y# z%Su*s+&p1p&%+S=9$K(HIIsl{b(seAB#Vcff<%`TkgAKv;7>14+5krJijqp8x3PYh z1?;uVYl`j#hU593@#rt63w{YeTc zMx)`gKgxJ++r%OGVK%w<^xXTLbDr~ZfByRV1Hb~7;t=pa!W5=O42e)BBr(IcS$;DY zLrNk!&y|H3(p)Zzc*v00uI#=pR<<`wJ6jAhW!q_~`dh92#?;li?dYm*b=w`aXj@Ig zY47OGuGOfzn%nJc(8Ur%JTTr^XAlglX)`G0L+waYP0eblRo5}B7U9HfZLR!rqslP* zs{bg_BhBpU9ftW_{y)rxqTSFL2Fiw|Z+F}Ky0fe8n{*<2ek)Ce_1s0)`TmJ2WxKAK zHO(=2fFO!sX>AIY-qPIzyYWJENOg6G(upn`mf@~2}}yx>7Y-7In#?u)~+Q&XXUprMo4sVMDq6#ZU~f<+>Tr3+K4SvmO+0|8l?e zS)oCYs&?0@>zf9z|HMBAYno4xj4OPYhh#j$V}|MeW>dx}p2)b4r!oei@V^@}QW%ht z#sEX=&yez57$SAkwusaDYE6+n`R(TT$O0_icHKj{&~F^mitu99|}B>$viu+IpcA^e^+h7sDM-d%$5 zqZmWT!!MBJ7LpU(c=#D$T>7~a1cyeJcKr)P5Y08M!Ac5}C3L#58?&2Qp zJX@6{XCEnig!nh{5if#IJQ75R;XZPK@eY-ae{?yIZ5<5lw1d^vF1SR3Aa^yQ* lhmUD8_k?4})e|tDlV4Ilr$J($p*kdppieW80%1a!{0%;_KDPh> literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/enums/GooodsOrderStatusEnum.class b/target/classes/org/example/core/enums/GooodsOrderStatusEnum.class new file mode 100644 index 0000000000000000000000000000000000000000..30c88aed0e34d038f18ce2594a130f7808bd1fb1 GIT binary patch literal 1891 zcmb7EU2_^$7=9KOc7aW@*?hG5XqqOZ1)2t?L}t;Te=y-Itz3h zue|mr_$!pEb#!!k?ceZ!IKJ-zN7Ckoo!R%<=bZQZyl4OV=eIur?BHnxGV)QFI8d;u z;4q47c)+5-JD;mqi4s0!QdF_Z_(;VK#*&IP#JR#xGQCFdnP8$!Mv##aL01 zU_4P!m7qS(7Anti^pwmyzcDN07NaX z=hvMBmwUf>=@4)6+-SJXcWzU|V|*!LbDUeCVH-6KAL5CIBvSnKk%kpq*Raas28%To z>n!3dHdx$baf?L)*Xfr0KfqkAgiyWZwJGn5{VJcHIrT2pc6YSVxt87O?2a^Scn3y1 zJ-o8>qjp2JLb96KrXRvJ`W0!J1!pNh+ zeF5}E?lSQZBDjMs(6uDCM#xXJ59t>K-XQn`F$wRH42!)O>2KqG1cd$$AzMTZIrS?- zZy>XN;DY`Kw4x2P=+{cIahKkZgq?3$l}-pj;p_pS%*v_T%dZhm-T4{HkHiP=CTSPA zPif>3LmupQp7z-J$D%a;;^KlLz(f%Dbl?+ulccmuZvcCg$EVmQ$S6ot=C(@qmp(^{=|<+epI8+VEutxzaU!QxhucnvA}BPK;3OWcSHAHata zZ~UPfXK~NDhq*J~%*W^3JAe}$n6S|`prcop9fiKaE}Fq)44c~DEB(UkAdFsuQ@4QmEb5;b6oZb^3}S}$9F1-(FPeoNz7B7!B= Plp`Qcp(ja4yoT*B^^8lq literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/enums/PayTypeEnum.class b/target/classes/org/example/core/enums/PayTypeEnum.class new file mode 100644 index 0000000000000000000000000000000000000000..e583d05906c9ba3d8d0847bc01f99bd02726b9e0 GIT binary patch literal 1326 zcma)5ZBNrs6n^g3y>%Uo3e&-S!y(%cDhP-|2n)fmWD0ROL;PUMD5IonNw*RC=1)>k zF&Yh@{ZYnq+9eJlaZPSd&%Mui&U4N^{q_6XPXM!6j6uQ!8IzcbU@!trMgkA{HO(h8 zQS`}VAF(qVMUw4Y1oHy&>$TPO;?~>E;`iaH;UnE@8%=@n zT)xK;Y1P>^1p3RSZM`L7z+ZU|DPxYX*^MI3r`gcK;^I73i{BmAc=l~zQ4o8It4;C z%dsi<#Y#7J4vboh^v!j*Xw}l2&Bd-#JM-Dyqs~~Ty5l;qQogz}O+QP5eluw$&8h&h zB#d@c)(a$uxn}Z1h+zmR2wW#`lq^5;3B(r!&Jp}Tp1=)yhrP2n;nNsKz{AgySTyw9Jx;LOKKfIGv6U?tI?nuJwxmivggJnHSW1e=m#AKPiO+Sr4uNXQwXlf YZ>e9?0I5$=AL1m?mzhU_Fab>b0nYCmEdT%j literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/enums/RefundStatusEnum.class b/target/classes/org/example/core/enums/RefundStatusEnum.class new file mode 100644 index 0000000000000000000000000000000000000000..68f4e3f3d6a7606a3e7bc08f031a0df8173c9c21 GIT binary patch literal 1473 zcmb7DTTc@~6#k~&cFT5wvO-ldI7{E>5Zt>0S z1PqPj9R_z37-Tu0z!1w~0%?{DDi#G)^J%HHVwwWEvLDn6_A9IY(zOd!Kd=k7*Q_@R zoAzGQ+ciTgY&KTtWL_X%Dp$;v2Ljs0W`)gH*B=QamhZ1uHrJNR0*d49`2t4yg>_&R zT+6E!%rJ1g8X2pZt>yC56$+Vuc9NI}mfN%&0#n)CN$ix8ziSKhmmSYuZ`OD0;EA>4 z(upb^R`vuIvj6iuNjZ$NU$xvVD{$Cz$GzfNb&8T&v%`IVcf$$@hIT*+#EXvSgjD?O z5ph?Kpt3~;4fh=~)iT_ZOxtyD8~DMl<5{jikLlDr>QX>qhmLTaBR^`*4p(Jw2D7>U zLs1ipRkuSgnq`amE-h|<@z_0Eq-JZT-wdkuLx(Fq^zSIm@ObDr%QHNz;~tg-CXP9V zI!3XqBZK=oPU8&!UD09Sl#W5(hImWkltAB~A>;%EVpZ4oh|k|8sO-G3t08fo>#kkN zwHl4?8g%BkyLg>fk?ywZsIBI{{ZU**MC#9yWDCtu@?Q`;gu?ofzw|HB ziQd*C{}daSX~hJ_Ub8CI6jAByF-e7$^ONU4Bc7lB2=yJ|w!1#M1;&ZS1d_;t-KOb| zosY}Z_>Yr|$^gAlOr(G;t<$8GqZL7(cuZo7cFwjylG(@dAE5qAJR>8tiN`t-5}3wJ z$M_AEj=$&Mplln7sFC=Lp7+osOe#iFLS4e%n9(a?pM?E!qhG?5`kjoUEt=tNr3KyG sjxM^HOk?IiXBv!yx(v9HSZ-xduBLDyZ literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/enums/WeChatTradeStateEnum.class b/target/classes/org/example/core/enums/WeChatTradeStateEnum.class new file mode 100644 index 0000000000000000000000000000000000000000..d33bee288e6312ee3997f05f7fe4cd4ab75617b7 GIT binary patch literal 1670 zcmb7FTXWM!7(HvtmaHg_Q7$AQ;S$nfJ52->dP^FT8Usg_YUgRQJZ$F@rZ}?1IKQXRki*=K%chH|$zY68mA7 z0;{X7-P(aok~V%ASJN{$=y_)XH;bileU(adZ`netAo&!0}{nYe&_}QImhpYZqkb>?d& zH*gi#xVK?o9t#E*xw*v65;x1-T;}Eq76kJDpH*I)K&BH!A<2BVI*r21(pjCl46M@S|aI|NYW*edWp0E z@-%tDKw*)qM?8ZZR`C%8J|?z8$dBHK_#LU&NdHPq;0Co>Ij50*5hbLg{T)K~&`qWM z2Qsgruzl(s`!bCf11qd?ZhS&-hIZ^{Hl@-dErUHIRM@z@w)6_w^7>1tzY!mV%hN1y zi)7r!1U?0aoufGpZpo!_j~ADg2`1CHSs({`uaePidQ;>k=#zSvT3)S1$m%oY7f|09 zZpjP-;hA9u4WHrjq4R%KI(~ln3rgG6(x&zbx#!R&olwjPNexLSGv=hEc}b_T=9Hub zNiV481xZawr!{k0(iur-3t4kk^0|WgH|0wA>4vnGJ`AUw=_Bv7vwaktw%Uj3w6#8F zoOXeR=A7pcT))Bgtw5uG9#fd613gc5U#5S`3SFKX_?{|uLi4F%nZCf6WShcQZvhZb BVdnq< literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/exception/ServiceException.class b/target/classes/org/example/core/exception/ServiceException.class new file mode 100644 index 0000000000000000000000000000000000000000..7b55bfceb5ce3af0d8d841f6a2e071d5a31a72a7 GIT binary patch literal 2844 zcmaJ@ZF3V<6n<{9FG<+YG|-k{p#^zKla?TeN=iY%0>!4(7EthwZMr0jX%e>y!*B5i z$QM573epr&YQgv2_yluwLN>wX*eFyjt);_(erAa$|FKI>Puj1D28t?FqYoQnA1w^gC!oiV%UTc&c zParDGam;U%n9>Cw5p|$iB~O)*>Yop zt#e9tzJ*C#H^DuFtc3$eS(wF~g@bs@#D^SK9(XPj!+t|;K?MlDqPLQM!N< z&UBxByJ?5o;|Slr2|l19{;-5fVgb3w!Q63(`osLXqbz{2%u9$&wuR6OgypWifc~Sp zHpMjwjq4=WL$G*pKc+BE%{Z^~GU1MLm(trfMu6j#b-@oPv=hV742AX_<}PT*iFSf$ zCyACGf_9Q89ki1H+Dw497UY&xxoJNkqR@7MIz^})p-y9z4LVIfeqzZ^VoBNlU8sW! ziUUHGq%p@`aMv@>5&nTfhy($KQjRK*mTwSv6mq7h8N93yULN1|@+l(v1sHK%j`k#DbdoVtOLTZUfCM8sjW%z6E_<5b|6LC7BVBUVgDC&zZjz94HuF7n?OFDB zM8AU`ewO_W(ZXz|g_!!JuxDkKOJ1A%1A9{1D~vvcHJ8#_u-X>!yiSvN-bm@v#(0I~ zQ^Zqx%4i#D&xjT7DS^+!4L^ns4`rO?e;9lSv5s@>;1GNFBfLjln2+B@yiZBPb=rSG zNk@S#aGsKZJpE52YDWISUK8`LF>c}le??kFIJ{f5+SLam4_=-{`JLoUE(7ERm^B1%QMdD;)zDx=uiR@FDb1m$BAocOQ zCJ$0ta1xQk@@R5*!er9)8iWxhAs^y0F=aScD1{JX-&|#AVb1yl$&-Xha&AI<}Dhu7#=GFjjr=04)Thw{Og?Rzl%A&9BDn)XdQRT>HAir3Y1 m5mNPv$`?36g&Ya~Z4EN%J{f#@2j_N=@;~@w++biKEd2+GKmUaQ literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/exception/ServiceExceptionHandler.class b/target/classes/org/example/core/exception/ServiceExceptionHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..38ccbfd915de4aba6e4ae2d9b8fde657d8acca30 GIT binary patch literal 1523 zcmb7Ee@_!Z5PjR9wt^rih#-oJ7Esq1OpH~MiV}=P444|@Uwd~eEMD&}+dc4O>0cz8 z_yPP-#@TBF(_0&CGkVJNNU~w;uqOu~bD7^JUzsB8S^$)XG?3C_PbuGAj)E z+Cqz=uo`-jVWg=7`8sYpQoj|BPoA-6=nB6jw6f=(vtV{rhhe!H>K!gWi+1Eo?uJ^@ z!IhCwVZgVg-dC=C@yD?)0?(Ja&M<5%zmv{06?jrJ@LH0m6KNIfeAJ>X4?_KkA4rEg z1mOgIE{y2H>y~ZF`fcc)(?l|iZb-8mdT)d+Vx%SwQ(JLhR9m)GN0Gor5QIip0ja)$ zyhMuSFG*34AH$IFyoNDaIkBM*&SlGs72lwq`-z}p+nNlsnR-$v!=p?<+NwTEN%E8i zwSBUaeIpDTU4|#T$ofLU;V-m^6mLXoOLh!ZVx;=+anRtmK{1a{EG*+i759Z7Q_+)m zhnPlm$8wu4JMK{Z`ONye#zcIbmK2xUe8o`R4rA@gHDxDcX246ow7geN0scME&ylA0@=ejhkO$JFu{}W z-@ut9aDtNAfNr3*Mlee2dGZ$R0T`pdtu>wiFW}<;GS3glJb}rh%oBZ?FD03$aJiTH zDeab406%$&2&zJB{Vdw&1t=U)IUq8!5@GTk_X zyD{|Ro{qH`qR7PYHr|QjKHlZmdvWw3%L?mpY+y5v2Y5e*hsg0Nuj2z9TYQ|+@kqyq z0)0j2OUu1unU!_3TD4q(@vP(SC8aodxA`z7(3!R?wznz}nVH=Zh-RFkMP9OY#o9P5 z?^cMq(BmkLQTC9_sb&4wht4rN+%4&8!G<%9=;{-Ra$?275xPDMHq z7zlY$eg%e`%Q&hAr3|+!r}O#LDy7}OZh8Ao@qy`@Wy`Z%s<%65?@^>fmy*e(^D7}! zKik!ps8R)(r7!|IVUx9MUJE|=DIUXpDnbl%k`2knKnMYqhJc|k3$`(}Rgs25Y1acW zff_(6#eSt2junwvkF@cSPB3U^TTB8ldvcyxctXsS1d{aK7TEcJ41)yOeJHAIs}JNU zA)^JSdL%IY;*R)z<128_*Oc{UoKlG>N~H3`O6lXnij*bS{6)anFh)M3THO$lsoC;o zo)4vb(k0(qN%R&E>3mKSb2@Z-!aBV`T5~>yziNwb?ghMU8}cRN`Iom2MbP`MbfM(W znpjR=u6e|))UjjWBYdo5+rTII)WB!> z+<=K)Hd@wEFi?c0<1z2|bnF|jabVyHN&>wNkBZ`Br;bR0Nj`hwaHAn19foEa4a`Oi zNnX#PS*(OoFJQDlm(AB)o)6E2(F^Q&K_>LAD#(X7^!8uwRN&(||g?8OcUqqzwCVe%QeGe@$_ah?T(k2pea8WuKR!X>t z2|8yNlek1qr)aI5v*cBhyvC;*DS`yRWqLGBlfevT{g{8!x0B?zo+G;b3?1u>0c-P z8zk?A_BZ-;Eb6%V7iHt)Fi%I5^e7x&r&N}(OeWm8hd%Z_iQf?S@sDu>75=^S1+G&b zHwfdKp+5A~`_LmR6EcGcgb{>g_!IOn?6=4dhuf#H-0D$+J1#JH3`4_D=s8BOhF{Uw z+WF;B#8Ha4Lbha$6w-d@6)X7cjr!SYGY3+1plW}U0DG%W+9{a|5Pyz-;=sTU(719D OV%`|-Zj(&Io&Nx9i<5r< literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/CronUtils.class b/target/classes/org/example/core/utils/CronUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..5b0fe9f18be11792bf2c2a787d2eabb7d8640e7d GIT binary patch literal 819 zcmah{O-~b16g{tB(=RAi5DKURqPE328+RBDDK;!RVrXsR%DlFZGT50R(^pgfm2M=_ z#H9=Wlg9IAh!R6$livI8=Q;P@`SI(^HvmttTSOkVg)Ix)dE6@^g`GU^8~wn-LxIx4 ze(%NG_R+Ds-xH{I&g6UPOk^;2x;pZL@t(j!D-5Pu2D&dNGbNCF>II&DCXlW-`U06& zIHI@G@dEX7<_}cVlYh23oC5~-8rPA{m>Pklf0N1f#Mc6wNkFT)cDkNHH@(_n zcJ6E2^^y59&+1*w8G#tH>k@S^T5eF)E!&x*`ZO=@;_-Bg8 zW}ju0u^_M>@Ag_`0sDXZ5LlT`ZQr*K5AD&&c3u0q{eeHzydgl@#4@Sb#cObt2m z6<2aowz^#A)kB+G=92NTg*3k#fTU4Ck-9`Hg$)0~OhdUyk3&stWSbWdpW>7XWiED> zu*7#cNx%(MX%%o2%WPtb=LAVp*S;e4rkc4xwo}cy&F?7eHb291AAMvn4b$)zvXpCN zQX}>{n{8kfw_^Z1X@V7Iff*G>)(E;l=o;-5^FjXNCsr+NSlDDCDRT>~7q~+sg}c82 Dw92(X literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/DateUtils.class b/target/classes/org/example/core/utils/DateUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..5c1f2cece604fc982ba01cfd9591d3f0ca02df86 GIT binary patch literal 2178 zcmai0TUQ%Z6#h;w3`vJTDS-;5rdToDn$lLZKwB-B0wz#}(xRvg$sr6)CUG)U`fv2z z2Yd;vvX-x|<&RRob7p9QO_!9JGiTqvZ|}4Bp@04T<_`e(;Knh4#W5)x=$Xul$1v;~~BUca0yVBjTc1x6WXDfNDv}w7v+6Tgj zw{O=3hO!m6n2|?TxmuE$e8rWSL(eYNGV_)vpQ*1IflGAHFC10pt=Dw9lFlAjuPkk+ z&1OcH1rmof>CU;5ZX0%)s9pcH5{TA3%k>0$npAUENje3~B}~|<{45|!d{&rFL8A%A z?#fATzfyQ=xmHIB#>+}T{z0is%KXmCTLVGj|FxFI@Uca|1xJ)b-x(+fj!FxWd7@w zLpLuMZPi+dw{3Du^@NFQ7&P#si5+mW3)U-fu~|$Mpd7VSlh0P1qH^3bQN+GLzgD$8 z0%c|k3^YPMab>Z>#&*v8$ix9&nwUgMeMu8#IBHvA2^G69xrR|2HLU(uVii?t#p+o0>#^W3u-e)Xy1nzKYUYb~qePo~7wc z2OXnN?c7QoPEC6LY_%9cUI3j8qx8#8&MuYIbn{|RlayXj_d~nwc$-$~kPwt}tdgx7 zj)q1MhiorUQD;pW=Y85}s+JvYyi!VR}{0wx`>2 z!?p4fH+VA+sLK^?;OJtI@9W%UxC*Y((G!T@`4Pg0ff3M!6u(X1fFXvsi{T^Oq?L01 zg~8gmPMso@9UHA9%#Ymo86sOJh;ln#N81=5`S=XR){P#tmroF{oGtv-xFp4pR=@Z5{ zCg^dCwoySRMLdJs0r4FggemJkgSo}bJF;g;kaK5ljFh|TxO_~lPcES?Z_|GgmkFDq zCgpoma)-MZ<#$O?aE;+pO(p=I)aogG763mFfRhS%jKH~ZmaY2~SL*0#V8&?fV>-Z`lP1so7x>} zE%foy8{id}V#rZy`}jOy#_D7S119S05jm-t9YL;NP~VG?@elty5H|3o{(TH#VD7vQ Oiuofx0`q)_u<$R`iqW|M literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/IpUtils.class b/target/classes/org/example/core/utils/IpUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..2c6f7da484b9d3370eb4b209f534e7521b25a8af GIT binary patch literal 1284 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 ESCY>P=>Px# literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/SpringUtils.class b/target/classes/org/example/core/utils/SpringUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..4a9b5efb9d9190d19da58427e8413a27a1c6db58 GIT binary patch literal 1449 zcmb7ET~8B16g{&o)NZRFO0^222-+59K}}37l3*iG^|O`tX&K96yW8we1^<;F4+bCn z0sbiCne8I01&mF0X71-XbMKx0`1$QSfCso|V;rR{#!$|of+e%u$>44V%NaNVQ?lRh zx^1al->dnaR{L6DrS1nEC+r8V*LfSrp4#(+cTRg~b~Z*LssiI{uIK7?fmEryC6KQ9 z+e%=f?t1F^px07CQ?|O)Ox69i>~6`xHFB&>>m4@~ScqWNzU=k8ig1B)2HNe0P9tLS z#+(T?9V$J_LEwJre`y=0nfO`)_S5~g>YGA@8LS9QK2v(f-+n1g1+)stFw;@`iISec zVyV6>-%F<}y^d4s$}p^!6Pg#TUDej6E;=#_oKIMX{sM(Ri}9gNgn+8`CIZnAq+G7<=|BkL5$Ftj-)CFq) zCUgR1lA_)42SHnHx@KG^6Rlr1$O6UJ15dj>wdIB`M`*+Id>xH1`%^h~0zx)V`G%uY z^Lu^YQ=YEoVI!Bv8Duk9&Epa-n`KU5-pu~#Lr7jnRT$QtBN+YkoP*6Hz1(jb?@#gP67G2r3RyZxUsJl7&Uw;%v!y z_zS%0MSBB-&Nv+}yzr0sADrpOb2bT02s3SF&Yt(YpU?ZA=j82QFJ1w-hM!_Mi7O_q z#t_G62CkX79)pe>aooh`aeRSWab%HGpW6mzOnj-#vnK8+k2w=}O?;(PUmKV=upki4 zxm7oq5zr=6YXbURZ%Yac<=v`WZd5j=YNjD?^o?o)% zu2ZR%rCs!VX*UA5T(=8>?^a9qm7EnY-1=PEsqP4zn#@0TesOG`N-d{s>LD@I17DTu zF$xS60;jmM2nw(5UFnpobCyoYdm@+eRh=W9?H{Ndob6#Q{{S6WP3F;Szf4tZv^@aZmH@7 z4WDygJkrVkOm%F(v4Yp|i*nvo7dqT=IhWMHEu2D902UVUEqgn93C*qr`f|IK@{IES z&OqM65|$0DSh$DpiQd8wC|Fp6#%S>ALjIp=8xl82C3E8N@_nOF^>C ziOJSMId&8H7w2pqr^SeiOO zzrZtODZ~W+Kzuoqu=X%8&6ODBCp~?Dp@_05&2Xn_{rTUoGl>&at!MU-_>E=s5b*>d zfNjRuXo`?76YVXcT_DO;f?LN${EYFiqcH+ZAw$h5B?6^>f_n@b_!N^IPl~7J2$e0( g(-_wvB7Y)jAY)+aJ!aeekJB{G6~QHj+M#s$AMX!%ga7~l literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/excel/ExportExcel$1.class b/target/classes/org/example/core/utils/excel/ExportExcel$1.class new file mode 100644 index 0000000000000000000000000000000000000000..bf363933c22a2bff2f02211099cd0dbcb51ed1a2 GIT binary patch literal 1281 zcma)5TTc@~6#izruy!f1T*M1rP^)Y&uz)BgMG`|w(xhGz2#MioSSDr3c7{y1hDV=G z@R#`FgAg?_Jo}@JXSP+U5W*%ibLPxB-}&a7vp;`*`vG7P&$4jw(8T~AIhc0f55Pvj zMFvGPl^jgE6j63C<6zc7z|f!UMy>oDL$R)OBM=9?xgU!lR9Xb>B#K+)3Pl`L5B8N# zs>ZHR)^a4HWQAeIzkFI@lfhn9JAz@j9!c@4-P{&>gKx*=8Lg|3$D3S7X5V$%h8#n# zCZ*7;F>kd5ZOfM~nV%=F-b<0}s+~7n^QK6ICIlx`&3&$^Y{B2E@9}p$h`DS8uebL^ zm{iVj6>1EYnr9e0=g=H2FiiVrq0V{?Qg%IRNS?F}gXd>MIv%5bu$mI(iPFpG6keh0 zx$CN}L$MYa6}_Hknl<+#sjD)KRV$K>jt&myau~*Z4ucpn7BL?=m7pdQ(GZ$p;lg&{ zQmTX}k&@II)Dvrwh<9>$j70oe^vjMCgsnZO5((LB+K!Z=yxb5k^i zYh?E^48Hd$nDnJE11r&&7V^I%^R|>(ID!4u#2usGc*_5Hj^KQvoKDf9H180%@DX_& zrp2c^SbvNAxQWS>oKJC+lxb*WEpme#@Lmv=+g&P4lx*%iSS+33N}0wHvZwWWFG(_) mz;2yCm>yx$uyKbDE!-tl&3X^_X|?fyXkI1DrDT^@`hEi>rYlSU literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/excel/ExportExcel.class b/target/classes/org/example/core/utils/excel/ExportExcel.class new file mode 100644 index 0000000000000000000000000000000000000000..138e13ff4d50701d0e5165e2bf5adfef9ed53509 GIT binary patch literal 14903 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 C{H!+s literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/excel/ImportExcel$1.class b/target/classes/org/example/core/utils/excel/ImportExcel$1.class new file mode 100644 index 0000000000000000000000000000000000000000..a15bec7c3317f2f5c49493e74f852ed52c4c63e5 GIT binary patch literal 1291 zcma)5TTj$L6#k}LsM{@2F5(3*sEc$jP*^W$7D)`3q{(_oAS8yTp-h&NZcEx(RaOiYdPyG$StCs)A>yT{?(T-(AiMH7;z>B14iiDwd zZaeTOiY1pp9JyIftOX+6v8V+fDaywd7VyNvRa~RSI+v)Y;3COupH$L$42H1``cDl8 z=c2R>g{F`zT=GVcN`|T4XUdwYzU7sAG*@mUY|hCVHl?=DHuP?~<0&lPZJ&*pVZ4{E zD_*_iVUqr{0;qSvY+Ff9KWL7|5Nv1|rqvQzjjUO&d;%*ULif%FS*m3lyyGJW#G2;Zl{x v0rDsLdM`;bDaUS}Kb$sk($H~>4mI2+Rh7MiyJU6TqcShk%A{bEEPcNLZmBQk literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/excel/ImportExcel.class b/target/classes/org/example/core/utils/excel/ImportExcel.class new file mode 100644 index 0000000000000000000000000000000000000000..b68827a95f6e0363f4de0abfe866f5549b9cf7c8 GIT binary patch literal 10692 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 IhByBGKNYTVT>t<8 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/excel/annotation/ExcelField.class b/target/classes/org/example/core/utils/excel/annotation/ExcelField.class new file mode 100644 index 0000000000000000000000000000000000000000..49080fcc443dd0d6bf759e4b6bd546e45d192bb3 GIT binary patch literal 778 zcmah`T~8B16umNO2?%Ld6Vs<*xooDH?l!x#g#I-j z`~m(bLo zMN<7rvA+EGzkbW@i6RpBA5}oe1uYrFG)pto6xqKss zBh7A@r0nKK=?oD1cBh&s2O(&+T=v<;fJ5wRw}hrh<#d_?`<=sQS6!>3E1Jh^0k29% z4uBc}!d<7uNx-K^0G4Kf$Fsoltkw#x!mJPvX^o!1WscUNwLwoO;{5__6z4N~j{7x| ZHW9A&slv2HFYNKs9^15Iai(3``wL<0x}N|5 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/excel/fieldtype/ListType.class b/target/classes/org/example/core/utils/excel/fieldtype/ListType.class new file mode 100644 index 0000000000000000000000000000000000000000..a67b8a39ea98e278bb75da3160558f0ecc0de6f1 GIT binary patch literal 1940 zcmb7FTUQfT7~LmKG9eiRqujJgtC35HL_}!?N-J1f+XQVvP^qnlYQ+`hF31&!mPEFkm(HSeZM_eShPQ541xB-F zcP*nH$zsJ(nS9w*nVM%iRhsh3$*kJSDR_@7DwDOV-U1hs0?{?)ElQ`x)cu3m`|_d8 zII^^snfF|~v^F`^WV*g`U*$c<2-Zq89R$9_{!lu^?l8STN8Ljs@C!1qYd3fz2nZzi z_)hK5KF#>Hc~9maov;Do?ot7_A;mEMU=0YzMz#d#Wf9 zs;&t1?1L~WCddL<(ivUS8aV)Z4I4Aw5}F9(PbiMVGh?#+_3N^ zzM`0E3-eg8a1*@uL;elyXl7vvx0u+%ZQQZ2jIYUc?!dypiy zd{=-CxPrVu=6^QJuF7@V0!Nnj$)p8(%i_(Me0E*B z^Xj{rD&^JW&>ewrwc^+;IMD3X_z(^x+9C@DfzD?CMt?D1l#{nh z9i`2V0XnJl=xg# zab%v|e5E<{F72A~@3J58jp02U;rproT0lPN;@HhyhBJE;;nXvTpScL3hhxMywxgG8 ztL}hfIL=)w-oXia>EKPy5zZH%Ba}@&N6U{GP9=;@gmdW^(=Fphr*YyZ^rSnD^Aq9W z-tZP8AuRo1h>h*PhMzLf@QWSulXP;|#izL&Nm|cx9%Dfb;9X))vhYdtA*{>M(&tBy zlGiE1JI$SjX+T?&T%Dn%8=-Bc3Y+LRF<@d)km=v#F~q~LU=~d$h2c6KkzgI2zmR%` zd#RT&vm!UVg{Z*X*)6mRJi#R{VgfG_pD=n2GJb-{#`d4--_h|atlPcDGqmM4(4N*R z9O~7>(#H00=~pyuqCL@(IJ}9()5PJo?8ni@nx}~UG|?ofz!~)Oe*^<$Geov2%plFz zYlJV?Ilfn;ko-Z^%A^?8k3pXHan*`jfgW)zQo#}OA{+9|aBgT+_iAW#5|KAZ`0|`H bG5Rk~Qmu~Hh`&bYAG9}1C2*c;LKyoGRmaY7 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/file/Md5Util.class b/target/classes/org/example/core/utils/file/Md5Util.class new file mode 100644 index 0000000000000000000000000000000000000000..54f10fca7af71d2f184bbc3d0b9ef3eead6dc7a1 GIT binary patch literal 1353 zcma)5%Tg0T6g^Fn=@7<8kf0G!d|`-$Q3QP80};_^0#@-V%he=l<7hIIn(0`uv0V5i zZrti7T3Y1?_yvB7EAdP~QHfQiD!2RIKKI^pAM@q=$Ik#J@F0PG7>mP7;2h4!F`mE$ zOoYm$#8d(jV+mZurOn2HHqs2##P64G%u0N$f`i}mRC^%`wEV$7Mk^v z@|W#Wjh5bmSGH@bw(o@cwlS)oIDx?Fg6CH)wQkoNHD#4OUs+A<)B@|VL%mp;T%k72 z6!praz;LGU)P8PTHQTLPOWJqb>h#EN6S+8A)dj??Kv%sYFt`N@RJrLpdc!KJAh4@y z&Z(+EGknbUeS3r8N1;bh5=id~JKJ<>73C8xSXAn__uK1b)zFUThC~DHhb8agDX?cr z+vR6PyU}ie#0`lViKFZ`n<}ussPq%B^1$}(y3)#LcM?lp(=V%e_Cmni?#5Uc+Qfb& znXNd-Y0a3p2@;R3EYIgIF|dhSm@{!3^8yF|X0ly}#2piNkvDM<_e~T~G_in1fde}Z zzX}sL`5$v)4LiPzrKhT_|1fP$Okkjm>O2gAo~qJ$H_*0QX4U8aJ@U>0IDwk@u`p9K0c9rEKi_VQB>e_dd|k)-UUX7Lm}W7+o*@7m7?D2=vp zFZy^lw*W|?pISE#;t+$-S@a-^IBjdaT^|rBoXz$|TZpw_6hA>ee2@6T=#^+X`gtlA znKDvFD)t&@($SQ0VM^vwGKtL>T+f#u&>b~eNVL$i_R0`%HoxXtFy9u$+jin5EMpHM z2x$#7J&-27!>nL{w<8$GAo4sHag4|ztgzOQ_I0AhNj6Qa%)H2+ydHmOL7VTm&m8Ho`}!H#`Hc9Z1`K7}HSv&6^v4e$^c IrR+lP2il%G6aWAK literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/jackson/JsonHelper.class b/target/classes/org/example/core/utils/jackson/JsonHelper.class new file mode 100644 index 0000000000000000000000000000000000000000..d285ac43b596fb237980ea76b3dc3f45e7ee5929 GIT binary patch literal 4607 zcmb_gTXz%J75>H-#*$?WCQ#d?ftG~YGN3krki^tMv1JhG;#dQ&X&PlL9n2U>^p>WV(57p3bv18!Nka2rvI47l&;NkcJmnuW{mvO(MwVm&tM>Ao+dg}L-`@M| zGvm+y`{};{9L2jq?1vG=KAa0;5a)F)==fd`y;zjv3p&0p7hlrx1065-Asa+LUXe?t zjwRU|I&wkmlu8DX?}G^9B9`UgQUDfKWbbkS1r%kk6o8FY*?U#?94S)P;p$k^uR-DBhDHS|o|d7)u2VUt=DaAR;;25s@|5DwHEDX6|y?E=A7paat5sg)>Qut}VwJ4vr;O%qwQ3V3w96>7^Bs zb0^1rQyJH>O3U1#(f-jy&MrnSnq^lw>%~G%wX!Dl%{g{Xl*`-^ThEDA*Ro68+HEhb zNbpUDh@)t(5|M_(ZB*w?*Icqn`3knA5~t3Aj7we|DlgEBj0$6@VMkK9m+btU>6k@9 zoODh9s_B%4M^3|WKjR8LAGGO$SuQuYpyCw`yFD?>j>OY`emyJ7m41RXxAo=<=Jo3u zb~c&Nu%|Jc*H)_`-LqNvgkelhP3pL!<0>;#Lm*=lSXA>=Zh&o{PjwSImNypS7K$>H3|w%~narb9P@$+92~YIp=3ymER(9 zT{=Eu@G&ng3P+T3qILKOq+m@(L!=FFbsAbI?QnjYcT}UkuEFdaR` zatoidDS{eC>&0(=t>juoQ9A_E!1WM*h^IB|Qeur2CWJ9*_Sx2EYnDP z4v4&rtcIl-L*xCFyf$OH!YdFV{1~rk=slG*CZ5splMsFin*KR{q2re!ypA_QcoV8A>5F?zu*lG<4xon4cFt%+oK*P4}HUwm!?dSx|FJm zyuMnyqD?8_Wq8%GTyfqktchs3s&?34xQt7VeN|rblk$}y;0QCX#CZ+*#VRL9$_$i+ zTX&&`SVhhi>u#jJz~a^#Y%P=gapTP}q}WQIMGWTc1-ryk($51|AC0ww3s- zDC--iD;pc79u(nI9SAYSE#5xYP5DAHD=PQq$ijTwh-GJ@Ml6$!X0k>+8Os>a zu}(f}rIPIQyjAwz)$(HxrQ$)UAL~GUMwDBUADxZH6WMesdoFc0m0n0?=jPLMv3VmN zBm3i>ptsga{(+obx@aw{_mbs~9%!TH!h<K)1YjE^WkSveW65F`rIkr%y-c>6$Gs{boaSNw%FE>Tk^r*d`y4J}(Uq zaweWSm55~(ZX(@Pjc_bEXDnu4h(%MJeWG=~Y{J4KzmMNX@<)dzFF-yIa1>#yvF#1t zg7zdU3}b?NsSSs4m~9Vs;D`eFZH|VZeZ_5E zI=-XhNoYEr;#VJmYZRBTj^Sx4lCb{4R+`#PSjj`-i4EvCQxezV8ZPW9?73NGx;W|!*REKBqEL+)o4wH)CPKB@wCphc*Nv?gDYZCKriMb!$I;M0y zUx9s6!47m$8z>7z`PYRP6ou&uh0iM#4tNwkL7>W_e{m>u3j?3|2z3$Y0JbYv4`8H5 zY?NV?CVB{OJ3$R%imT6K6ektIqx?7? zhHFfQ5yu%7v`3nl$hEWnpjDY9HU~|zi1W`2T2iq{Rai9VT@!`oynBfhUS^VHnLn@8 zD74GFDuq^gw~0bE@0uvcysJ}4lLB9bNnReE8>Ax3!P(mwT)c%HXT!I#lbxXr>{h)y`u|= si%N;d&E{cPrB7caFh@B-9;QA_t4PWH^GZtwe`FivnvLJ%4<|?d2U^0`6951J literal 0 HcmV?d00001 diff --git a/target/classes/org/example/core/utils/jackson/MyDateFormat.class b/target/classes/org/example/core/utils/jackson/MyDateFormat.class new file mode 100644 index 0000000000000000000000000000000000000000..e32b8e39074050003794b7f2b7a76031b8456efe GIT binary patch literal 1083 zcmb7CTTc@~6#k|cwv^>oC?KGKqPAVjitq%+7m)DKqNapI-=@1GUEJNNyHivCioXIA zrHLlSCm;M##xqMp8})_VWaiAde&;*q*YB_20c>MChkJRLST}G#k2D^PVhj&+DCJQ` zMO!Sbro+S|162bX4CAqK_qh@WG77k2*s3`)u;21niKrX+_8E8H#WJ*Au6WZ6UAv<^ z-);;C?J|r!^+HcQV@Q|ECk&ZA=?aF)niqm^$Db%FH{SzK}`rTJ%RLhGQ zsx=v%+M>&Ywl8c)Mk1*dUqh&$4}en5Y@0_h%9CMiz-E}L3)PbDOCIq+5H|!k>-aJx0JEij zxdg$B=9zGm#wS%vP`P|Vb|Oa{c$$Fe;U+dT4u+X?`l|JM)pb`74|jrKCyq@_;xWVK zjfbHFr%a4vf`J_y*fjA3TPEf(Z{iMC7_1x6%&?enr9@ZR4Np&IFaw5#fsu%b#WiOP z#s5u(R%7aK?iq593>Ei6qI79EYOlqkhIro*p(A$7Z?Hz|Y|^GPq;!8IrAelC>71t5 ze)0wil>+M_Rr!YW>mD*+ko`o~6bf`skPmragrsTA&=1PV65T9{bTdsAdFhOtqEd7( zTR%~-3L}>=K4P?D^^m)$d`8x~#OMXt(?hxE3EKkYT}*P%UB%-nH)SH*Evm7YM6nqx zk&q$9GH#QUB~IyLdQx<146i7=#!#&EkpF?Pnl$tmr0GyKaKL7v# literal 0 HcmV?d00001 diff --git a/target/classes/org/example/dto/TaskCallbackDataDto.class b/target/classes/org/example/dto/TaskCallbackDataDto.class new file mode 100644 index 0000000000000000000000000000000000000000..818b0e37f42975498c0df582a41bbff85b888913 GIT binary patch literal 18013 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/example/dto/TaskCallbackDto.class b/target/classes/org/example/dto/TaskCallbackDto.class new file mode 100644 index 0000000000000000000000000000000000000000..731a56b15a2333da3564f942c5c8c2af743c7acc GIT binary patch literal 2135 zcma)7ZBrXn6n<{9o86>K2`K@h)Pho*5NN8_mxh;Wfwt6yB4IkCpIpceNgJ{l7DxYz zKR~|lL1#3b(HTd-v@`w&e}*5e^*Os6NMfeLB)Rw8bDw)&o^$Tapa1^y8-SarB#^@G zI5d1L!zTvrBsj0guqu0NBHb0~o`L%bByiiry37w`_|!znL|McQ0}mCfUAxiPv3H+r ze|z94Tq-@bzqShvySZ0bZ+gz2(^^o_sX0CWgRLtuU0=) zn0~b{-_P)#<8{0T;it2?fe9EyN_+~}h&W#s!-xIW$Fc*AONPm^(!i=!icap(_7P& zzt^XX`@o>Ci2x8RhAJMrp==-c^c>NZmpNs7#!tT z%Q-x1cnU*({`8r^yy>|WuT^jEDU9|ME6}og5*7ETwd>riON)&5beQK}m)tFkW5U8E zj9N%zOySBaE9$ux-b2>H8@OWOnn+Waws@P~R~SDdGl<~MQN2+WDlhlB&UUl9WMLDZ z$*{#*&rL~kOQaxYVF8Qmh%>W6jYy4saNsnn3iI8?4b$#!+nzW`NDsc#3|&poi^nt{ zfD|8#2tTCAm&g+5IG8UcIA*via8{i4*{4uH`monH#(ZT0uT!=H048ynD^=Mw zB0uyUP7XXw&IcTh_8(3UJp3l!Vmjiv=qJWFXY)TJGC1xrVkDCwZjpotg&AsfK5|HM zaTRY5G8sLuN#XR=WZE~$-U?0r&Do&0T7LF>=-NsC4`|;(kDlazhgP1OZA15$6k;25 z9E#ffb6m)1&oFWfYd)j3VRR5?Q76PK#xlBKV$YB|#!yDj#5y4DgubHauiyP3hEpDD z$YGX2r%^$kHI0ywRm@Qr4D95viyp{`TXQD!X)lw!C+`%{P;=0CV-;GGv3Gw?3I zrh0*iK#ZS~ks}$JT)B{pTXZP}(S-$xH1fYlgNo^=k?M?3A`L5+_vz(@rAnIMFPhLf z7n2K%+LBM=WOAWK3e9Bx7{+`X@h?Sh7B$((XyJ}2#BytLFkv?Xt6>;Xe25SD;}b{E zA5n_%fAa=zF|;Tfa-7X5gb6thpuMC*BRNWu5GeJMptE&E6lv%kKnJ7sstBV$z9C_z wTl6WnH2W(OpFhQgl-0(NB;3Zu)Nml1A}1-gG17mXx-W7z%u8X379&{x4;YJzQUCw| literal 0 HcmV?d00001 diff --git a/target/classes/org/example/entity/AIOBCallbackEntity.class b/target/classes/org/example/entity/AIOBCallbackEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..1ffaa62eafe8e9b1cf2ca2caadfeb7a3fa2446af GIT binary patch literal 4395 zcmb7G+jAS`75}Zgt6j;fOBC#&5@-NJ9A8kNg~B=seUb%O5bG?KNkPi3DcC%B#y)3P z>ULwPGTZQ-C8s%~pnSC5@ZA;Xgxhi#>(1Ur!}D$5^%^Y&({ojCrLt&yD{jqeS5_`8 z($ZS3w_6pvi>n;7$(yawmv+vsw;ctle_@r|)Q0G@wPQq+t?oU3?63l}YS-(FcJ-{N zV~+=H-&RnH9b&<6x{W0=Gfl^?Eii22vsFI$4$*ulhUm8M)+?eRHrrmUb?xb0Zo~EW zC>R>wae@)-_iAJn=G=yJsJ*i2G=sCruX>E?gxz%ItdUanmt7`l`<&NYsyOHEmDRda zahOd1LS^sl;eGp~a~up*lAa~UpJgFN#&^U{(JMuP_6{jLd|VTr|AszpHv=ZAM|(-g ziKkc|N*z`_69PIOONQ18!y6q>h)&W|oOk?XuXe<4+AEIlGj7&y^w{JBPt$r+IhBZ*BMFQuN+=H<5c~b9ZxAxy#A(%Ost0IFFQ>I zx|DHDE{G9m0&!EIWX)rpSPISk%6?#Y-~nK$%m*HMzD}bSLU(aZ_@l8L6r-PvsR{uo z-oz0ouFCN;RL{=at3j)Byy*Bd&sVh@2PIt;m+jVa*zIinS!UzN(b@TfOc&*J(`mKq zK5s>ki`-cMk$cbK$+BayGYpT#@89rPJSxNY!t(RRF1Sk#+iy2{-A=DRCY@YDQ(j=x#Ok+yH9UGb%CZ5KuiFu2Io zdH4nHGjTs2Fky)_gIy+e%kpddhG*-I_%PM`+HSojZ9aPasmI;gZWDjO+p@gF%RIHM za}pUpyZba!Yii7?ZQW|~F-JZ%CrBmNYBWSdwURo9P4f_Wn!<-7BiWnma%iJ2rOy;Z zF1H6R_hElhl0>X+Db3FdTJUBhq(VOkm?rj;&hf=Pdg(k0}|S~(p9sX z-pUY^x3cAofU*%NQ_jXf1#6g~f@PM61!P7bN-@)0Ok&UZlSWuAWs zcXN%;q`!rE>Gt^*Jch@a$PxU2InJpR#_%oXsT<;3?;9MVq~Z~Lg2R+FT0X!LN@>*b z4t_~VM-y-2C?x~$;w%;@W$;%xI7TUpH5U3frD6Pst$%`&iSIa!pP-b(_qYisDdq7b zBb~#DZd^fL$5U4^s^eGuGnA{iF%&cZm)N;zkFhyac^5}5ETd4yfhJucSxQ}(rEnT( z-7IO0OtSQl&=fw%G~g?nD+f&KQM$;`^nP(>m%2M>s;$MDWww-2oV)~mdJUUSi{7+U zF_hKFVo0Nfrkte(CiYlBGRj)Vl(*7>Dcv=(^Fmg^(gPElE@J5&Q_(U4lhHM?70KF~ z+!#-XCy0(bg!ga?r+GdN|Ab8`#ZvwQi%i21ZpTGbDXG}Q?}Hj8jpdtX$)z!Tj^k%2 z>3ADkutdp_;wrbnyheq};wlOY3Prg_XT9f?C`O=l03D3luZm#l7_5gJ)J9;vAKb$y z7$S;s9i_)gwnfBD60yf!*GxL|&F`(StMD>&E?*cY|Bcdtv?Y`| z6GlrnhH{QusT|521EZy%gmOXTn?kuL@>a@gxOwn38vkfH+3f?D5u|X27hCpv@D(-8 MxK{Yjuc*d<0XVXG#{VG6M#pIGu&kuW*8|9*QTmDc0m+uvE?0;<+`F(xfLDrLVHIgduKMj zBX=k{nzpfBOWFq^$4w)FX57kKFP{n@Dv~|B#tKOtO+3)c>uNS z?}C=4u_=3UZu+@3{iacPIKTKC_}8p(e+jRUApb=_P*Au^b)Ei%q;C3ti$OoLFXQH8 AJOBUy literal 0 HcmV?d00001 diff --git a/target/classes/org/example/service/IAIOBCallbackService.class b/target/classes/org/example/service/IAIOBCallbackService.class new file mode 100644 index 0000000000000000000000000000000000000000..51da580a7147943d8f8c57ecb29c330947106448 GIT binary patch literal 509 zcmb7B!A`?440Xn!Yz)|yKNuGx0k45>SEaobR`rAd{f6Z8X z=3KmDQ7XYRZ}@aQlhDivJ&wEykH@JgI4YT7g8UhspE;vX`CUADm?Sfi`jA2YUicT2 zJ)*@zcwrq8NNITuG+ma0K|3Qn2Ax>u8hvG{RBljOBQ?7cG=T3cwO)0!2p553~HWjy0(f*@ovullZQrpB} zuxZWr#y|Q=`;W0J6%5X5%l;{2hXI2Yoh|xH)+Wbbo3b6sIxPq&?9ypLr@6bZ*Tmiz DLwcNu literal 0 HcmV?d00001 diff --git a/target/classes/org/example/service/impl/AIOBCallbackServiceImpl.class b/target/classes/org/example/service/impl/AIOBCallbackServiceImpl.class new file mode 100644 index 0000000000000000000000000000000000000000..1a42c12284a1ef8a357772985a149bce3201f8e6 GIT binary patch literal 2153 zcmbVNZBrXn6n<_91j5n+ZP8fNT5Zcq=^}zwf+#PoO${#+gjQ?yCb>x$lHJVi4VItc zH-Cc8I8bHA&yIh^zu-7Ncavb&3CcK`+_U%Yx#v9RoadbV?a!Zo0WgcNlNiBV0`Ddf z!(1=kOX4oxH=FrhqaKRG zYR3tjd_^s}uBWATJU0-yn%$EJ^0_Tf5A7`#cy+&^c(Z50aUH!V&^0!`BM@Klib~*O z)^XK(y_#44wxmG<%z6b`*^$0u_RYh%e&*1_Oay13`~#<;Y=@{LXmgDh8J^RzrDd>h z0$FCn0#C+5n07_FWjo_)RaSmFVz;P0d%JnZWNB4uxvIVNc(&kGZCP>hGB53t4D?>$ zxij{|+{XGweoqxNy+!hSkGax^|IDunPa}vMiUurW4@Ep6^TgT#<@^4 z^S;u=Cvg2d0Sx4HgBfA!Nk)OeHKm_<#ZBqUs?y45CHits*_FEP6XbDdHZQ%ZQ}pU~ z^)OFH1hq;%Af>c&1Jc8e6sxU33y~nsrd~wt>-zmfbRIVHB?lT>CGwu#N@xKmu6{Ygo6i zflYQtH7E-tf_kB#g22M3*kYyI+w;ueE#$DBz-JbAuxsHF9$WYv+X5F%1a@6J6`NdE z7QVm}3oj#;z?T-D;wypab`Pzr{aa%Rq)mYTv+7J|Cx@NNBrp`hZ|_$o=s;HLYNI4D zGL{+d*d=`>YPfo{t_2>nH+@c<8m8MWHM{p*4c_axddD~qCs~FgEKs^NCmUTm((bJ_ zV$9G>b>c)gKg^i&%phri6S&!K;}qZDnP>(Pb#Eq>z?Jr^O+Dk?BG4@*i)?UB^aBRB zulQ_8!CBM1cFL2qxfG$^neE9T^QyuZ%0-nJe{1}Zu;3fWJhI^E+@T=EDd6hCo z$-d$G8h19OpzNMFhWH_T{W@2p3|z)Fu2w^VhOcuc@Fw1(5p(%>bfKHFbb{F9V|1-g z4abM@>kD)rp=UTT+)J@Ld4#@i(Qic0cUU+2gRw{n`1qP0AAr7G5oZxM z!U$%Gau(Cv-9+5rZN_4rZec8puY_^hjnU>)+Ph6pQ`GE3><>&PaOW;F#choGpr%1G R%{7L%F%!ynPLn(f`~~P`R2KjM literal 0 HcmV?d00001