Przeglądaj źródła

feat 新增脚手架

classic_blue 2 dni temu
rodzic
commit
1b8ef4e5df
96 zmienionych plików z 5163 dodań i 0 usunięć
  1. 69 0
      babyApplication-common/babyApplication-common-cache/pom.xml
  2. 17 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/annotation/ClearAndReloadCache.java
  3. 14 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/annotation/EnableRedis.java
  4. 16 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/annotation/EnableRedisCache.java
  5. 67 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/aspects/CacheAspects.java
  6. 82 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/config/EduTravelCacheConfig.java
  7. 51 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/config/RedisConfig.java
  8. 55 0
      babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/config/RedisLock.java
  9. 28 0
      babyApplication-common/babyApplication-common-constant/pom.xml
  10. 28 0
      babyApplication-common/babyApplication-common-constant/src/main/java/edu/travel/FinalParam.java
  11. 10 0
      babyApplication-common/babyApplication-common-constant/src/main/java/edu/travel/RPCStatus.java
  12. 15 0
      babyApplication-common/babyApplication-common-constant/src/main/java/edu/travel/RedisKeyConstant.java
  13. 60 0
      babyApplication-common/babyApplication-common-core/pom.xml
  14. 23 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/errors/ErrorPO.java
  15. 59 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/exception/BaseException.java
  16. 4 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/interfaces/InsertGroups.java
  17. 4 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/interfaces/UpdateGroups.java
  18. 18 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/CustomDeepCopy.java
  19. 175 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/ModelMapperUtil.java
  20. 38 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/MyTreeUtil.java
  21. 53 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/TreeNode.java
  22. 16 0
      babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/web/MapToJsonStringSerializer.java
  23. 67 0
      babyApplication-common/babyApplication-common-datasource/pom.xml
  24. 25 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/annotation/LinkConst.java
  25. 31 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/annotation/LinkMany.java
  26. 30 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/annotation/LinkOne.java
  27. 21 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/DruidConfig.java
  28. 66 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/FieldMetaObjectHandler.java
  29. 20 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/MybatisPlusConfig.java
  30. 28 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/MysqlConfig.java
  31. 26 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/PGConfig.java
  32. 122 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/datasource/ProjectInterceptor.java
  33. 4 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/interfaces/InsertGroups.java
  34. 4 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/interfaces/UpdateGroups.java
  35. 208 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/service/SysServiceImpl.java
  36. 100 0
      babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/web/BaseController.java
  37. 26 0
      babyApplication-common/babyApplication-common-resp/pom.xml
  38. 57 0
      babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/emun/ResponseCode.java
  39. 21 0
      babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/emun/StatusCode.java
  40. 20 0
      babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/resp/BaseResponse.java
  41. 33 0
      babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/resp/PageResponse.java
  42. 57 0
      babyApplication-common/babyApplication-common-upload/pom.xml
  43. 40 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/cos/TencentCosClient.java
  44. 45 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/cos/TencentCosUtils.java
  45. 27 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/cos/property/CosProperties.java
  46. 23 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioClient.java
  47. 228 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioUtils.java
  48. 26 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/minio/property/MinioProperties.java
  49. 20 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSClient.java
  50. 106 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSUtils.java
  51. 26 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/obs/property/ObsProperties.java
  52. 23 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSClient.java
  53. 35 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSUtils.java
  54. 25 0
      babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/oss/property/CloudOssProperty.java
  55. 42 0
      babyApplication-common/babyApplication-common-util/pom.xml
  56. 31 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/AuthUserUtil.java
  57. 107 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/Base64Util.java
  58. 51 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/ContextUtil.java
  59. 42 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/ContextUtils.java
  60. 83 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/EncryptUtil.java
  61. 63 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/MD5Util.java
  62. 59 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/PropertiesUtil.java
  63. 160 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/RedisUtil.java
  64. 50 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/SMSUtils.java
  65. 38 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/SmsSwitch.java
  66. 169 0
      babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/TokenUtil.java
  67. 29 0
      babyApplication-common/pom.xml
  68. 50 0
      babyApplication-dao/pom.xml
  69. 7 0
      babyApplication-dao/src/main/java/edu/travel/mapper/BtAccountInfoMapper.java
  70. 28 0
      babyApplication-model/babyApplication-model-base/pom.xml
  71. 96 0
      babyApplication-model/babyApplication-model-base/src/main/java/edu/travel/entity/AccountInfo.java
  72. 35 0
      babyApplication-model/babyApplication-model-base/src/main/java/edu/travel/entity/BaseEntity.java
  73. 27 0
      babyApplication-model/babyApplication-model-entity/pom.xml
  74. 30 0
      babyApplication-model/babyApplication-model-entity/src/main/java/edu/travel/dto/LoginDto.java
  75. 23 0
      babyApplication-model/babyApplication-model-entity/src/main/java/edu/travel/dto/SendSmsDto.java
  76. 101 0
      babyApplication-model/babyApplication-model-entity/src/main/java/edu/travel/entity/BtAccountInfo.java
  77. 35 0
      babyApplication-model/pom.xml
  78. 65 0
      babyApplication-service/pom.xml
  79. 15 0
      babyApplication-service/src/main/java/edu/travel/service/BtAccountInfoService.java
  80. 95 0
      babyApplication-service/src/main/java/edu/travel/service/impl/AccountInfoServiceImpl.java
  81. 132 0
      babyApplication-service/src/main/java/edu/travel/service/impl/BtAccountInfoServiceImpl.java
  82. 64 0
      babyApplication-web/pom.xml
  83. 20 0
      babyApplication-web/src/main/java/edu/travel/BabyApplication.java
  84. 31 0
      babyApplication-web/src/main/java/edu/travel/config/CORSFilter.java
  85. 62 0
      babyApplication-web/src/main/java/edu/travel/config/CustomObjectMapper.java
  86. 101 0
      babyApplication-web/src/main/java/edu/travel/config/SecurityConfig.java
  87. 69 0
      babyApplication-web/src/main/java/edu/travel/config/WebConfig.java
  88. 38 0
      babyApplication-web/src/main/java/edu/travel/constanst/Constants.java
  89. 47 0
      babyApplication-web/src/main/java/edu/travel/controller/LoginController.java
  90. 103 0
      babyApplication-web/src/main/java/edu/travel/filter/LoginFilter.java
  91. 78 0
      babyApplication-web/src/main/java/edu/travel/filter/TokenAuthenticationFilter.java
  92. 41 0
      babyApplication-web/src/main/resources/application-dev.properties
  93. 41 0
      babyApplication-web/src/main/resources/application-prod.properties
  94. 50 0
      babyApplication-web/src/main/resources/application-test.properties
  95. 51 0
      babyApplication-web/src/main/resources/application.properties
  96. 212 0
      pom.xml

+ 69 - 0
babyApplication-common/babyApplication-common-cache/pom.xml

@@ -0,0 +1,69 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-cache</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-cache</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <!--redis start-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>redis.clients</groupId>
+                    <artifactId>jedis</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>io.lettuce</groupId>
+                    <artifactId>lettuce-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-spring-boot-starter</artifactId>
+            <version>3.23.1</version>
+        </dependency>
+        <!--spring2.0集成redis所需common-pool2-->
+        <!-- 必须加上,jedis依赖此  -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <!--redis end-->
+        <!--cache start-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+        <!--cache end-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 17 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/annotation/ClearAndReloadCache.java

@@ -0,0 +1,17 @@
+package edu.travel.cache.annotation;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Inherited
+public @interface ClearAndReloadCache {
+    boolean value() default true;
+
+    String cachePrefix();
+
+    String cacheSuffix();
+
+    boolean prefixFactory() default true;
+}

+ 14 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/annotation/EnableRedis.java

@@ -0,0 +1,14 @@
+package edu.travel.cache.annotation;
+
+import edu.travel.cache.config.RedisConfig;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Import(RedisConfig.class)
+@Documented
+@Inherited
+public @interface EnableRedis {
+}

+ 16 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/annotation/EnableRedisCache.java

@@ -0,0 +1,16 @@
+package edu.travel.cache.annotation;
+
+import edu.travel.cache.config.EduTravelCacheConfig;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Import;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Import(EduTravelCacheConfig.class)
+@EnableCaching
+@Documented
+@Inherited
+public @interface EnableRedisCache {
+}

+ 67 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/aspects/CacheAspects.java

@@ -0,0 +1,67 @@
+package edu.travel.cache.aspects;
+
+import edu.travel.cache.annotation.ClearAndReloadCache;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.Set;
+
+@Aspect
+@Component
+public class CacheAspects {
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    // 定义切点,例如拦截所有service层的方法
+    @Pointcut("@annotation(edu.travel.cache.annotation.ClearAndReloadCache)")
+    public void cachePointcut() {}
+
+    @Around("cachePointcut()")
+    public Object cacheAround(ProceedingJoinPoint joinPoint) throws Throwable {
+        Signature signature = joinPoint.getSignature();
+        Object result = null;
+        if (signature instanceof MethodSignature) {
+            MethodSignature methodSignature = (MethodSignature)signature;
+            Method targetMethod = methodSignature.getMethod();//方法对象
+            ClearAndReloadCache annotation = targetMethod.getAnnotation(ClearAndReloadCache.class);
+            boolean value = annotation.value();
+            String pattern;
+            if (value) {
+                Set keys;
+                if (annotation.prefixFactory()){
+                    keys = getKeys(annotation.cachePrefix());
+                    pattern = annotation.cachePrefix();
+                }else {
+                    keys = getKeys(annotation.cacheSuffix());
+                    pattern = annotation.cacheSuffix();
+                }
+                redisTemplate.delete(keys);
+            } else {
+                pattern = null;
+            }
+            result = joinPoint.proceed(joinPoint.getArgs());
+            new Thread(()->{
+                try {
+                    Thread.sleep(1000);
+                    Set keys = getKeys(pattern);
+                    redisTemplate.delete(keys);
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }).start();
+        }
+        return result;
+    }
+
+    private Set getKeys(String pattern) {
+        return redisTemplate.keys("*"+pattern+"*");
+    }
+}

+ 82 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/config/EduTravelCacheConfig.java

@@ -0,0 +1,82 @@
+
+
+package edu.travel.cache.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+
+@Configuration
+public class EduTravelCacheConfig {
+//    @Autowired
+//    private RedisTemplate redisTemplate;
+//    @Autowired
+//    private RedisConnectionFactory redisConnectionFactory;
+    @Bean
+    public RedisCacheConfiguration redisCacheConfiguration(){
+        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
+//设置redis缓存值的序列化方式,此处采用json方式序列化
+        redisCacheConfiguration = redisCacheConfiguration.
+                serializeValuesWith(RedisSerializationContext.SerializationPair.
+                        fromSerializer(new GenericJackson2JsonRedisSerializer()));
+        return redisCacheConfiguration;
+    }
+
+
+
+//    @Bean
+//    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
+//        redisTemplate.setConnectionFactory(factory);
+//        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
+//        redisTemplate.setDefaultSerializer(serializer);
+//        //设置序列化Key的实例化对象
+//        redisTemplate.setKeySerializer(new StringRedisSerializer());
+//        //设置序列化Value的实例化对象
+//        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+//
+//        return redisTemplate;
+//    }
+//
+//    @Bean
+//    public RedisMessageListenerContainer redisContainer() {
+//        final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
+//        container.setConnectionFactory(redisConnectionFactory);
+//        return container;
+//    }
+//
+//    @Bean
+//    public RedisScript<Long> limitRedisScript() {
+//        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
+//        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/limit.lua")));
+//        redisScript.setResultType(Long.class);
+//        return redisScript;
+//    }
+
+
+//    @Bean(name = "redisTemplate")
+//    public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
+//        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
+//        redisTemplate.setConnectionFactory(factory);
+//        RedisSerializer stringSerializer = new StringRedisSerializer();
+//        redisTemplate.setKeySerializer(stringSerializer);
+//        redisTemplate.setValueSerializer(stringSerializer);
+//        redisTemplate.setHashKeySerializer(stringSerializer);
+//        redisTemplate.setHashValueSerializer(stringSerializer);
+////        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+////        ObjectMapper objectMapper = new ObjectMapper();
+////        // 使用Jackson序列化对象
+////        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+////        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
+////                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+////        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+////        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+////
+////        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
+////        redisTemplate.setHashKeySerializer(stringRedisSerializer);
+////        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+//        redisTemplate.afterPropertiesSet();
+//        return redisTemplate;
+//    }
+}

+ 51 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/config/RedisConfig.java

@@ -0,0 +1,51 @@
+package edu.travel.cache.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.data.redis.core.script.RedisScript;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.scripting.support.ResourceScriptSource;
+
+@Configuration
+public class RedisConfig {
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Autowired
+    private RedisConnectionFactory redisConnectionFactory;
+
+    @Bean
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
+        redisTemplate.setConnectionFactory(factory);
+        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
+        redisTemplate.setDefaultSerializer(serializer);
+        //设置序列化Key的实例化对象
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        //设置序列化Value的实例化对象
+        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+
+        return redisTemplate;
+    }
+
+    @Bean
+    public RedisMessageListenerContainer redisContainer() {
+        final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
+        container.setConnectionFactory(redisConnectionFactory);
+        return container;
+    }
+
+    @Bean
+    public RedisScript<Long> limitRedisScript() {
+        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
+        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("scripts/limit.lua")));
+        redisScript.setResultType(Long.class);
+        return redisScript;
+    }
+}

+ 55 - 0
babyApplication-common/babyApplication-common-cache/src/main/java/edu/travel/cache/config/RedisLock.java

@@ -0,0 +1,55 @@
+package edu.travel.cache.config;
+
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.data.redis.core.script.RedisScript;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class RedisLock {
+
+    private final StringRedisTemplate redisTemplate;
+
+    // 锁键的前缀,可根据业务自定义
+    private static final String LOCK_PREFIX = "lock:";
+
+    public RedisLock(StringRedisTemplate redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+
+    /**
+     * 获取分布式锁(使用SETNX和过期时间,保证原子性)
+     * @param lockKey   锁的键
+     * @param expire    锁的过期时间(秒)
+     * @return 锁的唯一标识(用于释放锁)
+     */
+    public String acquireLock(String lockKey, long expire) {
+        String lockValue = UUID.randomUUID().toString();
+        String key = LOCK_PREFIX + lockKey;
+        // 使用SET命令:SET key value NX EX expire
+        Boolean success = redisTemplate.opsForValue()
+                .setIfAbsent(key, lockValue, expire, TimeUnit.SECONDS);
+        return Boolean.TRUE.equals(success) ? lockValue : null;
+    }
+
+    /**
+     * 释放分布式锁(使用Lua脚本保证原子性)
+     * @param lockKey   锁的键
+     * @param lockValue 锁的唯一标识
+     * @return 是否释放成功
+     */
+    public boolean releaseLock(String lockKey, String lockValue) {
+        if (lockValue == null) return false;
+        String key = LOCK_PREFIX + lockKey;
+        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
+                        "return redis.call('del', KEYS[1]) " +
+                        "else return 0 end";
+        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
+        Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), lockValue);
+        return result != null && result == 1;
+    }
+}

+ 28 - 0
babyApplication-common/babyApplication-common-constant/pom.xml

@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-constant</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-constant</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 28 - 0
babyApplication-common/babyApplication-common-constant/src/main/java/edu/travel/FinalParam.java

@@ -0,0 +1,28 @@
+package edu.travel;
+
+public interface FinalParam {
+    /**
+     * JWT存储权限前缀
+     */
+    String AUTHORITY_PREFIX = "ROLE_";
+
+    /**
+     * JWT存储权限属性
+     */
+    String AUTHORITY_CLAIM_NAME = "authorities";
+
+    /**
+     * 认证信息Http请求头
+     */
+    String JWT_TOKEN_HEADER = "Authorization";
+
+    /**
+     * JWT令牌前缀
+     */
+    String JWT_TOKEN_PREFIX = "Bearer ";
+
+    /**
+     * JWT载体key
+     */
+    String JWT_PAYLOAD_KEY = "payload";
+}

