From eca07e5209f5315d32ea2b4c9c005c708be9f908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?weizhenfeng=E9=9F=A6=E6=8C=AF=E5=87=A4?= Date: Wed, 9 Jul 2025 14:05:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=20xfg-ddd?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加基础目录结构和文件 - 配置 Spring Boot 应用 - 添加数据库配置和 MyBatis 映射文件 - 实现简单的用户服务接口和仓库接口 - 添加日志配置和示例日志 - 配置 Docker 和 Docker Compose 文件 - 添加 Jackson 配置和工具类 - 实现简单的 API 测试用例 --- .gitignore | 38 +++ README.md | 10 + data/log/log_error.log | 3 + data/log/log_info.log | 40 +++ docs/dev-ops/app/start.sh | 20 ++ docs/dev-ops/app/stop.sh | 1 + docs/dev-ops/docker-compose-app.yml | 27 ++ .../docker-compose-environment-aliyun.yml | 87 ++++++ docs/dev-ops/docker-compose-environment.yml | 86 ++++++ docs/dev-ops/mysql/sql/modify.sql | 55 ++++ .../dev-ops/mysql/sql/xfg-frame-archetype.sql | 108 ++++++++ pom.xml | 239 +++++++++++++++++ xfg-ddd-api/pom.xml | 54 ++++ .../java/com/in/api/dto/package-info.java | 4 + .../main/java/com/in/api/package-info.java | 4 + .../java/com/in/api/response/Response.java | 173 ++++++++++++ .../java/com/in/api/util/JacksonUtil.java | 249 ++++++++++++++++++ xfg-ddd-app/Dockerfile | 17 ++ xfg-ddd-app/build.sh | 6 + xfg-ddd-app/pom.xml | 137 ++++++++++ .../src/main/java/com/in/Application.java | 15 ++ .../main/java/com/in/config/GuavaConfig.java | 20 ++ .../java/com/in/config/ThreadPoolConfig.java | 50 ++++ .../in/config/ThreadPoolConfigProperties.java | 26 ++ .../main/java/com/in/config/package-info.java | 6 + .../src/main/java/com/in/package-info.java | 4 + .../src/main/resources/application-dev.yml | 42 +++ .../src/main/resources/application-prod.yml | 41 +++ .../src/main/resources/application-test.yml | 41 +++ .../src/main/resources/application.yml | 5 + .../src/main/resources/logback-spring.xml | 113 ++++++++ .../mybatis/config/mybatis-config.xml | 9 + .../mybatis/mapper/frame_case_mapper.xml | 25 ++ .../src/test/java/com/in/test/ApiTest.java | 19 ++ xfg-ddd-domain/pom.xml | 93 +++++++ .../domain/xxx/adapter/IUserRepository.java | 60 +++++ .../in/domain/xxx/adapter/package-info.java | 4 + .../domain/xxx/adapter/port/package-info.java | 4 + .../xxx/adapter/repository/package-info.java | 5 + .../xxx/model/aggregate/package-info.java | 7 + .../xxx/model/entity/UserDetailEntity.java | 115 ++++++++ .../domain/xxx/model/entity/UserEntity.java | 121 +++++++++ .../domain/xxx/model/entity/package-info.java | 7 + .../domain/xxx/model/valobj/package-info.java | 6 + .../in/domain/xxx/service/IUserService.java | 60 +++++ .../xxx/service/impl/UserServiceImpl.java | 69 +++++ .../in/domain/xxx/service/package-info.java | 1 + .../yyy/adapter/repository/package-info.java | 0 .../yyy/model/aggregate/package-info.java | 7 + .../domain/yyy/model/entity/package-info.java | 7 + .../domain/yyy/model/valobj/package-info.java | 6 + .../in/domain/yyy/service/package-info.java | 1 + xfg-ddd-infrastructure/pom.xml | 64 +++++ .../adapter/UserRepository.java | 99 +++++++ .../adapter/port/package-info.java | 4 + .../adapter/repository/package-info.java | 4 + .../com/in/infrastructure/dao/UserMapper.java | 63 +++++ .../in/infrastructure/dao/package-info.java | 4 + .../infrastructure/dao/po/UserDetailPO.java | 115 ++++++++ .../com/in/infrastructure/dao/po/UserPO.java | 115 ++++++++ .../infrastructure/dao/po/package-info.java | 4 + .../gateway/dto/package-info.java | 0 .../infrastructure/gateway/package-info.java | 4 + .../in/infrastructure/redis/package-info.java | 4 + .../resources/mybatis/mapper/UserMapper.xml | 85 ++++++ xfg-ddd-trigger/pom.xml | 63 +++++ .../com/in/trigger/config/JacksonConfig.java | 31 +++ .../com/in/trigger/http/UserController.java | 95 +++++++ .../com/in/trigger/http/package-info.java | 4 + .../java/com/in/trigger/job/package-info.java | 4 + .../com/in/trigger/listener/package-info.java | 5 + xfg-ddd-types/pom.xml | 53 ++++ .../java/com/in/types/common/Constants.java | 7 + .../java/com/in/types/enums/ResponseCode.java | 20 ++ .../com/in/types/exception/AppException.java | 46 ++++ 75 files changed, 3240 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 data/log/log_error.log create mode 100644 data/log/log_info.log create mode 100644 docs/dev-ops/app/start.sh create mode 100644 docs/dev-ops/app/stop.sh create mode 100644 docs/dev-ops/docker-compose-app.yml create mode 100644 docs/dev-ops/docker-compose-environment-aliyun.yml create mode 100644 docs/dev-ops/docker-compose-environment.yml create mode 100644 docs/dev-ops/mysql/sql/modify.sql create mode 100644 docs/dev-ops/mysql/sql/xfg-frame-archetype.sql create mode 100644 pom.xml create mode 100644 xfg-ddd-api/pom.xml create mode 100644 xfg-ddd-api/src/main/java/com/in/api/dto/package-info.java create mode 100644 xfg-ddd-api/src/main/java/com/in/api/package-info.java create mode 100644 xfg-ddd-api/src/main/java/com/in/api/response/Response.java create mode 100644 xfg-ddd-api/src/main/java/com/in/api/util/JacksonUtil.java create mode 100644 xfg-ddd-app/Dockerfile create mode 100644 xfg-ddd-app/build.sh create mode 100644 xfg-ddd-app/pom.xml create mode 100644 xfg-ddd-app/src/main/java/com/in/Application.java create mode 100644 xfg-ddd-app/src/main/java/com/in/config/GuavaConfig.java create mode 100644 xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfig.java create mode 100644 xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfigProperties.java create mode 100644 xfg-ddd-app/src/main/java/com/in/config/package-info.java create mode 100644 xfg-ddd-app/src/main/java/com/in/package-info.java create mode 100644 xfg-ddd-app/src/main/resources/application-dev.yml create mode 100644 xfg-ddd-app/src/main/resources/application-prod.yml create mode 100644 xfg-ddd-app/src/main/resources/application-test.yml create mode 100644 xfg-ddd-app/src/main/resources/application.yml create mode 100644 xfg-ddd-app/src/main/resources/logback-spring.xml create mode 100644 xfg-ddd-app/src/main/resources/mybatis/config/mybatis-config.xml create mode 100644 xfg-ddd-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml create mode 100644 xfg-ddd-app/src/test/java/com/in/test/ApiTest.java create mode 100644 xfg-ddd-domain/pom.xml create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/IUserRepository.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/port/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/repository/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/aggregate/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserDetailEntity.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserEntity.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/valobj/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/IUserService.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/impl/UserServiceImpl.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/yyy/adapter/repository/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/aggregate/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/entity/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/valobj/package-info.java create mode 100644 xfg-ddd-domain/src/main/java/com/in/domain/yyy/service/package-info.java create mode 100644 xfg-ddd-infrastructure/pom.xml create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/UserRepository.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/port/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/repository/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/UserMapper.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserDetailPO.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserPO.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/dto/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/redis/package-info.java create mode 100644 xfg-ddd-infrastructure/src/main/resources/mybatis/mapper/UserMapper.xml create mode 100644 xfg-ddd-trigger/pom.xml create mode 100644 xfg-ddd-trigger/src/main/java/com/in/trigger/config/JacksonConfig.java create mode 100644 xfg-ddd-trigger/src/main/java/com/in/trigger/http/UserController.java create mode 100644 xfg-ddd-trigger/src/main/java/com/in/trigger/http/package-info.java create mode 100644 xfg-ddd-trigger/src/main/java/com/in/trigger/job/package-info.java create mode 100644 xfg-ddd-trigger/src/main/java/com/in/trigger/listener/package-info.java create mode 100644 xfg-ddd-types/pom.xml create mode 100644 xfg-ddd-types/src/main/java/com/in/types/common/Constants.java create mode 100644 xfg-ddd-types/src/main/java/com/in/types/enums/ResponseCode.java create mode 100644 xfg-ddd-types/src/main/java/com/in/types/exception/AppException.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..35e0c19 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# xfg-frame-archetype - DDD 脚手架 - @小傅哥 v2.2 + +- docker 使用文档:[https://bugstack.cn/md/road-map/docker.html](https://bugstack.cn/md/road-map/docker.html) +- DDD 教程; + - [DDD 概念理论](https://bugstack.cn/md/road-map/ddd-guide-01.html) + - [DDD 建模方法](https://bugstack.cn/md/road-map/ddd-guide-02.html) + - [DDD 工程模型](https://bugstack.cn/md/road-map/ddd-guide-03.html) + - [DDD 架构设计](https://bugstack.cn/md/road-map/ddd.html) + - [DDD 建模案例](https://bugstack.cn/md/road-map/ddd-model.html) + diff --git a/data/log/log_error.log b/data/log/log_error.log new file mode 100644 index 0000000..4448269 --- /dev/null +++ b/data/log/log_error.log @@ -0,0 +1,3 @@ +25-07-09.11:51:57.372 [main ] WARN ClassPathMapperScanner - No MyBatis mapper was found in '[com.in]' package. Please check your configuration. +25-07-09.11:55:04.199 [main ] WARN ClassPathMapperScanner - No MyBatis mapper was found in '[com.in]' package. Please check your configuration. +25-07-09.13:34:09.718 [http-nio-8091-exec-1] WARN DefaultHandlerExceptionResolver - Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "2023-01-01 12:00:00": not a valid representation (error: Failed to parse Date value '2023-01-01 12:00:00': Cannot parse date "2023-01-01 12:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2023-01-01 12:00:00": not a valid representation (error: Failed to parse Date value '2023-01-01 12:00:00': Cannot parse date "2023-01-01 12:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null)) at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 11, column: 22] (through reference chain: com.in.domain.xxx.model.entity.UserEntity["lastLoginTime"])] diff --git a/data/log/log_info.log b/data/log/log_info.log new file mode 100644 index 0000000..aefdf51 --- /dev/null +++ b/data/log/log_info.log @@ -0,0 +1,40 @@ +25-07-09.11:51:56.658 [main ] INFO Application - Starting Application using Java 1.8.0_381 on FenGYu with PID 38224 (D:\Workspaces\Java\github\xfg-ddd\xfg-ddd-app\target\classes started by 10590 in D:\Workspaces\Java\github\xfg-ddd) +25-07-09.11:51:56.660 [main ] INFO Application - The following 1 profile is active: "dev" +25-07-09.11:51:57.372 [main ] WARN ClassPathMapperScanner - No MyBatis mapper was found in '[com.in]' package. Please check your configuration. +25-07-09.11:51:57.914 [main ] INFO TomcatWebServer - Tomcat initialized with port(s): 8091 (http) +25-07-09.11:51:57.928 [main ] INFO Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8091"] +25-07-09.11:51:57.929 [main ] INFO StandardService - Starting service [Tomcat] +25-07-09.11:51:57.929 [main ] INFO StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.75] +25-07-09.11:51:58.117 [main ] INFO [/] - Initializing Spring embedded WebApplicationContext +25-07-09.11:51:58.117 [main ] INFO ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1416 ms +25-07-09.11:51:58.689 [main ] INFO Http11NioProtocol - Starting ProtocolHandler ["http-nio-8091"] +25-07-09.11:51:58.709 [main ] INFO TomcatWebServer - Tomcat started on port(s): 8091 (http) with context path '' +25-07-09.11:51:58.718 [main ] INFO Application - Started Application in 2.534 seconds (JVM running for 3.656) +25-07-09.11:55:03.454 [main ] INFO Application - Starting Application using Java 1.8.0_381 on FenGYu with PID 10904 (D:\Workspaces\Java\github\xfg-ddd\xfg-ddd-app\target\classes started by 10590 in D:\Workspaces\Java\github\xfg-ddd) +25-07-09.11:55:03.457 [main ] INFO Application - The following 1 profile is active: "dev" +25-07-09.11:55:04.199 [main ] WARN ClassPathMapperScanner - No MyBatis mapper was found in '[com.in]' package. Please check your configuration. +25-07-09.11:55:05.272 [main ] INFO TomcatWebServer - Tomcat initialized with port(s): 8091 (http) +25-07-09.11:55:05.283 [main ] INFO Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8091"] +25-07-09.11:55:05.284 [main ] INFO StandardService - Starting service [Tomcat] +25-07-09.11:55:05.285 [main ] INFO StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.75] +25-07-09.11:55:05.446 [main ] INFO [/] - Initializing Spring embedded WebApplicationContext +25-07-09.11:55:05.446 [main ] INFO ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1941 ms +25-07-09.11:55:06.068 [main ] INFO Http11NioProtocol - Starting ProtocolHandler ["http-nio-8091"] +25-07-09.11:55:06.095 [main ] INFO TomcatWebServer - Tomcat started on port(s): 8091 (http) with context path '' +25-07-09.11:55:06.105 [main ] INFO Application - Started Application in 3.159 seconds (JVM running for 3.55) +25-07-09.13:31:50.021 [main ] INFO Application - Starting Application using Java 1.8.0_381 on FenGYu with PID 13348 (D:\Workspaces\Java\github\xfg-ddd\xfg-ddd-app\target\classes started by 10590 in D:\Workspaces\Java\github\xfg-ddd) +25-07-09.13:31:50.028 [background-preinit] INFO Version - HV000001: Hibernate Validator 6.1.5.Final +25-07-09.13:31:50.028 [main ] INFO Application - The following 1 profile is active: "dev" +25-07-09.13:31:51.733 [main ] INFO TomcatWebServer - Tomcat initialized with port(s): 8091 (http) +25-07-09.13:31:51.747 [main ] INFO Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8091"] +25-07-09.13:31:51.748 [main ] INFO StandardService - Starting service [Tomcat] +25-07-09.13:31:51.748 [main ] INFO StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.75] +25-07-09.13:31:51.993 [main ] INFO [/] - Initializing Spring embedded WebApplicationContext +25-07-09.13:31:51.993 [main ] INFO ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1684 ms +25-07-09.13:31:52.867 [main ] INFO Http11NioProtocol - Starting ProtocolHandler ["http-nio-8091"] +25-07-09.13:31:52.900 [main ] INFO TomcatWebServer - Tomcat started on port(s): 8091 (http) with context path '' +25-07-09.13:31:52.912 [main ] INFO Application - Started Application in 3.631 seconds (JVM running for 5.261) +25-07-09.13:34:09.450 [http-nio-8091-exec-1] INFO [/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +25-07-09.13:34:09.450 [http-nio-8091-exec-1] INFO DispatcherServlet - Initializing Servlet 'dispatcherServlet' +25-07-09.13:34:09.451 [http-nio-8091-exec-1] INFO DispatcherServlet - Completed initialization in 1 ms +25-07-09.13:34:09.718 [http-nio-8091-exec-1] WARN DefaultHandlerExceptionResolver - Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "2023-01-01 12:00:00": not a valid representation (error: Failed to parse Date value '2023-01-01 12:00:00': Cannot parse date "2023-01-01 12:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2023-01-01 12:00:00": not a valid representation (error: Failed to parse Date value '2023-01-01 12:00:00': Cannot parse date "2023-01-01 12:00:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null)) at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 11, column: 22] (through reference chain: com.in.domain.xxx.model.entity.UserEntity["lastLoginTime"])] diff --git a/docs/dev-ops/app/start.sh b/docs/dev-ops/app/start.sh new file mode 100644 index 0000000..9c2be01 --- /dev/null +++ b/docs/dev-ops/app/start.sh @@ -0,0 +1,20 @@ +CONTAINER_NAME=xfg-ddd +IMAGE_NAME=system/xfg-ddd:1.0-SNAPSHOT +PORT=8091 + +echo "容器部署开始 ${CONTAINER_NAME}" + +# 停止容器 +docker stop ${CONTAINER_NAME} + +# 删除容器 +docker rm ${CONTAINER_NAME} + +# 启动容器 +docker run --name ${CONTAINER_NAME} \ +-p ${PORT}:${PORT} \ +-d ${IMAGE_NAME} + +echo "容器部署成功 ${CONTAINER_NAME}" + +docker logs -f ${CONTAINER_NAME} \ No newline at end of file diff --git a/docs/dev-ops/app/stop.sh b/docs/dev-ops/app/stop.sh new file mode 100644 index 0000000..3bf5fb2 --- /dev/null +++ b/docs/dev-ops/app/stop.sh @@ -0,0 +1 @@ +docker stop xfg-ddd \ No newline at end of file diff --git a/docs/dev-ops/docker-compose-app.yml b/docs/dev-ops/docker-compose-app.yml new file mode 100644 index 0000000..f7f6a29 --- /dev/null +++ b/docs/dev-ops/docker-compose-app.yml @@ -0,0 +1,27 @@ +# /usr/local/bin/docker-compose -f /docs/dev-ops/environment/environment-docker-compose-2.4.yml up -d +version: '3.8' +# docker-compose -f docker-compose-app.yml up -d +# 你需要修改system为你自身系统的仓库名 +services: + xfg-ddd: + image: system/xfg-ddd:1.0-SNAPSHOT + container_name: xfg-ddd + restart: on-failure + ports: + - "8091:8091" + environment: + - TZ=PRC + - SERVER_PORT=8091 + volumes: + - ./log:/data/log + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + networks: + - my-network + +networks: + my-network: + driver: bridge diff --git a/docs/dev-ops/docker-compose-environment-aliyun.yml b/docs/dev-ops/docker-compose-environment-aliyun.yml new file mode 100644 index 0000000..87bdbe0 --- /dev/null +++ b/docs/dev-ops/docker-compose-environment-aliyun.yml @@ -0,0 +1,87 @@ +# 命令执行 docker-compose -f docker-compose-environment-aliyun.yml up -d +# docker 代理和使用文档;https://bugstack.cn/md/road-map/docker.html +version: '3.9' +services: + mysql: + image: registry.cn-hangzhou.aliyuncs.com/xfg-studio/mysql:8.0.32 + container_name: mysql + command: --default-authentication-plugin=mysql_native_password + restart: always + environment: + TZ: Asia/Shanghai + MYSQL_ROOT_PASSWORD: 123456 + ports: + - "13306:3306" + volumes: + - ./mysql/sql:/docker-entrypoint-initdb.d + healthcheck: + test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] + interval: 5s + timeout: 10s + retries: 10 + start_period: 15s + networks: + - my-network + + # phpmyadmin https://hub.docker.com/_/phpmyadmin + phpmyadmin: + image: registry.cn-hangzhou.aliyuncs.com/xfg-studio/phpmyadmin:5.2.1 + container_name: phpmyadmin + hostname: phpmyadmin + ports: + - 8899:80 + environment: + - PMA_HOST=mysql + - PMA_PORT=3306 + - MYSQL_ROOT_PASSWORD=123qwe!@#QWE + depends_on: + mysql: + condition: service_healthy + networks: + - my-network + + # Redis + redis: + image: registry.cn-hangzhou.aliyuncs.com/xfg-studio/redis:6.2 + container_name: redis + restart: always + hostname: redis + privileged: true + ports: + - 16379:6379 + volumes: + - ./redis/redis.conf:/usr/local/etc/redis/redis.conf + command: redis-server /usr/local/etc/redis/redis.conf + networks: + - my-network + healthcheck: + test: [ "CMD", "redis-cli", "ping" ] + interval: 10s + timeout: 5s + retries: 3 + + # RedisAdmin https://github.com/joeferner/redis-commander + # 账密 admin/admin + redis-admin: + image: registry.cn-hangzhou.aliyuncs.com/xfg-studio/redis-commander:0.8.0 + container_name: redis-admin + hostname: redis-commander + restart: always + ports: + - 8081:8081 + environment: + - REDIS_HOSTS=local:redis:6379 + - HTTP_USER=admin + - HTTP_PASSWORD=admin + - LANG=C.UTF-8 + - LANGUAGE=C.UTF-8 + - LC_ALL=C.UTF-8 + networks: + - my-network + depends_on: + redis: + condition: service_healthy + +networks: + my-network: + driver: bridge \ No newline at end of file diff --git a/docs/dev-ops/docker-compose-environment.yml b/docs/dev-ops/docker-compose-environment.yml new file mode 100644 index 0000000..2a270b8 --- /dev/null +++ b/docs/dev-ops/docker-compose-environment.yml @@ -0,0 +1,86 @@ +# 命令执行 docker-compose -f docker-compose-environment-aliyun.yml up -d +# docker 代理和使用文档;https://bugstack.cn/md/road-map/docker.html +version: '3.9' +services: + mysql: + image: mysql:8.0.32 + container_name: mysql + command: --default-authentication-plugin=mysql_native_password + restart: always + environment: + TZ: Asia/Shanghai + MYSQL_ROOT_PASSWORD: 123456 + ports: + - "13306:3306" + volumes: + - ./mysql/sql:/docker-entrypoint-initdb.d + healthcheck: + test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] + interval: 5s + timeout: 10s + retries: 10 + start_period: 15s + networks: + - my-network + + # phpmyadmin https://hub.docker.com/_/phpmyadmin + phpmyadmin: + image: phpmyadmin:5.2.1 + container_name: phpmyadmin + hostname: phpmyadmin + ports: + - 8899:80 + environment: + - PMA_HOST=mysql + - PMA_PORT=3306 + - MYSQL_ROOT_PASSWORD=123456 + depends_on: + mysql: + condition: service_healthy + networks: + - my-network + + # Redis + redis: + image: redis:6.2 + container_name: redis + restart: always + hostname: redis + privileged: true + ports: + - 16379:6379 + volumes: + - ./redis/redis.conf:/usr/local/etc/redis/redis.conf + command: redis-server /usr/local/etc/redis/redis.conf + networks: + - my-network + healthcheck: + test: [ "CMD", "redis-cli", "ping" ] + interval: 10s + timeout: 5s + retries: 3 + + # RedisAdmin https://github.com/joeferner/redis-commander + redis-admin: + image: spryker/redis-commander:0.8.0 + container_name: redis-admin + hostname: redis-commander + restart: always + ports: + - 8081:8081 + environment: + - REDIS_HOSTS=local:redis:6379 + - HTTP_USER=admin + - HTTP_PASSWORD=admin + - LANG=C.UTF-8 + - LANGUAGE=C.UTF-8 + - LC_ALL=C.UTF-8 + networks: + - my-network + depends_on: + redis: + condition: service_healthy + +networks: + my-network: + driver: bridge \ No newline at end of file diff --git a/docs/dev-ops/mysql/sql/modify.sql b/docs/dev-ops/mysql/sql/modify.sql new file mode 100644 index 0000000..c7d15d0 --- /dev/null +++ b/docs/dev-ops/mysql/sql/modify.sql @@ -0,0 +1,55 @@ +/* + * 用户相关表结构 + */ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for user +-- ---------------------------- +DROP TABLE IF EXISTS `user`; +CREATE TABLE `user` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `user_identifier` varchar(32) NOT NULL DEFAULT '' COMMENT '用户标识', + `user_nickname` varchar(64) NOT NULL DEFAULT '' COMMENT '用户昵称', + `user_avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '用户头像', + `mobile_phone` varchar(11) DEFAULT NULL COMMENT '手机号', + `contact_info` varchar(64) NOT NULL DEFAULT '' COMMENT '用户联系方式', + `user_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '用户状态:0-未激活 1-正常 2-禁用', + `user_level` tinyint(4) NOT NULL DEFAULT '0' COMMENT '用户等级', + `register_channel` tinyint(4) NOT NULL DEFAULT '0' COMMENT '注册渠道:1-网页 2-安卓 3-iOS 4-小程序', + `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间', + `last_login_ip` varchar(32) DEFAULT NULL COMMENT '最后登录IP', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_user_identifier` (`user_identifier`), + KEY `idx_user_nickname` (`user_nickname`), + KEY `idx_mobile_phone` (`mobile_phone`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + +-- ---------------------------- +-- Table structure for user_detail +-- ---------------------------- +DROP TABLE IF EXISTS `user_detail`; +CREATE TABLE `user_detail` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `user_identifier` varchar(32) NOT NULL DEFAULT '' COMMENT '用户标识', + `real_name` varchar(64) NOT NULL DEFAULT '' COMMENT '真实姓名(加密存储)', + `id_number` varchar(64) NOT NULL DEFAULT '' COMMENT '身份证号(加密存储)', + `birth_date` date DEFAULT NULL COMMENT '出生日期', + `gender` tinyint(4) NOT NULL DEFAULT '0' COMMENT '性别:0-未知 1-男 2-女', + `address` varchar(255) DEFAULT NULL COMMENT '地址', + `education_level` tinyint(4) DEFAULT NULL COMMENT '教育程度:1-小学 2-初中 3-高中 4-大专 5-本科 6-硕士 7-博士', + `profession` varchar(64) DEFAULT NULL COMMENT '职业', + `hobbies` varchar(255) DEFAULT NULL COMMENT '兴趣爱好', + `personal_profile` text COMMENT '个人简介', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_user_identifier` (`user_identifier`), + KEY `idx_real_name` (`real_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户详情表'; + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql b/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql new file mode 100644 index 0000000..8b598d3 --- /dev/null +++ b/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql @@ -0,0 +1,108 @@ +/* + Navicat Premium Data Transfer + + Source Server : 127.0.0.1 + Source Server Type : MySQL + Source Server Version : 50639 + Source Host : localhost:3306 + Source Schema : road-map + + Target Server Type : MySQL + Target Server Version : 50639 + File Encoding : 65001 + + Date: 15/07/2023 09:26:39 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +CREATE database if NOT EXISTS `xfg_frame_archetype` default character set utf8mb4 collate utf8mb4_0900_ai_ci; +use `xfg_frame_archetype`; + +-- ---------------------------- +-- Table structure for employee +-- ---------------------------- +DROP TABLE IF EXISTS `employee`; +CREATE TABLE `employee` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `employee_number` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员ID', + `employee_name` varchar(32) NOT NULL DEFAULT '' COMMENT '雇员姓名', + `employee_level` varchar(8) NOT NULL DEFAULT '' COMMENT '雇员级别', + `employee_title` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员岗位Title', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_employee_number` (`employee_number`) +) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8; + +-- ---------------------------- +-- Records of employee +-- ---------------------------- +BEGIN; +INSERT INTO `employee` VALUES (1, '10000001', 'sXvfDpsWnJdLsCVk64tJgw==', 'T-3', '中级工程师', '2023-07-14 15:26:26', '2023-07-14 15:26:26'); +INSERT INTO `employee` VALUES (2, '10000010', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40'); +INSERT INTO `employee` VALUES (3, '10000011', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40'); +INSERT INTO `employee` VALUES (4, '10000012', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40'); +INSERT INTO `employee` VALUES (5, '10000013', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40'); +INSERT INTO `employee` VALUES (6, '10000014', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-14 15:34:40', '2023-07-14 15:34:40'); +INSERT INTO `employee` VALUES (9, '10000002', 'sXvfDpsWnJdLsCVk64tJgw==', 'T2', '见习工程师', '2023-07-15 07:42:52', '2023-07-15 07:42:52'); +INSERT INTO `employee` VALUES (22, '10000015', 'hMCgLG6WV3CsNBQ1UD6PEQ==', 'T2', '见习工程师', '2023-07-15 08:02:31', '2023-07-15 08:02:31'); +INSERT INTO `employee` VALUES (23, '10000016', 'hMCgLG6WV3CsNBQ1UD6PEQ==', 'T2', '见习工程师', '2023-07-15 08:02:31', '2023-07-15 08:02:31'); +INSERT INTO `employee` VALUES (24, '10000017', 'hMCgLG6WV3CsNBQ1UD6PEQ==', 'T2', '见习工程师', '2023-07-15 08:02:31', '2023-07-15 08:02:31'); +INSERT INTO `employee` VALUES (39, '10000022', 'GyG+V0r6mBCNsdusuKl03g==', 'T1', '实习工程师', '2023-07-15 09:17:49', '2023-07-15 09:17:49'); +COMMIT; + +-- ---------------------------- +-- Table structure for employee_salary +-- ---------------------------- +DROP TABLE IF EXISTS `employee_salary`; +CREATE TABLE `employee_salary` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `employee_number` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员编号', + `salary_total_amount` decimal(8,2) NOT NULL COMMENT '薪资总额', + `salary_merit_amount` decimal(8,2) NOT NULL COMMENT '绩效工资', + `salary_base_amount` decimal(8,2) NOT NULL COMMENT '基础工资', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_employee_number` (`employee_number`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; + +-- ---------------------------- +-- Records of employee_salary +-- ---------------------------- +BEGIN; +INSERT INTO `employee_salary` VALUES (1, '10000001', 5100.00, 1020.00, 4080.00, '2023-07-14 16:09:06', '2023-07-14 16:09:06'); +INSERT INTO `employee_salary` VALUES (2, '10000010', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10'); +INSERT INTO `employee_salary` VALUES (3, '10000011', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10'); +INSERT INTO `employee_salary` VALUES (4, '10000012', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10'); +INSERT INTO `employee_salary` VALUES (5, '10000013', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10'); +INSERT INTO `employee_salary` VALUES (6, '10000014', 5000.00, 1000.00, 4000.00, '2023-07-14 16:17:10', '2023-07-14 16:17:10'); +INSERT INTO `employee_salary` VALUES (8, '10000022', 100.00, 10.00, 90.00, '2023-07-15 09:17:49', '2023-07-15 09:17:49'); +COMMIT; + +-- ---------------------------- +-- Table structure for employee_salary_adjust +-- ---------------------------- +DROP TABLE IF EXISTS `employee_salary_adjust`; +CREATE TABLE `employee_salary_adjust` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `employee_number` varchar(16) NOT NULL DEFAULT '' COMMENT '雇员编号', + `adjust_order_id` varchar(32) NOT NULL DEFAULT '' COMMENT '调薪单号', + `adjust_total_amount` decimal(8,2) NOT NULL COMMENT '总额调薪', + `adjust_base_amount` decimal(8,2) NOT NULL COMMENT '基础调薪', + `adjust_merit_amount` decimal(8,2) NOT NULL COMMENT '绩效调薪', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_order_id` (`adjust_order_id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; + +-- ---------------------------- +-- Records of employee_salary_adjust +-- ---------------------------- +BEGIN; +INSERT INTO `employee_salary_adjust` VALUES (1, '10000001', '109089990198888811', 1000.00, 800.00, 200.00, '2023-07-14 16:55:53', '2023-07-14 16:55:53'); +INSERT INTO `employee_salary_adjust` VALUES (2, '10000001', '100908977676001', 100.00, 20.00, 80.00, '2023-07-14 21:57:39', '2023-07-14 21:57:39'); +COMMIT; \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6949962 --- /dev/null +++ b/pom.xml @@ -0,0 +1,239 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + pom + + + xfg-ddd-api + xfg-ddd-app + xfg-ddd-domain + xfg-ddd-trigger + xfg-ddd-infrastructure + xfg-ddd-types + + + + + nexus-aliyun + nexus-aliyun + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + false + + + + + + 1.8 + UTF-8 + 8 + 8 + UTF-8 + 1.5.22 + 1.9.3 + + + + + xiaofuge + 184172133@qq.com + fuzhengwei + https://github.com/fuzhengwei + + + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0 + + + + + org.springframework.boot + spring-boot-starter-parent + 2.7.12 + + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.4 + + + + mysql + mysql-connector-java + 8.0.22 + + + com.alibaba + fastjson + 2.0.28 + + + org.apache.commons + commons-lang3 + 3.9 + + + com.google.guava + guava + 32.1.3-jre + + + dom4j + dom4j + 1.6.1 + + + com.thoughtworks.xstream + xstream + 1.4.10 + + + io.jsonwebtoken + jjwt + 0.9.1 + + + com.auth0 + java-jwt + 4.4.0 + + + commons-codec + commons-codec + 1.15 + + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + io.swagger + swagger-models + ${swagger-models.version} + + + com.github.xiaoymin + swagger-bootstrap-ui + ${swagger-bootstrap-ui.version} + + + + + javax.validation + validation-api + 2.0.1.Final + + + org.hibernate.validator + hibernate-validator + 6.1.5.Final + + + + + com.in + xfg-ddd-api + 1.0-SNAPSHOT + + + com.in + xfg-ddd-domain + 1.0-SNAPSHOT + + + com.in + xfg-ddd-infrastructure + 1.0-SNAPSHOT + + + com.in + xfg-ddd-types + 1.0-SNAPSHOT + + + com.in + xfg-ddd-trigger + 1.0-SNAPSHOT + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.5 + + UTF-8 + + + + org.codehaus.mojo + versions-maven-plugin + 2.7 + + + + + + + dev + + true + + + -Xms1G -Xmx1G -server -XX:MaxPermSize=256M -Xss256K -Dspring.profiles.active=test -XX:+DisableExplicitGC -XX:+UseG1GC -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs/xfg-ddd-boot -Xloggc:/export/Logs/xfg-ddd-boot/gc-xfg-ddd-boot.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps + dev + + + + test + + -Xms1G -Xmx1G -server -XX:MaxPermSize=256M -Xss256K -Dspring.profiles.active=test -XX:+DisableExplicitGC -XX:+UseG1GC -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs/xfg-ddd-boot -Xloggc:/export/Logs/xfg-ddd-boot/gc-xfg-ddd-boot.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps + test + + + + prod + + -Xms6G -Xmx6G -server -XX:MaxPermSize=256M -Xss256K -Dspring.profiles.active=release -XX:+DisableExplicitGC -XX:+UseG1GC -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs/fq-mall-activity-app -Xloggc:/export/Logs/xfg-ddd-boot/gc-xfg-ddd-boot.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps + prod + + + + + diff --git a/xfg-ddd-api/pom.xml b/xfg-ddd-api/pom.xml new file mode 100644 index 0000000..3af20b1 --- /dev/null +++ b/xfg-ddd-api/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + + + xfg-ddd-api + + + + org.projectlombok + lombok + 1.18.26 + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.4.2 + + + com.fasterxml.jackson.core + jackson-core + 2.13.4 + + + com.fasterxml.jackson.core + jackson-annotations + 2.13.4 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + + diff --git a/xfg-ddd-api/src/main/java/com/in/api/dto/package-info.java b/xfg-ddd-api/src/main/java/com/in/api/dto/package-info.java new file mode 100644 index 0000000..1a3546b --- /dev/null +++ b/xfg-ddd-api/src/main/java/com/in/api/dto/package-info.java @@ -0,0 +1,4 @@ +/** + * 数据传输对象 xxxRequestDTO xxxResponseDTO + */ +package com.in.api.dto; \ No newline at end of file diff --git a/xfg-ddd-api/src/main/java/com/in/api/package-info.java b/xfg-ddd-api/src/main/java/com/in/api/package-info.java new file mode 100644 index 0000000..53d516f --- /dev/null +++ b/xfg-ddd-api/src/main/java/com/in/api/package-info.java @@ -0,0 +1,4 @@ +/** + * 定义api接口 + */ +package com.in.api; \ No newline at end of file diff --git a/xfg-ddd-api/src/main/java/com/in/api/response/Response.java b/xfg-ddd-api/src/main/java/com/in/api/response/Response.java new file mode 100644 index 0000000..feb71f1 --- /dev/null +++ b/xfg-ddd-api/src/main/java/com/in/api/response/Response.java @@ -0,0 +1,173 @@ +package com.in.api.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Response implements Serializable { + + private static final long serialVersionUID = 7000723935764546321L; + + /** + * 成功码 + */ + public static final String SUCCESS_CODE = "0000"; + + /** + * 未知错误码 + */ + public static final String UNKNOWN_ERROR_CODE = "9999"; + + /** + * 参数错误码 + */ + public static final String PARAM_ERROR_CODE = "1001"; + + /** + * 业务错误码 + */ + public static final String BIZ_ERROR_CODE = "2001"; + + /** + * 系统错误码 + */ + public static final String SYS_ERROR_CODE = "3001"; + + /** + * 响应码 + */ + private String code; + + /** + * 响应信息 + */ + private String info; + + /** + * 响应数据 + */ + private T data; + + /** + * 成功响应 + * + * @param 数据类型 + * @return 响应对象 + */ + public static Response success() { + return Response.builder() + .code(SUCCESS_CODE) + .info("操作成功") + .build(); + } + + /** + * 成功响应 + * + * @param data 响应数据 + * @param 数据类型 + * @return 响应对象 + */ + public static Response success(T data) { + return Response.builder() + .code(SUCCESS_CODE) + .info("操作成功") + .data(data) + .build(); + } + + /** + * 成功响应 + * + * @param info 响应信息 + * @param data 响应数据 + * @param 数据类型 + * @return 响应对象 + */ + public static Response success(String info, T data) { + return Response.builder() + .code(SUCCESS_CODE) + .info(info) + .data(data) + .build(); + } + + /** + * 成功响应(无数据) + * + * @param info 响应信息 + * @return 响应对象 + */ + public static Response successWithoutData(String info) { + return Response.builder() + .code(SUCCESS_CODE) + .info(info) + .build(); + } + + /** + * 失败响应 + * + * @param code 错误码 + * @param info 错误信息 + * @param 数据类型 + * @return 响应对象 + */ + public static Response failure(String code, String info) { + return Response.builder() + .code(code) + .info(info) + .build(); + } + + /** + * 失败响应 + * + * @param info 错误信息 + * @param 数据类型 + * @return 响应对象 + */ + public static Response failure(String info) { + return failure(UNKNOWN_ERROR_CODE, info); + } + + /** + * 参数错误响应 + * + * @param info 错误信息 + * @param 数据类型 + * @return 响应对象 + */ + public static Response paramError(String info) { + return failure(PARAM_ERROR_CODE, info); + } + + /** + * 业务错误响应 + * + * @param info 错误信息 + * @param 数据类型 + * @return 响应对象 + */ + public static Response bizError(String info) { + return failure(BIZ_ERROR_CODE, info); + } + + /** + * 系统错误响应 + * + * @param info 错误信息 + * @param 数据类型 + * @return 响应对象 + */ + public static Response sysError(String info) { + return failure(SYS_ERROR_CODE, info); + } +} diff --git a/xfg-ddd-api/src/main/java/com/in/api/util/JacksonUtil.java b/xfg-ddd-api/src/main/java/com/in/api/util/JacksonUtil.java new file mode 100644 index 0000000..16f275c --- /dev/null +++ b/xfg-ddd-api/src/main/java/com/in/api/util/JacksonUtil.java @@ -0,0 +1,249 @@ +package com.in.api.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +/** + * Jackson工具类,用于JSON与对象之间的转换 + */ +public class JacksonUtil { + + /** + * 对象映射器 + */ + private static final ObjectMapper MAPPER; + + static { + MAPPER = new ObjectMapper(); + // 设置日期格式 + MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); + // 设置时区 + MAPPER.setTimeZone(TimeZone.getTimeZone("GMT+8")); + // 忽略未知属性 + MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // 允许空对象 + MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + } + + /** + * 对象转JSON字符串 + * + * @param obj 对象 + * @return JSON字符串 + */ + public static String bean2Json(Object obj) { + try { + return MAPPER.writeValueAsString(obj); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 对象转格式化的JSON字符串 + * + * @param obj 对象 + * @return 格式化的JSON字符串 + */ + public static String bean2JsonPretty(Object obj) { + try { + return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * JSON字符串转对象 + * + * @param jsonStr JSON字符串 + * @param objClass 对象类型 + * @param 泛型 + * @return 对象 + */ + public static T json2Bean(String jsonStr, Class objClass) { + try { + return MAPPER.readValue(jsonStr, objClass); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * JSON字符串转对象列表 + * + * @param jsonStr JSON字符串 + * @param objClass 对象类型 + * @param 泛型 + * @return 对象列表 + */ + public static List json2List(String jsonStr, Class objClass) { + try { + JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, objClass); + return MAPPER.readValue(jsonStr, javaType); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * JSON字符串转Map + * + * @param jsonStr JSON字符串 + * @param Key泛型 + * @param Value泛型 + * @return Map对象 + */ + public static Map json2Map(String jsonStr) { + try { + return MAPPER.readValue(jsonStr, new TypeReference>() {}); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * JSON字符串转复杂类型对象 + * + * @param jsonStr JSON字符串 + * @param typeReference 类型引用 + * @param 泛型 + * @return 对象 + */ + public static T json2Object(String jsonStr, TypeReference typeReference) { + try { + return MAPPER.readValue(jsonStr, typeReference); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 获取ObjectMapper实例 + * + * @return ObjectMapper实例 + */ + public static ObjectMapper getMapper() { + return MAPPER; + } + + /** + * 示例:如何使用JacksonUtil + */ + public static void example() { + // 创建一个对象 + User user = new User(); + user.setId(1L); + user.setName("张三"); + user.setAge(25); + + // 对象转JSON字符串 + String jsonStr = bean2Json(user); + System.out.println("对象转JSON:" + jsonStr); + + // 对象转格式化的JSON字符串 + String prettyJsonStr = bean2JsonPretty(user); + System.out.println("对象转格式化JSON:\n" + prettyJsonStr); + + // JSON字符串转对象 + User parsedUser = json2Bean(jsonStr, User.class); + System.out.println("JSON转对象:" + parsedUser); + + // 创建一个对象列表 + List userList = new ArrayList<>(); + userList.add(new User(1L, "张三", 25)); + userList.add(new User(2L, "李四", 30)); + userList.add(new User(3L, "王五", 35)); + + // 对象列表转JSON字符串 + String listJsonStr = bean2Json(userList); + System.out.println("对象列表转JSON:" + listJsonStr); + + // JSON字符串转对象列表 + List parsedUserList = json2List(listJsonStr, User.class); + System.out.println("JSON转对象列表:" + parsedUserList); + + // 创建一个Map + Map map = new HashMap<>(); + map.put("id", 1L); + map.put("name", "张三"); + map.put("age", 25); + + // Map转JSON字符串 + String mapJsonStr = bean2Json(map); + System.out.println("Map转JSON:" + mapJsonStr); + + // JSON字符串转Map + Map parsedMap = json2Map(mapJsonStr); + System.out.println("JSON转Map:" + parsedMap); + } + + /** + * 示例用户类 + */ + private static class User { + private Long id; + private String name; + private Integer age; + + public User() { + } + + public User(Long id, String name, Integer age) { + this.id = id; + this.name = name; + this.age = age; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } + } +} \ No newline at end of file diff --git a/xfg-ddd-app/Dockerfile b/xfg-ddd-app/Dockerfile new file mode 100644 index 0000000..fbb7cf4 --- /dev/null +++ b/xfg-ddd-app/Dockerfile @@ -0,0 +1,17 @@ +# 基础镜像 +FROM openjdk:8-jre-slim + +# 作者 +MAINTAINER xiaofuge + +# 配置 +ENV PARAMS="" + +# 时区 +ENV TZ=PRC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# 添加应用 +ADD target/xfg-ddd-app.jar /xfg-ddd-app.jar + +ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /xfg-ddd-app.jar $PARAMS"] \ No newline at end of file diff --git a/xfg-ddd-app/build.sh b/xfg-ddd-app/build.sh new file mode 100644 index 0000000..fc3a842 --- /dev/null +++ b/xfg-ddd-app/build.sh @@ -0,0 +1,6 @@ + +# 普通镜像构建,随系统版本构建 amd/arm +docker build -t system/xfg-ddd-app:1.0-SNAPSHOT -f ./Dockerfile . + +# 兼容 amd、arm 构建镜像 +# docker buildx build --load --platform liunx/amd64,linux/arm64 -t xiaofuge/xfg-frame-archetype-app:1.0 -f ./Dockerfile . --push \ No newline at end of file diff --git a/xfg-ddd-app/pom.xml b/xfg-ddd-app/pom.xml new file mode 100644 index 0000000..65208b4 --- /dev/null +++ b/xfg-ddd-app/pom.xml @@ -0,0 +1,137 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + + + xfg-ddd-app + + jar + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.tomcat.embed + tomcat-embed-core + + + org.springframework.boot + spring-boot-configuration-processor + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + + mysql + mysql-connector-java + + + com.alibaba + fastjson + + + org.apache.commons + commons-lang3 + + + org.projectlombok + lombok + + + com.google.guava + guava + + + junit + junit + test + + + io.jsonwebtoken + jjwt + + + com.auth0 + java-jwt + + + commons-codec + commons-codec + + + com.squareup.retrofit2 + converter-gson + 2.9.0 + + + + + com.in + xfg-ddd-trigger + + + com.in + xfg-ddd-infrastructure + + + + + xfg-ddd-app + + + src/main/resources + true + + **/** + + + + + + src/test/resources + true + + **/** + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.6 + + true + false + + **/*Test.java + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.in.Application + JAR + + + + + + diff --git a/xfg-ddd-app/src/main/java/com/in/Application.java b/xfg-ddd-app/src/main/java/com/in/Application.java new file mode 100644 index 0000000..dd20db4 --- /dev/null +++ b/xfg-ddd-app/src/main/java/com/in/Application.java @@ -0,0 +1,15 @@ +package com.in; + +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@Configurable +public class Application { + + public static void main(String[] args){ + SpringApplication.run(Application.class); + } + +} diff --git a/xfg-ddd-app/src/main/java/com/in/config/GuavaConfig.java b/xfg-ddd-app/src/main/java/com/in/config/GuavaConfig.java new file mode 100644 index 0000000..5fdf06c --- /dev/null +++ b/xfg-ddd-app/src/main/java/com/in/config/GuavaConfig.java @@ -0,0 +1,20 @@ +package com.in.config; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.TimeUnit; + +@Configuration +public class GuavaConfig { + + @Bean(name = "cache") + public Cache cache() { + return CacheBuilder.newBuilder() + .expireAfterWrite(3, TimeUnit.SECONDS) + .build(); + } + +} diff --git a/xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfig.java b/xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfig.java new file mode 100644 index 0000000..0044b74 --- /dev/null +++ b/xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfig.java @@ -0,0 +1,50 @@ +package com.in.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; + +import java.util.concurrent.*; + +@Slf4j +@EnableAsync +@Configuration +@EnableConfigurationProperties(ThreadPoolConfigProperties.class) +public class ThreadPoolConfig { + + @Bean + @ConditionalOnMissingBean(ThreadPoolExecutor.class) + public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties properties) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + // 实例化策略 + RejectedExecutionHandler handler; + switch (properties.getPolicy()){ + case "AbortPolicy": + handler = new ThreadPoolExecutor.AbortPolicy(); + break; + case "DiscardPolicy": + handler = new ThreadPoolExecutor.DiscardPolicy(); + break; + case "DiscardOldestPolicy": + handler = new ThreadPoolExecutor.DiscardOldestPolicy(); + break; + case "CallerRunsPolicy": + handler = new ThreadPoolExecutor.CallerRunsPolicy(); + break; + default: + handler = new ThreadPoolExecutor.AbortPolicy(); + break; + } + // 创建线程池 + return new ThreadPoolExecutor(properties.getCorePoolSize(), + properties.getMaxPoolSize(), + properties.getKeepAliveTime(), + TimeUnit.SECONDS, + new LinkedBlockingQueue<>(properties.getBlockQueueSize()), + Executors.defaultThreadFactory(), + handler); + } + +} diff --git a/xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfigProperties.java b/xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfigProperties.java new file mode 100644 index 0000000..a9538fe --- /dev/null +++ b/xfg-ddd-app/src/main/java/com/in/config/ThreadPoolConfigProperties.java @@ -0,0 +1,26 @@ +package com.in.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Data +@ConfigurationProperties(prefix = "thread.pool.executor.config", ignoreInvalidFields = true) +public class ThreadPoolConfigProperties { + + /** 核心线程数 */ + private Integer corePoolSize = 20; + /** 最大线程数 */ + private Integer maxPoolSize = 200; + /** 最大等待时间 */ + private Long keepAliveTime = 10L; + /** 最大队列数 */ + private Integer blockQueueSize = 5000; + /* + * AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 + * DiscardPolicy:直接丢弃任务,但是不会抛出异常 + * DiscardOldestPolicy:将最早进入队列的任务删除,之后再尝试加入队列的任务被拒绝 + * CallerRunsPolicy:如果任务添加线程池失败,那么主线程自己执行该任务 + * */ + private String policy = "AbortPolicy"; + +} diff --git a/xfg-ddd-app/src/main/java/com/in/config/package-info.java b/xfg-ddd-app/src/main/java/com/in/config/package-info.java new file mode 100644 index 0000000..00cb3c8 --- /dev/null +++ b/xfg-ddd-app/src/main/java/com/in/config/package-info.java @@ -0,0 +1,6 @@ +/** + * 1. 用于管理引入的Jar所需的资源启动或者初始化处理 + * 2. 如果有AOP切面,可以再建一个aop包,来写切面逻辑 + */ +package com.in.config; + diff --git a/xfg-ddd-app/src/main/java/com/in/package-info.java b/xfg-ddd-app/src/main/java/com/in/package-info.java new file mode 100644 index 0000000..86a9e43 --- /dev/null +++ b/xfg-ddd-app/src/main/java/com/in/package-info.java @@ -0,0 +1,4 @@ +/** + * 应用启动层,注意Application所在的包路径,是在上一层。这样才能扫描到其他 module + * */ +package com.in; \ No newline at end of file diff --git a/xfg-ddd-app/src/main/resources/application-dev.yml b/xfg-ddd-app/src/main/resources/application-dev.yml new file mode 100644 index 0000000..e60ee71 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/application-dev.yml @@ -0,0 +1,42 @@ +server: + port: 8091 + +# 线程池配置 +thread: + pool: + executor: + config: + core-pool-size: 20 + max-pool-size: 50 + keep-alive-time: 5000 + block-queue-size: 5000 + policy: CallerRunsPolicy + +# 数据库配置;启动时配置数据库资源信息 +spring: + datasource: + url: jdbc:mysql://113.45.244.160:3306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: root000000 + hikari: + pool-name: Retail_HikariCP + minimum-idle: 15 #最小空闲连接数量 + idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟) + maximum-pool-size: 25 #连接池最大连接数,默认是10 + auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true + max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 + connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000 + connection-test-query: SELECT 1 + type: com.zaxxer.hikari.HikariDataSource + +# MyBatis 配置【如需使用记得打开】 +#mybatis: +# mapper-locations: classpath:/mybatis/mapper/*.xml +# config-location: classpath:/mybatis/config/mybatis-config.xml + +# 日志 +logging: + level: + root: info + config: classpath:logback-spring.xml \ No newline at end of file diff --git a/xfg-ddd-app/src/main/resources/application-prod.yml b/xfg-ddd-app/src/main/resources/application-prod.yml new file mode 100644 index 0000000..f369619 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/application-prod.yml @@ -0,0 +1,41 @@ +server: + port: 8091 + +# 线程池配置 +thread: + pool: + executor: + config: + core-pool-size: 20 + max-pool-size: 50 + keep-alive-time: 5000 + block-queue-size: 5000 + policy: CallerRunsPolicy + +# 数据库配置 +#spring: +# datasource: +# username: root +# password: 123456 +# url: jdbc:mysql://127.0.0.1:3306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true +# driver-class-name: com.mysql.cj.jdbc.Driver +# hikari: +# pool-name: Retail_HikariCP +# minimum-idle: 15 #最小空闲连接数量 +# idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟) +# maximum-pool-size: 25 #连接池最大连接数,默认是10 +# auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true +# max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 +# connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000 +# connection-test-query: SELECT 1 +# type: com.zaxxer.hikari.HikariDataSource + +#mybatis: +# mapper-locations: classpath:/mybatis/mapper/*.xml +# config-location: classpath:/mybatis/config/mybatis-config.xml + +# 日志 +logging: + level: + root: info + config: classpath:logback-spring.xml \ No newline at end of file diff --git a/xfg-ddd-app/src/main/resources/application-test.yml b/xfg-ddd-app/src/main/resources/application-test.yml new file mode 100644 index 0000000..f369619 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/application-test.yml @@ -0,0 +1,41 @@ +server: + port: 8091 + +# 线程池配置 +thread: + pool: + executor: + config: + core-pool-size: 20 + max-pool-size: 50 + keep-alive-time: 5000 + block-queue-size: 5000 + policy: CallerRunsPolicy + +# 数据库配置 +#spring: +# datasource: +# username: root +# password: 123456 +# url: jdbc:mysql://127.0.0.1:3306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true +# driver-class-name: com.mysql.cj.jdbc.Driver +# hikari: +# pool-name: Retail_HikariCP +# minimum-idle: 15 #最小空闲连接数量 +# idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟) +# maximum-pool-size: 25 #连接池最大连接数,默认是10 +# auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true +# max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 +# connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000 +# connection-test-query: SELECT 1 +# type: com.zaxxer.hikari.HikariDataSource + +#mybatis: +# mapper-locations: classpath:/mybatis/mapper/*.xml +# config-location: classpath:/mybatis/config/mybatis-config.xml + +# 日志 +logging: + level: + root: info + config: classpath:logback-spring.xml \ No newline at end of file diff --git a/xfg-ddd-app/src/main/resources/application.yml b/xfg-ddd-app/src/main/resources/application.yml new file mode 100644 index 0000000..c037d36 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/application.yml @@ -0,0 +1,5 @@ +spring: + config: + name: xfg-ddd-app + profiles: + active: dev diff --git a/xfg-ddd-app/src/main/resources/logback-spring.xml b/xfg-ddd-app/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..932ad72 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/logback-spring.xml @@ -0,0 +1,113 @@ + + + + + logback + + + + + + + + + + + + info + + + %d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0}%X{ServiceId} -%X{trace-id} %m%n + UTF-8 + + + + + + + + ./data/log/log_info.log + + + %d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0}%X{ServiceId} -%X{trace-id} %m%n + UTF-8 + + + + + ./data/log/log-info-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 15 + 10GB + + + + + + + ./data/log/log_error.log + + + %d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0}%X{ServiceId} -%X{trace-id} %m%n + UTF-8 + + + + ./data/log/log-error-%d{yyyy-MM-dd}.%i.log + + 100MB + + + 7 + 5GB + + + + WARN + + + + + + + 0 + + 8192 + + true + + false + + + + + + 0 + + 1024 + + true + + false + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xfg-ddd-app/src/main/resources/mybatis/config/mybatis-config.xml b/xfg-ddd-app/src/main/resources/mybatis/config/mybatis-config.xml new file mode 100644 index 0000000..ed8ee96 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/mybatis/config/mybatis-config.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/xfg-ddd-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml b/xfg-ddd-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml new file mode 100644 index 0000000..b140be7 --- /dev/null +++ b/xfg-ddd-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + INSERT INTO table(a,b,c) VALUES(#{a}, #{b}, #{c}) + + + + UPDATE table SET a = #{a} WHERE b = #{b} + + + + + diff --git a/xfg-ddd-app/src/test/java/com/in/test/ApiTest.java b/xfg-ddd-app/src/test/java/com/in/test/ApiTest.java new file mode 100644 index 0000000..30ef4a6 --- /dev/null +++ b/xfg-ddd-app/src/test/java/com/in/test/ApiTest.java @@ -0,0 +1,19 @@ +package com.in.test; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@Slf4j +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApiTest { + + @Test + public void test() { + log.info("测试完成"); + } + +} diff --git a/xfg-ddd-domain/pom.xml b/xfg-ddd-domain/pom.xml new file mode 100644 index 0000000..206d509 --- /dev/null +++ b/xfg-ddd-domain/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + + + xfg-ddd-domain + + + + org.projectlombok + lombok + + + com.alibaba + fastjson + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + io.jsonwebtoken + jjwt + + + com.auth0 + java-jwt + + + commons-codec + commons-codec + + + + io.springfox + springfox-swagger2 + + + io.swagger + swagger-models + + + + javax.validation + validation-api + + + org.hibernate.validator + hibernate-validator + + + + com.in + xfg-ddd-types + + + + + xfg-ddd-domain + + + org.apache.maven.plugins + maven-archetype-plugin + 3.2.0 + + + + create-from-project + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + ${java.version} + + + + + + diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/IUserRepository.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/IUserRepository.java new file mode 100644 index 0000000..1e4e251 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/IUserRepository.java @@ -0,0 +1,60 @@ +package com.in.domain.xxx.adapter; + +import com.in.domain.xxx.model.entity.UserEntity; + +import java.util.List; + +/** + * 用户仓库接口 + */ +public interface IUserRepository { + + /** + * 保存用户 + * + * @param userEntity 用户实体 + * @return 用户ID + */ + Long saveUser(UserEntity userEntity); + + /** + * 更新用户 + * + * @param userEntity 用户实体 + * @return 是否更新成功 + */ + boolean updateUser(UserEntity userEntity); + + /** + * 删除用户 + * + * @param userId 用户ID + * @return 是否删除成功 + */ + boolean deleteUser(Long userId); + + /** + * 根据ID查询用户 + * + * @param userId 用户ID + * @return 用户实体 + */ + UserEntity getUserById(Long userId); + + /** + * 根据手机号查询用户 + * + * @param mobilePhone 手机号 + * @return 用户实体 + */ + UserEntity getUserByMobilePhone(String mobilePhone); + + /** + * 分页查询用户列表 + * + * @param pageIndex 页码 + * @param pageSize 每页大小 + * @return 用户列表 + */ + List listUsers(int pageIndex, int pageSize); +} \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/package-info.java new file mode 100644 index 0000000..70a31eb --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/package-info.java @@ -0,0 +1,4 @@ +/** + * 外部接口适配器层;当需要调用外部接口时,则创建出这一层,并定义接口,之后由基础设施层的 adapter 层具体实现 + */ +package com.in.domain.xxx.adapter; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/port/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/port/package-info.java new file mode 100644 index 0000000..fa4a011 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/port/package-info.java @@ -0,0 +1,4 @@ +/** + * 外部接口适配器层;当需要调用外部接口时,则创建出这一层,并定义接口,之后由基础设施层的 adapter 层具体实现 + */ +package com.in.domain.xxx.adapter.port; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/repository/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/repository/package-info.java new file mode 100644 index 0000000..dc8c7af --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/adapter/repository/package-info.java @@ -0,0 +1,5 @@ +/** + * 仓储服务 + * 1. 定义仓储接口,之后由基础设施层做具体实现 + */ +package com.in.domain.xxx.adapter.repository; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/aggregate/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/aggregate/package-info.java new file mode 100644 index 0000000..adca2ed --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/aggregate/package-info.java @@ -0,0 +1,7 @@ +/** + * 聚合对象; + * 1. 聚合实体和值对象 + * 2. 聚合是聚合的对象,和提供基础处理对象的方法。但不建议在聚合中引入仓储和接口来做过大的逻辑。而这些复杂的操作应该放到service中处理 + * 3. 对象名称 XxxAggregate + */ +package com.in.domain.xxx.model.aggregate; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserDetailEntity.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserDetailEntity.java new file mode 100644 index 0000000..148b1cd --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserDetailEntity.java @@ -0,0 +1,115 @@ +package com.in.domain.xxx.model.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Past; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 用户详情实体类 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "用户详情实体", description = "用户详细信息") +public class UserDetailEntity { + + /** + * 主键ID + */ + @ApiModelProperty(value = "主键ID", example = "1") + private Long id; + + /** + * 用户标识 + */ + @NotBlank(message = "用户标识不能为空") + @ApiModelProperty(value = "用户标识", required = true, example = "user123456") + private String userIdentifier; + + /** + * 真实姓名(加密存储) + */ + @Size(max = 64, message = "真实姓名长度不能超过64") + @ApiModelProperty(value = "真实姓名(加密存储)", example = "张三") + private String realName; + + /** + * 身份证号(加密存储) + */ + @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "身份证号格式不正确") + @ApiModelProperty(value = "身份证号(加密存储)", example = "加密后的身份证号") + private String idNumber; + + /** + * 出生日期 + */ + @Past(message = "出生日期必须是过去的日期") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @ApiModelProperty(value = "出生日期", example = "1990-01-01") + private Date birthDate; + + /** + * 性别:0-未知 1-男 2-女 + */ + @ApiModelProperty(value = "性别:0-未知 1-男 2-女", example = "1") + private Integer gender; + + /** + * 地址 + */ + @Size(max = 255, message = "地址长度不能超过255") + @ApiModelProperty(value = "地址", example = "北京市朝阳区xxx街道") + private String address; + + /** + * 教育程度:1-小学 2-初中 3-高中 4-大专 5-本科 6-硕士 7-博士 + */ + @ApiModelProperty(value = "教育程度:1-小学 2-初中 3-高中 4-大专 5-本科 6-硕士 7-博士", example = "5") + private Integer educationLevel; + + /** + * 职业 + */ + @Size(max = 64, message = "职业长度不能超过64") + @ApiModelProperty(value = "职业", example = "软件工程师") + private String profession; + + /** + * 兴趣爱好 + */ + @Size(max = 255, message = "兴趣爱好长度不能超过255") + @ApiModelProperty(value = "兴趣爱好", example = "阅读,旅游,摄影") + private String hobbies; + + /** + * 个人简介 + */ + @Size(max = 500, message = "个人简介长度不能超过500") + @ApiModelProperty(value = "个人简介", example = "这是一段个人简介...") + private String personalProfile; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "创建时间", example = "2023-01-01 12:00:00") + private Date createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "更新时间", example = "2023-01-01 12:00:00") + private Date updateTime; +} \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserEntity.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserEntity.java new file mode 100644 index 0000000..4dbec37 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/UserEntity.java @@ -0,0 +1,121 @@ +package com.in.domain.xxx.model.entity; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 用户实体类 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "用户实体", description = "用户基本信息") +public class UserEntity { + + /** + * 主键ID + */ + @ApiModelProperty(value = "主键ID", example = "1") + private Long id; + + /** + * 用户标识 + */ + @NotBlank(message = "用户标识不能为空") + @Size(min = 6, max = 32, message = "用户标识长度必须在6-32之间") + @ApiModelProperty(value = "用户标识", required = true, example = "user123456") + private String userIdentifier; + + /** + * 用户昵称 + */ + @NotBlank(message = "用户昵称不能为空") + @Size(max = 64, message = "用户昵称长度不能超过64") + @ApiModelProperty(value = "用户昵称", required = true, example = "张三") + private String userNickname; + + /** + * 用户头像 + */ + @ApiModelProperty(value = "用户头像URL", example = "http://example.com/avatar.jpg") + private String userAvatar; + + /** + * 手机号 + */ + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") + @ApiModelProperty(value = "手机号", example = "13812345678") + private String mobilePhone; + + /** + * 用户联系方式 + */ + @Pattern(regexp = "^1[3-9]\\d{9}$|^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "联系方式格式不正确") + @ApiModelProperty(value = "用户联系方式(手机号或邮箱)", example = "13812345678") + private String contactInfo; + + /** + * 用户状态:0-未激活 1-正常 2-禁用 + */ + @NotNull(message = "用户状态不能为空") + @ApiModelProperty(value = "用户状态:0-未激活 1-正常 2-禁用", required = true, example = "1") + private Integer userStatus; + + /** + * 用户等级 + */ + @ApiModelProperty(value = "用户等级", example = "1") + private Integer userLevel; + + /** + * 注册渠道:1-网页 2-安卓 3-iOS 4-小程序 + */ + @NotNull(message = "注册渠道不能为空") + @ApiModelProperty(value = "注册渠道:1-网页 2-安卓 3-iOS 4-小程序", required = true, example = "1") + private Integer registerChannel; + + /** + * 最后登录时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "最后登录时间", example = "2023-01-01 12:00:00") + private Date lastLoginTime; + + /** + * 最后登录IP + */ + @ApiModelProperty(value = "最后登录IP", example = "192.168.1.1") + private String lastLoginIp; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "创建时间", example = "2023-01-01 12:00:00") + private Date createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "更新时间", example = "2023-01-01 12:00:00") + private Date updateTime; + + /** + * 用户详情信息 + */ + @ApiModelProperty(value = "用户详情信息") + private UserDetailEntity userDetail; +} \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/package-info.java new file mode 100644 index 0000000..e1accc3 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/entity/package-info.java @@ -0,0 +1,7 @@ +/** + * 实体对象; + * 1. 一般和数据库持久化对象1v1的关系,但因各自开发系统的不同,也有1vn的可能。 + * 2. 如果是老系统改造,那么旧的库表冗余了太多的字段,可能会有nv1的情况 + * 3. 对象名称 XxxEntity + */ +package com.in.domain.xxx.model.entity; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/valobj/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/valobj/package-info.java new file mode 100644 index 0000000..054651d --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/model/valobj/package-info.java @@ -0,0 +1,6 @@ +/** + * 值对象; + * 1. 用于描述对象属性的值,如一个库表中有json后者一个字段多个属性信息的枚举对象 + * 2. 对象名称如;XxxVO + */ +package com.in.domain.xxx.model.valobj; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/IUserService.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/IUserService.java new file mode 100644 index 0000000..e7e97b4 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/IUserService.java @@ -0,0 +1,60 @@ +package com.in.domain.xxx.service; + +import com.in.domain.xxx.model.entity.UserEntity; + +import java.util.List; + +/** + * 用户服务接口 + */ +public interface IUserService { + + /** + * 创建用户 + * + * @param userEntity 用户实体 + * @return 用户ID + */ + Long createUser(UserEntity userEntity); + + /** + * 更新用户 + * + * @param userEntity 用户实体 + * @return 是否更新成功 + */ + boolean updateUser(UserEntity userEntity); + + /** + * 删除用户 + * + * @param userId 用户ID + * @return 是否删除成功 + */ + boolean deleteUser(Long userId); + + /** + * 根据ID查询用户 + * + * @param userId 用户ID + * @return 用户实体 + */ + UserEntity getUserById(Long userId); + + /** + * 根据手机号查询用户 + * + * @param mobilePhone 手机号 + * @return 用户实体 + */ + UserEntity getUserByMobilePhone(String mobilePhone); + + /** + * 分页查询用户列表 + * + * @param pageIndex 页码 + * @param pageSize 每页大小 + * @return 用户列表 + */ + List listUsers(int pageIndex, int pageSize); +} \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/impl/UserServiceImpl.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..b3d9a63 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/impl/UserServiceImpl.java @@ -0,0 +1,69 @@ +package com.in.domain.xxx.service.impl; + +import com.in.domain.xxx.model.entity.UserEntity; +import com.in.domain.xxx.service.IUserService; +import com.in.domain.xxx.adapter.IUserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; + +/** + * 用户服务实现类 + */ +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements IUserService { + + private final IUserRepository userRepository; + + @Override + public Long createUser(UserEntity userEntity) { + // 设置创建时间和更新时间 + Date now = new Date(); + userEntity.setCreateTime(now); + userEntity.setUpdateTime(now); + + // 如果用户状态为空,设置默认状态为未激活 + if (userEntity.getUserStatus() == null) { + userEntity.setUserStatus(0); + } + + // 保存用户 + return userRepository.saveUser(userEntity); + } + + @Override + public boolean updateUser(UserEntity userEntity) { + // 设置更新时间 + userEntity.setUpdateTime(new Date()); + + // 更新用户 + return userRepository.updateUser(userEntity); + } + + @Override + public boolean deleteUser(Long userId) { + // 删除用户 + return userRepository.deleteUser(userId); + } + + @Override + public UserEntity getUserById(Long userId) { + // 根据ID查询用户 + return userRepository.getUserById(userId); + } + + @Override + public UserEntity getUserByMobilePhone(String mobilePhone) { + // 根据手机号查询用户 + return userRepository.getUserByMobilePhone(mobilePhone); + } + + @Override + public List listUsers(int pageIndex, int pageSize) { + // 分页查询用户列表 + return userRepository.listUsers(pageIndex, pageSize); + } +} \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/package-info.java new file mode 100644 index 0000000..31fa872 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/xxx/service/package-info.java @@ -0,0 +1 @@ +package com.in.domain.xxx.service; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/yyy/adapter/repository/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/adapter/repository/package-info.java new file mode 100644 index 0000000..e69de29 diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/aggregate/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/aggregate/package-info.java new file mode 100644 index 0000000..511419b --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/aggregate/package-info.java @@ -0,0 +1,7 @@ +/** + * 聚合对象; + * 1. 聚合实体和值对象 + * 2. 聚合是聚合的对象,和提供基础处理对象的方法。但不建议在聚合中引入仓储和接口来做过大的逻辑。而这些复杂的操作应该放到service中处理 + * 3. 对象名称 XxxAggregate + */ +package com.in.domain.yyy.model.aggregate; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/entity/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/entity/package-info.java new file mode 100644 index 0000000..670bdc3 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/entity/package-info.java @@ -0,0 +1,7 @@ +/** + * 实体对象; + * 1. 一般和数据库持久化对象1v1的关系,但因各自开发系统的不同,也有1vn的可能。 + * 2. 如果是老系统改造,那么旧的库表冗余了太多的字段,可能会有nv1的情况 + * 3. 对象名称 XxxEntity + */ +package com.in.domain.yyy.model.entity; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/valobj/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/valobj/package-info.java new file mode 100644 index 0000000..a0d3266 --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/model/valobj/package-info.java @@ -0,0 +1,6 @@ +/** + * 值对象; + * 1. 用于描述对象属性的值,如一个库表中有json后者一个字段多个属性信息的枚举对象 + * 2. 对象名称如;XxxVO + */ +package com.in.domain.yyy.model.valobj; \ No newline at end of file diff --git a/xfg-ddd-domain/src/main/java/com/in/domain/yyy/service/package-info.java b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/service/package-info.java new file mode 100644 index 0000000..2c4651d --- /dev/null +++ b/xfg-ddd-domain/src/main/java/com/in/domain/yyy/service/package-info.java @@ -0,0 +1 @@ +package com.in.domain.yyy.service; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/pom.xml b/xfg-ddd-infrastructure/pom.xml new file mode 100644 index 0000000..99a1a91 --- /dev/null +++ b/xfg-ddd-infrastructure/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + + + xfg-ddd-infrastructure + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + org.projectlombok + lombok + + + + io.springfox + springfox-swagger2 + + + io.swagger + swagger-models + + + + javax.validation + validation-api + + + org.hibernate.validator + hibernate-validator + + + + com.in + xfg-ddd-domain + + + + + xfg-ddd-infrastructure + + + org.apache.maven.plugins + maven-archetype-plugin + 3.2.0 + + + + create-from-project + + + + + + + + diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/UserRepository.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/UserRepository.java new file mode 100644 index 0000000..13f8072 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/UserRepository.java @@ -0,0 +1,99 @@ +package com.in.infrastructure.adapter; + +import com.in.domain.xxx.adapter.IUserRepository; +import com.in.domain.xxx.model.entity.UserEntity; +import com.in.infrastructure.dao.UserMapper; +import com.in.infrastructure.dao.po.UserPO; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用户仓库实现类 + */ +@Repository +@RequiredArgsConstructor +public class UserRepository implements IUserRepository { + + private final UserMapper userMapper; + + @Override + public Long saveUser(UserEntity userEntity) { + // 将实体转换为PO + UserPO userPO = new UserPO(); + BeanUtils.copyProperties(userEntity, userPO); + + // 保存用户 + userMapper.insert(userPO); + + return userPO.getId(); + } + + @Override + public boolean updateUser(UserEntity userEntity) { + // 将实体转换为PO + UserPO userPO = new UserPO(); + BeanUtils.copyProperties(userEntity, userPO); + + // 更新用户 + return userMapper.update(userPO) > 0; + } + + @Override + public boolean deleteUser(Long userId) { + // 删除用户 + return userMapper.deleteById(userId) > 0; + } + + @Override + public UserEntity getUserById(Long userId) { + // 查询用户 + UserPO userPO = userMapper.selectById(userId); + if (userPO == null) { + return null; + } + + // 将PO转换为实体 + UserEntity userEntity = new UserEntity(); + BeanUtils.copyProperties(userPO, userEntity); + + return userEntity; + } + + @Override + public UserEntity getUserByMobilePhone(String mobilePhone) { + // 查询用户 + UserPO userPO = userMapper.selectByMobilePhone(mobilePhone); + if (userPO == null) { + return null; + } + + // 将PO转换为实体 + UserEntity userEntity = new UserEntity(); + BeanUtils.copyProperties(userPO, userEntity); + + return userEntity; + } + + @Override + public List listUsers(int pageIndex, int pageSize) { + // 计算偏移量 + int offset = (pageIndex - 1) * pageSize; + + // 查询用户列表 + List userPOList = userMapper.selectList(offset, pageSize); + + // 将PO列表转换为实体列表 + List userEntityList = new ArrayList<>(); + for (UserPO userPO : userPOList) { + UserEntity userEntity = new UserEntity(); + BeanUtils.copyProperties(userPO, userEntity); + userEntityList.add(userEntity); + } + + return userEntityList; + } +} \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/port/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/port/package-info.java new file mode 100644 index 0000000..16b6176 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/port/package-info.java @@ -0,0 +1,4 @@ +/** + * 实现对外部的api调用,类的名称为 XxxPort 接口定义在 domain 中 + */ +package com.in.infrastructure.adapter.port; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/repository/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/repository/package-info.java new file mode 100644 index 0000000..ba27725 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/adapter/repository/package-info.java @@ -0,0 +1,4 @@ +/** + * 仓储实现;用于实现 domain 中定义的仓储接口,如;IXxxRepository 在 Repository 中调用服务 + */ +package com.in.infrastructure.adapter.repository; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/UserMapper.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/UserMapper.java new file mode 100644 index 0000000..8f25e8c --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/UserMapper.java @@ -0,0 +1,63 @@ +package com.in.infrastructure.dao; + +import com.in.infrastructure.dao.po.UserPO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户Mapper接口 + */ +@Mapper +public interface UserMapper { + + /** + * 插入用户 + * + * @param userPO 用户PO + * @return 影响行数 + */ + int insert(UserPO userPO); + + /** + * 更新用户 + * + * @param userPO 用户PO + * @return 影响行数 + */ + int update(UserPO userPO); + + /** + * 根据ID删除用户 + * + * @param id 用户ID + * @return 影响行数 + */ + int deleteById(@Param("id") Long id); + + /** + * 根据ID查询用户 + * + * @param id 用户ID + * @return 用户PO + */ + UserPO selectById(@Param("id") Long id); + + /** + * 根据手机号查询用户 + * + * @param mobilePhone 手机号 + * @return 用户PO + */ + UserPO selectByMobilePhone(@Param("mobilePhone") String mobilePhone); + + /** + * 分页查询用户列表 + * + * @param offset 偏移量 + * @param limit 限制 + * @return 用户PO列表 + */ + List selectList(@Param("offset") int offset, @Param("limit") int limit); +} \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/package-info.java new file mode 100644 index 0000000..74f379f --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/package-info.java @@ -0,0 +1,4 @@ +/** + * DAO 接口;IXxxDao + */ +package com.in.infrastructure.dao; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserDetailPO.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserDetailPO.java new file mode 100644 index 0000000..c89c9c9 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserDetailPO.java @@ -0,0 +1,115 @@ +package com.in.infrastructure.dao.po; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Past; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 用户详情持久化对象 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "用户详情持久化对象", description = "用户详情数据库映射对象") +public class UserDetailPO { + + /** + * 主键ID + */ + @ApiModelProperty(value = "主键ID", example = "1") + private Long id; + + /** + * 用户标识 + */ + @NotBlank(message = "用户标识不能为空") + @ApiModelProperty(value = "用户标识", required = true, example = "user123456") + private String userIdentifier; + + /** + * 真实姓名(加密存储) + */ + @Size(max = 64, message = "真实姓名长度不能超过64") + @ApiModelProperty(value = "真实姓名(加密存储)", example = "张三") + private String realName; + + /** + * 身份证号(加密存储) + */ + @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "身份证号格式不正确") + @ApiModelProperty(value = "身份证号(加密存储)", example = "加密后的身份证号") + private String idNumber; + + /** + * 出生日期 + */ + @Past(message = "出生日期必须是过去的日期") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @ApiModelProperty(value = "出生日期", example = "1990-01-01") + private Date birthDate; + + /** + * 性别:0-未知 1-男 2-女 + */ + @ApiModelProperty(value = "性别:0-未知 1-男 2-女", example = "1") + private Integer gender; + + /** + * 地址 + */ + @Size(max = 255, message = "地址长度不能超过255") + @ApiModelProperty(value = "地址", example = "北京市朝阳区xxx街道") + private String address; + + /** + * 教育程度:1-小学 2-初中 3-高中 4-大专 5-本科 6-硕士 7-博士 + */ + @ApiModelProperty(value = "教育程度:1-小学 2-初中 3-高中 4-大专 5-本科 6-硕士 7-博士", example = "5") + private Integer educationLevel; + + /** + * 职业 + */ + @Size(max = 64, message = "职业长度不能超过64") + @ApiModelProperty(value = "职业", example = "软件工程师") + private String profession; + + /** + * 兴趣爱好 + */ + @Size(max = 255, message = "兴趣爱好长度不能超过255") + @ApiModelProperty(value = "兴趣爱好", example = "阅读,旅游,摄影") + private String hobbies; + + /** + * 个人简介 + */ + @Size(max = 500, message = "个人简介长度不能超过500") + @ApiModelProperty(value = "个人简介", example = "这是一段个人简介...") + private String personalProfile; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "创建时间", example = "2023-01-01 12:00:00") + private Date createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "更新时间", example = "2023-01-01 12:00:00") + private Date updateTime; +} \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserPO.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserPO.java new file mode 100644 index 0000000..51a1625 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/UserPO.java @@ -0,0 +1,115 @@ +package com.in.infrastructure.dao.po; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.Date; + +/** + * 用户持久化对象 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "用户持久化对象", description = "用户数据库映射对象") +public class UserPO { + + /** + * 主键ID + */ + @ApiModelProperty(value = "主键ID", example = "1") + private Long id; + + /** + * 用户标识 + */ + @NotBlank(message = "用户标识不能为空") + @Size(min = 6, max = 32, message = "用户标识长度必须在6-32之间") + @ApiModelProperty(value = "用户标识", required = true, example = "user123456") + private String userIdentifier; + + /** + * 用户昵称 + */ + @NotBlank(message = "用户昵称不能为空") + @Size(max = 64, message = "用户昵称长度不能超过64") + @ApiModelProperty(value = "用户昵称", required = true, example = "张三") + private String userNickname; + + /** + * 用户头像 + */ + @ApiModelProperty(value = "用户头像URL", example = "http://example.com/avatar.jpg") + private String userAvatar; + + /** + * 手机号 + */ + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确") + @ApiModelProperty(value = "手机号", example = "13812345678") + private String mobilePhone; + + /** + * 用户联系方式 + */ + @Pattern(regexp = "^1[3-9]\\d{9}$|^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "联系方式格式不正确") + @ApiModelProperty(value = "用户联系方式(手机号或邮箱)", example = "13812345678") + private String contactInfo; + + /** + * 用户状态:0-未激活 1-正常 2-禁用 + */ + @NotNull(message = "用户状态不能为空") + @ApiModelProperty(value = "用户状态:0-未激活 1-正常 2-禁用", required = true, example = "1") + private Integer userStatus; + + /** + * 用户等级 + */ + @ApiModelProperty(value = "用户等级", example = "1") + private Integer userLevel; + + /** + * 注册渠道:1-网页 2-安卓 3-iOS 4-小程序 + */ + @NotNull(message = "注册渠道不能为空") + @ApiModelProperty(value = "注册渠道:1-网页 2-安卓 3-iOS 4-小程序", required = true, example = "1") + private Integer registerChannel; + + /** + * 最后登录时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "最后登录时间", example = "2023-01-01 12:00:00") + private Date lastLoginTime; + + /** + * 最后登录IP + */ + @ApiModelProperty(value = "最后登录IP", example = "192.168.1.1") + private String lastLoginIp; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "创建时间", example = "2023-01-01 12:00:00") + private Date createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @ApiModelProperty(value = "更新时间", example = "2023-01-01 12:00:00") + private Date updateTime; +} \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/package-info.java new file mode 100644 index 0000000..6e23882 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/dao/po/package-info.java @@ -0,0 +1,4 @@ +/** + * 持久化对象;XxxPO 最后的 PO 是大写,UserPO + */ +package com.in.infrastructure.dao.po; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/dto/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/dto/package-info.java new file mode 100644 index 0000000..e69de29 diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/package-info.java new file mode 100644 index 0000000..fc3f351 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/gateway/package-info.java @@ -0,0 +1,4 @@ +/** + * 定义http、rpc接口,调用外部。在 adapter 中调用这部分内容。 + */ +package com.in.infrastructure.gateway; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/redis/package-info.java b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/redis/package-info.java new file mode 100644 index 0000000..83481fb --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/java/com/in/infrastructure/redis/package-info.java @@ -0,0 +1,4 @@ +/** + * 提供redis链接配置 + */ +package com.in.infrastructure.redis; \ No newline at end of file diff --git a/xfg-ddd-infrastructure/src/main/resources/mybatis/mapper/UserMapper.xml b/xfg-ddd-infrastructure/src/main/resources/mybatis/mapper/UserMapper.xml new file mode 100644 index 0000000..f22b438 --- /dev/null +++ b/xfg-ddd-infrastructure/src/main/resources/mybatis/mapper/UserMapper.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + id, user_identifier, user_nickname, user_avatar, mobile_phone, contact_info, user_status, + user_level, register_channel, last_login_time, last_login_ip, create_time, update_time + + + + + INSERT INTO user ( + user_identifier, user_nickname, user_avatar, mobile_phone, contact_info, user_status, + user_level, register_channel, last_login_time, last_login_ip, create_time, update_time + ) VALUES ( + #{userIdentifier}, #{userNickname}, #{userAvatar}, #{mobilePhone}, #{contactInfo}, #{userStatus}, + #{userLevel}, #{registerChannel}, #{lastLoginTime}, #{lastLoginIp}, #{createTime}, #{updateTime} + ) + + + + + UPDATE user + + user_nickname = #{userNickname}, + user_avatar = #{userAvatar}, + mobile_phone = #{mobilePhone}, + contact_info = #{contactInfo}, + user_status = #{userStatus}, + user_level = #{userLevel}, + last_login_time = #{lastLoginTime}, + last_login_ip = #{lastLoginIp}, + update_time = #{updateTime}, + + WHERE id = #{id} + + + + + DELETE FROM user WHERE id = #{id} + + + + + + + + + + + \ No newline at end of file diff --git a/xfg-ddd-trigger/pom.xml b/xfg-ddd-trigger/pom.xml new file mode 100644 index 0000000..96962da --- /dev/null +++ b/xfg-ddd-trigger/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + + + xfg-ddd-trigger + + + + org.springframework.boot + spring-boot-starter-web + + + com.alibaba + fastjson + + + org.springframework + spring-tx + + + org.apache.commons + commons-lang3 + + + + + com.in + xfg-ddd-api + + + com.in + xfg-ddd-types + + + com.in + xfg-ddd-domain + + + + + xfg-ddd-trigger + + + org.apache.maven.plugins + maven-archetype-plugin + 3.2.0 + + + + create-from-project + + + + + + + + diff --git a/xfg-ddd-trigger/src/main/java/com/in/trigger/config/JacksonConfig.java b/xfg-ddd-trigger/src/main/java/com/in/trigger/config/JacksonConfig.java new file mode 100644 index 0000000..04f5bd4 --- /dev/null +++ b/xfg-ddd-trigger/src/main/java/com/in/trigger/config/JacksonConfig.java @@ -0,0 +1,31 @@ +package com.in.trigger.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +/** + * Jackson配置类 + */ +@Configuration +public class JacksonConfig { + + /** + * 配置ObjectMapper + */ + @Bean + public ObjectMapper objectMapper() { + return Jackson2ObjectMapperBuilder.json() + .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .featuresToEnable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + .dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")) + .timeZone(TimeZone.getDefault()) + .build(); + } +} \ No newline at end of file diff --git a/xfg-ddd-trigger/src/main/java/com/in/trigger/http/UserController.java b/xfg-ddd-trigger/src/main/java/com/in/trigger/http/UserController.java new file mode 100644 index 0000000..2de48d6 --- /dev/null +++ b/xfg-ddd-trigger/src/main/java/com/in/trigger/http/UserController.java @@ -0,0 +1,95 @@ +package com.in.trigger.http; + +import com.in.api.response.Response; +import com.in.domain.xxx.model.entity.UserEntity; +import com.in.domain.xxx.service.IUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * 用户控制器 + */ +@Api(tags = "用户管理") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/users") +public class UserController { + + private final IUserService userService; + + @ApiOperation(value = "创建用户", notes = "创建新用户") + @PostMapping + public Response createUser(@Valid @RequestBody UserEntity userEntity) { + Long userId = userService.createUser(userEntity); + return Response.success("创建用户成功", userId); + } + + @ApiOperation(value = "更新用户", notes = "根据用户ID更新用户信息") + @PutMapping("/{id}") + public Response updateUser( + @ApiParam(value = "用户ID", required = true) @PathVariable("id") Long id, + @Valid @RequestBody UserEntity userEntity) { + userEntity.setId(id); + boolean success = userService.updateUser(userEntity); + + if (success) { + return Response.successWithoutData("更新用户成功"); + } else { + return Response.bizError("更新用户失败"); + } + } + + @ApiOperation(value = "删除用户", notes = "根据用户ID删除用户") + @DeleteMapping("/{id}") + public Response deleteUser( + @ApiParam(value = "用户ID", required = true) @PathVariable("id") Long id) { + boolean success = userService.deleteUser(id); + + if (success) { + return Response.successWithoutData("删除用户成功"); + } else { + return Response.bizError("删除用户失败"); + } + } + + @ApiOperation(value = "获取用户", notes = "根据用户ID获取用户信息") + @GetMapping("/{id}") + public Response getUser( + @ApiParam(value = "用户ID", required = true) @PathVariable("id") Long id) { + UserEntity userEntity = userService.getUserById(id); + + if (userEntity != null) { + return Response.success("获取用户成功", userEntity); + } else { + return Response.bizError("用户不存在"); + } + } + + @ApiOperation(value = "根据手机号获取用户", notes = "根据手机号获取用户信息") + @GetMapping("/mobile/{mobilePhone}") + public Response getUserByMobilePhone( + @ApiParam(value = "手机号", required = true) @PathVariable("mobilePhone") String mobilePhone) { + UserEntity userEntity = userService.getUserByMobilePhone(mobilePhone); + + if (userEntity != null) { + return Response.success("获取用户成功", userEntity); + } else { + return Response.bizError("用户不存在"); + } + } + + @ApiOperation(value = "获取用户列表", notes = "分页获取用户列表") + @GetMapping + public Response> listUsers( + @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") int pageIndex, + @ApiParam(value = "每页大小", defaultValue = "10") @RequestParam(defaultValue = "10") int pageSize) { + List userEntityList = userService.listUsers(pageIndex, pageSize); + return Response.success("获取用户列表成功", userEntityList); + } +} diff --git a/xfg-ddd-trigger/src/main/java/com/in/trigger/http/package-info.java b/xfg-ddd-trigger/src/main/java/com/in/trigger/http/package-info.java new file mode 100644 index 0000000..15ed161 --- /dev/null +++ b/xfg-ddd-trigger/src/main/java/com/in/trigger/http/package-info.java @@ -0,0 +1,4 @@ +/** + * HTTP 接口服务 + */ +package com.in.trigger.http; \ No newline at end of file diff --git a/xfg-ddd-trigger/src/main/java/com/in/trigger/job/package-info.java b/xfg-ddd-trigger/src/main/java/com/in/trigger/job/package-info.java new file mode 100644 index 0000000..9ad6e30 --- /dev/null +++ b/xfg-ddd-trigger/src/main/java/com/in/trigger/job/package-info.java @@ -0,0 +1,4 @@ +/** + * 任务服务,可以选择使用 Spring 默认提供的 Schedule https://bugstack.cn/md/road-map/quartz.html + */ +package com.in.trigger.job; \ No newline at end of file diff --git a/xfg-ddd-trigger/src/main/java/com/in/trigger/listener/package-info.java b/xfg-ddd-trigger/src/main/java/com/in/trigger/listener/package-info.java new file mode 100644 index 0000000..6de20ab --- /dev/null +++ b/xfg-ddd-trigger/src/main/java/com/in/trigger/listener/package-info.java @@ -0,0 +1,5 @@ +/** + * 监听服务;在单体服务中,解耦流程。类似MQ的使用,如Spring的Event,Guava的事件总线都可以。如果使用了 Redis 那么也可以有发布/订阅使用。 + * Guava:https://bugstack.cn/md/road-map/guava.html + */ +package com.in.trigger.listener; \ No newline at end of file diff --git a/xfg-ddd-types/pom.xml b/xfg-ddd-types/pom.xml new file mode 100644 index 0000000..d03ffe9 --- /dev/null +++ b/xfg-ddd-types/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + com.in + xfg-ddd + 1.0-SNAPSHOT + + + xfg-ddd-types + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + + + com.thoughtworks.xstream + xstream + + + dom4j + dom4j + + + org.apache.commons + commons-lang3 + + + + + xfg-ddd-types + + + org.apache.maven.plugins + maven-archetype-plugin + 3.2.0 + + + + create-from-project + + + + + + + + diff --git a/xfg-ddd-types/src/main/java/com/in/types/common/Constants.java b/xfg-ddd-types/src/main/java/com/in/types/common/Constants.java new file mode 100644 index 0000000..e1a333f --- /dev/null +++ b/xfg-ddd-types/src/main/java/com/in/types/common/Constants.java @@ -0,0 +1,7 @@ +package com.in.types.common; + +public class Constants { + + public final static String SPLIT = ","; + +} diff --git a/xfg-ddd-types/src/main/java/com/in/types/enums/ResponseCode.java b/xfg-ddd-types/src/main/java/com/in/types/enums/ResponseCode.java new file mode 100644 index 0000000..319a76b --- /dev/null +++ b/xfg-ddd-types/src/main/java/com/in/types/enums/ResponseCode.java @@ -0,0 +1,20 @@ +package com.in.types.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public enum ResponseCode { + + SUCCESS("0000", "成功"), + UN_ERROR("0001", "未知失败"), + ILLEGAL_PARAMETER("0002", "非法参数"), + ; + + private String code; + private String info; + +} diff --git a/xfg-ddd-types/src/main/java/com/in/types/exception/AppException.java b/xfg-ddd-types/src/main/java/com/in/types/exception/AppException.java new file mode 100644 index 0000000..9bc21a3 --- /dev/null +++ b/xfg-ddd-types/src/main/java/com/in/types/exception/AppException.java @@ -0,0 +1,46 @@ +package com.in.types.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class AppException extends RuntimeException { + + private static final long serialVersionUID = 5317680961212299217L; + + /** 异常码 */ + private String code; + + /** 异常信息 */ + private String info; + + public AppException(String code) { + this.code = code; + } + + public AppException(String code, Throwable cause) { + this.code = code; + super.initCause(cause); + } + + public AppException(String code, String message) { + this.code = code; + this.info = message; + } + + public AppException(String code, String message, Throwable cause) { + this.code = code; + this.info = message; + super.initCause(cause); + } + + @Override + public String toString() { + return "com.in.x.api.types.exception.XApiException{" + + "code='" + code + '\'' + + ", info='" + info + '\'' + + '}'; + } + +}