重构项目结构:迁移到单体架构并优化代码组织

- 删除分布式架构相关文件和配置
- 将backend-distributed重命名为backend保留分布式代码作为参考
- 优化backend-single单体架构实现
- 添加Coze API集成相关文档和测试
- 清理项目根目录的部署脚本和配置文件
- 更新WebSocket和消息服务实现
- 完善认证服务和密码加密功能
This commit is contained in:
2025-07-24 22:16:27 +08:00
parent 847f5126cf
commit ca42a7d9a4
308 changed files with 1263 additions and 13496 deletions
@@ -90,15 +90,16 @@ public class MessageController {
*/
@PostMapping
public Result<MessageResponse> create(@Valid @RequestBody MessageCreateRequest request) {
Message message = messageService.createMessage(
request.getConversationId(),
request.getUserId(),
request.getContent(),
request.getContentType(),
request.getSenderType(),
request.getSenderId()
);
return Result.success(convertToResponse(message));
Message message = new Message();
message.setConversationId(request.getConversationId());
message.setCreateBy(request.getUserId());
message.setContent(request.getContent());
message.setType(request.getContentType());
message.setSender(request.getSenderType());
// 可以根据需要设置其他字段
Message savedMessage = messageService.createMessage(message);
return Result.success(convertToResponse(savedMessage));
}
/**
@@ -35,12 +35,13 @@ public class WebSocketAuthInterceptor implements ChannelInterceptor {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (accessor != null && StompCommand.CONNECT.equals(accessor.getCommand())) {
log.info("WebSocket CONNECT命令检测到,开始处理认证");
// 处理WebSocket连接时的认证
handleAuthentication(accessor);
}
return message;
}
@@ -52,46 +53,54 @@ public class WebSocketAuthInterceptor implements ChannelInterceptor {
// 从连接头中获取token
String authHeader = accessor.getFirstNativeHeader("Authorization");
String userId = accessor.getFirstNativeHeader("X-User-Id");
log.info("WebSocket连接认证: authHeader={}, userId={}",
authHeader != null ? "Bearer ***" : null, userId);
log.info("WebSocket连接认证开始: authHeader={}, userId={}, sessionId={}",
authHeader != null ? "Bearer ***" : null, userId, accessor.getSessionId());
if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
log.info("提取到token: {}...", token.length() > 10 ? token.substring(0, 10) : token);
// 验证token
if (authService.validateToken(token)) {
boolean isValidToken = authService.validateToken(token);
log.info("Token验证结果: {}", isValidToken);
if (isValidToken) {
String tokenUserId = authService.getUserIdFromToken(token);
String username = authService.getUsernameFromToken(token);
log.info("WebSocket token验证成功: userId={}, username={}", tokenUserId, username);
// 创建认证对象
Authentication authentication = new UsernamePasswordAuthenticationToken(
tokenUserId,
null,
tokenUserId,
null,
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
);
// 设置用户认证信息
accessor.setUser(authentication);
// 设置会话属性
accessor.getSessionAttributes().put("userId", tokenUserId);
accessor.getSessionAttributes().put("username", username);
accessor.getSessionAttributes().put("authenticated", true);
if (accessor.getSessionAttributes() != null) {
accessor.getSessionAttributes().put("userId", tokenUserId);
accessor.getSessionAttributes().put("username", username);
accessor.getSessionAttributes().put("authenticated", true);
}
log.info("WebSocket认证用户设置完成: principal={}", authentication.getName());
} else {
log.warn("WebSocket token验证失败: token无效");
log.warn("WebSocket token验证失败: token无效或已过期");
// token无效,但不阻止连接,作为访客处理
handleGuestUser(accessor, userId);
}
} else {
log.info("WebSocket连接无token,作为访客处理: userId={}", userId);
log.info("WebSocket连接无token或格式错误,作为访客处理: userId={}", userId);
// 无token,作为访客处理
handleGuestUser(accessor, userId);
}
} catch (Exception e) {
log.error("WebSocket认证处理失败", e);
// 认证失败,作为访客处理
@@ -117,8 +126,10 @@ public class WebSocketAuthInterceptor implements ChannelInterceptor {
accessor.setUser(guestAuth);
// 设置会话属性
accessor.getSessionAttributes().put("userId", guestId);
accessor.getSessionAttributes().put("username", guestId);
accessor.getSessionAttributes().put("authenticated", false);
if (accessor.getSessionAttributes() != null) {
accessor.getSessionAttributes().put("userId", guestId);
accessor.getSessionAttributes().put("username", guestId);
accessor.getSessionAttributes().put("authenticated", false);
}
}
}
@@ -84,8 +84,7 @@ public interface MessageService extends IService<Message> {
/**
* 创建消息
*/
Message createMessage(String conversationId, String userId, String content,
String contentType, String senderType, String senderId);
Message createMessage(Message message);
/**
* 标记消息为已读
@@ -3,6 +3,7 @@ package com.emotion.service;
import com.emotion.dto.websocket.ChatRequest;
import com.emotion.dto.websocket.ConnectRequest;
import com.emotion.dto.websocket.WebSocketMessage;
import com.emotion.entity.Message;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
@@ -219,14 +220,13 @@ public class WebSocketService {
new Thread(() -> {
try {
// 保存用户消息到数据库
messageService.createMessage(
request.getConversationId(),
request.getSenderId(),
request.getContent(),
request.getMessageType().name(),
request.getSenderType().name(),
request.getSenderId()
);
Message userMessage = new Message();
userMessage.setConversationId(request.getConversationId());
userMessage.setCreateBy(request.getSenderId());
userMessage.setContent(request.getContent());
userMessage.setType(request.getMessageType().name());
userMessage.setSender(request.getSenderType().name());
messageService.createMessage(userMessage);
// 调用AI服务
String aiReply = aiChatService.sendChatMessage(
@@ -248,14 +248,13 @@ public class WebSocketService {
.build();
// 保存AI回复到数据库
messageService.createMessage(
request.getConversationId(),
"ai",
aiReply,
"text",
"ai",
"ai"
);
Message aiDbMessage = new Message();
aiDbMessage.setConversationId(request.getConversationId());
aiDbMessage.setCreateBy("ai");
aiDbMessage.setContent(aiReply);
aiDbMessage.setType("text");
aiDbMessage.setSender("ai");
messageService.createMessage(aiDbMessage);
// 发送AI回复
messagingTemplate.convertAndSendToUser(request.getSenderId(), "/queue/messages", aiMessage);
@@ -18,10 +18,8 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* AI聊天服务实现类
@@ -51,6 +49,9 @@ public class AiChatServiceImpl implements AIChatService {
@Value("${emotion.coze.api.base-url:https://api.coze.cn}")
private String cozeBaseUrl;
@Value("${emotion.coze.api.chat.path:/v3/chat}")
private String chatPath;
@Value("${emotion.coze.api.chat.talk.bot-id:}")
private String chatBotId;
@@ -74,6 +75,15 @@ public class AiChatServiceImpl implements AIChatService {
private static final String DEFAULT_USER_ID = "emotion-museum-user";
// API 相关常量
private static final String CONTENT_KEY = "content";
private static final String ROLE_KEY = "role";
private static final String USER_ROLE = "user";
private static final String ASSISTANT_ROLE = "assistant";
private static final String CONTENT_TYPE_KEY = "content_type";
private static final String TEXT_TYPE = "text";
private static final String ANSWER_TYPE = "answer";
@Override
public String sendChatMessage(String conversationId, String message, String userId) {
log.info("发送聊天消息: conversationId={}, userId={}, message={}", conversationId, userId, message);
@@ -83,22 +93,22 @@ public class AiChatServiceImpl implements AIChatService {
String aiReply = sendMessage(conversationId, message, userId);
// 保存用户消息
Message userMessage = messageService.createMessage(
conversationId,
userId,
message,
"text",
"user",
userId);
Message userMessage = new Message();
userMessage.setConversationId(conversationId);
userMessage.setCreateBy(userId);
userMessage.setContent(message);
userMessage.setType("text");
userMessage.setSender("user");
userMessage = messageService.createMessage(userMessage);
// 保存AI回复
Message aiMessage = messageService.createMessage(
conversationId,
"ai",
aiReply,
"text",
"ai",
"ai");
Message aiMessage = new Message();
aiMessage.setConversationId(conversationId);
aiMessage.setCreateBy("ai");
aiMessage.setContent(aiReply);
aiMessage.setType("text");
aiMessage.setSender("ai");
aiMessage = messageService.createMessage(aiMessage);
log.info("聊天消息处理完成: userMessageId={}, aiMessageId={}",
userMessage.getId(), aiMessage.getId());
@@ -166,13 +176,14 @@ public class AiChatServiceImpl implements AIChatService {
headers.set("Authorization", "Bearer " + cozeApiToken);
headers.set("Content-Type", "application/json");
// 构建请求体 - 参考backend-distributed的实现
// 构建请求体 - 使用正确的Coze API格式
Map<String, Object> requestBody = buildCozeRequest(conversationId, userMessage, userId);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
// 构建完整的API URL
String cozeApiUrl = cozeBaseUrl + "/api/message";
String cozeApiUrl = cozeBaseUrl + chatPath;
log.info("发送Coze请求到: {}, 请求体: {}", cozeApiUrl, requestBody);
// 发送请求
ResponseEntity<String> response = restTemplate.exchange(
@@ -181,13 +192,22 @@ public class AiChatServiceImpl implements AIChatService {
request,
String.class);
// 解析响应
log.info("收到Coze初始响应: {}", response.getBody());
// 解析响应获取chat_id和conversation_id
JSONObject responseJson = JSON.parseObject(response.getBody());
String aiReply = extractContentFromCozeResponse(responseJson);
String chatId = extractChatIdFromResponse(responseJson);
String cozeConversationId = extractConversationIdFromResponse(responseJson);
log.info("Coze AI响应成功: reply={}", aiReply);
return aiReply;
if (chatId != null && cozeConversationId != null) {
// 轮询聊天状态直到完成并获取回复内容
String aiReply = waitForChatCompletion(chatId, cozeConversationId);
log.info("Coze AI响应成功: reply={}", aiReply);
return aiReply;
} else {
log.error("无法从Coze响应中获取chat_id或conversation_id");
return "抱歉,AI服务响应异常,请稍后再试。";
}
} catch (Exception e) {
log.error("发送消息到Coze AI失败", e);
@@ -209,22 +229,22 @@ public class AiChatServiceImpl implements AIChatService {
String aiReply = sendMessage(guestConversationId, message, "guest");
// 保存访客消息
Message guestMessage = messageService.createMessage(
guestConversationId,
"guest",
message,
"text",
"guest",
clientIp);
Message guestMessage = new Message();
guestMessage.setConversationId(guestConversationId);
guestMessage.setCreateBy("guest");
guestMessage.setContent(message);
guestMessage.setType("text");
guestMessage.setSender("guest");
guestMessage = messageService.createMessage(guestMessage);
// 保存AI回复
Message aiMessage = messageService.createMessage(
guestConversationId,
"ai",
aiReply,
"text",
"ai",
"ai");
Message aiMessage = new Message();
aiMessage.setConversationId(guestConversationId);
aiMessage.setCreateBy("ai");
aiMessage.setContent(aiReply);
aiMessage.setType("text");
aiMessage.setSender("ai");
aiMessage = messageService.createMessage(aiMessage);
result.put("message", aiReply);
result.put("messageId", aiMessage.getId());
@@ -252,9 +272,6 @@ public class AiChatServiceImpl implements AIChatService {
Map<String, Object> result = new HashMap<>();
try {
// 创建数据库对话记录
String conversationId = UUID.randomUUID().toString();
// 调用数据库服务创建对话
Conversation conversation = conversationService.createConversation(userId, title, "user");
@@ -324,20 +341,19 @@ public class AiChatServiceImpl implements AIChatService {
@Override
public boolean healthCheck() {
try {
// 调用Coze bot信息接口检查健康状态
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + cozeApiToken);
// 简化健康检查 - 检查必要配置是否存在
boolean configValid = cozeApiToken != null && !cozeApiToken.trim().isEmpty() &&
chatBotId != null && !chatBotId.trim().isEmpty() &&
cozeBaseUrl != null && !cozeBaseUrl.trim().isEmpty();
HttpEntity<String> request = new HttpEntity<>(headers);
if (!configValid) {
log.warn("Coze API 配置不完整");
return false;
}
ResponseEntity<String> response = restTemplate.exchange(
cozeBaseUrl + "/v1/bot/get_online_info?bot_id=" + chatBotId,
HttpMethod.GET,
request,
String.class);
JSONObject responseJson = JSON.parseObject(response.getBody());
return responseJson != null && responseJson.get("code") != null;
// 可选:发送一个简单的测试请求
// 这里可以调用一个轻量级的API来验证连接
return true;
} catch (Exception e) {
log.error("健康检查失败: {}", e.getMessage());
@@ -346,7 +362,7 @@ public class AiChatServiceImpl implements AIChatService {
}
/**
* 构建Coze API请求 - 参考backend-distributed的实现
* 构建Coze API请求 - 根据官方文档修正格式
*/
private Map<String, Object> buildCozeRequest(String conversationId, String userMessage, String userId) {
Map<String, Object> cozeRequest = new HashMap<>();
@@ -360,21 +376,14 @@ public class AiChatServiceImpl implements AIChatService {
cozeRequest.put("user_id", userId != null ? userId : DEFAULT_USER_ID);
cozeRequest.put("stream", false);
// 构建消息内容
String message = userMessage;
if (conversationId != null && !conversationId.trim().isEmpty()) {
// 可以在这里添加上下文信息
message = "会话ID: " + conversationId + "\n\n用户消息: " + message;
}
// 添加聊天历史(简化版本)
// 构建消息列表 - 按照 Coze API 标准格式
java.util.List<Map<String, Object>> messages = new java.util.ArrayList<>();
// 添加当前消息
// 添加当前用户消息
Map<String, Object> currentMsg = new HashMap<>();
currentMsg.put("role", "user");
currentMsg.put("content", message);
currentMsg.put("content_type", "text");
currentMsg.put(ROLE_KEY, USER_ROLE);
currentMsg.put(CONTENT_KEY, userMessage);
currentMsg.put(CONTENT_TYPE_KEY, TEXT_TYPE);
currentMsg.put("type", "question");
messages.add(currentMsg);
@@ -385,36 +394,156 @@ public class AiChatServiceImpl implements AIChatService {
}
/**
* 从Coze响应中提取内容
* 从Coze响应中提取chat_id
*/
private String extractContentFromCozeResponse(JSONObject responseJson) {
private String extractChatIdFromResponse(JSONObject responseJson) {
try {
if (responseJson != null && responseJson.get("data") != null) {
JSONObject data = responseJson.getJSONObject("data");
// 根据Coze API响应格式解析内容
if (data.get("messages") != null) {
java.util.List<JSONObject> messages = data.getJSONArray("messages").toJavaList(JSONObject.class);
for (JSONObject message : messages) {
if ("assistant".equals(message.getString("role")) &&
"answer".equals(message.getString("type"))) {
return message.getString("content");
}
}
}
// 兼容旧格式
if (data.getString("reply") != null) {
return data.getString("reply");
}
if (responseJson != null && responseJson.getJSONObject("data") != null) {
return responseJson.getJSONObject("data").getString("id");
}
return "抱歉,我现在无法理解您的消息。";
} catch (Exception e) {
log.error("解析Coze响应失败: {}", e.getMessage());
return "抱歉,响应解析出现问题。";
log.error("提取chat_id失败: {}", e.getMessage());
}
return null;
}
/**
* 从Coze响应中提取conversation_id
*/
private String extractConversationIdFromResponse(JSONObject responseJson) {
try {
if (responseJson != null && responseJson.getJSONObject("data") != null) {
return responseJson.getJSONObject("data").getString("conversation_id");
}
} catch (Exception e) {
log.error("提取conversation_id失败: {}", e.getMessage());
}
return null;
}
/**
* 等待聊天完成并获取回复内容
*/
private String waitForChatCompletion(String chatId, String conversationId) {
try {
// 最多等待30秒,每2秒轮询一次
int maxAttempts = 15;
int attempt = 0;
while (attempt < maxAttempts) {
log.info("轮询聊天状态,第{}次尝试: chatId={}, conversationId={}", attempt + 1, chatId, conversationId);
// 构建状态查询URL
String statusUrl = cozeBaseUrl + "/v3/chat/retrieve?chat_id=" + chatId + "&conversation_id=" + conversationId;
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + cozeApiToken);
headers.set("Content-Type", "application/json");
HttpEntity<String> request = new HttpEntity<>(headers);
// 发送状态查询请求
ResponseEntity<String> response = restTemplate.exchange(
statusUrl,
HttpMethod.GET,
request,
String.class);
JSONObject statusResponse = JSON.parseObject(response.getBody());
log.info("轮询响应: {}", statusResponse);
if (statusResponse != null && statusResponse.getJSONObject("data") != null) {
JSONObject data = statusResponse.getJSONObject("data");
String status = data.getString("status");
log.info("聊天状态: {}", status);
if ("completed".equals(status)) {
// 聊天完成,获取消息
log.info("聊天完成,开始获取消息: chatId={}, conversationId={}", chatId, conversationId);
return getChatMessages(chatId, conversationId);
} else if ("failed".equals(status)) {
log.error("Coze聊天失败: chatId={}, conversationId={}", chatId, conversationId);
return "抱歉,AI服务暂时不可用,请稍后再试。";
}
} else {
log.warn("轮询响应为空或无data字段: {}", statusResponse);
}
// 等待2秒后重试
Thread.sleep(2000);
attempt++;
}
log.warn("Coze聊天超时: chatId={}, conversationId={}", chatId, conversationId);
return "抱歉,AI响应超时,请稍后再试。";
} catch (Exception e) {
log.error("等待Coze聊天完成失败: chatId={}, conversationId={}, error={}",
chatId, conversationId, e.getMessage(), e);
return "抱歉,AI服务出现错误,请稍后再试。";
}
}
/**
* 获取聊天消息
*/
private String getChatMessages(String chatId, String conversationId) {
try {
log.info("获取聊天消息: chatId={}, conversationId={}", chatId, conversationId);
// 构建消息查询URL
String messagesUrl = cozeBaseUrl + "/v3/chat/message/list?chat_id=" + chatId + "&conversation_id=" + conversationId;
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + cozeApiToken);
headers.set("Content-Type", "application/json");
HttpEntity<String> request = new HttpEntity<>(headers);
// 发送消息查询请求
ResponseEntity<String> response = restTemplate.exchange(
messagesUrl,
HttpMethod.GET,
request,
String.class);
JSONObject messagesResponse = JSON.parseObject(response.getBody());
log.info("消息响应: {}", messagesResponse);
if (messagesResponse != null && messagesResponse.getJSONArray("data") != null) {
java.util.List<JSONObject> messages = messagesResponse.getJSONArray("data").toJavaList(JSONObject.class);
log.info("收到{}条消息", messages.size());
// 查找AI的回复消息(role=assistant, type=answer
for (JSONObject message : messages) {
String role = message.getString("role");
String type = message.getString("type");
log.info("消息详情: role={}, type={}, content={}", role, type, message.getString("content"));
if (ASSISTANT_ROLE.equals(role) && ANSWER_TYPE.equals(type)) {
String content = message.getString("content");
log.info("找到AI回复: {}", content);
return content;
}
}
log.warn("未找到AI回复消息");
} else {
log.warn("消息响应为空或无data字段");
}
return "抱歉,未能获取到AI回复。";
} catch (Exception e) {
log.error("获取Coze聊天消息失败: chatId={}, conversationId={}, error={}",
chatId, conversationId, e.getMessage(), e);
return "抱歉,获取AI回复失败。";
}
}
/**
* 发送总结消息到Coze AI
*/
@@ -433,8 +562,9 @@ public class AiChatServiceImpl implements AIChatService {
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
// 构建完整的API URL
String cozeApiUrl = cozeBaseUrl + "/api/message";
String cozeApiUrl = cozeBaseUrl + chatPath;
log.info("发送Coze总结请求到: {}, 请求体: {}", cozeApiUrl, requestBody);
// 发送请求
ResponseEntity<String> response = restTemplate.exchange(
cozeApiUrl,
@@ -442,13 +572,22 @@ public class AiChatServiceImpl implements AIChatService {
request,
String.class);
// 解析响应
log.info("收到Coze总结初始响应: {}", response.getBody());
// 解析响应获取chat_id和conversation_id
JSONObject responseJson = JSON.parseObject(response.getBody());
String aiReply = extractContentFromCozeResponse(responseJson);
String chatId = extractChatIdFromResponse(responseJson);
String cozeConversationId = extractConversationIdFromResponse(responseJson);
log.info("Coze AI总结响应成功: reply={}", aiReply);
return aiReply;
if (chatId != null && cozeConversationId != null) {
// 轮询聊天状态直到完成并获取回复内容
String aiReply = waitForChatCompletion(chatId, cozeConversationId);
log.info("Coze AI总结响应成功: reply={}", aiReply);
return aiReply;
} else {
log.error("无法从Coze总结响应中获取chat_id或conversation_id");
return "抱歉,AI总结服务响应异常,请稍后再试。";
}
} catch (Exception e) {
log.error("发送总结消息到Coze AI失败", e);
@@ -461,7 +600,7 @@ public class AiChatServiceImpl implements AIChatService {
*/
private Map<String, Object> buildSummaryRequest(String conversationId, String userMessage, String userId) {
Map<String, Object> cozeRequest = new HashMap<>();
cozeRequest.put("bot_id", summaryBotId);
cozeRequest.put("bot_id", summaryBotId != null && !summaryBotId.trim().isEmpty() ? summaryBotId : chatBotId);
// 如果有总结workflow_id,则添加
if (summaryWorkflowId != null && !summaryWorkflowId.trim().isEmpty()) {
@@ -470,27 +609,24 @@ public class AiChatServiceImpl implements AIChatService {
cozeRequest.put("user_id", userId != null ? userId : DEFAULT_USER_ID);
cozeRequest.put("stream", false);
cozeRequest.put("auto_save_history", true);
// 构建消息内容
String message = userMessage;
// 如果有会话ID,则添加
if (conversationId != null && !conversationId.trim().isEmpty()) {
// 可以在这里添加上下文信息
message = "会话ID: " + conversationId + "\n\n总结内容: " + message;
cozeRequest.put("conversation_id", conversationId);
}
// 添加聊天历史(简化版本)
// 构建消息列表 - 按照 Coze API 标准格式
java.util.List<Map<String, Object>> messages = new java.util.ArrayList<>();
// 添加当前消息
// 添加当前用户消息
Map<String, Object> currentMsg = new HashMap<>();
currentMsg.put("role", "user");
currentMsg.put("content", message);
currentMsg.put("content_type", "text");
currentMsg.put("type", "question");
currentMsg.put(ROLE_KEY, USER_ROLE);
currentMsg.put(CONTENT_KEY, userMessage);
currentMsg.put(CONTENT_TYPE_KEY, TEXT_TYPE);
messages.add(currentMsg);
cozeRequest.put("additional_messages", messages);
cozeRequest.put("parameters", new HashMap<>());
return cozeRequest;
}
@@ -15,6 +15,7 @@ import com.emotion.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -45,6 +46,9 @@ public class AuthServiceImpl implements AuthService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private PasswordEncoder passwordEncoder;
private static final String CAPTCHA_PREFIX = "captcha:";
private static final String TOKEN_PREFIX = "token:";
private static final String REFRESH_TOKEN_PREFIX = "refresh_token:";
@@ -111,11 +115,11 @@ public class AuthServiceImpl implements AuthService {
throw new BusinessException("邮箱已被使用");
}
// 创建用户
// 创建用户(密码在UserService中加密,这里不需要预先加密)
User user = userService.createUser(
request.getAccount(),
StringUtils.hasText(request.getUsername()) ? request.getUsername() : request.getAccount(),
encryptPassword(request.getPassword()),
request.getPassword(),
request.getEmail(),
request.getPhone()
);
@@ -374,18 +378,16 @@ public class AuthServiceImpl implements AuthService {
* 验证密码
*/
private boolean verifyPassword(String rawPassword, String encodedPassword) {
// 这里应该使用BCrypt等加密算法进行密码验证
// 简化实现,实际项目中应该使用加密后的密码
return rawPassword.equals(encodedPassword);
// 使用BCrypt进行密码验证
return passwordEncoder.matches(rawPassword, encodedPassword);
}
/**
* 加密密码
*/
private String encryptPassword(String rawPassword) {
// 这里应该使用BCrypt等加密算法进行密码加密
// 简化实现,实际项目中应该使用加密算法
return rawPassword;
// 使用BCrypt进行密码加密
return passwordEncoder.encode(rawPassword);
}
/**
@@ -148,17 +148,17 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
}
@Override
public Message createMessage(String conversationId, String userId, String content,
String contentType, String senderType, String senderId) {
Message message = new Message();
message.setConversationId(conversationId);
message.setContent(content);
message.setType(contentType);
message.setSender(senderType);
message.setCreateBy(userId);
message.setTimestamp(LocalDateTime.now());
message.setStatus("sent");
message.setIsRead(0);
public Message createMessage(Message message) {
// 设置默认值
if (message.getTimestamp() == null) {
message.setTimestamp(LocalDateTime.now());
}
if (message.getStatus() == null) {
message.setStatus("sent");
}
if (message.getIsRead() == null) {
message.setIsRead(0);
}
this.save(message);
return message;
@@ -0,0 +1,44 @@
# Coze API 配置示例
# 请根据您的实际情况修改以下配置
emotion:
coze:
api:
# Coze API 访问令牌 - 从 https://www.coze.cn/docs/developer_guides/pat 获取
token: "your-coze-api-token-here"
# Coze API 基础URL
base-url: "https://api.coze.cn"
# 聊天相关配置
chat:
talk:
# 聊天机器人ID - 从您的 Coze 工作空间获取
bot-id: "your-chat-bot-id-here"
# 工作流ID(可选)- 如果使用工作流模式
workflow-id: "your-chat-workflow-id-here"
summary:
# 总结机器人ID(可选)- 如果有专门的总结机器人
bot-id: "your-summary-bot-id-here"
# 总结工作流ID(可选)
workflow-id: "your-summary-workflow-id-here"
# 请求超时配置(毫秒)
timeout: 30000
# 重试配置
retry-count: 3
retry-delay: 1000
# 配置说明:
# 1. token: 个人访问令牌,需要在 Coze 平台创建
# 2. bot-id: 机器人ID,在发布机器人时选择"发布到API"获得
# 3. workflow-id: 工作流ID,如果使用工作流模式则需要配置
# 4. base-url: 通常为 https://api.coze.cn,国际版可能不同
# 5. 确保机器人已发布并启用API访问
# 重要提醒:
# - 请勿将真实的 token 和 ID 提交到版本控制系统
# - 建议使用环境变量或配置中心管理敏感信息
# - 测试时可以先使用简单的聊天机器人验证配置
@@ -75,6 +75,7 @@ emotion:
base-url: https://api.coze.cn
# 对话聊天
chat:
path: /v3/chat
talk:
bot-id: 7523042446285439016
workflow-id: 7523047462895796287