+ 10 - 0
babyApplication-common/babyApplication-common-constant/src/main/java/edu/travel/RPCStatus.java

@@ -0,0 +1,10 @@
+package edu.travel;
+
+public interface RPCStatus {
+
+     final Integer RESOURCES_NOT_FOUND = 404;
+
+     final Integer RESOURCES_SUCCESS = 200;
+
+     final Integer RESOURCES_ERROR = 500;
+}

+ 15 - 0
babyApplication-common/babyApplication-common-constant/src/main/java/edu/travel/RedisKeyConstant.java

@@ -0,0 +1,15 @@
+package edu.travel;
+
+/**
+ * RedisKeyConstant 。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/10
+ */
+public interface RedisKeyConstant {
+    /**
+     *
+     */
+}

+ 60 - 0
babyApplication-common/babyApplication-common-core/pom.xml

@@ -0,0 +1,60 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-core</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-core</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-extension</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-tx</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-resp</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <!-- 对象转换工具-->
+        <dependency>
+            <groupId>org.modelmapper</groupId>
+            <artifactId>modelmapper</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 23 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/errors/ErrorPO.java

@@ -0,0 +1,23 @@
+package edu.travel.errors;
+
+public class ErrorPO {
+    Integer errorCode;
+    String errorMessage;
+    public ErrorPO(Integer errorCode, String errorMessage) {
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+    }
+    public Integer getErrorCode() {
+        return errorCode;
+    }
+    public void setErrorCode(Integer errorCode) {
+        this.errorCode = errorCode;
+    }
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+}

+ 59 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/exception/BaseException.java

@@ -0,0 +1,59 @@
+package edu.travel.exception;
+
+import edu.travel.emun.ResponseCode;
+
+/**
+ * BaseException 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/11
+ */
+
+
+public class BaseException extends RuntimeException {
+
+    private static final long serialVersionUID = -8458116729669426482L;
+
+    private Integer code;
+
+
+    public BaseException() {
+        super();
+    }
+
+    public BaseException(String message) {
+        super(message);
+    }
+
+    public BaseException(Integer code, String message, Throwable cause,
+                         boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+        this.code = code;
+    }
+
+    public BaseException(Integer code, String message, Throwable cause) {
+        super(message, cause);
+        this.code = code;
+    }
+
+    public BaseException(ResponseCode responseCode) {
+        super(responseCode.getMessage());
+        this.code = responseCode.getCode();
+    }
+
+    public BaseException(Integer code, String message) {
+        super(message);
+        this.code = code;
+    }
+
+    public BaseException(Throwable cause) {
+        super(cause);
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+}

+ 4 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/interfaces/InsertGroups.java

@@ -0,0 +1,4 @@
+package edu.travel.interfaces;
+
+public interface InsertGroups {
+}

+ 4 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/interfaces/UpdateGroups.java

@@ -0,0 +1,4 @@
+package edu.travel.interfaces;
+
+public interface UpdateGroups {
+}

+ 18 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/CustomDeepCopy.java

@@ -0,0 +1,18 @@
+package edu.travel.utils.tree;
+
+import com.alibaba.fastjson.JSON;
+
+import java.util.List;
+
+public class CustomDeepCopy {
+    public static <T> T toClass(T source, Class<T> targetClass) {
+        String jsonString = JSON.toJSONString(source);
+        return JSON.parseObject(jsonString, targetClass);
+    }
+    public static <T> List<T> toObject(Object source, Class<T> targetClass) {
+        String jsonString = JSON.toJSONString(source);
+        return JSON.parseArray(jsonString, targetClass);
+    }
+
+
+}

+ 175 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/ModelMapperUtil.java

@@ -0,0 +1,175 @@
+package edu.travel.utils.tree;
+
+import org.modelmapper.ModelMapper;
+import org.modelmapper.convention.MatchingStrategies;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+/**
+ * 对象映射转换工具类,转换逻辑属性名完全匹配进行转换
+ */
+public final class ModelMapperUtil {
+
+    public static final ModelMapper MODEL_MAPPER;
+
+    static {
+
+        MODEL_MAPPER = new ModelMapper();
+        // 完全类型匹配
+        //MODEL_MAPPER.getConfiguration().setFullTypeMatchingRequired(true);
+        // 设置属性匹配规则,设置为最严格匹配,必须属性名相同
+        MODEL_MAPPER.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
+    }
+
+    /**
+     * 禁止实列化该类
+     * @throws InstantiationException 不能实列化
+     */
+    private ModelMapperUtil() throws InstantiationException {
+        throw new InstantiationException("Tool Class Cannot Be Created Instantiation !");
+    }
+
+    /**
+     * 将对象转换为指定class类型对象。
+     * @param source 源对象
+     * @param targetClass 转换目标类型
+     * @return 转换后对象
+     * @param <Target> 目标类型
+     */
+    public static <Target> Target map(Object source, Class<Target> targetClass) {
+        return source == null ? null : MODEL_MAPPER.map(source, targetClass);
+    }
+
+
+    /**
+     * 将源对象中的属性转换到目标对象中,源对象与目标对象属性名相同的则转换
+     * @param source 源对象
+     * @param target 目标对象
+     */
+    public static void map(Object source, Object target) {
+        if (source == null || target == null) {
+            return;
+        } else {
+            MODEL_MAPPER.map(source, target);
+        }
+    }
+
+    /**
+     * 将对象转换为指定class类型对象,并对转换后对象进行处理
+     * @param source 源对象
+     * @param targetClass 转换目标类型
+     * @param consumer 对转换后对象进行消费处理
+     * @return 转换后对象
+     * @param <Target> 目标类型
+     */
+    public static <Target> Target map(Object source, Class<Target> targetClass, Consumer<Target> consumer) {
+        Target target = source == null ? null : MODEL_MAPPER.map(source, targetClass);
+        if (consumer != null) {
+            consumer.accept(target);
+        }
+        return target;
+    }
+
+    /**
+     * 将对象转换为指定class类型对象,并对转换后对象进行处理
+     * @param source 源对象
+     * @param targetClass 转换目标类型
+     * @param consumer 对转换后对象进行消费处理
+     * @return 转换后对象
+     * @param <Source> 源对象类型
+     * @param <Target> 目标类型
+     */
+    public static <Source, Target> Target map(Source source, Class<Target> targetClass, BiConsumer<Source, Target> consumer) {
+        Target target = source == null ? null : MODEL_MAPPER.map(source, targetClass);
+        if (consumer != null) {
+            consumer.accept(source, target);
+        }
+        return target;
+    }
+
+    /**
+     * 将集合中的元素抓换为指定类型
+     * @param sourceList 源集合
+     * @param targetClass 转换目标类型
+     * @return 转换后的目标类型集合
+     * @param <TSource> 源类型
+     * @param <Target> 目标类型
+     */
+    public static <TSource, Target> List<Target> mapList(Collection<TSource> sourceList, Class<Target> targetClass) {
+
+        if (sourceList == null) {
+            return new ArrayList<Target>();
+        }
+
+        ArrayList<Target> targets = new ArrayList<>(sourceList.size());
+
+        sourceList.forEach(p -> {
+            Target item = map(p, targetClass);
+            targets.add(item);
+        });
+
+        return targets;
+    }
+
+    /**
+     * 将集合中的元素抓换为指定类型,并对转换后的元素处理
+     * @param sourceList 源集合
+     * @param targetClass 转换目标类型
+     * @param consumer 对转换后元素处理
+     * @return 转换后的集合
+     * @param <TSource> 源类型
+     * @param <Target> 目标类型
+     */
+    public static <TSource, Target> List<Target> mapList(Collection<TSource> sourceList, Class<Target> targetClass, Consumer<Target> consumer) {
+
+        if (sourceList == null) {
+            return new ArrayList<Target>();
+        }
+
+        ArrayList<Target> targets = new ArrayList<>(sourceList.size());
+
+        sourceList.forEach(p -> {
+            Target item = map(p, targetClass);
+
+            if (consumer != null) {
+                consumer.accept(item);
+            }
+            targets.add(item);
+        });
+
+        return targets;
+    }
+
+    /**
+     * 将集合中的元素抓换为指定类型,并对转换后的元素处理
+     * @param sourceList 源集合
+     * @param targetClass 转换目标类型
+     * @param consumer 对转换后元素处理
+     * @return 转换后的集合
+     * @param <TSource> 源类型
+     * @param <Target> 目标类型
+     */
+    public static <TSource, Target> List<Target> mapList(Collection<TSource> sourceList, Class<Target> targetClass, BiConsumer<TSource, Target> consumer) {
+
+        if (sourceList == null) {
+            return new ArrayList<Target>();
+        }
+
+        ArrayList<Target> targets = new ArrayList<>(sourceList.size());
+
+        sourceList.forEach(p -> {
+            Target map = ModelMapperUtil.map(p, targetClass);
+            if (consumer != null) {
+                consumer.accept(p, map);
+            }
+            targets.add(map);
+        });
+        return targets;
+    }
+
+}
+

+ 38 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/MyTreeUtil.java

@@ -0,0 +1,38 @@
+package edu.travel.utils.tree;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 树形菜单构建工具
+ *
+ */
+public class MyTreeUtil {
+    /**
+     * 构建树形工具
+     *
+     * @param resource 数据源
+     * @param <T>      node
+     * @return 树形
+     */
+    public static <T extends TreeNode> List<T> buildTree(List<T> resource) {
+        Map<String, List<TreeNode>> groups = ifNullDefault(resource)
+                .stream()
+                .collect(Collectors.groupingBy(TreeNode::getParentId, LinkedHashMap::new, Collectors.toList()));
+        return resource.stream()
+                .filter(Objects::nonNull)
+                .peek(node -> node.setChildren(groups.get(node.getId())))
+                .filter(TreeNode::getRootNode)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 防止空指针异常处理
+     *
+     * @param list 集合数据
+     * @return 如果为空返
+     */
+    private static <L> List<L> ifNullDefault(List<L> list) {
+        return Optional.ofNullable(list).orElseGet(Collections::emptyList);
+    }
+}

+ 53 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/utils/tree/TreeNode.java

@@ -0,0 +1,53 @@
+package edu.travel.utils.tree;
+
+import lombok.Getter;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 树结点
+ *
+ */
+public abstract class TreeNode {
+    /**
+     * 获取当前节点id
+     *
+     * @return 节点id
+     */
+    public abstract String getId();
+
+    /**
+     * 获取父级节点id
+     *
+     * @return 父级节点id
+     */
+    public abstract String getParentId();
+
+    /**
+     * 是否根节点
+     */
+    @Getter
+    private Boolean rootNode;
+
+    /**
+     * 是否叶子节点
+     **/
+    @Getter
+    private Boolean leafNode;
+
+    /**
+     * 子节点数据
+     **/
+    @Getter
+    private List<TreeNode> children;
+
+    /**
+     * 设置子节点数据,设置为protected禁止外部调用
+     **/
+    protected void setChildren(List<TreeNode> children) {
+        this.children = children;
+        this.rootNode = Objects.equals(getParentId(), "0");
+        this.leafNode = children == null || children.isEmpty();
+    }
+}

+ 16 - 0
babyApplication-common/babyApplication-common-core/src/main/java/edu/travel/web/MapToJsonStringSerializer.java

@@ -0,0 +1,16 @@
+package edu.travel.web;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class MapToJsonStringSerializer extends JsonSerializer<Map<?, ?>> {
+    @Override
+    public void serialize(Map<?, ?> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeObject(new ObjectMapper().writeValueAsString(value));
+    }
+}

+ 67 - 0
babyApplication-common/babyApplication-common-datasource/pom.xml

@@ -0,0 +1,67 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-datasource</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-datasource</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-resp</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.jsqlparser</groupId>
+            <artifactId>jsqlparser</artifactId>
+            <version>4.5</version>  <!-- 检查最新版本 -->
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 25 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/annotation/LinkConst.java

@@ -0,0 +1,25 @@
+package edu.travel.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author 畅
+ *  常量字典注解
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@Inherited
+public @interface LinkConst {
+    /**
+     * 字典类
+     * @return
+     */
+    Class clazz() ;
+
+    /**
+     * 需要字典翻译字段
+     * @return
+     */
+    String fieldName();
+}

+ 31 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/annotation/LinkMany.java

@@ -0,0 +1,31 @@
+package edu.travel.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author 畅
+ * 一对多注解
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@Inherited
+public @interface LinkMany {
+    /**
+     * 主表字段
+     * @return
+     */
+    String linkField() ;
+
+    /**
+     * 使用哪个mapper来关联查询
+     * @return
+     */
+    Class linkMapper();
+
+    /**
+     * 从表关联字段
+     * @return
+     */
+    String linkPrimaryField();
+}

+ 30 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/annotation/LinkOne.java

@@ -0,0 +1,30 @@
+package edu.travel.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@Inherited
+public @interface LinkOne {
+    /**
+     *  主表关联字段
+     * @return
+     */
+    String linkField();
+
+    /**
+     * 使用哪个mapper来关联查询
+     * @return
+     */
+    Class linkMapper();
+
+    /**
+     * 从表关联字段
+     * @return
+     */
+    String linkPrimaryField();
+}

+ 21 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/DruidConfig.java

@@ -0,0 +1,21 @@
+package edu.travel.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+/**
+ * @author 畅
+ * druid进行
+ */
+@Configuration
+public class DruidConfig {
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource")
+    public DataSource druidDataSource() {
+        return new DruidDataSource();
+    }
+}

+ 66 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/FieldMetaObjectHandler.java

@@ -0,0 +1,66 @@
+package edu.travel.config;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Date;
+
+/**
+ * @author 畅
+ *  通用字段处理
+ */
+@Component
+public class FieldMetaObjectHandler implements MetaObjectHandler {
+    private final static String UPDATE_USER_ID = "updateUserId";
+    private final static String UPDATE_TIME = "updateTime";
+    private final static String CREATE_USER_ID = "createUserId";
+    private final static String CREATE_TIME = "createTime";
+    private final static String PROJECT = "project";
+    private final static String DELETE_FLAG = "deleteFlag";
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
+//        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+//        Object principal = authentication.getPrincipal();
+//        if (principal == null) {
+//            return;
+//        }
+//        Long userId = null;
+//
+//        if (!(principal instanceof String && "anonymousUser".equals(principal))) {
+//            //走登录用户
+//            String jsonString = JSON.toJSONString(principal);
+//            JSONObject jsonObject = JSON.parseObject(jsonString);
+//            userId = jsonObject.getLong("id");
+//        }
+
+        if (metaObject.hasSetter(CREATE_USER_ID)) {
+//            this.strictInsertFill(metaObject, CREATE_USER_ID, String.class, userId != null ? userId.toString() : "");
+        }
+        if (metaObject.hasSetter(CREATE_TIME)) {
+            this.strictInsertFill(metaObject, CREATE_TIME, Date.class, new Date());
+        }
+        if (metaObject.hasSetter(PROJECT)){
+            this.strictInsertFill(metaObject, PROJECT, String.class, request.getHeader("project"));
+        }
+        if (metaObject.hasSetter(DELETE_FLAG)) {
+            this.strictInsertFill(metaObject, DELETE_FLAG, Integer.class, 0);
+        }
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+//        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+//        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(principal));
+        if (metaObject.hasSetter(UPDATE_USER_ID)) {
+//            this.strictInsertFill(metaObject, UPDATE_USER_ID, String.class,  jsonObject.getLong("id").toString());
+        }
+        if (metaObject.hasSetter(UPDATE_TIME)) {
+            this.strictInsertFill(metaObject, UPDATE_TIME, Date.class, new Date());
+        }
+    }
+}

+ 20 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/MybatisPlusConfig.java

@@ -0,0 +1,20 @@
+package edu.travel.config;
+
+import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author 畅
+ * mybatis-plus一些配置问题
+ */
+@Configuration
+public class MybatisPlusConfig {
+
+
+    @Bean
+    public ConfigurationCustomizer configurationCustomizer() {
+        return configuration -> configuration.setUseDeprecatedExecutor(false);
+    }
+
+}

+ 28 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/MysqlConfig.java

@@ -0,0 +1,28 @@
+package edu.travel.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.mysql.cj.jdbc.Driver;
+import edu.travel.datasource.ProjectInterceptor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 处理mysql兼容问题
+ * @Author 处理mysql兼容问题
+ */
+@Configuration
+@ConditionalOnClass(Driver.class)
+public class MysqlConfig {
+    @Bean
+    @ConditionalOnClass(Driver.class)
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new ProjectInterceptor());
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        return interceptor;
+    }
+}

