feat/multi-channel-framework [AC-INIT]合并功能代码 #12

Merged
MerCry merged 37 commits from feat/multi-channel-framework into main 2026-02-24 03:55:00 +00:00
7 changed files with 120 additions and 18 deletions
Showing only changes of commit 0786e6a040 - Show all commits

View File

@ -0,0 +1,46 @@
package com.wecom.robot.config;
import com.wecom.robot.dto.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleValidationException(MethodArgumentNotValidException ex) {
String message = ex.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining("; "));
log.warn("参数校验失败: {}", message);
return ApiResponse.error(400, message);
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleConstraintViolationException(ConstraintViolationException ex) {
String message = ex.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.joining("; "));
log.warn("约束校验失败: {}", message);
return ApiResponse.error(400, message);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResponse<Void> handleException(Exception ex) {
log.error("服务器内部错误", ex);
return ApiResponse.error(500, "服务器内部错误");
}
}

View File

@ -13,6 +13,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
@ -31,7 +32,8 @@ public class SessionController {
@GetMapping
public ApiResponse<List<SessionInfo>> getSessions(
@RequestParam(required = false) String status,
@RequestParam(required = false) String csId) {
@RequestParam(required = false) String csId,
@RequestParam(required = false) String channelType) {
LambdaQueryWrapper<Session> query = new LambdaQueryWrapper<>();
if (status != null) {
@ -42,6 +44,10 @@ public class SessionController {
query.eq(Session::getManualCsId, csId);
}
if (channelType != null) {
query.eq(Session::getChannelType, channelType);
}
query.orderByDesc(Session::getUpdatedAt);
List<Session> sessions = sessionMapper.selectList(query);
@ -51,6 +57,7 @@ public class SessionController {
info.setSessionId(session.getSessionId());
info.setCustomerId(session.getCustomerId());
info.setKfId(session.getKfId());
info.setChannelType(session.getChannelType());
info.setStatus(session.getStatus());
info.setManualCsId(session.getManualCsId());
info.setCreatedAt(session.getCreatedAt());
@ -87,6 +94,7 @@ public class SessionController {
info.setSessionId(session.getSessionId());
info.setCustomerId(session.getCustomerId());
info.setKfId(session.getKfId());
info.setChannelType(session.getChannelType());
info.setStatus(session.getStatus());
info.setManualCsId(session.getManualCsId());
info.setCreatedAt(session.getCreatedAt());
@ -120,12 +128,9 @@ public class SessionController {
}
@PostMapping("/{sessionId}/accept")
public ApiResponse<Void> acceptSession(@PathVariable String sessionId, @RequestBody AcceptSessionRequest request) {
String csId = request.getCsId();
if (csId == null || csId.isEmpty()) {
return ApiResponse.error(400, "客服ID不能为空");
}
public ApiResponse<Void> acceptSession(
@PathVariable String sessionId,
@Valid @RequestBody AcceptSessionRequest request) {
Session session = sessionMapper.selectById(sessionId);
if (session == null) {
return ApiResponse.error(404, "会话不存在");
@ -135,14 +140,16 @@ public class SessionController {
return ApiResponse.error(400, "会话状态不正确");
}
sessionManagerService.acceptTransfer(sessionId, csId);
webSocketService.notifySessionAccepted(sessionId, csId);
sessionManagerService.acceptTransfer(sessionId, request.getCsId());
webSocketService.notifySessionAccepted(sessionId, request.getCsId());
return ApiResponse.success(null);
}
@PostMapping("/{sessionId}/message")
public ApiResponse<Void> sendMessage(@PathVariable String sessionId, @RequestBody SendMessageRequest request) {
public ApiResponse<Void> sendMessage(
@PathVariable String sessionId,
@Valid @RequestBody SendMessageRequest request) {
Session session = sessionMapper.selectById(sessionId);
if (session == null) {
return ApiResponse.error(404, "会话不存在");
@ -159,7 +166,7 @@ public class SessionController {
);
if (!success) {
return ApiResponse.error("消息发送失败");
return ApiResponse.error(500, "消息发送失败");
}
sessionManagerService.saveMessage(

View File

@ -2,8 +2,13 @@ package com.wecom.robot.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
public class AcceptSessionRequest {
@NotBlank(message = "客服ID不能为空")
@Size(min = 1, max = 64, message = "客服ID长度必须在1-64之间")
private String csId;
}

View File

@ -11,7 +11,7 @@ public class ApiResponse<T> {
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(200);
response.setCode(0);
response.setMessage("success");
response.setData(data);
return response;

View File

@ -2,16 +2,31 @@ package com.wecom.robot.dto;
import lombok.Data;
import java.time.LocalDateTime;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
public class MessageInfo {
@NotBlank
@Size(min = 1, max = 128)
private String msgId;
@NotBlank
@Size(min = 1, max = 64)
private String sessionId;
@NotBlank
private String senderType;
@Size(max = 64)
private String senderId;
@NotBlank
@Size(min = 1, max = 4096)
private String content;
private String msgType;
private LocalDateTime createdAt;
private java.time.LocalDateTime createdAt;
}

View File

@ -2,9 +2,15 @@ package com.wecom.robot.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
public class SendMessageRequest {
@NotBlank(message = "消息内容不能为空")
@Size(min = 1, max = 4096, message = "消息内容长度必须在1-4096之间")
private String content;
private String msgType;
}

View File

@ -2,20 +2,43 @@ package com.wecom.robot.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
@Data
public class SessionInfo {
@NotBlank
@Size(min = 1, max = 64)
private String sessionId;
@NotBlank
@Size(min = 1, max = 64)
private String customerId;
@Size(max = 64)
private String kfId;
@Size(max = 64)
private String channelType;
@NotBlank
private String status;
@Size(max = 64)
private String manualCsId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private String metadata;
private int messageCount;
@Size(max = 4096)
private String lastMessage;
private LocalDateTime lastMessageTime;
private int messageCount;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private String metadata;
}