소스 검색

refactor: 异步生成许愿图片逻辑提取至 ImageService

- appendWishImage 移入 ImageServiceImpl,@Async("mobileTaskExecutor") 异步执行
- AbstractUserWishService 精简,仅保留 treeWishesCounter
- UserWishServiceImpl.create 通过 imageService 代理调用,确保异步生效

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tanlie 2 주 전
부모
커밋
08ed3e0bb0

+ 117 - 0
wishing-platform/platform-service/platform-service-admin/src/main/resources/logback-spring.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <contextName>logback</contextName>
+
+    <property name="LOG_HOME" value="./logs/admin"/>
+    <springProperty scope="context" name="applicationName" source="spring.application.name" defaultValue="localhost" />
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>debug</level>
+        </filter>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [${applicationName},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!--2. 输出到文档-->
+    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
+    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${LOG_HOME}/debug.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
+    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/info.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
+    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/warn.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/error.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <springProfile name="dev">
+        <logger name="com.sdcm.pmp" level="debug"/>
+    </springProfile>
+
+    <root level="info">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="DEBUG_FILE"/>
+        <appender-ref ref="INFO_FILE"/>
+        <appender-ref ref="WARN_FILE"/>
+        <appender-ref ref="ERROR_FILE"/>
+    </root>
+</configuration>

+ 2 - 1
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/config/MobileMvcConfig.java

@@ -4,6 +4,7 @@ import cn.qinys.platform.properties.SystemProperties;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.AsyncTaskExecutor;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@@ -23,7 +24,7 @@ public class MobileMvcConfig implements WebMvcConfigurer {
      * 线程池配置
      */
     @Bean("mobileTaskExecutor")
-    public Executor mobileTaskExecutor() {
+    public AsyncTaskExecutor mobileTaskExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(4);
         executor.setMaxPoolSize(16);

+ 4 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/service/ImageService.java

@@ -1,5 +1,7 @@
 package cn.qinys.platform.mobile.service;
 
+import cn.qinys.platform.entity.wishing.UserWish;
+
 /**
  * @author lie tan
  * @description
@@ -10,4 +12,6 @@ public interface ImageService {
 
     String getImageUrl(String msg);
 
+    void appendWishImage(UserWish wish);
+
 }

+ 0 - 54
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/service/impl/AbstractUserWishService.java

@@ -1,23 +1,12 @@
 package cn.qinys.platform.mobile.service.impl;
 
-import cn.qinys.platform.entity.wishing.ChatMessage;
-import cn.qinys.platform.entity.wishing.SpringAiChatMemory;
-import cn.qinys.platform.entity.wishing.UserWish;
 import cn.qinys.platform.entity.wishing.WishingTreeExtension;
-import cn.qinys.platform.mobile.constants.MsgTypeEnum;
 import cn.qinys.platform.mobile.mapper.ChatMessageMapper;
 import cn.qinys.platform.mobile.mapper.SpringAiChatMemoryMapper;
 import cn.qinys.platform.mobile.mapper.UserWishMapper;
 import cn.qinys.platform.mobile.mapper.WishingTreeExtensionMapper;
 import cn.qinys.platform.mobile.service.ImageService;
-import com.alibaba.fastjson2.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import jakarta.annotation.Resource;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-
-import java.util.List;
 
 /**
  * @author lie tan
@@ -28,15 +17,6 @@ public abstract class AbstractUserWishService {
 
     @Resource
     WishingTreeExtensionMapper treeExtensionMapper;
-    @Resource
-    ImageService imageService;
-    @Resource
-    SpringAiChatMemoryMapper memoryMapper;
-    @Resource
-    UserWishMapper userWishMapper;
-    @Resource
-    ChatMessageMapper messageMapper;
-
 
     public void treeWishesCounter(Integer treeId, Integer isPublic) {
         WishingTreeExtension extension = treeExtensionMapper.selectByTreeId(treeId);
@@ -57,38 +37,4 @@ public abstract class AbstractUserWishService {
     }
 
 
-
-    @Async
-    public void appendWishImage(UserWish wish) {
-        QueryWrapper<SpringAiChatMemory> wrapper = new QueryWrapper<>();
-        wrapper.eq("conversation_id", wish.getUserId())
-                .orderByDesc("timestamp")
-                .last("limit 10");
-        List<SpringAiChatMemory> memoryList = memoryMapper.selectList(wrapper);
-        if (memoryList == null || memoryList.isEmpty()) {
-            return;
-        }
-
-        String sb = "请根据用户许下的愿望,以及最近几轮对话的内容,生成一张与许愿相关的图片。用户的愿望为" +
-                "content:" + wish.getContent() +
-                "tag:" + wish.getTags() +
-                "最近的聊天记录内容为:" + JSON.toJSONString(memoryList);
-
-        String imageUrl = imageService.getImageUrl(sb);
-
-        if (StringUtils.hasText(imageUrl)) {
-            wish.setImages(JSON.toJSONString(List.of(imageUrl)));
-            userWishMapper.updateById(wish);
-            ChatMessage chatMessage = new ChatMessage();
-            chatMessage.setUserId(wish.getUserId());
-            chatMessage.setTreeId(wish.getTreeId());
-            chatMessage.setType(MsgTypeEnum.TEXT.getValue());
-            chatMessage.setContent("小愿已为您的愿望生成了一张图片,您可以到许愿树下查看哦~~");
-            chatMessage.setRole("ai");
-            messageMapper.insert(chatMessage);
-        }
-
-
-    }
-
 }

+ 54 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/service/impl/ImageServiceImpl.java

@@ -1,11 +1,22 @@
 package cn.qinys.platform.mobile.service.impl;
 
+import cn.qinys.platform.entity.wishing.ChatMessage;
+import cn.qinys.platform.entity.wishing.SpringAiChatMemory;
+import cn.qinys.platform.entity.wishing.UserWish;
+import cn.qinys.platform.mobile.constants.MsgTypeEnum;
+import cn.qinys.platform.mobile.mapper.ChatMessageMapper;
+import cn.qinys.platform.mobile.mapper.SpringAiChatMemoryMapper;
+import cn.qinys.platform.mobile.mapper.UserWishMapper;
 import cn.qinys.platform.mobile.service.ImageService;
 import cn.qinys.platform.mobile.util.QwenImage;
 import cn.qinys.platform.properties.SystemProperties;
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
 
 import java.io.InputStream;
 import java.net.URI;
@@ -14,6 +25,7 @@ import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
+import java.util.List;
 import java.util.UUID;
 
 /**
@@ -28,6 +40,48 @@ public class ImageServiceImpl implements ImageService {
     @Resource
     private SystemProperties systemProperties;
 
+    @Resource
+    SpringAiChatMemoryMapper memoryMapper;
+    @Resource
+    UserWishMapper userWishMapper;
+    @Resource
+    ChatMessageMapper messageMapper;
+
+    @Override
+    @Async("mobileTaskExecutor")
+    public void appendWishImage(UserWish wish) {
+        QueryWrapper<SpringAiChatMemory> wrapper = new QueryWrapper<>();
+        wrapper.eq("conversation_id", wish.getUserId())
+                .orderByDesc("timestamp")
+                .last("limit 10");
+        List<SpringAiChatMemory> memoryList = memoryMapper.selectList(wrapper);
+        if (memoryList == null || memoryList.isEmpty()) {
+            return;
+        }
+
+        String sb = "请根据用户许下的愿望,以及最近几轮对话的内容,生成一张与许愿相关的图片,图片不要太大,控制在500k以内。用户的愿望为" +
+                "content:" + wish.getContent() +
+                "tag:" + wish.getTags() +
+                "最近的聊天记录内容为:" + JSON.toJSONString(memoryList);
+
+        String imageUrl = this.getImageUrl(sb);
+
+        if (StringUtils.hasText(imageUrl)) {
+            wish.setImages(JSON.toJSONString(List.of(imageUrl)));
+            userWishMapper.updateById(wish);
+            ChatMessage chatMessage = new ChatMessage();
+            chatMessage.setUserId(wish.getUserId());
+            chatMessage.setTreeId(wish.getTreeId());
+            chatMessage.setType(MsgTypeEnum.TEXT.getValue());
+            chatMessage.setContent("小愿已为您的愿望生成了一张图片,您可以到许愿树下查看哦~~");
+            chatMessage.setRole("ai");
+            messageMapper.insert(chatMessage);
+        }
+
+
+    }
+
+
     @Override
     public String getImageUrl(String msg) {
         // 调用 Qwen 生成图片

+ 6 - 2
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/service/impl/UserWishServiceImpl.java

@@ -9,6 +9,7 @@ import cn.qinys.platform.mobile.req.WishCreateReq;
 import cn.qinys.platform.mobile.req.WishPageReq;
 import cn.qinys.platform.mobile.resp.WishDetailResp;
 import cn.qinys.platform.mobile.resp.WishPageResp;
+import cn.qinys.platform.mobile.service.ImageService;
 import cn.qinys.platform.mobile.service.UserWishService;
 import com.alibaba.fastjson2.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -28,6 +29,9 @@ public class UserWishServiceImpl extends AbstractUserWishService implements User
     @Resource
     private WishingTreeMapper treeMapper;
 
+    @Resource
+    private ImageService imageService;
+
 
     @Override
     public Page<WishPageResp> pageByTree(Integer treeId, WishPageReq req) {
@@ -56,7 +60,7 @@ public class UserWishServiceImpl extends AbstractUserWishService implements User
         return wishMapper.selectWishDetail(id);
     }
 
-    @Transactional(rollbackFor = Exception.class)
+
     @Override
     public void create(WishCreateReq req) {
         WishingTree tree = treeMapper.selectById(req.getTreeId());
@@ -74,7 +78,7 @@ public class UserWishServiceImpl extends AbstractUserWishService implements User
         wish.setType(req.getType());
         wishMapper.insert(wish);
         this.treeWishesCounter(req.getTreeId(), wish.getIsPublic());
-        this.appendWishImage(wish);
+        imageService.appendWishImage(wish);
     }
 
     @Override

+ 1 - 1
wishing-platform/platform-service/platform-service-mobile/src/main/java/cn/qinys/platform/mobile/util/QwenImage.java

@@ -41,7 +41,7 @@ public class QwenImage {
         parameters.put("watermark", false);
         parameters.put("prompt_extend", true);
         parameters.put("negative_prompt", "低分辨率,低画质,肢体畸形,手指畸形,画面过饱和,蜡像感,人脸无细节,过度光滑,画面具有AI感。构图混乱。文字模糊,扭曲。");
-        parameters.put("size", "1000*1000");
+        parameters.put("size", "720*720");
 
         MultiModalConversationParam param = MultiModalConversationParam.builder()
                 .apiKey(apiKey)

+ 117 - 0
wishing-platform/platform-service/platform-service-mobile/src/main/resources/logback-spring.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <contextName>logback</contextName>
+
+    <property name="LOG_HOME" value="./logs/mobile"/>
+    <springProperty scope="context" name="applicationName" source="spring.application.name" defaultValue="localhost" />
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>debug</level>
+        </filter>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [${applicationName},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!--2. 输出到文档-->
+    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
+    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${LOG_HOME}/debug.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
+    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/info.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
+    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/warn.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/error.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <springProfile name="dev">
+        <logger name="com.sdcm.pmp" level="debug"/>
+    </springProfile>
+
+    <root level="info">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="DEBUG_FILE"/>
+        <appender-ref ref="INFO_FILE"/>
+        <appender-ref ref="WARN_FILE"/>
+        <appender-ref ref="ERROR_FILE"/>
+    </root>
+</configuration>

+ 3 - 4
wishing-platform/platform-service/platform-service-mobile/src/test/java/cn/qinys/platform/mobile/service/impl/UserWishServiceImplTest.java

@@ -1,7 +1,7 @@
 package cn.qinys.platform.mobile.service.impl;
 
-import cn.qinys.platform.entity.wishing.UserWish;
 import cn.qinys.platform.mobile.mapper.UserWishMapper;
+import cn.qinys.platform.mobile.service.ImageService;
 import jakarta.annotation.Resource;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -15,14 +15,13 @@ import org.springframework.boot.test.context.SpringBootTest;
 class UserWishServiceImplTest {
 
     @Resource
-    UserWishServiceImpl userWishService;
+    ImageService imageService;
     @Resource
     UserWishMapper userWishMapper;
 
     @Test
     void appendWishImage() {
-        UserWish userWish = userWishMapper.selectById(84);
-        userWishService.appendWishImage(userWish);
+
     }
 
 

+ 117 - 0
wishing-platform/platform-service/platform-service-upms/src/main/resources/logback-spring.xml

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <contextName>logback</contextName>
+
+    <property name="LOG_HOME" value="./logs/upms"/>
+    <springProperty scope="context" name="applicationName" source="spring.application.name" defaultValue="localhost" />
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>debug</level>
+        </filter>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [${applicationName},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!--2. 输出到文档-->
+    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
+    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${LOG_HOME}/debug.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
+    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/info.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
+    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/warn.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/error.log</file>
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} >====> [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM, aux}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <springProfile name="dev">
+        <logger name="com.sdcm.pmp" level="debug"/>
+    </springProfile>
+
+    <root level="info">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="DEBUG_FILE"/>
+        <appender-ref ref="INFO_FILE"/>
+        <appender-ref ref="WARN_FILE"/>
+        <appender-ref ref="ERROR_FILE"/>
+    </root>
+</configuration>