+ 26 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/config/PGConfig.java

@@ -0,0 +1,26 @@
+package edu.travel.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import edu.travel.datasource.ProjectInterceptor;
+import org.postgresql.Driver;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 处理pgsql 兼容问题
+ * @Author 畅
+ */
+@Configuration
+@ConditionalOnClass(Driver.class)
+public class PGConfig {
+    @Bean
+    public MybatisPlusInterceptor plusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new ProjectInterceptor());
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
+        return interceptor;
+    }
+}

+ 122 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/datasource/ProjectInterceptor.java

@@ -0,0 +1,122 @@
+package edu.travel.datasource;
+
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.StringValue;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.schema.Column;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.statement.select.PlainSelect;
+import net.sf.jsqlparser.statement.select.Select;
+import net.sf.jsqlparser.statement.select.SelectBody;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.sql.SQLException;
+
+/**
+ * @anthor 畅
+ *  处理基础架构中统一带上 project 字段
+ */
+public class ProjectInterceptor implements InnerInterceptor {
+    Logger logger = LoggerFactory.getLogger(ProjectInterceptor.class);
+    private String convertDeleteToUpdate(String originalSql) {
+        // 示例:将DELETE FROM table WHERE ... 转为 UPDATE table SET deleted=1 WHERE ...
+        String newUPDATE = originalSql.replaceFirst("DELETE FROM", "UPDATE");
+        if (newUPDATE.contains("where")||newUPDATE.contains("WHERE")) {
+           newUPDATE =  newUPDATE.replace("WHERE", "SET delete_flag=1 WHERE ");
+        }else {
+            newUPDATE =  "";
+        }
+        return newUPDATE;
+
+    }
+
+//    @Override
+//    public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {
+//        BoundSql boundSql = ms.getBoundSql(parameter);
+//        if (ms.getSqlCommandType().equals(SqlCommandType.DELETE)) {
+//
+////            // 转换DELETE为UPDATE,此处需复杂处理,示例简化
+////            // 实际需解析原始SQL并替换,此处仅为思路
+////            String newSql = convertDeleteToUpdate(boundSql.getSql());
+////            // 反射修改BoundSql中的SQL
+////            Class<? extends BoundSql> aClass = boundSql.getClass();
+////            Field declaredField = null;
+////            try {
+////                declaredField = aClass.getDeclaredField("sql");
+////                declaredField.setAccessible(true);
+////                declaredField.set(boundSql,newSql);
+////            } catch (Exception e) {
+////                throw new RuntimeException(e);
+////            }
+//
+//        }
+//    }
+
+    @Override
+    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
+        String project = request.getHeader("project");
+        if (StringUtils.isNotBlank(project)) {
+            String originSql = boundSql.getSql();
+            if (originSql.contains("join") || originSql.contains("JOIN")) {
+                return;
+            }
+            logger.debug("origin sql: " + originSql);
+            //获取 Statement 执行sql的对象
+            Statement statement = null;
+            try {
+                statement = CCJSqlParserUtil.parse(originSql);
+            } catch (JSQLParserException e) {
+                throw new RuntimeException(e);
+            }
+            Select select = (Select) statement;
+
+            SelectBody selectBody = select.getSelectBody();
+            if (selectBody == null) {
+                return;
+            }
+            String targetSql = "";
+            if (selectBody instanceof PlainSelect) {
+                PlainSelect plainSelect = (PlainSelect) selectBody;
+                Expression where = plainSelect.getWhere();
+                EqualsTo projectEq = new EqualsTo();
+                projectEq.setLeftExpression(new Column("project"));
+                projectEq.setRightExpression(new StringValue(project));
+                String plainSelectString = plainSelect.toString();
+                if (!plainSelectString.contains("project = ")) {
+                    if (plainSelectString.contains("where") || plainSelectString.contains("WHERE")) {
+                        AndExpression andExpression = new AndExpression(projectEq,where);
+                        plainSelect.setWhere(andExpression);
+                    }else {
+                        plainSelect.setWhere(projectEq);
+                    }
+
+                    targetSql = plainSelect.toString();
+                }else {
+                    targetSql = plainSelect.toString();
+                }
+
+            }
+            // 修改完成的sql 再设置回去
+            PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
+            System.out.println(targetSql);
+            mpBoundSql.sql(targetSql);
+
+        }
+    }
+}

+ 4 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/interfaces/InsertGroups.java

@@ -0,0 +1,4 @@
+package edu.travel.interfaces;
+
+public interface InsertGroups {
+}

+ 4 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/interfaces/UpdateGroups.java

@@ -0,0 +1,4 @@
+package edu.travel.interfaces;
+
+public interface UpdateGroups {
+}

+ 208 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/service/SysServiceImpl.java

