Commit 63e13557 by zhangxingmin

push

parent e00f6e6d
......@@ -31,16 +31,17 @@ public class ApiCoSessionController implements ApiCoSessionFeignClient {
private ApiCoSessionService apiCoSessionService;
/**
* 客户创建会话(生成共享码)
* @param request
* 创建协同会话
* @param request 创建会话请求
* @return
*/
@Override
public Result<CreateResponse> create(CreateRequest request) {
return apiCoSessionService.create(request);
}
/**
* 顾问加入会话(输入共享码加入房间,可以多次加入)
* 加入协同会话
* @param request
* @return
*/
......
......@@ -14,6 +14,7 @@ import com.yd.communication.service.model.CoSession;
public interface ApiCoSessionService {
Result<CreateResponse> create(CreateRequest request);
Result<JoinResponse> join(JoinRequest request);
......
......@@ -4,10 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.ByteArrayMultipartFile;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.common.utils.RedisUtil;
import com.yd.communication.api.service.ApiCoSessionService;
import com.yd.communication.api.utils.ClientInfoUtils;
import com.yd.communication.api.utils.QRCodeUtils;
import com.yd.communication.feign.dto.RoomRedisInfoDTO;
import com.yd.communication.feign.enums.CoSessionStatusEnum;
import com.yd.communication.feign.enums.ControlHolderTypeEnum;
......@@ -25,11 +27,17 @@ import com.yd.communication.service.service.ICoOperationLogService;
import com.yd.communication.service.service.ICoSessionService;
import com.yd.communication.service.service.IRecordingTaskService;
import com.yd.communication.service.utils.RandomUtil;
import com.yd.oss.feign.client.ApiOssFeignClient;
import com.yd.oss.feign.request.ApiUploadFileRequest;
import com.yd.oss.feign.response.ApiUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.UUID;
......@@ -50,40 +58,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
@Resource
private RedisUtil redisUtil;
/**
* 客户创建会话(生成共享码)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Result<CreateResponse> create(CreateRequest request) {
log.info("【创建会话】收到创建请求, request={}", request);
try {
CoSession session = createSession(
request.getScope(),
request.getResourceType(),
request.getResourceId(),
request.getResourceInit(),
request.getOwnerId(),
request.getOwnerType(),
request.getUserId(),
request.getToken()
);
if (session == null) {
log.warn("【创建会话】创建失败,返回空会话");
return Result.success();
}
CreateResponse response = new CreateResponse();
response.setRoomId(session.getRoomId());
response.setRoomPwd(session.getRoomPwd());
response.setSessionBizId(session.getCoSessionBizId());
response.setStatus(session.getStatus());
log.info("【创建会话】成功,roomId={}, roomPwd={}, sessionBizId={}", session.getRoomId(), session.getRoomPwd(), session.getCoSessionBizId());
return Result.success(response);
} catch (Exception e) {
log.error("【创建会话】异常", e);
throw e;
}
}
@Resource
private ApiOssFeignClient apiOssFeignClient;
@Value("${co.room.base-url:https://default-domain.com/co/join}")
private String roomBaseUrl;
/**
* 客户创建会话(生成共享码)——内部方法
......@@ -133,7 +112,9 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
roomRedisInfoDTO.setUserId(userId);
roomRedisInfoDTO.setControlHolderType(session.getControlHolderType());
roomRedisInfoDTO.setControlHolderId(session.getControlHolderId());
redisUtil.setCacheObject(RedisEnum.ROOM.getPrefix() + roomId, roomRedisInfoDTO,
roomRedisInfoDTO.setRoomId(roomId);
roomRedisInfoDTO.setRoomPwd(roomPwd);
redisUtil.setCacheObject(RedisEnum.ROOM.getPrefix() + roomId + ":" + roomPwd, roomRedisInfoDTO,
RedisEnum.ROOM.getTimeout(), RedisEnum.ROOM.getTimeUnit());
log.info("【创建会话-内部】Redis缓存已设置, key={}", RedisEnum.ROOM.getPrefix() + roomId);
......@@ -163,7 +144,95 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
/**
* 顾问加入会话(输入共享码加入房间,可以多次加入)
* 创建协同会话
* @param request
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Result<CreateResponse> create(CreateRequest request) {
log.info("【创建协同会话】收到创建请求, request={}", request);
try {
// 1. 创建会话
CoSession session = createSession(
request.getScope(),
request.getResourceType(),
request.getResourceId(),
request.getResourceInit(),
request.getOwnerId(),
request.getOwnerType(),
request.getUserId(),
request.getToken()
);
if (session == null) {
log.warn("【创建协同会话-生成二维码】创建会话失败");
return Result.success();
}
// 2. 构建房间链接(从配置读取)
String roomLink = roomBaseUrl + "?roomId=" + session.getRoomId() + "&pwd=" + session.getRoomPwd();
log.info("【创建协同会话】生成房间链接: {}", roomLink);
// 3. 生成二维码图片字节数组(PNG格式)
byte[] qrCodeBytes = QRCodeUtils.generateQRCode(roomLink, 300, 300);
// 4. 将字节数组转换为 MultipartFile
String fileName = session.getCoSessionBizId() + ".png";
MultipartFile multipartFile = new ByteArrayMultipartFile(
qrCodeBytes, // 图片字节数组
"file", // 字段名,与 Feign @RequestPart("file") 匹配
fileName, // 原始文件名
"image/png" // 内容类型
);
// 5. 构建 OSS 上传请求参数
ApiUploadFileRequest ossRequest = new ApiUploadFileRequest();
ossRequest.setObjectBizId(session.getCoSessionBizId()); // 必填,使用会话业务ID
ossRequest.setObjectType("co_session_qr"); // 自定义对象类型
ossRequest.setObjectName("协同会话二维码");
ossRequest.setProjectBizId(request.getResourceId()); // 可关联资源ID
ossRequest.setTenantBizId(request.getOwnerId()); // 可关联所有者
// 6. 调用 Feign 上传
Result<ApiUploadResponse> uploadResult = apiOssFeignClient.uploadFileBody(multipartFile, ossRequest);
if (uploadResult == null || uploadResult.getCode() != 200 || uploadResult.getData() == null) {
log.error("【创建协同会话】OSS上传失败,result={}", uploadResult);
throw new BusinessException("二维码上传失败:" + (uploadResult != null ? uploadResult.getMsg() : "未知错误"));
}
// 7. 获取文件访问 URL(假设 ApiUploadResponse 包含 url 字段)
ApiUploadResponse uploadData = uploadResult.getData();
String roomQrCodeUrl = uploadData.getUrl(); // 若字段名为 fileUrl 则对应调整
log.info("【创建协同会话】OSS上传成功,文件URL: {}", roomQrCodeUrl);
//8. 更新会话信息表数据
session.setRoomQrCode(roomQrCodeUrl);
session.setRoomLink(roomLink);
iCoSessionService.saveOrUpdate(session);
//设置房间链接失效时间(用于扫码和链接直接访问,加载页面后调用校验接口判断是否失效)
redisUtil.setCacheObject(RedisEnum.ROOM_LINK.getPrefix() + session.getRoomId() + ":" + session.getRoomPwd(), session.getRoomLink(),
RedisEnum.ROOM_LINK.getTimeout(), RedisEnum.ROOM_LINK.getTimeUnit());
//9. 组装响应
CreateResponse response = new CreateResponse();
response.setRoomId(session.getRoomId());
response.setRoomPwd(session.getRoomPwd());
response.setSessionBizId(session.getCoSessionBizId());
response.setStatus(session.getStatus());
response.setRoomLink(roomLink);
response.setRoomQrCode(roomQrCodeUrl);
log.info("【创建协同会话】成功,roomId={}, sessionBizId={}", session.getRoomId(), session.getCoSessionBizId());
return Result.success(response);
} catch (Exception e) {
log.error("【创建协同会话】异常", e);
throw new BusinessException("创建协同会话失败:" + e.getMessage());
}
}
/**
* 加入协同会话
*/
@Override
@Transactional(rollbackFor = Exception.class)
......@@ -171,6 +240,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
log.info("【加入会话】收到加入请求, request={}", request);
try {
CoSession session = joinSession(
request.getRoomId(),
request.getRoomPwd(),
request.getParticipantId(),
request.getParticipantType()
......@@ -206,19 +276,30 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
/**
* 顾问加入会话(内部方法)
* 顾问加入会话
* @param roomId
* @param roomPwd
* @param participantId
* @param participantType
* @return
*/
@Transactional(rollbackFor = Exception.class)
public CoSession joinSession(String roomPwd, String participantId, String participantType) {
log.info("【加入会话-内部】开始, roomPwd={}, participantId={}, participantType={}", roomPwd, participantId, participantType);
public CoSession joinSession(String roomId,String roomPwd, String participantId, String participantType) {
log.info("【加入会话-内部】开始, roomId={}, roomPwd={}, participantId={}, participantType={}", roomId, roomPwd, participantId, participantType);
try {
//校验房间链接是否失效
String roomLink = redisUtil.getCacheObject(RedisEnum.ROOM_LINK.getPrefix() + roomId + ":" + roomPwd);
if (StringUtils.isBlank(roomLink)) {
throw new BusinessException("访问链接已失效,请重新生成");
}
LambdaQueryWrapper<CoSession> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CoSession::getRoomPwd, roomPwd)
wrapper.eq(CoSession::getRoomId, roomId)
.eq(CoSession::getRoomPwd, roomPwd)
.last(" limit 1 ");
CoSession session = iCoSessionService.getOne(wrapper);
if (session == null) {
log.error("【加入会话-内部】未找到会话,roomPwd={}", roomPwd);
throw new BusinessException("房间密码(共享码)错误,或客户未发起会话");
log.error("【加入会话-内部】未找到会话,roomId={}, roomPwd={}", roomId, roomPwd);
throw new BusinessException("房间号或者密码错误,无法加入");
}
log.info("【加入会话-内部】找到会话, roomId={}, status={}, currentHolder={}:{}",
session.getRoomId(), session.getStatus(), session.getControlHolderType(), session.getControlHolderId());
......
package com.yd.communication.api.utils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class QRCodeUtils {
/**
* 生成二维码图片的字节数组(PNG格式)
*
* @param content 二维码内容(如URL)
* @param width 图片宽度(像素)
* @param height 图片高度(像素)
* @return PNG图片的字节数组
*/
public static byte[] generateQRCode(String content, int width, int height) {
try {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1); // 边距
QRCodeWriter writer = new QRCodeWriter();
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", baos);
return baos.toByteArray();
} catch (Exception e) {
log.error("生成二维码失败,content={}, width={}, height={}", content, width, height, e);
throw new RuntimeException("生成二维码失败", e);
}
}
}
\ No newline at end of file
......@@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.*;
public interface ApiCoSessionFeignClient {
/**
* 客户创建协同会话(生成共享码)
* 创建协同会话
*
* @param request 创建会话请求
* @return 会话信息
......
......@@ -10,4 +10,6 @@ public class RedisConstants {
*/
public static final String ROOM_KEY_PREFIX = "room:";
public static final String ROOM_LINK_KEY_PREFIX = "room:link:";
}
......@@ -13,6 +13,16 @@ public class RoomRedisInfoDTO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 协同房间号(房间ID)
*/
private String roomId;
/**
* 协同房间密码(输入密码进入房间,协同共享码,进入这个协同房间号的密码)
*/
private String roomPwd;
/**
* 控制权持有者类型:owner(资源所有者类型)/participant(参与者类型)
*/
private String controlHolderType;
......
......@@ -10,7 +10,9 @@ import java.util.concurrent.TimeUnit;
public enum RedisEnum {
//协同房间缓存信息redis参数
ROOM(RedisConstants.ROOM_KEY_PREFIX,600000000,TimeUnit.MINUTES),
ROOM(RedisConstants.ROOM_KEY_PREFIX,120,TimeUnit.MINUTES),
//房间链接缓存信息redis参数
ROOM_LINK(RedisConstants.ROOM_KEY_PREFIX,120,TimeUnit.MINUTES),
;
//缓存key前缀
......
......@@ -11,12 +11,12 @@ import javax.validation.constraints.NotBlank;
@Data
public class JoinRequest {
// /**
// * 协同房间号(房间ID)
// * 客户创建会话时生成的唯一房间标识
// * 示例:room_abc12345
// */
// private String roomId;
/**
* 协同房间号(房间ID)
* 客户创建会话时生成的唯一房间标识
* 示例:room_abc12345
*/
private String roomId;
/**
* 协同房间密码(共享码)
......
......@@ -27,4 +27,14 @@ public class CreateResponse {
* 会话状态:0-进行中,1-已结束,2-已超时
*/
private String status;
/**
* 协同房间二维码(扫码进入房间)
*/
private String roomQrCode;
/**
* 协同房间链接(访问链接进入房间)
*/
private String roomLink;
}
\ No newline at end of file
......@@ -74,6 +74,15 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
</dependency>
<!-- &lt;!&ndash; 阿里云 Java SDK 核心库 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.aliyun</groupId>-->
......
......@@ -97,12 +97,24 @@ public class CoSession implements Serializable {
private String roomId;
/**
* 协同房间密码(协同共享码,进入这个协同房间号的密码)
* 协同房间密码(输入密码进入房间,协同共享码,进入这个协同房间号的密码)
*/
@TableField("room_pwd")
private String roomPwd;
/**
* 协同房间二维码(扫码进入房间)
*/
@TableField("room_qr_code")
private String roomQrCode;
/**
* 协同房间链接(访问链接进入房间)
*/
@TableField("room_link")
private String roomLink;
/**
* RTC频道前缀,便于区分业务
*/
@TableField("channel_prefix")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment