From 9eb9223bd832fc9d2d13f28228814fe960da719a Mon Sep 17 00:00:00 2001 From: wangli Date: Fri, 30 Jan 2026 21:48:57 +0800 Subject: [PATCH] init --- .../dto/request/AccountUpdateRequest.java | 15 +++ .../dto/response/DefaultReplyResponse.java | 26 ++++ .../dto/response/GoofishAccountResponse.java | 6 + .../core/entity/DefaultReplyEntity.java | 45 +++++++ .../repository/DefaultReplyRepository.java | 9 ++ .../service/GoofishPwdLoginService.java | 5 +- .../xianyu/goofish/util/SliderUtils.java | 114 +++++++++++++----- .../controller/GoofishAccountController.java | 49 ++++++++ .../server/controller/KeywordController.java | 61 ++++++++-- .../src/main/resources/application.yml | 2 +- 10 files changed, 289 insertions(+), 43 deletions(-) create mode 100644 xianyu-common/src/main/java/top/biwin/xinayu/common/dto/request/AccountUpdateRequest.java create mode 100644 xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/DefaultReplyResponse.java create mode 100644 xianyu-core/src/main/java/top/biwin/xianyu/core/entity/DefaultReplyEntity.java create mode 100644 xianyu-core/src/main/java/top/biwin/xianyu/core/repository/DefaultReplyRepository.java diff --git a/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/request/AccountUpdateRequest.java b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/request/AccountUpdateRequest.java new file mode 100644 index 0000000..9c7b4d9 --- /dev/null +++ b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/request/AccountUpdateRequest.java @@ -0,0 +1,15 @@ +package top.biwin.xinayu.common.dto.request; + +import lombok.Data; + +/** + * TODO + * + * @author wangli + * @since 2026-01-30 21:28 + */ +@Data +public class AccountUpdateRequest { + private Boolean enabled; + private String remark; +} diff --git a/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/DefaultReplyResponse.java b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/DefaultReplyResponse.java new file mode 100644 index 0000000..a5e2bac --- /dev/null +++ b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/DefaultReplyResponse.java @@ -0,0 +1,26 @@ +package top.biwin.xinayu.common.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +/** + * TODO + * + * @author wangli + * @since 2026-01-30 21:10 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class DefaultReplyResponse extends BaseResponse { + + private Boolean enabled; + @JsonProperty("reply_content") + private String replyContent; + @JsonProperty("reply_once") + private Boolean replyOnce; + @JsonProperty("reply_image_url") + private String replyImageUrl; +} diff --git a/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/GoofishAccountResponse.java b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/GoofishAccountResponse.java index 70d671e..bad9b31 100644 --- a/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/GoofishAccountResponse.java +++ b/xianyu-common/src/main/java/top/biwin/xinayu/common/dto/response/GoofishAccountResponse.java @@ -1,7 +1,10 @@ package top.biwin.xinayu.common.dto.response; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; /** * TODO @@ -10,6 +13,9 @@ import lombok.Data; * @since 2026-01-22 21:52 */ @Data +@Builder +@AllArgsConstructor +@NoArgsConstructor public class GoofishAccountResponse { private String id; private String cookie; diff --git a/xianyu-core/src/main/java/top/biwin/xianyu/core/entity/DefaultReplyEntity.java b/xianyu-core/src/main/java/top/biwin/xianyu/core/entity/DefaultReplyEntity.java new file mode 100644 index 0000000..eab3968 --- /dev/null +++ b/xianyu-core/src/main/java/top/biwin/xianyu/core/entity/DefaultReplyEntity.java @@ -0,0 +1,45 @@ +package top.biwin.xianyu.core.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name = "default_replies") +public class DefaultReplyEntity { + + @Id + @Column(name = "goofish_id") + @JsonProperty("goofish_id") + private String goofishId; + + private Boolean enabled = false; + + @Column(name = "reply_content", columnDefinition = "TEXT") + @JsonProperty("reply_content") + private String replyContent; + + @Column(name = "reply_image_url") + @JsonProperty("reply_image_url") + private String replyImageUrl; + + @Column(name = "reply_once") + @JsonProperty("reply_once") + private Boolean replyOnce = false; + + @CreationTimestamp + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @UpdateTimestamp + @Column(name = "updated_at") + private LocalDateTime updatedAt; +} diff --git a/xianyu-core/src/main/java/top/biwin/xianyu/core/repository/DefaultReplyRepository.java b/xianyu-core/src/main/java/top/biwin/xianyu/core/repository/DefaultReplyRepository.java new file mode 100644 index 0000000..1332b7a --- /dev/null +++ b/xianyu-core/src/main/java/top/biwin/xianyu/core/repository/DefaultReplyRepository.java @@ -0,0 +1,9 @@ +package top.biwin.xianyu.core.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import top.biwin.xianyu.core.entity.DefaultReplyEntity; + +@Repository +public interface DefaultReplyRepository extends JpaRepository { +} diff --git a/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/service/GoofishPwdLoginService.java b/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/service/GoofishPwdLoginService.java index 54ce669..0925e7d 100644 --- a/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/service/GoofishPwdLoginService.java +++ b/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/service/GoofishPwdLoginService.java @@ -86,10 +86,13 @@ public class GoofishPwdLoginService { boolean resolveResult = attemptSolveSlider(loginFrame, account, new AtomicInteger(3)); log.debug("【{}】滑块结果: {}!", account, resolveResult ? "成功" : "失败"); if(resolveResult) { + // 这里可能已经登录成功,等待选择是否持久化登录 + loginFrame.waitForTimeout(10000); log.debug("【{}】验证是否登录成功...", account); Frame lastCheckFrame = findLoginFrame(page, account); if(Objects.nonNull(lastCheckFrame)) { - log.debug("【{}】登录失败,仍存在登录页面...", account); + log.error("【{}】登录失败,仍存在登录页面...", account); + return; } } else { log.error("【{}】账号密码登录失败", account); diff --git a/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/util/SliderUtils.java b/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/util/SliderUtils.java index 1dce622..e44d015 100644 --- a/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/util/SliderUtils.java +++ b/xianyu-goofish/src/main/java/top/biwin/xianyu/goofish/util/SliderUtils.java @@ -3,6 +3,7 @@ package top.biwin.xianyu.goofish.util; import cn.hutool.core.collection.CollUtil; import com.microsoft.playwright.ElementHandle; import com.microsoft.playwright.Frame; +import com.microsoft.playwright.Locator; import com.microsoft.playwright.Mouse; import com.microsoft.playwright.options.BoundingBox; import lombok.extern.slf4j.Slf4j; @@ -12,6 +13,9 @@ import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; +import com.microsoft.playwright.CDPSession; +import com.google.gson.JsonObject; + /** * 滑块验证码处理工具类 * 模拟人类操作行为解决滑块验证 @@ -58,7 +62,6 @@ public final class SliderUtils { // 定位滑块按钮 sliderButton = frame.querySelector("#nc_1_n1z"); if (sliderButton == null) sliderButton = frame.querySelector(".nc_iconfont"); - if (sliderButton != null && sliderButton.isVisible()) { log.info("【{}-处理滑块】检测到滑块验证,Frame: {}", goofishId, frame.url()); BoundingBox box = sliderButton.boundingBox(); @@ -79,15 +82,10 @@ public final class SliderUtils { // 等待验证结果 Thread.sleep(800 + ThreadLocalRandom.current().nextInt(400)); -// // 检查滑块是否消失(成功标志) -// if (!sliderButton.isVisible()) { -// log.info("【{}-处理滑块】滑块验证成功!(按钮已消失)", goofishId); -// return true; -// } - ElementHandle elementHandle = frame.querySelector("#nc_1_refresh1"); - if (Objects.nonNull(elementHandle)) { + ElementHandle sliderBox = frame.querySelector("#nc_1_refresh1"); + if (Objects.nonNull(sliderBox) && sliderBox.isVisible()) { log.info("【{}-处理滑块】滑块验证失败,点击滑块重试!", goofishId); - elementHandle.click(); + sliderBox.click(); if (maxRetryCount.decrementAndGet() > 0) { return attemptSolveSlider(frame, goofishId, maxRetryCount); } else { @@ -96,6 +94,8 @@ public final class SliderUtils { } } return success; + } else { + log.debug("【{}-处理滑块】未找到滑块按钮,可能是已经登录成功!", goofishId); } } catch (Exception e) { log.warn("【{}-处理滑块】解决滑块时出错: {}", goofishId, e.getMessage(), e); @@ -119,46 +119,98 @@ public final class SliderUtils { * @return 是否执行成功 */ private static boolean performSmoothSlide(Frame frame, BoundingBox buttonBox, double distance, String goofishId) { + CDPSession cdpSession = null; try { ThreadLocalRandom random = ThreadLocalRandom.current(); + cdpSession = frame.page().context().newCDPSession(frame.page()); - // 计算滑块起始位置(微小随机偏移) - double startX = buttonBox.x + buttonBox.width / 2 + (random.nextDouble() - 0.5) * 4; - double startY = buttonBox.y + buttonBox.height / 2 + (random.nextDouble() - 0.5) * 3; + // 1. 计算人类特征起点(加入随机生理震颤偏移) + double startX = buttonBox.x + buttonBox.width / 2 + random.nextDouble(-5.0, 5.0); + double startY = buttonBox.y + buttonBox.height / 2 + random.nextDouble(-3.0, 3.0); - // 步骤1:移动鼠标到滑块位置 - frame.page().mouse().move(startX, startY); + // 2. 鼠标移动到起点 + JsonObject moveParams = new JsonObject(); + moveParams.addProperty("type", "mouseMoved"); + moveParams.addProperty("x", startX); + moveParams.addProperty("y", startY); + cdpSession.send("Input.dispatchMouseEvent", moveParams); - // 步骤2:短暂停顿(人类反应时间:100-250ms) - Thread.sleep(100 + random.nextInt(150)); + // 视觉确认时间 + Thread.sleep(80 + random.nextInt(120)); - // 步骤3:按下鼠标 - frame.page().mouse().down(); + // 3. 点击鼠标按下 + JsonObject downParams = new JsonObject(); + downParams.addProperty("type", "mousePressed"); + downParams.addProperty("button", "left"); + downParams.addProperty("clickCount", 1); + downParams.addProperty("x", startX); + downParams.addProperty("y", startY); + cdpSession.send("Input.dispatchMouseEvent", downParams); - // 步骤4:按下后极短延迟(30-60ms) - Thread.sleep(30 + random.nextInt(30)); + // 肌肉准备发力延迟 + Thread.sleep(40 + random.nextInt(40)); - // 步骤5:生成丝滑轨迹 + // 4. 执行轨迹渲染 List trajectory = - BrowserTrajectoryUtils.generateFastTrajectory(distance); + BrowserTrajectoryUtils.generateSmoothTrajectory(distance); - log.debug("【{}-处理滑块】生成轨迹点数: {}", goofishId, trajectory.size()); + log.info("【{}-处理滑块】CDP 发送高仿真轨迹,总计点数: {}", goofishId, trajectory.size()); - // 步骤6:一气呵成快速滑动!!不加任何sleep!! - for (BrowserTrajectoryUtils.TrajectoryPoint point : trajectory) { - frame.page().mouse().move(startX + point.x, startY + point.y); - // 不加sleep!让Playwright自己处理速度! + int totalPoints = trajectory.size(); + for (int i = 0; i < totalPoints; i++) { + BrowserTrajectoryUtils.TrajectoryPoint point = trajectory.get(i); + + // 坐标映射:基础位置 + 轨迹偏移 + 微小生理抖动 + double targetX = startX + point.x; + double targetY = startY + point.y + random.nextDouble(-0.8, 0.8); + + JsonObject dragParams = new JsonObject(); + dragParams.addProperty("type", "mouseMoved"); + dragParams.addProperty("button", "left"); + dragParams.addProperty("x", targetX); + dragParams.addProperty("y", targetY); + cdpSession.send("Input.dispatchMouseEvent", dragParams); + + // 仿真节奏:菲茨定律应用。前期(0-40%)极速冲刺,后期(70%后)精准瞄准降速 + double progress = (double) i / totalPoints; + if (progress < 0.3) { + // 极速段 + if (i % 2 == 0) Thread.sleep(1 + random.nextInt(2)); + } else if (progress < 0.7) { + // 匀速段 + Thread.sleep(2 + random.nextInt(4)); + } else { + // 减速修正段:人眼在接近目标时会频繁修正,延迟拉长 + Thread.sleep(5 + random.nextInt(12)); + } } - // 步骤7:释放鼠标 - frame.page().mouse().up(); + // 瞄准终点后的生理停顿 + Thread.sleep(30 + random.nextInt(50)); - log.info("【{}-处理滑块】滑动执行完成,等待验证结果...", goofishId); + // 5. 释放鼠标(在终点附近的最后一次修正位置释放) + BrowserTrajectoryUtils.TrajectoryPoint lastPoint = trajectory.get(totalPoints - 1); + double finalX = startX + lastPoint.x; + double finalY = startY + lastPoint.y; + + JsonObject upParams = new JsonObject(); + upParams.addProperty("type", "mouseReleased"); + upParams.addProperty("button", "left"); + upParams.addProperty("clickCount", 1); + upParams.addProperty("x", finalX); + upParams.addProperty("y", finalY); + cdpSession.send("Input.dispatchMouseEvent", upParams); + + log.info("【{}-处理滑块】CDP 高仿交互已全量下发,Master 等待佳音吧! (๑•̀ㅂ•́)و✧", goofishId); return true; } catch (Exception e) { - log.error("【{}-处理滑块】执行滑动时出错: {}", goofishId, e.getMessage(), e); + log.error("【{}-处理滑块】CDP 执行滑动失败(可能是 JsonObject 序列化或协议异常): {}", goofishId, e.getMessage(), e); return false; + } finally { + if (cdpSession != null) { + cdpSession.detach(); + } } } } diff --git a/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/GoofishAccountController.java b/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/GoofishAccountController.java index da29f04..8161bd7 100644 --- a/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/GoofishAccountController.java +++ b/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/GoofishAccountController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -15,6 +16,7 @@ import top.biwin.xianyu.core.repository.GoofishAccountRepository; import top.biwin.xianyu.goofish.service.GoofishApiService; import top.biwin.xianyu.goofish.service.GoofishPwdLoginService; import top.biwin.xianyu.goofish.service.QrLoginService; +import top.biwin.xinayu.common.dto.request.AccountUpdateRequest; import top.biwin.xinayu.common.dto.request.GoofishAddCookieRequest; import top.biwin.xinayu.common.dto.request.GoofishPwdLoginRequest; import top.biwin.xinayu.common.dto.response.BaseResponse; @@ -153,4 +155,51 @@ public class GoofishAccountController { } goofishAccountRepository.delete(entity); } + + @PutMapping("/cookies/{id}/remark") + public ResponseEntity updateAccountRemark(@PathVariable("id") String goofishId, @RequestBody AccountUpdateRequest request) { + GoofishAccountEntity account = goofishAccountRepository.findById(goofishId).orElseThrow(() -> new IllegalStateException("账号不存在")); + if (!CurrentUserUtil.isSuperAdmin()) { + if (!Objects.equals(account.getUserId(), CurrentUserUtil.getCurrentUserId())) { + log.warn("该闲鱼账号不归属当前登录用户!"); + } + } + account.setRemark(request.getRemark()); + goofishAccountRepository.save(account); + return ResponseEntity.ok(GoofishAccountResponse.builder() + .id(account.getId()) + .cookie(account.getCookie()) + .enabled(account.getEnabled()) + .autoConfirm(account.getAutoConfirm()) + .remark(account.getRemark()) + .pauseDuration(account.getPauseDuration()) + .username(account.getUsername()) + .loginPassword(account.getPassword()) + .showBrowser(account.getShowBrowser() == 1) + .build()); + + } + + @PutMapping("/cookies/{id}/status") + public ResponseEntity updateAccountStatus(@PathVariable("id") String goofishId, @RequestBody AccountUpdateRequest request) { + GoofishAccountEntity account = goofishAccountRepository.findById(goofishId).orElseThrow(() -> new IllegalStateException("账号不存在")); + if (!CurrentUserUtil.isSuperAdmin()) { + if (!Objects.equals(account.getUserId(), CurrentUserUtil.getCurrentUserId())) { + log.warn("该闲鱼账号不归属当前登录用户!"); + } + } + account.setEnabled(request.getEnabled()); + goofishAccountRepository.save(account); + return ResponseEntity.ok(GoofishAccountResponse.builder() + .id(account.getId()) + .cookie(account.getCookie()) + .enabled(account.getEnabled()) + .autoConfirm(account.getAutoConfirm()) + .remark(account.getRemark()) + .pauseDuration(account.getPauseDuration()) + .username(account.getUsername()) + .loginPassword(account.getPassword()) + .showBrowser(account.getShowBrowser() == 1) + .build()); + } } diff --git a/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/KeywordController.java b/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/KeywordController.java index e3a40b8..8bb0010 100644 --- a/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/KeywordController.java +++ b/xianyu-server/src/main/java/top/biwin/xinayu/server/controller/KeywordController.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; @@ -11,16 +12,20 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import top.biwin.xianyu.core.entity.AiReplySettingEntity; +import top.biwin.xianyu.core.entity.DefaultReplyEntity; import top.biwin.xianyu.core.entity.GoofishAccountEntity; import top.biwin.xianyu.core.entity.KeywordEntity; import top.biwin.xianyu.core.repository.AiReplySettingRepository; +import top.biwin.xianyu.core.repository.DefaultReplyRepository; import top.biwin.xianyu.core.repository.GoofishAccountRepository; import top.biwin.xianyu.core.repository.KeywordRepository; import top.biwin.xinayu.common.dto.request.AiSettingRequest; +import top.biwin.xinayu.common.dto.response.DefaultReplyResponse; import top.biwin.xinayu.common.dto.response.KeywordResponse; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -39,6 +44,8 @@ public class KeywordController { private AiReplySettingRepository aiReplySettingRepository; @Autowired private KeywordRepository keywordRepository; + @Autowired + private DefaultReplyRepository defaultReplyRepository; @GetMapping("/ai-reply-settings") @@ -52,19 +59,19 @@ public class KeywordController { return ResponseEntity.ok(settings.stream().collect(Collectors.toMap(AiReplySettingEntity::getGoofishId, s -> s))); } - @GetMapping("/ai-reply-settings/{accountId}") - public ResponseEntity getAiSetting(@PathVariable String accountId) { - return ResponseEntity.ok(aiReplySettingRepository.findById(accountId).orElse(null)); + @GetMapping("/ai-reply-settings/{goofishId}") + public ResponseEntity getAiSetting(@PathVariable String goofishId) { + return ResponseEntity.ok(aiReplySettingRepository.findById(goofishId).orElse(null)); } - @PutMapping("/ai-reply-settings/{accountId}") - public ResponseEntity upsertAiSetting(@PathVariable String accountId, @RequestBody AiSettingRequest request) { + @PutMapping("/ai-reply-settings/{goofishId}") + public ResponseEntity upsertAiSetting(@PathVariable String goofishId, @RequestBody AiSettingRequest request) { // Upsert 逻辑:存在则更新,不存在则创建 - AiReplySettingEntity entity = aiReplySettingRepository.findById(accountId) + AiReplySettingEntity entity = aiReplySettingRepository.findById(goofishId) .orElseGet(() -> { // 不存在时创建新实体 AiReplySettingEntity newEntity = new AiReplySettingEntity(); - newEntity.setGoofishId(accountId); + newEntity.setGoofishId(goofishId); return newEntity; }); // 忽略 null 值,防止前端未传的字段覆盖已有值或默认值 @@ -72,11 +79,11 @@ public class KeywordController { return ResponseEntity.ok(aiReplySettingRepository.save(entity)); } - @GetMapping("/keywords-with-item-id/{gid}") - public ResponseEntity> getKeywordsWithItemId(@PathVariable Long gid) { + @GetMapping("/keywords-with-item-id/{goofishId}") + public ResponseEntity> getKeywordsWithItemId(@PathVariable Long goofishId) { // 获取关键词列表 - List keywordEntities = keywordRepository.findByGoofishId(gid); + List keywordEntities = keywordRepository.findByGoofishId(goofishId); // 转换为前端需要的格式(与 Python 实现一致) return ResponseEntity.ok(keywordEntities.stream() @@ -89,4 +96,38 @@ public class KeywordController { k.getImageUrl())) .collect(Collectors.toList())); } + + @GetMapping("/default-reply/{goofishId}") + public ResponseEntity getDefaultReply(@PathVariable String goofishId) { + DefaultReplyEntity defaultReply = defaultReplyRepository.findById(goofishId).orElse(null); + DefaultReplyResponse response = DefaultReplyResponse.builder() + .success(true) + .enabled(false) + .replyContent("") + .replyOnce(false) + .replyImageUrl("") + .build(); + if (Objects.isNull(defaultReply)) { + return ResponseEntity.ok(response); + } + + response.setEnabled(defaultReply.getEnabled()); + response.setReplyContent(StringUtils.hasText(defaultReply.getReplyContent()) ? defaultReply.getReplyContent() : ""); + response.setReplyOnce(defaultReply.getReplyOnce()); + response.setReplyImageUrl(StringUtils.hasText(defaultReply.getReplyImageUrl()) ? defaultReply.getReplyImageUrl() : ""); + return ResponseEntity.ok(response); + } + + @PutMapping("/default-reply/{goofishId}") + public ResponseEntity updateDefaultReply(@PathVariable String goofishId, @RequestBody DefaultReplyEntity request) { + request.setGoofishId(goofishId); + DefaultReplyEntity saved = defaultReplyRepository.save(request); + return ResponseEntity.ok(DefaultReplyResponse.builder() + .success(true) + .enabled(saved.getEnabled()) + .replyContent(StringUtils.hasText(saved.getReplyContent()) ? saved.getReplyContent() : "") + .replyOnce(saved.getReplyOnce()) + .replyImageUrl(StringUtils.hasText(saved.getReplyImageUrl()) ? saved.getReplyImageUrl() : "") + .build()); + } } \ No newline at end of file diff --git a/xianyu-server/src/main/resources/application.yml b/xianyu-server/src/main/resources/application.yml index 7c011ca..cbf6b4c 100644 --- a/xianyu-server/src/main/resources/application.yml +++ b/xianyu-server/src/main/resources/application.yml @@ -1,5 +1,5 @@ app: - ddl-auto: create # valid values: none, validate, update, create, create-drop + ddl-auto: update # valid values: none, validate, update, create, create-drop # 应用验证码配置 verification: code-length: 6 # 验证码长度(6位数字)