@@ -0,0 +1,208 @@
+package edu.travel.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import edu.travel.annotation.LinkConst;
+import edu.travel.annotation.LinkMany;
+import edu.travel.annotation.LinkOne;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 扩展mbp ServiceImpl
+ * @param <M>
+ * @param <T>
+ * @author 忠畅
+ */
+public class SysServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M,T> implements IService<T> {
+    private ApplicationContext applicationContext;
+    @Autowired
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
+    /**
+     * 一对一字典查询处理
+     * @param queryWrapper
+     * @return
+     */
+    public T getOneLink(Wrapper<T> queryWrapper) {
+        T one = super.getOne(queryWrapper);
+        if (one == null) {
+            return null;
+        }
+        doOneLink(one);
+        return one;
+    }
+
+    /**
+     * 一对多字典查询处理
+     * @param queryWrapper
+     * @return
+     */
+    public List<T> getListLink(Wrapper<T> queryWrapper) {
+        List<T> list = super.list(queryWrapper);
+        if (list == null || list.isEmpty()) {
+            return list;
+        }
+        doManyLink(list);
+        return list;
+    }
+
+    /**
+     * 分页查询处理
+     * @param queryWrapper
+     * @param page
+     * @return
+     */
+    public IPage<T> getPageLink(Wrapper<T> queryWrapper,IPage<T> page) {
+        IPage<T> iPage = super.page(page, queryWrapper);
+        if (iPage == null ) {
+            return new Page();
+        }
+        List<T> records = iPage.getRecords();
+        doManyLink(records);
+        iPage.setRecords(records);
+        return iPage;
+    }
+
+    /**
+     * 多对多查询字典处理
+     * @param list
+     */
+    private void doManyLink(List<T> list) {
+        for (T many : list) {
+            doOneLink(many);
+        }
+    }
+
+    /**
+     * 单个字典处理
+     * @param one
+     */
+    private void doOneLink(T one) {
+        Class<?> clazz = one.getClass();
+        Field[] declaredFields = clazz.getDeclaredFields();
+        for (Field field : declaredFields) {
+            field.setAccessible(true);
+            doLinkOneToOne(one, field);
+            doLinkOneToMany(one,field);
+            doConst(one,field);
+        }
+    }
+
+    /**
+     * 常量字典处理
+     * @param one
+     * @param field
+     */
+    private void doConst(T one,Field field) {
+        try {
+            LinkConst linkConst = field.getAnnotation(LinkConst.class);
+            if (linkConst != null) {
+                Class clazz = linkConst.clazz();
+                Object object = clazz.newInstance();
+                Method getValueMethod = clazz.getDeclaredMethod("getValue", Integer.class);
+                if (getValueMethod == null) {
+                    throw new RuntimeException("没有获取到getValue方法");
+                }
+                getValueMethod.setAccessible(true);
+                Field declaredField = one.getClass().getDeclaredField(linkConst.fieldName());
+                declaredField.setAccessible(true);
+                Object getValue = getValueMethod.invoke(object, Integer.valueOf(declaredField.get(one).toString()));
+                if (getValue == null) {
+                    throw new RuntimeException("常量字典没有这个类");
+                }
+                ConcurrentHashMap objectObjectHashMap = new ConcurrentHashMap();
+                objectObjectHashMap.put("key",Integer.valueOf(declaredField.get(one).toString()));
+                objectObjectHashMap.put("value", getValue);
+                field.set(one, objectObjectHashMap);
+            }
+        }catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    /**
+     * 处理一对多字典情况
+     * @param one
+     * @param field
+     */
+    private void doLinkOneToMany(T one, Field field) {
+        try {
+            LinkMany linkMany = field.getAnnotation(LinkMany.class);
+            if (linkMany != null) {
+                String linkField = linkMany.linkField();
+                Field declaredField = one.getClass().getDeclaredField(linkField);
+                declaredField.setAccessible(true);
+                Object object = declaredField.get(one);
+                Class aClass = linkMany.linkMapper();
+                if (object != null) {
+                    BaseMapper applicationContextBean = (BaseMapper) this.applicationContext.getBean(aClass);
+                    if (applicationContextBean != null) {
+                        List<Map> oneToManyResult = applicationContextBean.selectMaps(new QueryWrapper<T>().eq(linkMany.linkPrimaryField(), object));
+                        if (oneToManyResult != null && !oneToManyResult.isEmpty()) {
+                            field.set(one,oneToManyResult);
+                        }
+                    }   else {
+                        return;
+                    }
+                }else {
+                    return;
+                }
+            }
+        }catch (Exception e) {
+            e.printStackTrace();
+            return;
+        }
+
+    }
+
+    /**
+     * 处理一对一字典情况
+     * @param one
+     * @param field
+     */
+    private void doLinkOneToOne(T one,Field field) {
+        try {
+            LinkOne linkOne = field.getAnnotation(LinkOne.class);
+            if (linkOne != null) {
+                String linkField = linkOne.linkField();
+                Field declaredField = one.getClass().getDeclaredField(linkField);
+                declaredField.setAccessible(true);
+                Object object = declaredField.get(one);
+                Class aClass = linkOne.linkMapper();
+                if (object != null) {
+                    BaseMapper applicationContextBean = (BaseMapper) this.applicationContext.getBean(aClass);
+                    if (applicationContextBean != null) {
+                        List<Map> list = applicationContextBean.selectMaps(new QueryWrapper<T>().eq(linkOne.linkPrimaryField(), object));
+                        if (list != null && !list.isEmpty()) {
+                            Object oneToOneResult = list.get(0);
+                            field.set(one,oneToOneResult);
+                        }
+                    }   else {
+                        return;
+                    }
+                } else {
+                    return;
+                }
+            }
+        }catch (Exception e) {
+            e.printStackTrace();
+            return;
+        }
+
+    }
+}

+ 100 - 0
babyApplication-common/babyApplication-common-datasource/src/main/java/edu/travel/web/BaseController.java

@@ -0,0 +1,100 @@
+package edu.travel.web;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import edu.travel.resp.BaseResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.List;
+
+public class BaseController<T> {
+    Logger logger = LoggerFactory.getLogger(BaseController.class);
+    @Autowired
+    private IService<T> service;
+//    @GetMapping("/download")
+//    public void download(T clazz,HttpServletResponse response) throws IOException {
+//        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+//        response.setCharacterEncoding("utf-8");
+//        String fileName = URLEncoder.encode("导出数据.xlsx", "UTF-8").replaceAll("\\+", "%20");
+//        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
+//        List<T> list = service.list();
+//        EasyExcel.write(response.getOutputStream(), clazz.getClass())
+//                .sheet("数据")
+//                .doWrite(list);
+//    }
+//    @PostMapping("/upload/excel")
+//    public RPCBaseResponse uploadExcel(@RequestBody T clazz ,@RequestPart("file") MultipartFile file) throws IOException {
+//        EasyExcel.read(file.getInputStream(),clazz.getClass(),new ReadListener<T>(){
+//
+//            @Override
+//            public void invoke(T t, AnalysisContext analysisContext) {
+//                saveTarget(t);
+//            }
+//
+//            @Override
+//            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+//                logger.debug("读取完成");
+//            }
+//        })
+//                .sheet()
+//                .doRead();
+//        return RPCBaseResponse.success();
+//    }
+
+    @GetMapping("/getById")
+    public BaseResponse<T> getId(String id) {
+        T byId = service.getById(id);
+        return new BaseResponse(HttpStatus.OK.value(), HttpStatus.OK.getReasonPhrase(), byId);
+    }
+    @PostMapping("/updateById")
+    @Transactional
+    public BaseResponse<T> updateTargetById(@RequestBody T entity) {
+        boolean update = service.updateById(entity);
+        if (update) {
+            return new BaseResponse<>(200,"success",entity);
+        }
+        return new BaseResponse(500,"error",entity);
+    }
+    @PostMapping("/save")
+    @Transactional
+    public BaseResponse<T> saveTarget(@RequestBody T entity) {
+        boolean save = service.save(entity);
+        if (save) {
+            return new BaseResponse<>(200,"success",entity);
+        }
+        return new BaseResponse<>(500,"error",entity);
+    }
+    @PostMapping("/deleteById")
+    @Transactional
+    public BaseResponse<T> deleteTargetById(@RequestBody List<String> ids) {
+        if (ids == null || ids.isEmpty()) {
+            return new BaseResponse<>(404,"error,not found delete data",null);
+        }
+        boolean byIds = service.removeByIds(ids);
+        if (byIds) {
+            return new BaseResponse<>(200,"success",null);
+        }
+        return new BaseResponse<>(500,"error, delete data error",null);
+    }
+    @GetMapping("/list")
+    public BaseResponse<List<T>> listAll() {
+        List<T> list = service.list();
+        if (list.isEmpty()) {
+            return new BaseResponse<>(404,"error,not found delete data",null);
+        }
+        return new BaseResponse<>(200,"success",list);
+    }
+
+
+
+}

+ 26 - 0
babyApplication-common/babyApplication-common-resp/pom.xml

@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-resp</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-resp</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 57 - 0
babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/emun/ResponseCode.java

@@ -0,0 +1,57 @@
+package edu.travel.emun;
+
+/**
+ * ResponseCode 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/11
+ */
+public enum ResponseCode implements StatusCode {
+    /**
+     * 成功
+     */
+    SUCCESS(200, "操作成功"),
+    /**
+     * 失败
+     */
+    ERROR(500, "服务端错误。"),
+    /**
+     * 业务逻辑错误
+     */
+    LOGIC_ERROR(400, "业务逻辑错误"),
+    /**
+     * 需要登录
+     */
+    LOGIN_ERROR(401, "账号登录过期,请重新登录!"),
+
+    /**
+     * 需要登录
+     */
+    NO_PERMISSION(400, "没有接口访问权限");
+
+
+    private final Integer code;
+    private String message;
+
+    ResponseCode(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    @Override
+    public Integer getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public ResponseCode setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+}

+ 21 - 0
babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/emun/StatusCode.java

@@ -0,0 +1,21 @@
+package edu.travel.emun;
+
+/**
+ * StatusCode 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/2/11
+ */
+public interface StatusCode {
+    /**
+     * 获取code
+     */
+    Integer getCode();
+
+    /**
+     * 获取信息
+     */
+    String getMessage();
+}

+ 20 - 0
babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/resp/BaseResponse.java

@@ -0,0 +1,20 @@
+package edu.travel.resp;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class BaseResponse<T> implements Serializable {
+
+    private Integer code;
+
+    private String msg;
+
+    private T data;
+
+}

+ 33 - 0
babyApplication-common/babyApplication-common-resp/src/main/java/edu/travel/resp/PageResponse.java

@@ -0,0 +1,33 @@
+package edu.travel.resp;
+
+import lombok.Data;
+
+@Data
+public class PageResponse extends BaseResponse {
+    private int total;
+    private int size;
+
+    private PageResponse() {
+    }
+    private PageResponse(int code, String msg,Object data) {
+        super(code, msg, data);
+    }
+    private PageResponse(int code, String msg) {
+        super(code, msg, null);
+    }
+    private PageResponse(int code, String msg,Object data,int total,int size) {
+        super(code, msg, data);
+        this.total = total;
+        this.size = size;
+    }
+
+    public static <R> BaseResponse<R> out(Integer code,String msg,R data,int total, int size){
+        return new PageResponse(code,msg,data,total,size);
+    }
+    public static <R> BaseResponse<R> out(Integer code,String msg,R data){
+        return new PageResponse(code,msg,data);
+    }
+    public static  BaseResponse out(Integer code,String msg){
+        return new PageResponse(code,msg);
+    }
+}

+ 57 - 0
babyApplication-common/babyApplication-common-upload/pom.xml

@@ -0,0 +1,57 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-upload</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-upload</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.huaweicloud</groupId>
+            <artifactId>esdk-obs-java</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 40 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/cos/TencentCosClient.java

@@ -0,0 +1,40 @@
+package edu.travel.upload.cos;
+
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.region.Region;
+import edu.travel.upload.cos.property.CosProperties;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(COSClient.class)
+public class TencentCosClient {
+    @Autowired
+    private CosProperties cosProperties;
+    private static PoolingHttpClientConnectionManager connectionManager;
+    public static void initializeConnectionManager() {
+        // 在这里初始化连接池
+        connectionManager = createConnectionManager();
+    }
+
+    private static PoolingHttpClientConnectionManager createConnectionManager() {
+        // 创建并配置连接池
+        return new PoolingHttpClientConnectionManager();
+    }
+
+    @Bean
+    public COSClient getCosClient() {
+        initializeConnectionManager();
+        COSCredentials cred = new BasicCOSCredentials(cosProperties.getAccessKey(), cosProperties.getSecretKey());
+        ClientConfig clientConfig = new ClientConfig(new Region(cosProperties.getRegionName()));
+        COSClient cosClient = new COSClient(cred, clientConfig);
+        return cosClient;
+    }
+}

+ 45 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/cos/TencentCosUtils.java

@@ -0,0 +1,45 @@
+package edu.travel.upload.cos;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.model.PutObjectRequest;
+import com.qcloud.cos.transfer.TransferManager;
+import com.qcloud.cos.transfer.Upload;
+import edu.travel.upload.cos.property.CosProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+
+@Configuration
+@ConditionalOnClass(COSClient.class)
+public class TencentCosUtils {
+    @Autowired
+    private CosProperties cosProperties;
+    @Autowired
+    private COSClient cosClient;
+
+    /**
+     * 上传文件到COS
+     *
+     * @param inputStream 流
+     * @param key 文件名称
+     * @return
+     */
+    public  String uploadFileToCOS(InputStream inputStream, String key) throws InterruptedException, IOException, NoSuchAlgorithmException, KeyStoreException {
+        // 每次上传前重新初始化连接池
+        PutObjectRequest putObjectRequest = new PutObjectRequest(cosProperties.getBucketName(), key, inputStream, null);
+        TransferManager transferManager = new TransferManager(cosClient);
+        try {
+            Upload upload = transferManager.upload(putObjectRequest);
+            upload.waitForCompletion(); // 等待上传完成
+            String filePath = cosProperties.getBaseUrl() + "/" + key;
+            return filePath;
+        } finally {
+//            cosClient.shutdown(); // 关闭 COS 客户端
+        }
+    }
+}

+ 27 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/cos/property/CosProperties.java

@@ -0,0 +1,27 @@
+package edu.travel.upload.cos.property;
+
+
+import com.qcloud.cos.COSClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "tencent.cos")
+@ConditionalOnClass(COSClient.class)
+public class CosProperties {
+   private String baseUrl;
+   private String  accessKey;
+   private String  secretKey;
+   private String  regionName;
+   private String  bucketName;
+   private String  folderPrefix;
+}

+ 23 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioClient.java

@@ -0,0 +1,23 @@
+package edu.travel.upload.minio;
+
+import edu.travel.upload.minio.property.MinioProperties;
+import io.minio.MinioClient;
+import io.minio.errors.InvalidEndpointException;
+import io.minio.errors.InvalidPortException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(MinioClient.class)
+public class CloudMinioClient {
+    @Autowired
+    public MinioProperties minioProperties;
+
+    @Bean
+    public MinioClient minioClient() throws InvalidPortException, InvalidEndpointException {
+        MinioClient minioClient = new MinioClient(minioProperties.getHost(), minioProperties.getAccessKey(), minioProperties.getSecretKey());
+        return minioClient;
+    }
+}

+ 228 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/minio/CloudMinioUtils.java

@@ -0,0 +1,228 @@
+package edu.travel.upload.minio;
+
+import edu.travel.upload.minio.property.MinioProperties;
+import io.minio.MinioClient;
+import io.minio.ObjectStat;
+import io.minio.PutObjectOptions;
+import io.minio.Result;
+import io.minio.messages.Bucket;
+import io.minio.messages.Item;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.util.UriUtils;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+@Configuration
+@ConditionalOnClass(MinioClient.class)
+public class CloudMinioUtils {
+    @Autowired
+    private MinioClient minioClient;
+    @Autowired
+    private MinioProperties minioProperties;
+    /**
+     * 上传
+     */
+    public String putObject(MultipartFile multipartFile) throws Exception {
+        // bucket 不存在,创建
+        if (!minioClient.bucketExists(minioProperties.getBucket())) {
+            minioClient.makeBucket(minioProperties.getBucket());
+        }
+        try (InputStream inputStream = multipartFile.getInputStream()) {
+            // 上传文件的名称
+            String fileName = multipartFile.getOriginalFilename();
+            // PutObjectOptions,上传配置(文件大小,内存中文件分片大小)
+            PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);
+            // 文件的ContentType
+            putObjectOptions.setContentType(multipartFile.getContentType());
+            minioClient.putObject(minioProperties.getBucket(), fileName, inputStream, putObjectOptions);
+            // 返回访问路径
+            return minioProperties.getUrl() + UriUtils.encode(fileName, StandardCharsets.UTF_8);
+        }
+    }
+    /**
+     * 文件下载
+     */
+    public void download(String fileName, HttpServletResponse response){
+        // 从链接中得到文件名
+        InputStream inputStream;
+        try {
+
+            ObjectStat stat = minioClient.statObject(minioProperties.getBucket(), fileName);
+            inputStream = minioClient.getObject(minioProperties.getBucket(), fileName);
+            response.setContentType(stat.contentType());
+            response.setCharacterEncoding("UTF-8");
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = inputStream.read(buffer)) > 0) {
+                response.getOutputStream().write(buffer, 0, length);
+            }
+            inputStream.close();
+        } catch (Exception e){
+            e.printStackTrace();
+            System.out.println("有异常:" + e);
+        }
+    }
+    /**
+     * 列出所有存储桶名称
+     *
+     * @return
+     * @throws Exception
+     */
+    public List<String> listBucketNames()
+            throws Exception {
+        List<Bucket> bucketList = listBuckets();
+        List<String> bucketListName = new ArrayList<>();
+        for (Bucket bucket : bucketList) {
+            bucketListName.add(bucket.name());
+        }
+        return bucketListName;
+    }
+
+    /**
+     * 查看所有桶
+     *
+     * @return
+     * @throws Exception
+     */
+    public List<Bucket> listBuckets()
+            throws Exception {
+        return minioClient.listBuckets();
+    }
+    /**
+     * 检查存储桶是否存在
+     *
+     * @param bucketName
+     * @return
+     * @throws Exception
+     */
+    public boolean bucketExists(String bucketName) throws Exception {
+        boolean flag = minioClient.bucketExists(bucketName);
+        if (flag) {
+            return true;
+        }
+        return false;
+    }
+    /**
+     * 创建存储桶
+     *
+     * @param bucketName
+     * @return
+     * @throws Exception
+     */
+    public boolean makeBucket(String bucketName)
+            throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (!flag) {
+            minioClient.makeBucket(bucketName);
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * 删除桶
+     *
+     * @param bucketName
+     * @return
+     * @throws Exception
+     */
+    public boolean removeBucket(String bucketName)
+            throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            Iterable<Result<Item>> myObjects = listObjects(bucketName);
+            for (Result<Item> result : myObjects) {
+                Item item = result.get();
+                // 有对象文件,则删除失败
+                if (item.size() > 0) {
+                    return false;
+                }
+            }
+            // 删除存储桶,注意,只有存储桶为空时才能删除成功。
+            minioClient.removeBucket(bucketName);
+            flag = bucketExists(bucketName);
+            if (!flag) {
+                return true;
+            }
+        }
+        return false;
+    }
+    /**
+     * 列出存储桶中的所有对象
+     *
+     * @param bucketName 存储桶名称
+     * @return
+     * @throws Exception
+     */
+    public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            return minioClient.listObjects(bucketName);
+        }
+        return null;
+    }
+    /**
+     * 列出存储桶中的所有对象名称
+     *
+     * @param bucketName 存储桶名称
+     * @return
+     * @throws Exception
+     */
+    public List<String> listObjectNames(String bucketName) throws Exception {
+        List<String> listObjectNames = new ArrayList<>();
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            Iterable<Result<Item>> myObjects = listObjects(bucketName);
+            for (Result<Item> result : myObjects) {
+                Item item = result.get();
+                listObjectNames.add(item.objectName());
+            }
+        }
+        return listObjectNames;
+    }
+    /**
+     * 删除一个对象
+     *
+     * @param bucketName 存储桶名称
+     * @param objectName 存储桶里的对象名称
+     * @throws Exception
+     */
+    public boolean removeObject(String bucketName, String objectName) throws Exception {
+        boolean flag = bucketExists(bucketName);
+        if (flag) {
+            List<String> objectList = listObjectNames(bucketName);
+            for (String s : objectList) {
+                if(s.equals(objectName)){
+                    minioClient.removeObject(bucketName, objectName);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    /**
+     * 文件访问路径
+     *
+     * @param bucketName 存储桶名称
+     * @param objectName 存储桶里的对象名称
+     * @return
+     * @throws Exception
+     */
+    public String getObjectUrl(String bucketName, String objectName) throws Exception {
+        boolean flag = bucketExists(bucketName);
+        String url = "";
+        if (flag) {
+            url = minioClient.getObjectUrl(bucketName, objectName);
+        }
+        return url;
+    }
+
+}

+ 26 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/minio/property/MinioProperties.java

@@ -0,0 +1,26 @@
+package edu.travel.upload.minio.property;
+
+import io.minio.MinioClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@ConditionalOnClass(MinioClient.class)
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "minio")
+public class MinioProperties {
+    private String bucket;
+    private String host;
+    private String url;
+    private String accessKey;
+    private String secretKey;
+
+}

+ 20 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSClient.java

@@ -0,0 +1,20 @@
+package edu.travel.upload.obs;
+
+import com.obs.services.ObsClient;
+import edu.travel.upload.obs.property.ObsProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConditionalOnClass(ObsClient.class)
+public class HuaweiOBSClient {
+    @Autowired
+    private ObsProperties obsProperties;
+    @Bean
+    public ObsClient obsClient() {
+      ObsClient  obsClient = new ObsClient(obsProperties.getAccessKey(), obsProperties.getSecretAccessKey(),obsProperties.getEndpoint());
+      return obsClient;
+    }
+}

+ 106 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/obs/HuaweiOBSUtils.java

@@ -0,0 +1,106 @@
+package edu.travel.upload.obs;
+
+
+import com.aliyun.oss.ServiceException;
+import com.obs.services.ObsClient;
+import com.obs.services.exception.ObsException;
+import com.obs.services.model.HttpMethodEnum;
+import com.obs.services.model.ObsObject;
+import com.obs.services.model.TemporarySignatureRequest;
+import com.obs.services.model.TemporarySignatureResponse;
+import edu.travel.upload.obs.property.ObsProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.Optional;
+
+@Component
+@ConditionalOnClass(ObsClient.class)
+public class HuaweiOBSUtils {
+    Logger log = LoggerFactory.getLogger(HuaweiOBSUtils.class);
+    @Autowired
+    private ObsClient obsClient;
+    @Autowired
+    private ObsProperties obsProperties;
+   
+
+    // 计算 MD5 值的方法
+    private static byte[] calculateMd5(byte[] data) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            return md.digest(data);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("MD5 algorithm not found.", e);
+        }
+    }
+
+    // 将字节数组转换为 Base64 编码的字符串
+    private static String toBase64String(byte[] bytes) {
+        return Base64.getEncoder().encodeToString(bytes);
+    }
+
+    //该方法是用于检查bucket 内是否有指定文件,内部调用了 obs 的获取文件方法
+    public Boolean checkExist(String fileName,String bucketName) {
+        ObsObject object = null;
+        InputStream inputStream = null;
+        try {
+            object = obsClient.getObject(bucketName, fileName);
+            inputStream = object.getObjectContent();
+            if (inputStream != null) {
+                return true;
+            }
+        } catch (Exception e) {
+            log.error("请求异常:{}", fileName, e);
+            return false;
+        } finally {
+            // 确保关闭 InputStream
+            try {
+                if (inputStream != null) {
+                    inputStream.close();
+                }
+            } catch (IOException e) {
+                log.error("关闭 InputStream 异常", e);
+            }
+        }
+        return false;
+    }
+
+
+    //该方法是用于获取指定时间内的文件下载链接
+    public String getPicViewUrlByInternal(String fileName) {
+        Boolean aBoolean = checkExist(fileName,obsProperties.getBucketName());
+        if (!aBoolean) {
+            return null;
+        }
+        // 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
+        String url = generatePresignedUrl(obsProperties.getExpiration(), fileName,obsProperties.getBucketName());
+        return url;
+    }
+
+    private  String generatePresignedUrl(Long expire,String fileName,String bucketName) {
+        TemporarySignatureResponse response = null;
+        try {
+            // URL有效期,3600秒
+            //long expireSeconds = 3600L;
+            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expire);
+            request.setBucketName(bucketName);
+            request.setObjectKey(fileName);
+            response = obsClient.createTemporarySignature(request);
+        } catch (ObsException e) {
+            log.error("get obs failed :{}", e.getMessage());
+            throw new ServiceException(e.getMessage());
+        }
+        return Optional.ofNullable(response)
+                .map(TemporarySignatureResponse::getSignedUrl)
+                .orElse(null);
+    }
+
+}

+ 26 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/obs/property/ObsProperties.java

@@ -0,0 +1,26 @@
+package edu.travel.upload.obs.property;
+
+import com.obs.services.ObsClient;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "huawei.obs")
+@ConditionalOnClass(ObsClient.class)
+public class ObsProperties {
+ 
+    private String endpoint;
+    private String accessKey;
+    private String secretAccessKey;
+    private String bucketName;
+    private Long expiration;
+}

+ 23 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSClient.java

@@ -0,0 +1,23 @@
+package edu.travel.upload.oss;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import edu.travel.upload.oss.property.CloudOssProperty;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(OSS.class)
+public class AlibabaOSSClient {
+    @Autowired
+    private CloudOssProperty cloudOssProperty;
+
+    @Bean
+    public OSS ossClient() {
+        OSS ossClient = new OSSClientBuilder().build(cloudOssProperty.getEndpoint(), cloudOssProperty.getAccessKeyId(), cloudOssProperty.getAccessKeySecret());
+        return ossClient;
+    }
+
+}

+ 35 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/oss/AlibabaOSSUtils.java

@@ -0,0 +1,35 @@
+package edu.travel.upload.oss;
+
+import com.aliyun.oss.OSS;
+import edu.travel.upload.oss.property.CloudOssProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.stereotype.Component;
+
+import java.io.InputStream;
+import java.util.UUID;
+
+@Component
+@ConditionalOnClass(OSS.class)
+public class AlibabaOSSUtils {
+    Logger log = LoggerFactory.getLogger(AlibabaOSSUtils.class);
+
+    @Autowired
+    private OSS ossClient;
+    @Autowired
+    private CloudOssProperty cloudOssProperty;
+
+    public String uploadToOss(InputStream inputStream, String originalFilename){
+        // 生成唯一文件名
+        String filename = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
+        // 上传文件
+        ossClient.putObject(cloudOssProperty.getBucketName(), filename, inputStream);
+        // 返回文件的URL
+        return "https://" + cloudOssProperty.getBucketName() + "." + cloudOssProperty.getEndpoint() + "/" + filename;
+    }
+
+
+
+}

+ 25 - 0
babyApplication-common/babyApplication-common-upload/src/main/java/edu/travel/upload/oss/property/CloudOssProperty.java

@@ -0,0 +1,25 @@
+package edu.travel.upload.oss.property;
+
+import com.aliyun.oss.OSS;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Component
+@ConfigurationProperties(prefix = "alibaba.obs")
+@ConditionalOnClass(OSS.class)
+public class CloudOssProperty {
+    private String endpoint;
+    private String accessKeyId;
+    private String accessKeySecret;
+    private String bucketName;
+
+}

+ 42 - 0
babyApplication-common/babyApplication-common-util/pom.xml

@@ -0,0 +1,42 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-common</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-common-util</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-common-util</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.volcengine</groupId>
+            <artifactId>volc-sdk-java</artifactId>
+            <version>1.0.105</version>
+        </dependency>
+    </dependencies>
+</project>

+ 31 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/AuthUserUtil.java

@@ -0,0 +1,31 @@
+//package edu.travel.util;
+//
+//import com.alibaba.ttl.TransmittableThreadLocal;
+//import com.qhzl.baby.dto.AccountInfo;
+//
+///**
+// *  类。
+// * <p>
+// * 描述:
+// *
+// * @author huangwenwen
+// * @date 2025/3/7
+// */
+//public class AuthUserUtil {
+//
+//    private static final ThreadLocal<AccountInfo> USER_INFO_IN_TOKEN_HOLDER = new TransmittableThreadLocal<>();
+//
+//    public static AccountInfo get() {
+//        return USER_INFO_IN_TOKEN_HOLDER.get();
+//    }
+//
+//    public static void set(AccountInfo userInfoInTokenBo) {
+//        USER_INFO_IN_TOKEN_HOLDER.set(userInfoInTokenBo);
+//    }
+//
+//    public static void clean() {
+//      if (USER_INFO_IN_TOKEN_HOLDER.get() != null) {
+//            USER_INFO_IN_TOKEN_HOLDER.remove();
+//      }
+//    }
+//}

+ 107 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/Base64Util.java

@@ -0,0 +1,107 @@
+package edu.travel.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Base64;
+
+/**
+ * 编码工具
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+public class Base64Util {
+
+    private static final Logger logger = LoggerFactory.getLogger(Base64Util.class);
+
+    public Base64Util() {
+        // empty
+    }
+
+    public static byte[] baseEncode(byte[] bytes) {
+        return Base64.getEncoder().encode(bytes);
+    }
+
+    public static String baseEncode(String s) {
+        try {
+            byte[] e = s.getBytes("UTF-8");
+            return Base64.getEncoder().encodeToString(e);
+        } catch (UnsupportedEncodingException var2) {
+            logger.error(var2.getMessage(), var2);
+            return null;
+        }
+    }
+
+    public static byte[] baseDecode(byte[] bytes) {
+        return Base64.getDecoder().decode(bytes);
+    }
+
+    public static String baseDecode(String s) {
+        try {
+            byte[] e = Base64.getDecoder().decode(s);
+            return new String(e, "UTF-8");
+        } catch (UnsupportedEncodingException var2) {
+            logger.error(var2.getMessage(), var2);
+            return null;
+        }
+    }
+
+    public static byte[] urlEncode(byte[] bytes) {
+        return Base64.getUrlEncoder().encode(bytes);
+    }
+
+    public static String urlEncode(String s) {
+        try {
+            byte[] e = s.getBytes("UTF-8");
+            return Base64.getUrlEncoder().encodeToString(e);
+        } catch (UnsupportedEncodingException var2) {
+            logger.error(var2.getMessage(), var2);
+            return null;
+        }
+    }
+
+    public static byte[] urlDecode(byte[] bytes) {
+        return Base64.getUrlDecoder().decode(bytes);
+    }
+
+    public static String urlDecode(String s) {
+        byte[] result = Base64.getUrlDecoder().decode(s);
+
+        try {
+            return new String(result, "UTF-8");
+        } catch (UnsupportedEncodingException var3) {
+            logger.error(var3.getMessage(), var3);
+            return null;
+        }
+    }
+
+    public static byte[] mimeEncode(byte[] bytes) {
+        return Base64.getMimeEncoder().encode(bytes);
+    }
+
+    public static String mimeEncode(String s) {
+        try {
+            byte[] e = s.getBytes("UTF-8");
+            return Base64.getMimeEncoder().encodeToString(e);
+        } catch (UnsupportedEncodingException var2) {
+            logger.error(var2.getMessage(), var2);
+            return null;
+        }
+    }
+
+    public static byte[] mimeDecode(byte[] bytes) {
+        return Base64.getMimeDecoder().decode(bytes);
+    }
+
+    public static String mimeDecode(String s) {
+        try {
+            byte[] e = Base64.getMimeDecoder().decode(s);
+            return new String(e, "UTF-8");
+        } catch (UnsupportedEncodingException var2) {
+            logger.error(var2.getMessage(), var2);
+            return null;
+        }
+    }
+}

+ 51 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/ContextUtil.java

@@ -0,0 +1,51 @@
+package edu.travel.util;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 获取Servlet HttpRequest和HttpResponse的工具类。
+ *
+ * @author 吃饭睡觉
+ * @date 2024-09-06
+ */
+public class ContextUtil {
+
+    /**
+     * 判断当前是否处于HttpServletRequest上下文环境。
+     *
+     * @return 是返回true,否则false。
+     */
+    public static boolean hasRequestContext() {
+        return RequestContextHolder.getRequestAttributes() != null;
+    }
+
+    /**
+     * 获取Servlet请求上下文的HttpRequest对象。
+     *
+     * @return 请求上下文中的HttpRequest对象。
+     */
+    public static HttpServletRequest getHttpRequest() {
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        return attributes == null ? null : attributes.getRequest();
+    }
+
+    /**
+     * 获取Servlet请求上下文的HttpResponse对象。
+     *
+     * @return 请求上下文中的HttpResponse对象。
+     */
+    public static HttpServletResponse getHttpResponse() {
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        return attributes == null ? null : attributes.getResponse();
+    }
+
+    /**
+     * 私有构造函数,明确标识该常量类的作用。
+     */
+    private ContextUtil() {
+    }
+}

+ 42 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/ContextUtils.java

@@ -0,0 +1,42 @@
+package edu.travel.util;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * Context 工具类
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+@Component
+public class ContextUtils implements ApplicationContextAware {
+    public static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        ContextUtils.applicationContext = applicationContext;
+    }
+
+    public static Object getBean(String name) {
+        return applicationContext.getBean(name);
+    }
+
+    public static <T> T getBean(String name, Class<T> requiredType) {
+        return applicationContext.getBean(name, requiredType);
+    }
+
+    public static boolean containsBean(String name) {
+        return applicationContext.containsBean(name);
+    }
+
+    public static boolean isSingleton(String name) {
+        return applicationContext.isSingleton(name);
+    }
+
+    public static Class<? extends Object> getType(String name) {
+        return applicationContext.getType(name);
+    }
+}

+ 83 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/EncryptUtil.java

@@ -0,0 +1,83 @@
+package edu.travel.util;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Base64;
+
+public class EncryptUtil {
+
+    public static String encodeBase64(byte[] bytes) {
+        String encoded = Base64.getEncoder().encodeToString(bytes);
+        return encoded;
+    }
+
+    public static byte[] decodeBase64(String str) {
+        byte[] bytes = null;
+        bytes = Base64.getDecoder().decode(str);
+        return bytes;
+    }
+
+    public static String encodeUTF8StringBase64(String str) {
+        String encoded = null;
+        try {
+            encoded = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+
+        }
+        return encoded;
+
+    }
+
+    public static String decodeUTF8StringBase64(String str) {
+        String decoded = null;
+        byte[] bytes = Base64.getDecoder().decode(str);
+        try {
+            decoded = new String(bytes, "utf-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return decoded;
+    }
+
+    public static String encodeURL(String url) {
+        String encoded = null;
+        try {
+            encoded = URLEncoder.encode(url, "utf-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return encoded;
+    }
+
+
+    public static String decodeURL(String url) {
+        String decoded = null;
+        try {
+            decoded = URLDecoder.decode(url, "utf-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return decoded;
+    }
+
+    public static void main(String[] args) {
+        String str = "abcd{'a':'b'}";
+        String encoded = EncryptUtil.encodeUTF8StringBase64(str);
+        String decoded = EncryptUtil.decodeUTF8StringBase64(encoded);
+        System.out.println(str);
+        System.out.println(encoded);
+        System.out.println(decoded);
+
+        String url = "== wo";
+        String urlEncoded = EncryptUtil.encodeURL(url);
+        String urlDecoded =EncryptUtil.decodeURL(urlEncoded);
+
+        System.out.println(url);
+        System.out.println(urlEncoded);
+        System.out.println(urlDecoded);
+    }
+
+
+}

+ 63 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/MD5Util.java

@@ -0,0 +1,63 @@
+package edu.travel.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5工具类
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+public class MD5Util {
+    private static final Logger logger = LoggerFactory.getLogger(MD5Util.class);
+    private static final String CHARSET = "UTF-8";
+
+    public MD5Util() {
+    }
+
+    public static byte[] getMD5(byte[] bytes) {
+        try {
+            MessageDigest e = MessageDigest.getInstance("MD5");
+            return e.digest(bytes);
+        } catch (NoSuchAlgorithmException var2) {
+            logger.error(var2.getMessage(), var2);
+            return null;
+        }
+    }
+
+    public static String getMD5(String str) {
+        try {
+            MessageDigest e = MessageDigest.getInstance("MD5");
+            byte[] bytes = e.digest(str.getBytes("UTF-8"));
+            byte[] result = Base64Util.baseEncode(bytes);
+            return new String(result);
+        } catch (NoSuchAlgorithmException var4) {
+            logger.error(var4.getMessage(), var4);
+        } catch (UnsupportedEncodingException var5) {
+            logger.error(var5.getMessage(), var5);
+        }
+
+        return null;
+    }
+
+    public static Boolean validateMD5(byte[] cleartext, byte[] ciphertext) {
+        try {
+            String e = new String(cleartext, "UTF-8");
+            String cipher = new String(ciphertext, "UTF-8");
+            return validateMD5((String)e, (String)cipher);
+        } catch (UnsupportedEncodingException var4) {
+            logger.error(var4.getMessage(), var4);
+            return Boolean.valueOf(false);
+        }
+    }
+
+    public static Boolean validateMD5(String cleartext, String ciphertext) {
+        String str = getMD5((String)cleartext);
+        return str != null && str.equals(ciphertext)?Boolean.valueOf(true):Boolean.valueOf(false);
+    }
+}

+ 59 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/PropertiesUtil.java

@@ -0,0 +1,59 @@
+package edu.travel.util;
+
+
+import org.springframework.util.StringUtils;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+public class PropertiesUtil {
+
+    public static final ResourceBundle messageResource = ResourceBundle.getBundle("international.message", Locale.getDefault());
+
+    /**
+     * 获取请求返回Code对应的Message
+     * @param code
+     * @param params
+     * @return
+     */
+    public static String getResponseErrorMessageByCode(int code, String...params) {
+        if (messageResource == null) {
+            return "";
+        }
+        String pStr = messageResource.getString("response.error." + code);
+        if (StringUtils.isEmpty(pStr) || pStr == null) {
+           return "";
+        }
+        if (params == null || params.length == 0) {
+            return pStr;
+        }
+        MessageFormat format = new MessageFormat(pStr, Locale.getDefault());
+        return format.format(params);
+    }
+
+    /**
+     * 根据Key值获取Value
+     * @param key
+     * @param params
+     * @return
+     */
+    public static String getValueByKey(String key, String...params) {
+        String pStr = messageResource.getString(key);
+        if (messageResource == null) {
+            return "";
+        }
+        if (StringUtils.isEmpty(pStr)) {
+            return "";
+        }
+        if (params == null || params.length == 0) {
+            return pStr;
+        }
+        MessageFormat format = new MessageFormat(pStr, Locale.getDefault());
+        return format.format(params);
+    }
+}

+ 160 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/RedisUtil.java

@@ -0,0 +1,160 @@
+package edu.travel.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * redis 缓存工具
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+@Slf4j
+public class RedisUtil {
+
+    private static RedisTemplate<String, Object> redisTemplate = ContextUtils.getBean("redisTemplate", RedisTemplate.class);
+
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key  键
+     * @param time 时间(秒)
+     * @return
+     */
+    public static boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+//            log.error("设置redis指定key失效时间错误:", e);
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效 失效时间为负数,说明该主键未设置失效时间(失效时间默认为-1)
+     */
+    public static long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false 不存在
+     */
+    public static boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+//            log.error("redis判断key是否存在错误:", e);
+            return false;
+        }
+    }
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T get(String key) {
+        return key == null ? null : (T) redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key   键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public static boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+//            log.error("设置redis缓存错误:", e);
+            return false;
+        }
+
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+    public static boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值 或多个
+     */
+    @SuppressWarnings("unchecked")
+    public static void remove(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                redisTemplate.delete(key[0]);
+            } else {
+                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+
+    /**
+     * 递增 此时value值必须为int类型 否则报错
+     *
+     * @param key   键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+    public static long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 递减
+     *
+     * @param key   键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public static long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, -delta);
+    }
+}

+ 50 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/SMSUtils.java

@@ -0,0 +1,50 @@
+package edu.travel.util;
+
+import com.alibaba.fastjson.JSON;
+import com.volcengine.model.request.SmsSendRequest;
+import com.volcengine.model.response.SmsSendResponse;
+import com.volcengine.service.sms.SmsService;
+import com.volcengine.service.sms.SmsServiceInfoConfig;
+import com.volcengine.service.sms.impl.SmsServiceImpl;
+import edu.travel.util.SmsSwitch;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+public class SMSUtils {
+
+    @Autowired
+    private SmsSwitch smsSwitch;
+
+    private static SmsService smsService;
+
+    public void sendMsg(String countryCode, String phoneNumber, String code){
+        smsService = SmsServiceImpl.getInstance(new SmsServiceInfoConfig(smsSwitch.getAK(), smsSwitch.getSK()));
+
+        SmsSendRequest req = new SmsSendRequest();
+        req.setPhoneNumbers(countryCode.replaceAll("\\+", "") + phoneNumber);
+        req.setSmsAccount(smsSwitch.getSmsAccount());
+        if(countryCode.equals("86") || StringUtils.isBlank(countryCode)){
+            req.setTemplateId(smsSwitch.getChinaTemplateId());
+            req.setSign(smsSwitch.getChinaSign());
+        }else {
+            req.setTemplateId(smsSwitch.getOtherTemplateId());
+            req.setSign(smsSwitch.getOtherSign());
+        }
+
+        Map<String,String> param = new HashMap<>();
+        param.put("code", code);
+        req.setTemplateParamByMap(param);
+
+        try {
+            SmsSendResponse response = smsService.sendV2(req);
+            System.out.println(JSON.toJSONString(response));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 38 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/SmsSwitch.java

@@ -0,0 +1,38 @@
+package edu.travel.util;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "sms.blends.huoshan")
+public class SmsSwitch {
+    private String aK;
+
+    private String sK;
+    /**
+     * 短信开关
+     */
+    private boolean enable;
+    /**
+     * 短信账号
+     */
+    private String smsAccount;
+    /**
+     * 国内签名
+     */
+    private String chinaSign;
+    /**
+     * 国外签名
+     */
+    private String otherSign;
+    /**
+     * 国内模板ID
+     */
+    private String chinaTemplateId;
+    /**
+     * 国外模板ID
+     */
+    private String otherTemplateId;
+}

+ 169 - 0
babyApplication-common/babyApplication-common-util/src/main/java/edu/travel/util/TokenUtil.java

@@ -0,0 +1,169 @@
+//package edu.travel.util;
+//
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import com.qhzl.baby.constanst.Constants;
+//import com.qhzl.baby.dto.AccountInfo;
+//import org.springframework.stereotype.Component;
+//
+//import java.text.SimpleDateFormat;
+//import java.util.Date;
+//import java.util.Random;
+//
+///**
+// * 登录Token服务接口
+// *
+// * Created by FSQ
+// * CopyRight https://www.fuint.cn
+// */
+//@Component
+//public class TokenUtil {
+//
+//    public static int TOKEN_OVER_TIME = 604800;//7天
+//
+////    /**
+////     * 生成token
+////     *
+////     * @param userAgent
+////     * @param userId
+////     * @return
+////     * */
+////    public static String generateToken(String userAgent, Long userId) {
+////        StringBuilder stringBuilder = new StringBuilder();
+////        UserAgent userAgent1 = UserAgent.parseUserAgentString(userAgent);
+////        if (userAgent1.getOperatingSystem().isMobileDevice()) {
+////            stringBuilder.append("APP_");
+////        } else {
+////            stringBuilder.append("PC_");
+////        }
+////
+////        stringBuilder.append(userId);
+////        stringBuilder.append(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + "_");
+////        stringBuilder.append(new Random().nextInt((999999 - 111111 + 1)) + 111111);
+////        String token = MD5Util.getMD5(stringBuilder.toString()).replace("+", "1").replaceAll("&", "8");
+////
+////        UserInfo userLoginInfo = new UserInfo();
+////        userLoginInfo.setId(userId);
+////        userLoginInfo.setToken(token);
+////        saveToken(userLoginInfo);
+////
+////        return token;
+////    }
+//
+//    /**
+//     * 生成token
+//     *
+////     * @param userAgent
+//     * @param accountInfo
+//     * @return
+//     * */
+//    public static String generateToken( AccountInfo accountInfo) {
+//        StringBuilder stringBuilder = new StringBuilder();
+////        UserAgent userAgent1 = UserAgent.parseUserAgentString(userAgent);
+////        if (userAgent1.getOperatingSystem().isMobileDevice()) {
+////            stringBuilder.append("APP_");
+////        } else {
+////            stringBuilder.append("PC_");
+////        }
+//
+//        stringBuilder.append(accountInfo.getId());
+//        stringBuilder.append(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())).append("_");
+//        stringBuilder.append(new Random().nextInt((999999 - 111111 + 1)) + 111111);
+//        String token = MD5Util.getMD5(stringBuilder.toString()).replace("+", "1").replaceAll("&", "8");
+//
+//        accountInfo.setToken(token);
+//        saveAccountToken(accountInfo);
+//
+//        return token;
+//    }
+//
+////    /**
+////     * 保存token
+////     *
+////     * @param userInfo
+////     * @return
+////     * */
+////    public static void saveToken(UserInfo userInfo) {
+////        if (userInfo == null || userInfo.getToken() == null || userInfo.getId() == null) {
+////            return;
+////        }
+////        RedisUtil.set(Constants.SESSION_USER + userInfo.getToken(), userInfo, TOKEN_OVER_TIME);
+////    }
+////
+////    /**
+////     * 通过token获取后台登录信息
+////     *
+////     * @param token
+////     * @return
+////     * */
+////    public static UserInfo getUserInfoByToken(String token) {
+////        if (token == null || StringUtils.isEmpty(token)) {
+////            return null;
+////        }
+////        Object loginInfo = RedisUtil.get(Constants.SESSION_USER + token);
+////        ObjectMapper objectMapper = new ObjectMapper();
+////        UserInfo userInfo = objectMapper.convertValue(loginInfo, UserInfo.class);
+////        if (userInfo != null && userInfo.getToken().equals(token)) {
+////            return userInfo;
+////        }
+////        return null;
+////    }
+//
+////    /**
+////     * 检查是否登录
+////     *
+////     * @param token
+////     * @return
+////     * */
+////    public static boolean checkTokenLogin(String token) {
+////        try {
+////            UserInfo userInfo = RedisUtil.get(Constants.SESSION_USER + token);
+////            if (userInfo != null && userInfo.getToken().equals(token)) {
+////                return true;
+////            }
+////        } catch (Exception e) {
+////            return false;
+////        }
+////        return false;
+////    }
+//
+//    /**
+//     * 删除登录信息
+//     *
+//     * @param token
+//     * @return
+//     * */
+//    public static boolean removeToken(String token) {
+//        RedisUtil.remove(token);
+//        AuthUserUtil.clean();
+//        return true;
+//    }
+//
+//    /**
+//     * 保存后台登录token
+//     *
+//     * @param accountInfo
+//     * @return
+//     * */
+//    public static void saveAccountToken(AccountInfo accountInfo) {
+//        if (accountInfo == null) {
+//            return;
+//        }
+//        RedisUtil.set(Constants.SESSION_ADMIN_USER + accountInfo.getToken(), accountInfo, TOKEN_OVER_TIME);
+//    }
+//
+//    /**
+//     * 通过登录token获取后台登录信息
+//     *
+//     * @param token
+//     * @return
+//     * */
+//    public static AccountInfo getAccountInfoByToken(String token) {
+//        Object loginInfo = RedisUtil.get(Constants.SESSION_ADMIN_USER + token);
+//        ObjectMapper objectMapper = new ObjectMapper();
+//        AccountInfo accountInfo = objectMapper.convertValue(loginInfo, AccountInfo.class);
+//        if (accountInfo != null && accountInfo.getToken().equals(token)) {
+//            return accountInfo;
+//        }
+//        return null;
+//    }
+//}

+ 29 - 0
babyApplication-common/pom.xml

@@ -0,0 +1,29 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>edu.travel</groupId>
+    <artifactId>babyApplication</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>babyApplication-common</artifactId>
+
+  <name>babyApplication-common</name>
+  <url>http://maven.apache.org</url>
+
+  <modules>
+    <module>babyApplication-common-core</module>
+    <module>babyApplication-common-datasource</module>
+    <module>babyApplication-common-cache</module>
+    <module>babyApplication-common-resp</module>
+    <module>babyApplication-common-constant</module>
+    <module>babyApplication-common-upload</module>
+    <module>babyApplication-common-util</module>
+  </modules>
+  <packaging>pom</packaging>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+</project>

+ 50 - 0
babyApplication-dao/pom.xml

@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-dao</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-dao</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-model</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-datasource</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-cache</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-model-entity</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 7 - 0
babyApplication-dao/src/main/java/edu/travel/mapper/BtAccountInfoMapper.java

@@ -0,0 +1,7 @@
+package edu.travel.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import edu.travel.entity.BtAccountInfo;
+
+public interface BtAccountInfoMapper extends BaseMapper<BtAccountInfo> {
+}

+ 28 - 0
babyApplication-model/babyApplication-model-base/pom.xml

@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-model</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-model-base</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-model-base</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 96 - 0
babyApplication-model/babyApplication-model-base/src/main/java/edu/travel/entity/AccountInfo.java

@@ -0,0 +1,96 @@
+package edu.travel.entity;
+
+import lombok.Data;
+import lombok.NonNull;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户表
+ */
+@Data
+public class AccountInfo extends BaseEntity implements Serializable {
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 姓
+     */
+    @NonNull
+    private String surname;
+
+    /**
+     * 名
+     */
+    @NonNull
+    private String name;
+
+    /**
+     * 昵称
+     */
+    @NonNull
+    private String nickname;
+
+    /**
+     * 性别 0男 1女
+     */
+    @NonNull
+    private Integer sex;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * 手机号
+     */
+    @NonNull
+    private String phone;
+
+    /**
+     * 地区区号
+     */
+    @NonNull
+    private String area;
+
+    /**
+     * 生日日期
+     */
+    private Date birthday;
+
+    /**
+     * 用户状态:0-禁用,1-启用(默认启用)
+     */
+    private Integer userStatus;
+
+    /**
+     * 用户密码
+     */
+    @NonNull
+    private String password;
+
+    /**
+     * 默认语言
+     */
+    private Long defaultLanguageId;
+
+    /**
+     * 微信小程序openid
+     */
+    private String tenantOpenId;
+
+    /**
+     * 微信小程序unionid
+     */
+    private String tenantUnionid;
+
+    /**
+     * token
+     */
+    private String token;
+
+}

+ 35 - 0
babyApplication-model/babyApplication-model-base/src/main/java/edu/travel/entity/BaseEntity.java

@@ -0,0 +1,35 @@
+package edu.travel.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * BaseEntity 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/3/7
+ */
+
+@Data
+public class BaseEntity {
+    @TableField(value = "project",fill = FieldFill.INSERT)
+    public String project;
+    @TableField(value = "create_time",fill = FieldFill.INSERT)
+    public Date createTime;
+    @TableField(value = "create_user_id",fill = FieldFill.INSERT)
+    public String createUserId;
+    @TableField(value = "update_time",fill = FieldFill.UPDATE)
+    public Date updateTime;
+    @TableField(value = "update_user_id",fill = FieldFill.UPDATE)
+    public String updateUserId;
+    @TableField(value = "delete_flag",fill = FieldFill.INSERT)
+    @TableLogic(value = "0",delval = "1")
+    public Integer deleteFlag;
+}
+

+ 27 - 0
babyApplication-model/babyApplication-model-entity/pom.xml

@@ -0,0 +1,27 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication-model</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-model-entity</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-model-entity</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-model-base</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 30 - 0
babyApplication-model/babyApplication-model-entity/src/main/java/edu/travel/dto/LoginDto.java

@@ -0,0 +1,30 @@
+package edu.travel.dto;
+
+import lombok.Data;
+
+/**
+ * LoginDto 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/3/13
+ */
+
+@Data
+public class LoginDto {
+
+    /**
+     * 验证码
+     */
+    private String code;
+    /**
+     * 手机号
+     */
+    private String phoneNumber;
+
+    /**
+     * 地区编号
+     */
+    private String countryCode;
+}

+ 23 - 0
babyApplication-model/babyApplication-model-entity/src/main/java/edu/travel/dto/SendSmsDto.java

@@ -0,0 +1,23 @@
+package edu.travel.dto;
+import lombok.Data;
+
+@Data
+public class SendSmsDto {
+    /**
+     * 验证码标识
+     */
+    private String uuid;
+    /**
+     * 验证码
+     */
+    private String code;
+    /**
+     * 手机号
+     */
+    private String phoneNumber;
+
+    /**
+     * 地区编号
+     */
+    private String countryCode;
+}

+ 101 - 0
babyApplication-model/babyApplication-model-entity/src/main/java/edu/travel/entity/BtAccountInfo.java

@@ -0,0 +1,101 @@
+package edu.travel.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 用户表
+ */
+@Data
+@TableName(value = "baby.bt_account_info")
+public class BtAccountInfo extends BaseEntity {
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 姓
+     */
+    @TableField(value = "surname")
+    private String surname;
+
+    /**
+     * 名
+     */
+    @TableField(value = "`name`")
+    private String name;
+
+    /**
+     * 昵称
+     */
+    @TableField(value = "nickname")
+    private String nickname;
+
+    /**
+     * 性别 0男 1女
+     */
+    @TableField(value = "sex")
+    private Integer sex;
+
+    /**
+     * 头像
+     */
+    @TableField(value = "avatar")
+    private String avatar;
+
+    /**
+     * 手机号
+     */
+    @TableField(value = "phone")
+    private String phone;
+
+    /**
+     * 地区区号
+     */
+    @TableField(value = "area")
+    private String area;
+
+    /**
+     * 生日日期
+     */
+    @TableField(value = "birthday")
+    private Date birthday;
+
+    /**
+     * 用户状态:0-禁用,1-启用(默认启用)
+     */
+    @TableField(value = "user_status")
+    private Integer userStatus;
+
+    /**
+     * 用户密码
+     */
+    @TableField(value = "`password`")
+    private String password;
+
+    /**
+     * 默认语言
+     */
+    @TableField(value = "default_language_id")
+    private Long defaultLanguageId;
+
+    /**
+     * 微信小程序openid
+     */
+    @TableField(value = "tenant_open_id")
+    private String tenantOpenId;
+
+    /**
+     * 微信小程序unionid
+     */
+    @TableField(value = "tenant_unionid")
+    private String tenantUnionid;
+
+}

+ 35 - 0
babyApplication-model/pom.xml

@@ -0,0 +1,35 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-model</artifactId>
+    <packaging>pom</packaging>
+
+    <name>babyApplication-model</name>
+    <url>http://maven.apache.org</url>
+    <modules>
+        <module>babyApplication-model-base</module>
+        <module>babyApplication-model-entity</module>
+    </modules>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-annotation</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 65 - 0
babyApplication-service/pom.xml

@@ -0,0 +1,65 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-service</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-service</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-dao</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-core</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-upload</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-constant</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-common-util</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>4.0.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 15 - 0
babyApplication-service/src/main/java/edu/travel/service/BtAccountInfoService.java

@@ -0,0 +1,15 @@
+package edu.travel.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import edu.travel.dto.LoginDto;
+import edu.travel.dto.SendSmsDto;
+import edu.travel.entity.AccountInfo;
+import edu.travel.entity.BtAccountInfo;
+
+public interface BtAccountInfoService extends IService<BtAccountInfo> {
+    AccountInfo findByPhone(String phone);
+
+    BtAccountInfo doLogin(LoginDto loginDto);
+
+    void sendSms(SendSmsDto sendSmsDto);
+}

+ 95 - 0
babyApplication-service/src/main/java/edu/travel/service/impl/AccountInfoServiceImpl.java

@@ -0,0 +1,95 @@
+package edu.travel.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.apache.commons.lang3.StringUtils;
+import edu.travel.entity.BtAccountInfo;
+import edu.travel.mapper.BtAccountInfoMapper;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * AccountInfoServiceImpl 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/3/13
+ */
+
+@Service
+public class AccountInfoServiceImpl implements UserDetailsService {
+
+    @Autowired
+    private BtAccountInfoMapper btAccountInfoMapper;
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+//    @Autowired
+//    private SysRoleService roleService;
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+
+            // 1. 基本校验
+            if (StringUtils.isBlank(username)) {
+                throw new UsernameNotFoundException("手机号不能为空");
+            }
+
+            // 2. 获取当前请求
+            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
+                    .currentRequestAttributes()).getRequest();
+
+            // 3. 查询用户
+            BtAccountInfo tenant = btAccountInfoMapper.selectOne(new LambdaQueryWrapper<BtAccountInfo>()
+                    .eq(BtAccountInfo::getPhone, username));
+            if (tenant == null) {
+                throw new UsernameNotFoundException("用户不存在");
+            }
+
+            // 4. 处理不同登录方式
+            String loginType = request.getParameter("loginFrom");
+            if ("admin".equals(loginType)) {
+                // 管理员密码登录
+                String password = request.getParameter("password");
+                if (!tenant.getPassword().equals(password)) {
+                    throw new UsernameNotFoundException("密码错误");
+                }
+            } else {
+                // 用户短信登录
+                String code = request.getParameter("code");
+                String redisKey = username + "_sms_code";
+                String storedCode = redisTemplate.opsForValue().get(redisKey);
+
+                if (!StringUtils.equals(code, storedCode)) {
+                    throw new UsernameNotFoundException("验证码错误");
+                }
+                // 清除已用验证码
+                redisTemplate.delete(redisKey);
+            }
+
+            // 5. 获取角色信息
+//            List<SysRole> roles = roleService.getRoleListByUserId(tenant.getId());
+//            List<String> roleNames = roles.stream()
+//                    .map(SysRole::getName)
+//                    .collect(Collectors.toList());
+
+            // 6. 构建UserDetails对象
+//        String[] array = roleNames.toArray(new String[0]);
+        return User.builder()
+                    .username(username)
+                    .password(tenant.getPassword()) // 实际密码应从数据库获取
+                    .roles(new String[0])
+                    .build();
+        }
+}

+ 132 - 0
babyApplication-service/src/main/java/edu/travel/service/impl/BtAccountInfoServiceImpl.java

@@ -0,0 +1,132 @@
+package edu.travel.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import edu.travel.dto.LoginDto;
+import edu.travel.dto.SendSmsDto;
+import edu.travel.entity.AccountInfo;
+import edu.travel.entity.BtAccountInfo;
+import edu.travel.mapper.BtAccountInfoMapper;
+import edu.travel.service.BtAccountInfoService;
+import edu.travel.util.SMSUtils;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+
+
+@Service
+public class BtAccountInfoServiceImpl extends ServiceImpl<BtAccountInfoMapper, BtAccountInfo> implements BtAccountInfoService {
+
+//    private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+    @Autowired
+    private SMSUtils smsUtils;
+    @Autowired
+    private RedisTemplate redisTemplate;
+    @Override
+    public BtAccountInfo doLogin(LoginDto loginDto) {
+//        BtAccountInfo accountInfoByPhone = getAccountInfoByPhone(accountInfo.getPhone());
+//        if (accountInfoByPhone != null){
+//            boolean passwordMatches = encoder.matches(accountInfo.getPassword(), accountInfoByPhone.getPassword());
+//            if (passwordMatches) {
+//                String token = TokenUtil.generateToken(accountInfo);
+//                AccountInfo accountInfo1 = BeanUtil.copyProperties(accountInfoByPhone, AccountInfo.class);
+//                accountInfo1.setToken(token);
+//                return accountInfo1;
+//            } else {
+//                throw new RuntimeException("密码错误");
+//            }
+//        } else {
+//            accountInfo.setPassword(encoder.encode(accountInfo.getPassword()));
+//            BtAccountInfo entity = BeanUtil.copyProperties(accountInfo, BtAccountInfo.class);
+//            save(entity);
+//
+//            AccountInfo accountInfo1 = BeanUtil.copyProperties(entity, AccountInfo.class);
+//            String token = TokenUtil.generateToken(accountInfo);
+//            accountInfo1.setToken(token);
+//            return accountInfo1;
+//        }
+
+        String username = loginDto.getPhoneNumber();
+        // 1. 基本校验
+        if (ObjectUtil.isEmpty(loginDto) || StringUtils.isBlank(username) ) {
+            throw new UsernameNotFoundException("手机号不能为空");
+        }
+        if (StringUtils.isBlank(loginDto.getCode())){
+            throw new UsernameNotFoundException("验证码不能为空");
+        }
+
+        // 2. 获取当前请求
+        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
+                .currentRequestAttributes()).getRequest();
+
+        // 3. 查询用户
+        BtAccountInfo tenant = this.getOne(new LambdaQueryWrapper<BtAccountInfo>()
+                .eq(BtAccountInfo::getPhone, username));
+        if (tenant == null) {
+            throw new UsernameNotFoundException("用户不存在");
+        }
+
+        // 4. 处理不同登录方式
+        String loginType = request.getParameter("loginFrom");
+        if ("admin".equals(loginType)) {
+            // 管理员密码登录
+            String password = request.getParameter("password");
+            if (!tenant.getPassword().equals(password)) {
+                throw new UsernameNotFoundException("密码错误");
+            }
+        } else {
+            // 用户短信登录
+            String code = loginDto.getCode();
+            String redisKey = username + "_sms_code";
+            String storedCode = redisTemplate.opsForValue().get(redisKey).toString();
+
+            if (!StringUtils.equals(code, storedCode)) {
+                throw new UsernameNotFoundException("验证码错误");
+            }
+            // 清除已用验证码
+            redisTemplate.delete(redisKey);
+        }
+        return null;
+    }
+
+    @Override
+    public void sendSms(SendSmsDto sendSmsDto) {
+        if (ObjectUtil.isEmpty(sendSmsDto) || StringUtils.isBlank(sendSmsDto.getPhoneNumber())){
+           throw new RuntimeException("手机号不能为空");
+        }
+        // 校验图形验证码
+        String imageCode = (String) redisTemplate.opsForValue().get(sendSmsDto.getPhoneNumber() + "_image_code");
+        //发送短信
+        Object o = redisTemplate.opsForValue().get(sendSmsDto.getPhoneNumber() + "_user_sms");
+        if (o!=null) throw new RuntimeException("验证码已发送,请一分钟后重试");
+        //短信码
+        String smsCode = String.valueOf(new Random().nextInt(9000) + 1000);
+        redisTemplate.opsForValue().set(sendSmsDto.getPhoneNumber() + "_user_sms", smsCode, 1, TimeUnit.MINUTES);
+        smsUtils.sendMsg(sendSmsDto.getCountryCode(), sendSmsDto.getPhoneNumber(), smsCode);
+    }
+
+
+    /**
+     * 根据手机号查询用户
+     */
+    @Override
+    public AccountInfo findByPhone(String phone) {
+        BtAccountInfo one = this.getOne(new LambdaQueryWrapper<BtAccountInfo>().eq(BtAccountInfo::getPhone, phone).eq(BtAccountInfo::getUserStatus, 1));
+        if (one != null) {
+            AccountInfo accountInfo = BeanUtil.copyProperties(one, AccountInfo.class);
+            return accountInfo;
+        }
+        return null;
+    }
+}

+ 64 - 0
babyApplication-web/pom.xml

@@ -0,0 +1,64 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>edu.travel</groupId>
+        <artifactId>babyApplication</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>babyApplication-web</artifactId>
+    <packaging>jar</packaging>
+
+    <name>babyApplication-web</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>edu.travel</groupId>
+            <artifactId>babyApplication-service</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>nimbus-jose-jwt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <!-- Spring AOP -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!-- AspectJ 织入 -->
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+            <version>1.9.7</version>
+        </dependency>
+
+    </dependencies>
+</project>

+ 20 - 0
babyApplication-web/src/main/java/edu/travel/BabyApplication.java

@@ -0,0 +1,20 @@
+package edu.travel;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+
+
+@SpringBootApplication
+@MapperScan("edu.travel.mapper")
+@ServletComponentScan("edu.travel.filter")
+public class BabyApplication
+{
+    public static void main( String[] args )
+    {
+        SpringApplication.run(BabyApplication.class, args);
+    }
+}
+
+

+ 31 - 0
babyApplication-web/src/main/java/edu/travel/config/CORSFilter.java

@@ -0,0 +1,31 @@
+package edu.travel.config;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 跨域支持
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+@Component
+public class CORSFilter extends OncePerRequestFilter {
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+        response.setHeader("Access-Control-Allow-Origin", "*");
+        response.setHeader("Access-Control-Allow-Credentials", "true");
+        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
+        response.setHeader("Access-Control-Max-Age", "3600");
+        response.setHeader("Access-Control-Allow-Headers", "Authorization,Origin,X-Requested-With,token,Content-Type,Accept,Access-Token,platform,latitude,longitude,storeId,merchantNo,isWechat,tableId,orderId");
+        filterChain.doFilter(request, response);
+    }
+
+}

+ 62 - 0
babyApplication-web/src/main/java/edu/travel/config/CustomObjectMapper.java

@@ -0,0 +1,62 @@
+package edu.travel.config;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
+import org.springframework.context.annotation.Configuration;
+
+import java.math.BigInteger;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.TimeZone;
+
+@Configuration
+public class CustomObjectMapper extends ObjectMapper {
+
+
+	public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
+	public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+	public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
+
+	public CustomObjectMapper() {
+
+
+		super();
+		//去掉默认的时间戳格式
+		this.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+		//设置为东八区
+		this.setTimeZone(TimeZone.getTimeZone("GMT+8"));
+		// 设置输入:禁止把POJO中值为null的字段映射到json字符串中
+		//this.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
+//		this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+		// 空值不序列化
+//		this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+		// 反序列化时,属性不存在的兼容处理
+		this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+		// 序列化枚举是以toString()来输出,默认false,即默认以name()来输出
+		this.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
+
+		SimpleModule simpleModule = new SimpleModule()
+				.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
+				.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
+				.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
+				.addSerializer(BigInteger.class, ToStringSerializer.instance)
+				.addSerializer(Long.class, ToStringSerializer.instance)
+				.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
+				.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
+				.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
+
+		//注册功能模块 例如,可以添加自定义序列化器和反序列化器
+		this.registerModule(simpleModule);
+	}
+}

+ 101 - 0
babyApplication-web/src/main/java/edu/travel/config/SecurityConfig.java

@@ -0,0 +1,101 @@
+package edu.travel.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+/**
+ * 安全中心配置
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    /**
+     * 解决 无法直接注入 AuthenticationManager
+     *
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    @Override
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+        return super.authenticationManagerBean();
+    }
+
+    /**
+     * anyRequest          |   匹配所有请求路径
+     * access              |   SpringEl表达式结果为true时可以访问
+     * anonymous           |   匿名可以访问
+     * denyAll             |   用户不能访问
+     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
+     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
+     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
+     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
+     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
+     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
+     * permitAll           |   用户可以任意访问
+     * rememberMe          |   允许通过remember-me登录的用户访问
+     * authenticated       |   用户登录后可访问
+     */
+    @Override
+    protected void configure(HttpSecurity httpSecurity) throws Exception {
+        httpSecurity
+                // CSRF禁用,因为不使用session
+                .csrf().disable()
+                // 基于token,所以不需要session
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+                // 过滤请求
+                .authorizeRequests()
+                // 允许匿名访问
+                .antMatchers(
+                        "/happyEntry/**",
+                        "/uploadFile/**"
+                        ).anonymous()
+                .antMatchers(
+                        HttpMethod.GET,
+                        "/",
+                        "/static/**",
+                        "/*.html",
+                        "/**/*.html",
+                        "/**/*.css",
+                        "/**/*.js",
+                        "/profile/**"
+                ).permitAll()
+                .antMatchers("/swagger-ui.html").anonymous()
+                .antMatchers("/swagger-resources/**").anonymous()
+                .antMatchers("/webjars/**").anonymous()
+                .antMatchers("/*/api-docs").anonymous()
+                .antMatchers("/druid/**").anonymous()
+                // 除上面外的所有请求全部需要鉴权认证
+                .anyRequest().authenticated()
+                .and()
+                .headers().frameOptions().disable();
+    }
+
+    /**
+     * 强散列哈希加密实现
+     */
+    @Bean
+    public BCryptPasswordEncoder bCryptPasswordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 身份认证接口
+     */
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) {
+        // empty
+    }
+
+
+}

+ 69 - 0
babyApplication-web/src/main/java/edu/travel/config/WebConfig.java

@@ -0,0 +1,69 @@
+package edu.travel.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.CacheControl;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.filter.CharacterEncodingFilter;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
+import org.springframework.web.servlet.resource.CssLinkResourceTransformer;
+import org.springframework.web.servlet.resource.VersionResourceResolver;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * web配置
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+@Configuration
+public class WebConfig extends WebMvcConfigurationSupport {
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        registry.addResourceHandler("/resources/**")
+                .addResourceLocations("/resources/", "classpath:/other-resources/")
+                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
+                .resourceChain(false)
+                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
+                .addTransformer(new CssLinkResourceTransformer());
+        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
+
+        registry.addResourceHandler("/**").addResourceLocations(
+                "classpath:/static/");
+        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
+                "classpath:/META-INF/resources/");
+        registry.addResourceHandler("/webjars/**").addResourceLocations(
+                "classpath:/META-INF/resources/webjars/");
+        super.addResourceHandlers(registry);
+    }
+
+
+
+    @Bean
+    public CharacterEncodingFilter characterEncodingFilter() {
+        CharacterEncodingFilter filter = new CharacterEncodingFilter();
+        filter.setEncoding("UTF-8");
+        filter.setForceEncoding(true);
+        return filter;
+    }
+
+    @Autowired
+    private CustomObjectMapper customObjectMapper;
+    @Override
+    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
+
+        //创建消息转换器对象
+        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
+        //设置消息转换器,底层使用jackson将Java对象转成json
+        messageConverter.setObjectMapper(customObjectMapper);
+        //将我们自定义的消息转换器追加到mvc框架的集合转换器中
+        converters.add(0, messageConverter);
+    }
+}

+ 38 - 0
babyApplication-web/src/main/java/edu/travel/constanst/Constants.java

@@ -0,0 +1,38 @@
+package edu.travel.constanst;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 常量定义
+ *
+ * Created by FSQ
+ * CopyRight https://www.fuint.cn
+ */
+public class Constants {
+
+    // 第几页,默认第1页
+    public static final int PAGE_NUMBER = 1;
+
+    // 每页记录数,默认20条
+    public static final int PAGE_SIZE = 20;
+
+    // 读取数据最多行数
+    public static final int MAX_ROWS = 2000;
+
+    // 读取数据全部行数
+    public static final int ALL_ROWS = 1000000;
+
+    /**
+     * 系统配置, 从setting表中读取
+     */
+    public static Map<String, String> SYS_CONFIGS = new HashMap<String, String>();
+
+    public static final int HTTP_RESPONSE_CODE_PARAM_ERROR = 202;
+    public static final int HTTP_RESPONSE_CODE_USER_NOT_EXIST = 402;
+    public static final int HTTP_RESPONSE_CODE_USER_LOGIN_ERROR = 403;
+    public static final int HTTP_RESPONSE_CODE_NOLOGIN = 1001;
+
+    public static final String SESSION_USER = "BABY_USER";
+    public static final String SESSION_ADMIN_USER = "BABY_ADMIN_USER";
+}

+ 47 - 0
babyApplication-web/src/main/java/edu/travel/controller/LoginController.java

@@ -0,0 +1,47 @@
+package edu.travel.controller;
+
+import edu.travel.dto.LoginDto;
+import edu.travel.dto.SendSmsDto;
+import edu.travel.entity.AccountInfo;
+import edu.travel.entity.BtAccountInfo;
+import edu.travel.resp.BaseResponse;
+import edu.travel.service.BtAccountInfoService;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * LoginController 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/3/08
+ */
+
+@RestController
+@RequestMapping("/baby/login")
+public class LoginController {
+
+    private BtAccountInfoService btAccountInfoService;
+
+    /**
+     * 登录
+     *
+     * @param loginDto
+     * @return
+     */
+    @PostMapping("/doLogin")
+    public BaseResponse<BtAccountInfo> doLogin(LoginDto loginDto) {
+        return new BaseResponse<>(200,"登陆成功",btAccountInfoService.doLogin(loginDto)) ;
+    }
+
+    /**
+     * 发送手机验证码
+     */
+    @GetMapping("/sendSms")
+    public BaseResponse<String> sendSms(SendSmsDto sendSmsDto) {
+        btAccountInfoService.sendSms(sendSmsDto);
+        return new BaseResponse<>(200,"发送成功",null) ;
+    }
+
+}

+ 103 - 0
babyApplication-web/src/main/java/edu/travel/filter/LoginFilter.java

@@ -0,0 +1,103 @@
+package edu.travel.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang3.StringUtils;
+import com.nimbusds.jose.JWSObject;
+import edu.travel.FinalParam;
+import edu.travel.util.EncryptUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.*;
+/**
+ * LoginFilter 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/3/11
+ */
+
+@Component
+public class LoginFilter implements Filter {
+
+//    @Autowired
+//    private RedisTemplate<String, Object> redisTemplate;
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+            throws IOException, ServletException {
+
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+        // 获取 token
+        String token = request.getHeader("Authorization");
+
+        if (StringUtils.isBlank(token) || token.equals("null")) {
+            filterChain.doFilter(request, response);
+            return;
+        }
+
+        // 替换 Bearer 头
+        String realToken = token.replace("Bearer ", "");
+        try {
+            JWSObject jwsObject = JWSObject.parse(realToken);
+            String userStr = jwsObject.getPayload().toString();
+            JSONObject jsonObject = JSON.parseObject(userStr);
+
+            // 提取权限信息
+            Object object = jsonObject.get(FinalParam.AUTHORITY_CLAIM_NAME);
+            List<String> authorities = new ArrayList<>();
+
+            if (object != null) {
+                if (object instanceof JSONArray) {
+                    authorities = ((JSONArray) object).toJavaList(String.class);
+                } else {
+                    String authoritiesStr = object.toString();
+                    JSONArray authoritiesArray = JSON.parseArray(authoritiesStr);
+                    authorities = authoritiesArray.toJavaList(String.class);
+                }
+            }
+
+            // 提取用户名和客户端ID
+            String principal = jsonObject.getObject("user_name", String.class);
+            String clientId = jsonObject.getObject("client_id", String.class);
+
+            // 封装到 Map
+            Map<String, Object> map = new HashMap<>();
+            map.put("authorities", authorities);
+            map.put("client_id", clientId);
+            map.put("principal", principal);
+
+            // 生成新的 token(Base64 编码)
+            String newToken = EncryptUtil.encodeUTF8StringBase64(JSON.toJSONString(map));
+
+            // 将 token 添加到请求头
+            HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
+                @Override
+                public String getHeader(String name) {
+                    if ("token".equals(name)) {
+                        return newToken;
+                    }
+                    return super.getHeader(name);
+                }
+            };
+
+            filterChain.doFilter(requestWrapper, response);
+
+        } catch (ParseException e) {
+            e.printStackTrace();
+            filterChain.doFilter(request, response);
+        }
+    }
+}

+ 78 - 0
babyApplication-web/src/main/java/edu/travel/filter/TokenAuthenticationFilter.java

@@ -0,0 +1,78 @@
+package edu.travel.filter;
+
+/**
+ * TokenAuthenticationFilter 类。
+ * <p>
+ * 描述:
+ *
+ * @author huangwenwen
+ * @date 2025/3/13
+ */
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import edu.travel.entity.AccountInfo;
+import edu.travel.service.BtAccountInfoService;
+import edu.travel.util.EncryptUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+
+    @Autowired
+    private BtAccountInfoService btAccountInfoService;  // 在单体应用中用数据库查询
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws ServletException, IOException {
+        // 从请求头获取 token
+        String token = request.getHeader("Authorization");
+
+        if (StringUtils.isNotBlank(token) && token.startsWith("Bearer ")) {
+            try {
+                String realToken = token.replace("Bearer ", "");
+                String json = EncryptUtil.decodeUTF8StringBase64(realToken);
+                JSONObject jsonObject = JSON.parseObject(json);
+
+                // 获取用户名(电话)
+                String phone = jsonObject.getString("principal");
+
+                // 在单体应用中直接从数据库查询用户
+                AccountInfo accountInfo = btAccountInfoService.findByPhone(phone);
+                if (accountInfo == null) {
+                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User not found");
+                    return;
+                }
+
+                // 获取权限
+                String[] authorities = jsonObject.getJSONArray("authorities").toArray(new String[0]);
+
+                // 创建 Spring Security 认证对象
+                UsernamePasswordAuthenticationToken authenticationToken =
+                        new UsernamePasswordAuthenticationToken(accountInfo, null, AuthorityUtils.createAuthorityList(authorities));
+                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+
+                // 将认证对象放入 SecurityContext
+                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+            } catch (Exception e) {
+                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
+                return;
+            }
+        }
+
+        filterChain.doFilter(request, response);
+    }
+}

+ 41 - 0
babyApplication-web/src/main/resources/application-dev.properties

@@ -0,0 +1,41 @@
+spring.application.name=baby
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:mysql://101.126.146.250:3306/edu?useUnicode=true&characterEncoding=UTF8&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=XYY1q2w!
+
+mybatis.mapperLocations=classpath:/mapper/*Mapper.xml
+
+mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+huaweicloud.obs.mode = 1
+huaweicloud.obs.expireSeconds=1000
+huaweicloud.obs.endpoint=obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.obs.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.obs.bucketName=v-xiaoyaotravel
+huaweicloud.moderation.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.moderation.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.moderation.region=cn-north-4
+huaweicloud.moderation.projectId=23089a903d5041b4a55170556cf8cae1
+
+huaweicloud.obs.folder = fuint_uploads
+#huaweicloud.obs.domain = https://v-xiaoyaotravel.obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.domain = https://v.xiaoyaotravel.com
+
+images.root=C:/fuintFoodSystem_v1.3/fuintBackend/fuint-application/target/classes
+images.path=/static/uploadImages/
+
+images.upload.url=http://localhost:8080
+
+spring.redis.host=localhost
+spring.redis.port=6379
+spring.redis.database=0
+
+spring.jackson.date-format= yyyy-MM-dd HH:mm
+spring.jackson.time-zone= GMT+8
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=20MB
+spring.servlet.multipart.max-request-size=200MB

+ 41 - 0
babyApplication-web/src/main/resources/application-prod.properties

@@ -0,0 +1,41 @@
+spring.application.name=baby
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:mysql://101.126.146.250:3306/edu?useUnicode=true&characterEncoding=UTF8&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=XYY1q2w!
+
+mybatis.mapperLocations=classpath:/mapper/*Mapper.xml
+
+mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+huaweicloud.obs.mode = 1
+huaweicloud.obs.expireSeconds=1000
+huaweicloud.obs.endpoint=obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.obs.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.obs.bucketName=v-xiaoyaotravel
+huaweicloud.moderation.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.moderation.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.moderation.region=cn-north-4
+huaweicloud.moderation.projectId=23089a903d5041b4a55170556cf8cae1
+
+huaweicloud.obs.folder = fuint_uploads
+#huaweicloud.obs.domain = https://v-xiaoyaotravel.obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.domain = https://v.xiaoyaotravel.com
+
+images.root=C:/fuintFoodSystem_v1.3/fuintBackend/fuint-application/target/classes
+images.path=/static/uploadImages/
+
+images.upload.url=http://localhost:8080
+
+spring.redis.host=localhost
+spring.redis.port=6379
+spring.redis.database=0
+
+spring.jackson.date-format= yyyy-MM-dd HH:mm
+spring.jackson.time-zone= GMT+8
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=20MB
+spring.servlet.multipart.max-request-size=200MB

+ 50 - 0
babyApplication-web/src/main/resources/application-test.properties

@@ -0,0 +1,50 @@
+server.port=8081
+spring.application.name=baby
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:mysql://101.126.146.250:3306/baby?useUnicode=true&characterEncoding=UTF8&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=XYY1q2w!
+
+mybatis.mapperLocations=classpath:/mapper/*Mapper.xml
+
+mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+huaweicloud.obs.mode = 1
+huaweicloud.obs.expireSeconds=1000
+huaweicloud.obs.endpoint=obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.obs.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.obs.bucketName=v-xiaoyaotravel
+huaweicloud.moderation.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.moderation.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.moderation.region=cn-north-4
+huaweicloud.moderation.projectId=23089a903d5041b4a55170556cf8cae1
+
+huaweicloud.obs.folder = fuint_uploads
+#huaweicloud.obs.domain = https://v-xiaoyaotravel.obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.domain = https://v.xiaoyaotravel.com
+
+images.root=C:/fuintFoodSystem_v1.3/fuintBackend/fuint-application/target/classes
+images.path=/static/uploadImages/
+
+images.upload.url=http://localhost:8080
+
+spring.redis.host=192.168.1.44
+spring.redis.port=6379
+spring.redis.database=0
+
+spring.jackson.date-format= yyyy-MM-dd HH:mm
+spring.jackson.time-zone= GMT+8
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=20MB
+spring.servlet.multipart.max-request-size=200MB
+
+sms.blends.huoshan.ak=AKLTYzA3ZDNiY2M5MWNlNGM1NThhM2ZlN2JhNTIyYWMxZDA
+sms.blends.huoshan.sk=WXpVME1USTBNbVprTnpKaU5HTTNORGhsT1dJNU1tUXlaVFl4TjJVeE1Uaw==
+sms.blends.huoshan.smsAccount=7fe76339
+sms.blends.huoshan.chinaSign=??????????
+sms.blends.huoshan.otherSign=XYTravel
+sms.blends.huoshan.chinaTemplateId=ST_7fe71e56
+sms.blends.huoshan.otherTemplateId=ST_7fe70c7c

+ 51 - 0
babyApplication-web/src/main/resources/application.properties

@@ -0,0 +1,51 @@
+server.port=8081
+spring.application.name=baby
+spring.profiles.active=test
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.url=jdbc:mysql://101.126.146.250:3306/baby?useUnicode=true&characterEncoding=UTF8&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=XYY1q2w!
+
+mybatis.mapperLocations=classpath:/mapper/*Mapper.xml
+
+mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
+
+huaweicloud.obs.mode = 1
+huaweicloud.obs.expireSeconds=1000
+huaweicloud.obs.endpoint=obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.obs.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.obs.bucketName=v-xiaoyaotravel
+huaweicloud.moderation.accessKey=C9WI47G4DXXN2EMIL1OO
+huaweicloud.moderation.secretKey=tfrZ9aw8wjfotUlG6IUCMjtAgzIzErL5qpPPt9AO
+huaweicloud.moderation.region=cn-north-4
+huaweicloud.moderation.projectId=23089a903d5041b4a55170556cf8cae1
+
+huaweicloud.obs.folder = fuint_uploads
+#huaweicloud.obs.domain = https://v-xiaoyaotravel.obs.cn-north-4.myhuaweicloud.com
+huaweicloud.obs.domain = https://v.xiaoyaotravel.com
+
+images.root=C:/fuintFoodSystem_v1.3/fuintBackend/fuint-application/target/classes
+images.path=/static/uploadImages/
+
+images.upload.url=http://localhost:8080
+
+spring.redis.host=192.168.1.44
+spring.redis.port=6379
+spring.redis.database=0
+
+spring.jackson.date-format= yyyy-MM-dd HH:mm
+spring.jackson.time-zone= GMT+8
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=20MB
+spring.servlet.multipart.max-request-size=200MB
+
+sms.blends.huoshan.ak=AKLTYzA3ZDNiY2M5MWNlNGM1NThhM2ZlN2JhNTIyYWMxZDA
+sms.blends.huoshan.sk=WXpVME1USTBNbVprTnpKaU5HTTNORGhsT1dJNU1tUXlaVFl4TjJVeE1Uaw==
+sms.blends.huoshan.smsAccount=7fe76339
+sms.blends.huoshan.chinaSign=??????????
+sms.blends.huoshan.otherSign=XYTravel
+sms.blends.huoshan.chinaTemplateId=ST_7fe71e56
+sms.blends.huoshan.otherTemplateId=ST_7fe70c7c

+ 212 - 0
pom.xml

@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>edu.travel</groupId>
+    <artifactId>babyApplication</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <modules>
+        <module>babyApplication-common</module>
+        <module>babyApplication-service</module>
+        <module>babyApplication-web</module>
+        <module>babyApplication-dao</module>
+        <module>babyApplication-model</module>
+    </modules>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.12.RELEASE</version>
+    </parent>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+            <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
+            <mysql.version>8.0.22</mysql.version>
+            <druid.version>1.2.16</druid.version>
+            <mybatis.plus.verion>3.4.0</mybatis.plus.verion>
+            <fastjson.version>1.2.83</fastjson.version>
+            <hutool.version>5.8.23</hutool.version>
+            <alibaba.version>2.2.10-RC1</alibaba.version>
+            <mybaits.plus.annotation.version>3.4.0</mybaits.plus.annotation.version>
+            <bootstrap.version>4.1.3</bootstrap.version>
+            <pg.version>42.6.0</pg.version>
+            <sharding.sphere.version>5.1.0</sharding.sphere.version>
+            <obs.version>3.20.6.1</obs.version>
+            <oss.version>3.10.2</oss.version>
+            <cos.version>5.6.54</cos.version>
+            <minio.version>7.0.2</minio.version>
+            <elasticsearch.version>7.10.0</elasticsearch.version>
+            <debezium.version>1.9.4.final</debezium.version>
+            <beanutils.version>1.9.4</beanutils.version>
+            <modelmapper.version>3.2.0</modelmapper.version>
+            <excel.version>3.3.2</excel.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>easyexcel</artifactId>
+                <version>${excel.version}</version> <!-- 检查最新版本 -->
+            </dependency>
+            <!-- 对象转换工具-->
+            <dependency>
+                <groupId>org.modelmapper</groupId>
+                <artifactId>modelmapper</artifactId>
+                <version>${modelmapper.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-beanutils</groupId>
+                <artifactId>commons-beanutils</artifactId>
+                <version>${beanutils.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.debezium</groupId>
+                <artifactId>debezium-api</artifactId>
+                <version>${debezium.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.debezium</groupId>
+                <artifactId>debezium-embedded</artifactId>
+                <version>${debezium.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.debezium</groupId>
+                <artifactId>debezium-connector-postgres</artifactId>
+                <version>${debezium.version}</version>
+            </dependency>
+            <!--引入es-high-level-client相关依赖  start-->
+            <dependency>
+                <groupId>org.elasticsearch</groupId>
+                <artifactId>elasticsearch</artifactId>
+                <version>${elasticsearch.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.elasticsearch.client</groupId>
+                <artifactId>elasticsearch-rest-client</artifactId>
+                <version>${elasticsearch.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.elasticsearch.client</groupId>
+                <artifactId>elasticsearch-rest-high-level-client</artifactId>
+                <version>${elasticsearch.version}</version>
+            </dependency>
+            <!--引入es-high-level-client相关依赖  end-->
+            <dependency>
+                <groupId>io.minio</groupId>
+                <artifactId>minio</artifactId>
+                <version>${minio.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.aliyun.oss</groupId>
+                <artifactId>aliyun-sdk-oss</artifactId>
+                <version>${oss.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.qcloud</groupId>
+                <artifactId>cos_api</artifactId>
+                <version>${cos.version}</version>
+                <scope>provided</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.huaweicloud</groupId>
+                <artifactId>esdk-obs-java</artifactId>
+                <version>${obs.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-starter-bootstrap</artifactId>
+                <version>${bootstrap.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <version>${alibaba.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring.cloud.version}</version> <!-- 或者使用具体的子版本 -->
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-boot-starter</artifactId>
+                <version>${mybatis.plus.verion}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-core</artifactId>
+                <version>${mybatis.plus.verion}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-extension</artifactId>
+                <version>${mybatis.plus.verion}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-annotation</artifactId>
+                <version>${mybaits.plus.annotation.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.postgresql</groupId>
+                <artifactId>postgresql</artifactId>
+                <version>${pg.version}</version>
+            </dependency>
+
+        </dependencies>
+
+    </dependencyManagement>
+
+    <build>
+        <pluginManagement> <!-- 使用 pluginManagement 确保子模块继承插件配置 -->
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.8.1</version>
+                    <configuration>
+                        <source>1.8</source>
+                        <target>1.8</target>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+</project>