Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-communication
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-communication
Commits
6cccf32b
Commit
6cccf32b
authored
Oct 12, 2026
by
zhangxingmin
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/dev' into prod
parents
1250fdf1
f88f8c46
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
903 additions
and
98 deletions
+903
-98
yd-communication-api/src/main/java/com/yd/communication/api/controller/ApiCoSessionController.java
+48
-0
yd-communication-api/src/main/java/com/yd/communication/api/service/ApiCoSessionService.java
+10
-0
yd-communication-api/src/main/java/com/yd/communication/api/service/impl/ApiCoSessionServiceImpl.java
+251
-93
yd-communication-feign/src/main/java/com/yd/communication/feign/client/ApiCoSessionFeignClient.java
+44
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/dto/RoomLinkDTO.java
+21
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/enums/RedisEnum.java
+2
-1
yd-communication-feign/src/main/java/com/yd/communication/feign/fallback/ApiCoSessionFeignFallbackFactory.java
+22
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/request/SetLinkFailureRequest.java
+11
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/response/GetLinkStatusResponse.java
+18
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/response/JoinResponse.java
+6
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/response/SetLinkFailureResponse.java
+12
-0
yd-communication-feign/src/main/java/com/yd/communication/feign/response/http/QuerySfpUserResponse.java
+46
-0
yd-communication-service/src/main/java/com/yd/communication/service/utils/CffpTokenUtil.java
+207
-0
yd-communication-service/src/main/java/com/yd/communication/service/utils/MyBatisPlusCodeGenerator.java
+4
-4
yd-communication-service/src/main/java/com/yd/communication/service/utils/SfpTokenUtil.java
+201
-0
No files found.
yd-communication-api/src/main/java/com/yd/communication/api/controller/ApiCoSessionController.java
View file @
6cccf32b
...
@@ -8,6 +8,7 @@ import com.yd.communication.feign.response.*;
...
@@ -8,6 +8,7 @@ import com.yd.communication.feign.response.*;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
javax.servlet.http.HttpServletRequest
;
/**
/**
...
@@ -44,6 +45,53 @@ public class ApiCoSessionController implements ApiCoSessionFeignClient {
...
@@ -44,6 +45,53 @@ public class ApiCoSessionController implements ApiCoSessionFeignClient {
}
}
/**
/**
* 根据房间号和密码获取会话详情
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return 完整会话信息
*/
@Override
public
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
)
{
return
apiCoSessionService
.
get
(
roomId
,
roomPwd
);
}
/**
* 获取房间链接状态信息
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return
*/
@Override
public
Result
<
GetLinkStatusResponse
>
getLinkStatus
(
String
roomId
,
String
roomPwd
)
{
return
apiCoSessionService
.
getLinkStatus
(
roomId
,
roomPwd
);
}
/**
* 设置房间链接状态为失效
*
* @param request 加入会话请求
* @return 会话详情
*/
@Override
public
Result
<
SetLinkFailureResponse
>
setLinkFailure
(
SetLinkFailureRequest
request
)
{
return
apiCoSessionService
.
setLinkFailure
(
request
);
}
/**
* 判断资源创建者和参与者是否是同一个人(供参与者调用)
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return true-是同一人 false-不是同一人
*/
@Override
public
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
)
{
return
apiCoSessionService
.
isMy
(
roomId
,
roomPwd
,
httpRequest
);
}
/**
* 获取会话状态
* 获取会话状态
* @param request
* @param request
* @return
* @return
...
...
yd-communication-api/src/main/java/com/yd/communication/api/service/ApiCoSessionService.java
View file @
6cccf32b
...
@@ -6,6 +6,8 @@ import com.yd.communication.feign.request.*;
...
@@ -6,6 +6,8 @@ import com.yd.communication.feign.request.*;
import
com.yd.communication.feign.response.*
;
import
com.yd.communication.feign.response.*
;
import
com.yd.communication.service.model.CoSession
;
import
com.yd.communication.service.model.CoSession
;
import
javax.servlet.http.HttpServletRequest
;
public
interface
ApiCoSessionService
{
public
interface
ApiCoSessionService
{
...
@@ -26,4 +28,12 @@ public interface ApiCoSessionService {
...
@@ -26,4 +28,12 @@ public interface ApiCoSessionService {
void
updateCurrentPage
(
String
roomId
,
String
newPageJson
,
String
operatorId
);
void
updateCurrentPage
(
String
roomId
,
String
newPageJson
,
String
operatorId
);
CoSession
getByRoomId
(
String
roomId
);
CoSession
getByRoomId
(
String
roomId
);
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
);
Result
<
GetLinkStatusResponse
>
getLinkStatus
(
String
roomId
,
String
roomPwd
);
Result
<
SetLinkFailureResponse
>
setLinkFailure
(
SetLinkFailureRequest
request
);
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
);
}
}
yd-communication-api/src/main/java/com/yd/communication/api/service/impl/ApiCoSessionServiceImpl.java
View file @
6cccf32b
package
com
.
yd
.
communication
.
api
.
service
.
impl
;
package
com
.
yd
.
communication
.
api
.
service
.
impl
;
import
com.alibaba.fastjson2.JSON
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.alibaba.fastjson2.JSONObject
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.yd.common.enums.CommonEnum
;
import
com.yd.common.enums.CommonEnum
;
...
@@ -13,6 +14,7 @@ import com.yd.common.utils.RedisUtil;
...
@@ -13,6 +14,7 @@ import com.yd.common.utils.RedisUtil;
import
com.yd.communication.api.service.ApiCoSessionService
;
import
com.yd.communication.api.service.ApiCoSessionService
;
import
com.yd.communication.api.utils.ClientInfoUtils
;
import
com.yd.communication.api.utils.ClientInfoUtils
;
import
com.yd.communication.api.utils.QRCodeUtils
;
import
com.yd.communication.api.utils.QRCodeUtils
;
import
com.yd.communication.feign.dto.RoomLinkDTO
;
import
com.yd.communication.feign.dto.RoomRedisInfoDTO
;
import
com.yd.communication.feign.dto.RoomRedisInfoDTO
;
import
com.yd.communication.feign.enums.CoSessionStatusEnum
;
import
com.yd.communication.feign.enums.CoSessionStatusEnum
;
import
com.yd.communication.feign.enums.ControlHolderTypeEnum
;
import
com.yd.communication.feign.enums.ControlHolderTypeEnum
;
...
@@ -21,6 +23,7 @@ import com.yd.communication.feign.request.*;
...
@@ -21,6 +23,7 @@ import com.yd.communication.feign.request.*;
import
com.yd.communication.feign.request.http.GenerateTokenRequest
;
import
com.yd.communication.feign.request.http.GenerateTokenRequest
;
import
com.yd.communication.feign.response.*
;
import
com.yd.communication.feign.response.*
;
import
com.yd.communication.feign.response.http.GenerateTokenResponse
;
import
com.yd.communication.feign.response.http.GenerateTokenResponse
;
import
com.yd.communication.feign.response.http.QuerySfpUserResponse
;
import
com.yd.communication.service.model.CoSession
;
import
com.yd.communication.service.model.CoSession
;
import
com.yd.communication.service.service.ICoOperationLogService
;
import
com.yd.communication.service.service.ICoOperationLogService
;
import
com.yd.communication.service.service.ICoSessionService
;
import
com.yd.communication.service.service.ICoSessionService
;
...
@@ -33,6 +36,7 @@ import lombok.extern.slf4j.Slf4j;
...
@@ -33,6 +36,7 @@ import lombok.extern.slf4j.Slf4j;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.BeanUtils
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.core.env.Environment
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.MediaType
;
...
@@ -41,10 +45,12 @@ import org.springframework.stereotype.Service;
...
@@ -41,10 +45,12 @@ import org.springframework.stereotype.Service;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.web.client.RestTemplate
;
import
org.springframework.web.client.RestTemplate
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
javax.annotation.Resource
;
import
javax.servlet.http.HttpServletRequest
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.UUID
;
import
java.util.UUID
;
@Slf4j
@Slf4j
...
@@ -72,19 +78,71 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -72,19 +78,71 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
@Resource
@Resource
private
RestTemplate
restTemplate
;
private
RestTemplate
restTemplate
;
@Value
(
"${sfp.api.base-url:https://mdev.anjibao.cn/sfpApi}"
)
@Resource
private
String
sfpApiBaseUrl
;
private
Environment
env
;
// 注入 Environment 用于获取环境配置
/**
* 根据当前环境动态获取 SFP API 基础地址
*/
private
String
getSfpApiBaseUrl
()
{
String
activeProfile
=
env
.
getProperty
(
"spring.profiles.active"
,
"dev"
);
log
.
info
(
"当前环境: {}, 获取 SFP API 地址"
,
activeProfile
);
if
(
"prod"
.
equalsIgnoreCase
(
activeProfile
)
||
"production"
.
equalsIgnoreCase
(
activeProfile
))
{
// 生产环境
return
"https://hoservice.ydhomeoffice.cn/hoserviceApi"
;
}
else
{
// 测试/开发环境
return
"https://mdev.anjibao.cn/sfpApi"
;
}
}
/**
* 远程调用 /user/parse/token 接口解析 Token,获取用户信息
* @param authorization 请求头中的原始 X-Authorization 值(含前缀)
* @return 用户信息对象
*/
private
QuerySfpUserResponse
parseTokenRemotely
(
String
authorization
)
{
if
(
StringUtils
.
isBlank
(
authorization
))
{
throw
new
BusinessException
(
"Token 不能为空"
);
}
// 直接传递原始 authorization,远程接口内部自行剥离前缀
String
token
=
authorization
;
String
url
=
getSfpApiBaseUrl
()
+
"/user/parse/token"
;
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
Map
<
String
,
String
>
requestBody
=
new
HashMap
<>();
requestBody
.
put
(
"token"
,
token
);
HttpEntity
<
Map
<
String
,
String
>>
entity
=
new
HttpEntity
<>(
requestBody
,
headers
);
log
.
info
(
"【远程解析Token】url={}, token前50字符={}"
,
url
,
token
.
substring
(
0
,
Math
.
min
(
50
,
token
.
length
())));
try
{
ResponseEntity
<
JsonResult
>
responseEntity
=
restTemplate
.
postForEntity
(
url
,
entity
,
JsonResult
.
class
);
if
(
responseEntity
.
getStatusCode
().
is2xxSuccessful
())
{
JsonResult
body
=
responseEntity
.
getBody
();
if
(
body
!=
null
&&
body
.
isSuccess
())
{
Object
data
=
body
.
getData
();
if
(
data
!=
null
)
{
QuerySfpUserResponse
userInfo
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
data
),
QuerySfpUserResponse
.
class
);
if
(
userInfo
.
getId
()
==
null
)
{
throw
new
BusinessException
(
"远程解析Token返回的用户ID为空"
);
}
log
.
info
(
"【远程解析Token】成功,userId={}"
,
userInfo
.
getId
());
return
userInfo
;
}
}
}
log
.
error
(
"【远程解析Token】失败,response={}"
,
responseEntity
);
throw
new
BusinessException
(
"远程解析Token失败,请重新登录"
);
}
catch
(
Exception
e
)
{
log
.
error
(
"【远程解析Token】异常"
,
e
);
throw
new
BusinessException
(
"解析Token异常:"
+
e
.
getMessage
());
}
}
/**
/**
* 客户创建会话
* 客户创建会话
* @param scope
* @param resourceType
* @param resourceId
* @param resourceInit
* @param ownerId
* @param ownerType
* @param userId
* @return
*/
*/
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
CoSession
createSession
(
String
scope
,
String
resourceType
,
String
resourceId
,
public
CoSession
createSession
(
String
scope
,
String
resourceType
,
String
resourceId
,
...
@@ -127,41 +185,35 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -127,41 +185,35 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
// 获取 Token(调用 /user/generate/token)
// 获取 Token(调用 /user/generate/token)
String
token
=
null
;
String
token
=
null
;
GenerateTokenResponse
tokenResp
=
null
;
String
name
=
null
;
GenerateTokenResponse
tokenResp
=
null
;
try
{
try
{
// 构建请求体
GenerateTokenRequest
tokenRequest
=
new
GenerateTokenRequest
();
GenerateTokenRequest
tokenRequest
=
new
GenerateTokenRequest
();
// 注意:userId 是 String,转为 Long。若 userId 可能为空,需做判空处理
if
(
StringUtils
.
isNotBlank
(
userId
))
{
if
(
StringUtils
.
isNotBlank
(
userId
))
{
tokenRequest
.
setSfpUserId
(
Long
.
valueOf
(
userId
));
tokenRequest
.
setSfpUserId
(
Long
.
valueOf
(
userId
));
}
else
{
}
else
{
// 如果 userId 为空,可以尝试用 ownerId 或抛出业务异常,根据业务定
throw
new
BusinessException
(
"userId 不能为空,无法生成 Token"
);
throw
new
BusinessException
(
"userId 不能为空,无法生成 Token"
);
}
}
// 发起 POST 请求
String
url
=
getSfpApiBaseUrl
()
+
"/user/generate/token"
;
String
url
=
sfpApiBaseUrl
+
"/user/generate/token"
;
HttpHeaders
headers
=
new
HttpHeaders
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
headers
.
setContentType
(
MediaType
.
APPLICATION_JSON
);
HttpEntity
<
GenerateTokenRequest
>
entity
=
new
HttpEntity
<>(
tokenRequest
,
headers
);
HttpEntity
<
GenerateTokenRequest
>
entity
=
new
HttpEntity
<>(
tokenRequest
,
headers
);
log
.
info
(
"【Token生成】sfpApiBaseUrl = {}"
,
sfpApiBaseUrl
);
log
.
info
(
"【Token生成】完整URL = {}"
,
url
);
log
.
info
(
"【Token生成】完整URL = {}"
,
sfpApiBaseUrl
+
"/user/generate/token"
);
log
.
info
(
"【Token生成】请求体 = {}"
,
JSONObject
.
toJSONString
(
tokenRequest
));
log
.
info
(
"【Token生成】请求体GenerateTokenRequest = {}"
,
JSONObject
.
toJSONString
(
tokenRequest
));
log
.
info
(
"【Token生成】请求体entity = {}"
,
JSONObject
.
toJSONString
(
entity
));
ResponseEntity
<
JsonResult
>
responseEntity
=
restTemplate
.
postForEntity
(
url
,
entity
,
JsonResult
.
class
);
ResponseEntity
<
JsonResult
>
responseEntity
=
restTemplate
.
postForEntity
(
url
,
entity
,
JsonResult
.
class
);
log
.
info
(
"【Token生成】返回体
responseEntity
= {}"
,
JSONObject
.
toJSONString
(
responseEntity
));
log
.
info
(
"【Token生成】返回体 = {}"
,
JSONObject
.
toJSONString
(
responseEntity
));
if
(
responseEntity
.
getStatusCode
().
is2xxSuccessful
())
{
if
(
responseEntity
.
getStatusCode
().
is2xxSuccessful
())
{
JsonResult
body
=
responseEntity
.
getBody
();
JsonResult
body
=
responseEntity
.
getBody
();
if
(
body
!=
null
&&
body
.
isSuccess
())
{
if
(
body
!=
null
&&
body
.
isSuccess
())
{
// 假设 body.getData() 返回的是 LinkedHashMap,需要转为 GenerateTokenResponse
// 或者直接使用 fastjson 转换
Object
data
=
body
.
getData
();
Object
data
=
body
.
getData
();
if
(
data
!=
null
)
{
if
(
data
!=
null
)
{
tokenResp
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
data
),
GenerateTokenResponse
.
class
);
tokenResp
=
JSONObject
.
parseObject
(
JSONObject
.
toJSONString
(
data
),
GenerateTokenResponse
.
class
);
token
=
tokenResp
.
getToken
();
token
=
tokenResp
.
getToken
();
name
=
tokenResp
.
getName
();
}
}
}
}
}
}
...
@@ -183,12 +235,13 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -183,12 +235,13 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
roomRedisInfoDTO
.
setName
(
tokenResp
.
getName
());
roomRedisInfoDTO
.
setName
(
tokenResp
.
getName
());
roomRedisInfoDTO
.
setMobile
(
tokenResp
.
getMobile
());
roomRedisInfoDTO
.
setMobile
(
tokenResp
.
getMobile
());
}
}
roomRedisInfoDTO
.
setToken
(
token
);
// 设置 token
roomRedisInfoDTO
.
setToken
(
token
);
roomRedisInfoDTO
.
setUserId
(
userId
);
roomRedisInfoDTO
.
setUserId
(
userId
);
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
roomRedisInfoDTO
.
setRoomId
(
roomId
);
roomRedisInfoDTO
.
setRoomId
(
roomId
);
roomRedisInfoDTO
.
setRoomPwd
(
roomPwd
);
roomRedisInfoDTO
.
setRoomPwd
(
roomPwd
);
roomRedisInfoDTO
.
setName
(
name
);
redisUtil
.
setCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
roomPwd
,
roomRedisInfoDTO
,
redisUtil
.
setCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
roomPwd
,
roomRedisInfoDTO
,
RedisEnum
.
ROOM
.
getTimeout
(),
RedisEnum
.
ROOM
.
getTimeUnit
());
RedisEnum
.
ROOM
.
getTimeout
(),
RedisEnum
.
ROOM
.
getTimeUnit
());
log
.
info
(
"【创建会话-内部】Redis缓存已设置, key={}"
,
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
);
log
.
info
(
"【创建会话-内部】Redis缓存已设置, key={}"
,
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
);
...
@@ -219,9 +272,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -219,9 +272,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
/**
/**
* 创建会话
* 创建会话(对外接口)
* @param request
* @return
*/
*/
@Override
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
...
@@ -243,26 +294,30 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -243,26 +294,30 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
return
Result
.
success
();
return
Result
.
success
();
}
}
// 2. 构建房间链接(从配置读取)
// 2. 构建房间链接
String
roomLink
=
roomBaseUrl
+
"&roomId="
+
session
.
getRoomId
()
+
"&pwd="
+
session
.
getRoomPwd
();
//纯链接
log
.
info
(
"【创建会话】生成房间链接: {}"
,
roomLink
);
String
roomLink
=
roomBaseUrl
+
"&accessMethod=2&roomId="
+
session
.
getRoomId
()
+
"&roomPwd="
+
session
.
getRoomPwd
();
//二维码里面的链接
String
qrCodeRoomLink
=
roomBaseUrl
+
"&accessMethod=1&roomId="
+
session
.
getRoomId
()
+
"&roomPwd="
+
session
.
getRoomPwd
();
log
.
info
(
"【创建会话】生成房间纯链接: {}"
,
roomLink
);
log
.
info
(
"【创建会话】生成房间二维码里面的链接: {}"
,
qrCodeRoomLink
);
// 3. 生成二维码图片字节数组
(PNG格式)
// 3. 生成二维码图片字节数组
byte
[]
qrCodeBytes
=
QRCodeUtils
.
generateQRCode
(
r
oomLink
,
300
,
300
);
byte
[]
qrCodeBytes
=
QRCodeUtils
.
generateQRCode
(
qrCodeR
oomLink
,
300
,
300
);
// 4. 将字节数组转换为 MultipartFile
// 4. 将字节数组转换为 MultipartFile
String
fileName
=
session
.
getCoSessionBizId
()
+
".png"
;
String
fileName
=
session
.
getCoSessionBizId
()
+
".png"
;
MultipartFile
multipartFile
=
new
ByteArrayMultipartFile
(
MultipartFile
multipartFile
=
new
ByteArrayMultipartFile
(
qrCodeBytes
,
// 图片字节数组
qrCodeBytes
,
"file"
,
// 字段名,与 Feign @RequestPart("file") 匹配
"file"
,
fileName
,
// 原始文件名
fileName
,
"image/png"
// 内容类型
"image/png"
);
);
// 5. 构建 OSS 上传请求参数
// 5. 构建 OSS 上传请求参数
ApiUploadFileRequest
ossRequest
=
new
ApiUploadFileRequest
();
ApiUploadFileRequest
ossRequest
=
new
ApiUploadFileRequest
();
ossRequest
.
setObjectBizId
(
session
.
getCoSessionBizId
());
// 必填,使用会话业务ID
ossRequest
.
setObjectBizId
(
session
.
getCoSessionBizId
());
ossRequest
.
setObjectType
(
"co_session_qr"
);
// 自定义对象类型
ossRequest
.
setObjectType
(
"co_session_qr"
);
ossRequest
.
setObjectName
(
"协同会话二维码"
);
ossRequest
.
setObjectName
(
"协同会话二维码"
);
ossRequest
.
setProjectBizId
(
""
);
ossRequest
.
setProjectBizId
(
""
);
ossRequest
.
setTenantBizId
(
""
);
ossRequest
.
setTenantBizId
(
""
);
...
@@ -275,24 +330,26 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -275,24 +330,26 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
throw
new
BusinessException
(
"二维码上传失败:"
+
(
uploadResult
!=
null
?
uploadResult
.
getMsg
()
:
"未知错误"
));
throw
new
BusinessException
(
"二维码上传失败:"
+
(
uploadResult
!=
null
?
uploadResult
.
getMsg
()
:
"未知错误"
));
}
}
// 7. 获取文件访问 URL
(假设 ApiUploadResponse 包含 url 字段)
// 7. 获取文件访问 URL
ApiUploadResponse
uploadData
=
uploadResult
.
getData
();
ApiUploadResponse
uploadData
=
uploadResult
.
getData
();
String
roomQrCodeUrl
=
uploadData
.
getUrl
();
// 若字段名为 fileUrl 则对应调整
String
roomQrCodeUrl
=
uploadData
.
getUrl
();
log
.
info
(
"【创建会话】OSS上传成功,文件URL: {}"
,
roomQrCodeUrl
);
log
.
info
(
"【创建会话】OSS上传成功,文件URL: {}"
,
roomQrCodeUrl
);
//
8. 更新会话信息表数据
//
8. 更新会话信息
session
.
setRoomQrCode
(
roomQrCodeUrl
);
session
.
setRoomQrCode
(
roomQrCodeUrl
);
session
.
setRoomLink
(
roomLink
);
session
.
setRoomLink
(
roomLink
);
iCoSessionService
.
saveOrUpdate
(
session
);
iCoSessionService
.
saveOrUpdate
(
session
);
//设置房间链接失效时间(用于扫码和链接直接访问,加载页面后调用校验接口判断是否失效)
// 设置房间链接失效时间(用于扫码和链接直接访问,默认2小时)
//设置房间链接失效时间(用于扫码和链接直接访问)
RoomLinkDTO
roomLinkDTO
=
new
RoomLinkDTO
();
roomLinkDTO
.
setQrCodeRoomLink
(
qrCodeRoomLink
);
roomLinkDTO
.
setRoomLink
(
roomLink
);
redisUtil
.
setCacheObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
(),
redisUtil
.
setCacheObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
(),
session
.
getRoomLink
()
,
roomLinkDTO
,
RedisEnum
.
ROOM_LINK
.
getTimeout
(),
RedisEnum
.
ROOM_LINK
.
getTimeout
(),
RedisEnum
.
ROOM_LINK
.
getTimeUnit
());
RedisEnum
.
ROOM_LINK
.
getTimeUnit
());
// 计算链接失效时间点
(当前时间 + 缓存过期时长)
// 计算链接失效时间点
long
expireMillis
=
RedisEnum
.
ROOM_LINK
.
getTimeUnit
().
toMillis
(
RedisEnum
.
ROOM_LINK
.
getTimeout
());
long
expireMillis
=
RedisEnum
.
ROOM_LINK
.
getTimeUnit
().
toMillis
(
RedisEnum
.
ROOM_LINK
.
getTimeout
());
Date
expirationDate
=
new
Date
(
System
.
currentTimeMillis
()
+
expireMillis
);
Date
expirationDate
=
new
Date
(
System
.
currentTimeMillis
()
+
expireMillis
);
...
@@ -304,7 +361,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -304,7 +361,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
response
.
setStatus
(
session
.
getStatus
());
response
.
setStatus
(
session
.
getStatus
());
response
.
setRoomLink
(
roomLink
);
response
.
setRoomLink
(
roomLink
);
response
.
setRoomQrCode
(
roomQrCodeUrl
);
response
.
setRoomQrCode
(
roomQrCodeUrl
);
response
.
setExpirationTime
(
expirationDate
);
// 设置过期时间
response
.
setExpirationTime
(
expirationDate
);
log
.
info
(
"【创建会话】成功,roomId={}, sessionBizId={}"
,
session
.
getRoomId
(),
session
.
getCoSessionBizId
());
log
.
info
(
"【创建会话】成功,roomId={}, sessionBizId={}"
,
session
.
getRoomId
(),
session
.
getCoSessionBizId
());
return
Result
.
success
(
response
);
return
Result
.
success
(
response
);
...
@@ -341,7 +398,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -341,7 +398,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
joinResponse
.
setSessionBizId
(
session
.
getCoSessionBizId
());
joinResponse
.
setSessionBizId
(
session
.
getCoSessionBizId
());
// 获取资源所有者缓存中的登录信息
// 获取资源所有者缓存中的登录信息
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
if
(
roomRedisInfoDTO
==
null
)
{
if
(
roomRedisInfoDTO
==
null
)
{
log
.
error
(
"【加入会话】会话发起者缓存信息不存在,roomId={}"
,
session
.
getRoomId
());
log
.
error
(
"【加入会话】会话发起者缓存信息不存在,roomId={}"
,
session
.
getRoomId
());
throw
new
BusinessException
(
"会话发起者登录信息失效,建议联系会话发起者再次发起"
);
throw
new
BusinessException
(
"会话发起者登录信息失效,建议联系会话发起者再次发起"
);
...
@@ -354,8 +411,8 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -354,8 +411,8 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
log
.
info
(
"【加入会话】成功, roomId={}, participantId={}, controlHolderType={}"
,
log
.
info
(
"【加入会话】成功, roomId={}, participantId={}, controlHolderType={}"
,
session
.
getRoomId
(),
session
.
getParticipantId
(),
session
.
getControlHolderType
());
session
.
getRoomId
(),
session
.
getParticipantId
(),
session
.
getControlHolderType
());
//
删除房间链接缓存(只能访问一次,下次重新生成
)
//
删除房间链接缓存(注释掉,保留一次有效
)
redisUtil
.
deleteObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
());
//
redisUtil.deleteObject(RedisEnum.ROOM_LINK.getPrefix() + session.getRoomId() + ":" + session.getRoomPwd());
return
Result
.
success
(
joinResponse
);
return
Result
.
success
(
joinResponse
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
...
@@ -365,22 +422,17 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -365,22 +422,17 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
/**
/**
* 顾问加入会话
* 顾问加入会话(内部方法)
* @param roomId
* @param roomPwd
* @param participantId
* @param participantType
* @return
*/
*/
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
CoSession
joinSession
(
String
roomId
,
String
roomPwd
,
String
participantId
,
String
participantType
)
{
public
CoSession
joinSession
(
String
roomId
,
String
roomPwd
,
String
participantId
,
String
participantType
)
{
log
.
info
(
"【加入会话-内部】开始, roomId={}, roomPwd={}, participantId={}, participantType={}"
,
roomId
,
roomPwd
,
participantId
,
participantType
);
log
.
info
(
"【加入会话-内部】开始, roomId={}, roomPwd={}, participantId={}, participantType={}"
,
roomId
,
roomPwd
,
participantId
,
participantType
);
try
{
try
{
//校验房间链接是否失效
//
校验房间链接是否失效
String
roomLink
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
roomId
+
":"
+
roomPwd
);
//
String roomLink = redisUtil.getCacheObject(RedisEnum.ROOM_LINK.getPrefix() + roomId + ":" + roomPwd);
if
(
StringUtils
.
isBlank
(
roomLink
))
{
//
if (StringUtils.isBlank(roomLink)) {
throw
new
BusinessException
(
ResultCode
.
LINK_INVALID
.
getCode
(),
"访问链接已失效,请重新生成"
);
// throw new BusinessException(ResultCode.LINK_INVALID.getCode(),
"访问链接已失效,请重新生成");
}
//
}
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
)
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
)
.
eq
(
CoSession:
:
getRoomPwd
,
roomPwd
)
.
eq
(
CoSession:
:
getRoomPwd
,
roomPwd
)
...
@@ -397,11 +449,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -397,11 +449,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
log
.
warn
(
"【加入会话-内部】会话已结束,roomId={}"
,
session
.
getRoomId
());
log
.
warn
(
"【加入会话-内部】会话已结束,roomId={}"
,
session
.
getRoomId
());
throw
new
BusinessException
(
"会话已结束,不能再次加入房间"
);
throw
new
BusinessException
(
"会话已结束,不能再次加入房间"
);
}
}
// if (StringUtils.isNotBlank(session.getParticipantId()) && !session.getParticipantId().equals(participantId)) {
// log.warn("【加入会话-内部】房间被占用,当前参与者={}, 新参与者={}",
// session.getParticipantId(), participantId);
// throw new BusinessException("当前房间被占用,不能加入到房间");
// }
// 若为待开始状态,设置开始时间并转移控制权
// 若为待开始状态,设置开始时间并转移控制权
if
(
CoSessionStatusEnum
.
DKS
.
getItemValue
().
equals
(
session
.
getStatus
()))
{
if
(
CoSessionStatusEnum
.
DKS
.
getItemValue
().
equals
(
session
.
getStatus
()))
{
...
@@ -409,13 +456,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -409,13 +456,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
session
.
setStartTime
(
LocalDateTime
.
now
());
session
.
setStartTime
(
LocalDateTime
.
now
());
log
.
info
(
"【加入会话-内部】设置开始时间={}"
,
session
.
getStartTime
());
log
.
info
(
"【加入会话-内部】设置开始时间={}"
,
session
.
getStartTime
());
}
}
// 待开始状态下,控制权自动移交给参与者(顾问)
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
PARTICIPANT
.
getItemValue
());
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
PARTICIPANT
.
getItemValue
());
session
.
setControlHolderId
(
participantId
);
session
.
setControlHolderId
(
participantId
);
log
.
info
(
"【加入会话-内部】待开始状态,控制权移交给参与者={}"
,
participantId
);
log
.
info
(
"【加入会话-内部】待开始状态,控制权移交给参与者={}"
,
participantId
);
}
else
{
}
else
{
// 如果会话已经是进行中,但可能控制权不在顾问,此处强制转移给顾问(根据业务需求,可调整)
// 如果会话已经是进行中,但可能控制权不在顾问,此处强制转移给顾问
// 如果不希望强制转移,可注释掉以下行
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
PARTICIPANT
.
getItemValue
());
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
PARTICIPANT
.
getItemValue
());
session
.
setControlHolderId
(
participantId
);
session
.
setControlHolderId
(
participantId
);
log
.
info
(
"【加入会话-内部】强制控制权移交给参与者={}"
,
participantId
);
log
.
info
(
"【加入会话-内部】强制控制权移交给参与者={}"
,
participantId
);
...
@@ -430,7 +475,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -430,7 +475,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
log
.
info
(
"【加入会话-内部】数据库更新成功,新状态={}"
,
session
.
getStatus
());
log
.
info
(
"【加入会话-内部】数据库更新成功,新状态={}"
,
session
.
getStatus
());
// 更新 Redis 缓存
// 更新 Redis 缓存
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
session
.
getRoomId
()
+
":"
+
session
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
if
(
roomRedisInfoDTO
!=
null
)
{
if
(
roomRedisInfoDTO
!=
null
)
{
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
...
@@ -462,13 +507,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -462,13 +507,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
/**
/**
* 获取会话状态
* 获取会话状态
* @param request
* @return
*/
*/
@Override
@Override
public
Result
<
GetStatusResponse
>
getStatus
(
GetStatusRequest
request
)
{
public
Result
<
GetStatusResponse
>
getStatus
(
GetStatusRequest
request
)
{
CoSession
coSession
=
iCoSessionService
.
lambdaQuery
()
CoSession
coSession
=
iCoSessionService
.
lambdaQuery
()
.
eq
(
CoSession:
:
getCoSessionBizId
,
request
.
getSessionBizId
())
.
eq
(
CoSession:
:
getCoSessionBizId
,
request
.
getSessionBizId
())
.
last
(
" limit 1 "
)
.
last
(
" limit 1 "
)
.
one
();
.
one
();
if
(
coSession
==
null
)
{
if
(
coSession
==
null
)
{
...
@@ -477,10 +520,9 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -477,10 +520,9 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
GetStatusResponse
response
=
new
GetStatusResponse
();
GetStatusResponse
response
=
new
GetStatusResponse
();
String
roomLink
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
coSession
.
getRoomId
()
+
":"
+
coSession
.
getRoomPwd
());
String
roomLink
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
coSession
.
getRoomId
()
+
":"
+
coSession
.
getRoomPwd
());
if
(
StringUtils
.
isBlank
(
roomLink
))
{
if
(
StringUtils
.
isBlank
(
roomLink
))
{
//2-已失效
response
.
setStatus
(
2
);
// 已失效
response
.
setStatus
(
2
);
}
else
{
}
else
{
response
.
setStatus
(
1
);
// 有效
response
.
setStatus
(
1
);
}
}
return
Result
.
success
(
response
);
return
Result
.
success
(
response
);
}
}
...
@@ -508,7 +550,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -508,7 +550,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
/**
/**
* 结束会话
(客户调用)
* 结束会话
*/
*/
@Override
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
...
@@ -525,7 +567,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -525,7 +567,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
log
.
info
(
"【结束会话】找到会话,当前状态={}"
,
coSession
.
getStatus
());
log
.
info
(
"【结束会话】找到会话,当前状态={}"
,
coSession
.
getStatus
());
// 结束会话关闭共享,更新信息
coSession
.
setStatus
(
CoSessionStatusEnum
.
YJS
.
getItemValue
());
coSession
.
setStatus
(
CoSessionStatusEnum
.
YJS
.
getItemValue
());
coSession
.
setEndTime
(
LocalDateTime
.
now
());
coSession
.
setEndTime
(
LocalDateTime
.
now
());
iCoSessionService
.
saveOrUpdate
(
coSession
);
iCoSessionService
.
saveOrUpdate
(
coSession
);
...
@@ -535,7 +576,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -535,7 +576,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
redisUtil
.
deleteObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
coSession
.
getRoomId
()
+
":"
+
coSession
.
getRoomPwd
());
redisUtil
.
deleteObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
coSession
.
getRoomId
()
+
":"
+
coSession
.
getRoomPwd
());
log
.
info
(
"【结束会话】Redis缓存已删除"
);
log
.
info
(
"【结束会话】Redis缓存已删除"
);
// 添加操作日志,协同-操作日志表
operationLogService
.
log
(
operationLogService
.
log
(
coSession
.
getCoSessionBizId
(),
coSession
.
getCoSessionBizId
(),
null
,
null
,
...
@@ -558,7 +598,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -558,7 +598,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
/**
/**
* 切换控制权
(顾问调用)
* 切换控制权
*/
*/
@Override
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
...
@@ -583,7 +623,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -583,7 +623,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
public
void
transferControlUp
(
Integer
oprType
,
String
roomId
)
{
public
void
transferControlUp
(
Integer
oprType
,
String
roomId
)
{
log
.
info
(
"【切换控制权-内部】开始, oprType={}, roomId={}"
,
oprType
,
roomId
);
log
.
info
(
"【切换控制权-内部】开始, oprType={}, roomId={}"
,
oprType
,
roomId
);
try
{
try
{
// 根据房间号查询会话信息
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
).
last
(
" limit 1 "
);
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
).
last
(
" limit 1 "
);
CoSession
session
=
iCoSessionService
.
getOne
(
wrapper
);
CoSession
session
=
iCoSessionService
.
getOne
(
wrapper
);
...
@@ -593,14 +632,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -593,14 +632,11 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
log
.
info
(
"【切换控制权-内部】找到会话, 当前控制者={}:{}"
,
session
.
getControlHolderType
(),
session
.
getControlHolderId
());
log
.
info
(
"【切换控制权-内部】找到会话, 当前控制者={}:{}"
,
session
.
getControlHolderType
(),
session
.
getControlHolderId
());
// 移交控制权
if
(
oprType
==
1
)
{
if
(
oprType
==
1
)
{
// 1-开启客户操作,控制权移交给资源所有者(客户)
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
OWNER
.
getItemValue
());
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
OWNER
.
getItemValue
());
session
.
setControlHolderId
(
session
.
getOwnerId
());
session
.
setControlHolderId
(
session
.
getOwnerId
());
log
.
info
(
"【切换控制权-内部】开启客户操作,控制权移交给所有者={}"
,
session
.
getOwnerId
());
log
.
info
(
"【切换控制权-内部】开启客户操作,控制权移交给所有者={}"
,
session
.
getOwnerId
());
}
else
if
(
oprType
==
2
)
{
}
else
if
(
oprType
==
2
)
{
// 2-关闭客户操作,控制权移交给参与者(顾问)
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
PARTICIPANT
.
getItemValue
());
session
.
setControlHolderType
(
ControlHolderTypeEnum
.
PARTICIPANT
.
getItemValue
());
session
.
setControlHolderId
(
session
.
getParticipantId
());
session
.
setControlHolderId
(
session
.
getParticipantId
());
log
.
info
(
"【切换控制权-内部】关闭客户操作,控制权移交给参与者={}"
,
session
.
getParticipantId
());
log
.
info
(
"【切换控制权-内部】关闭客户操作,控制权移交给参与者={}"
,
session
.
getParticipantId
());
...
@@ -613,8 +649,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -613,8 +649,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
log
.
info
(
"【切换控制权-内部】数据库更新成功,新控制者={}:{}"
,
log
.
info
(
"【切换控制权-内部】数据库更新成功,新控制者={}:{}"
,
session
.
getControlHolderType
(),
session
.
getControlHolderId
());
session
.
getControlHolderType
(),
session
.
getControlHolderId
());
// 更新房间缓存redis信息
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
session
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
session
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
if
(
roomRedisInfoDTO
!=
null
)
{
if
(
roomRedisInfoDTO
!=
null
)
{
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
...
@@ -624,7 +659,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -624,7 +659,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
else
{
}
else
{
log
.
warn
(
"【切换控制权-内部】Redis缓存不存在,可能已过期"
);
log
.
warn
(
"【切换控制权-内部】Redis缓存不存在,可能已过期"
);
}
}
// 添加操作日志,协同-操作日志表
operationLogService
.
log
(
operationLogService
.
log
(
session
.
getCoSessionBizId
(),
session
.
getCoSessionBizId
(),
session
.
getParticipantId
(),
session
.
getParticipantId
(),
...
@@ -664,7 +698,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -664,7 +698,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderType
(
session
.
getControlHolderType
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
roomRedisInfoDTO
.
setControlHolderId
(
session
.
getControlHolderId
());
// 查询出来的信息更新回缓存
里面
// 查询出来的信息更新回缓存
redisUtil
.
setCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
session
.
getRoomPwd
(),
roomRedisInfoDTO
,
redisUtil
.
setCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
session
.
getRoomPwd
(),
roomRedisInfoDTO
,
RedisEnum
.
ROOM
.
getTimeout
(),
RedisEnum
.
ROOM
.
getTimeUnit
());
RedisEnum
.
ROOM
.
getTimeout
(),
RedisEnum
.
ROOM
.
getTimeUnit
());
log
.
info
(
"【获取当前控制者】从数据库加载并更新缓存,控制者={}:{}"
,
log
.
info
(
"【获取当前控制者】从数据库加载并更新缓存,控制者={}:{}"
,
...
@@ -699,7 +733,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -699,7 +733,6 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
if
(
history
==
null
||
history
.
equals
(
"[]"
)
||
history
.
isEmpty
())
{
if
(
history
==
null
||
history
.
equals
(
"[]"
)
||
history
.
isEmpty
())
{
history
=
"["
+
newPageJson
+
"]"
;
history
=
"["
+
newPageJson
+
"]"
;
}
else
{
}
else
{
// 简单追加(生产环境建议用JSONArray处理)
history
=
history
.
substring
(
0
,
history
.
length
()
-
1
)
+
","
+
newPageJson
+
"]"
;
history
=
history
.
substring
(
0
,
history
.
length
()
-
1
)
+
","
+
newPageJson
+
"]"
;
}
}
iCoSessionService
.
updateCurrentPageAndHistory
(
roomId
,
newPageJson
,
history
,
operatorId
);
iCoSessionService
.
updateCurrentPageAndHistory
(
roomId
,
newPageJson
,
history
,
operatorId
);
...
@@ -711,7 +744,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -711,7 +744,7 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
/**
/**
* 根据房间号获取会话
信息
* 根据房间号获取会话
*/
*/
@Override
@Override
public
CoSession
getByRoomId
(
String
roomId
)
{
public
CoSession
getByRoomId
(
String
roomId
)
{
...
@@ -731,7 +764,132 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
...
@@ -731,7 +764,132 @@ public class ApiCoSessionServiceImpl implements ApiCoSessionService {
}
}
}
}
/**
* 根据房间号和密码获取会话详情
*/
@Override
public
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
)
{
log
.
info
(
"【根据房间号和密码获取会话详情】roomId={}, roomPwd={}"
,
roomId
,
roomPwd
);
if
(
StringUtils
.
isBlank
(
roomId
))
{
throw
new
BusinessException
(
"房间号不能为空"
);
}
if
(
StringUtils
.
isBlank
(
roomPwd
))
{
throw
new
BusinessException
(
"房间密码不能为空"
);
}
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
)
.
eq
(
CoSession:
:
getRoomPwd
,
roomPwd
)
.
last
(
" limit 1 "
);
CoSession
session
=
iCoSessionService
.
getOne
(
wrapper
);
log
.
info
(
"根据房间号和密码获取会话详情CoSession对象:{}"
,
JSONObject
.
toJSONString
(
session
));
if
(
session
==
null
)
{
throw
new
BusinessException
(
"会话信息不存在"
);
}
SessionDetailResponse
response
=
new
SessionDetailResponse
();
BeanUtils
.
copyProperties
(
session
,
response
);
log
.
info
(
"根据房间号和密码获取会话详情出参:{}"
,
JSONObject
.
toJSONString
(
response
));
return
Result
.
success
(
response
);
}
/**
* 获取房间链接状态信息
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return
*/
@Override
public
Result
<
GetLinkStatusResponse
>
getLinkStatus
(
String
roomId
,
String
roomPwd
)
{
if
(
StringUtils
.
isBlank
(
roomId
))
{
throw
new
BusinessException
(
"房间号不能为空"
);
}
if
(
StringUtils
.
isBlank
(
roomPwd
))
{
throw
new
BusinessException
(
"房间密码不能为空"
);
}
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
roomId
+
":"
+
roomPwd
,
RoomRedisInfoDTO
.
class
);
GetLinkStatusResponse
response
=
new
GetLinkStatusResponse
();
response
.
setReportOwnerName
(
roomRedisInfoDTO
!=
null
?
roomRedisInfoDTO
.
getName
()
:
""
);
//报告归属人手机号尾号四位
String
ownerMobile
=
roomRedisInfoDTO
.
getMobile
();
String
ownerMobileLast
=
""
;
if
(
StringUtils
.
isNotBlank
(
ownerMobile
)
&&
ownerMobile
.
length
()
>=
4
)
{
ownerMobileLast
=
ownerMobile
.
substring
(
ownerMobile
.
length
()
-
4
);
}
else
{
ownerMobileLast
=
"****"
;
}
response
.
setReportOwnerMobileLast
(
ownerMobileLast
);
RoomLinkDTO
roomLinkDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
roomId
+
":"
+
roomPwd
,
RoomLinkDTO
.
class
);
if
(
roomLinkDTO
==
null
)
{
//访问链接已失效
return
Result
.
fail
(
ResultCode
.
LINK_INVALID
.
getCode
(),
ResultCode
.
LINK_INVALID
.
getMessage
(),
response
);
}
return
Result
.
success
(
response
);
}
/**
* 设置房间链接状态为失效
*
* @param request 加入会话请求
* @return 会话详情
*/
@Override
public
Result
<
SetLinkFailureResponse
>
setLinkFailure
(
SetLinkFailureRequest
request
)
{
if
(
StringUtils
.
isBlank
(
request
.
getRoomId
()))
{
throw
new
BusinessException
(
"房间号不能为空"
);
}
if
(
StringUtils
.
isBlank
(
request
.
getRoomPwd
()))
{
throw
new
BusinessException
(
"房间密码不能为空"
);
}
//删除
redisUtil
.
deleteObject
(
RedisEnum
.
ROOM_LINK
.
getPrefix
()
+
request
.
getRoomId
()
+
":"
+
request
.
getRoomPwd
());
RoomRedisInfoDTO
roomRedisInfoDTO
=
redisUtil
.
getCacheObject
(
RedisEnum
.
ROOM
.
getPrefix
()
+
request
.
getRoomId
()
+
":"
+
request
.
getRoomPwd
(),
RoomRedisInfoDTO
.
class
);
SetLinkFailureResponse
response
=
new
SetLinkFailureResponse
();
response
.
setReportOwnerName
(
roomRedisInfoDTO
!=
null
?
roomRedisInfoDTO
.
getName
()
:
""
);
return
Result
.
success
(
response
);
}
/**
* 判断资源创建者和参与者是否是同一个人
*/
@Override
public
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
)
{
log
.
info
(
"【判断资源创建者和参与者是否是同一个人】roomId={}, roomPwd={}"
,
roomId
,
roomPwd
);
if
(
StringUtils
.
isBlank
(
roomId
))
{
throw
new
BusinessException
(
"房间号不能为空"
);
}
if
(
StringUtils
.
isBlank
(
roomPwd
))
{
throw
new
BusinessException
(
"房间密码不能为空"
);
}
String
authorization
=
httpRequest
.
getHeader
(
"X-Authorization"
);
if
(
StringUtils
.
isBlank
(
authorization
))
{
throw
new
BusinessException
(
"访问者(参与者)token信息不能为空"
);
}
// 通过远程接口解析 Token 获取用户信息
QuerySfpUserResponse
userInfo
=
parseTokenRemotely
(
authorization
);
Long
userId
=
userInfo
.
getId
();
if
(
userId
==
null
)
{
throw
new
BusinessException
(
"访问者(参与者)token的用户ID解析为空"
);
}
LambdaQueryWrapper
<
CoSession
>
wrapper
=
new
LambdaQueryWrapper
<>();
wrapper
.
eq
(
CoSession:
:
getRoomId
,
roomId
)
.
eq
(
CoSession:
:
getRoomPwd
,
roomPwd
)
.
last
(
" limit 1 "
);
CoSession
session
=
iCoSessionService
.
getOne
(
wrapper
);
if
(
session
==
null
)
{
throw
new
BusinessException
(
"会话信息不存在"
);
}
String
creatorId
=
session
.
getOwnerId
();
if
(
userId
.
toString
().
equals
(
creatorId
))
{
return
Result
.
success
(
true
);
}
return
Result
.
success
(
false
);
}
private
boolean
autoStartRecording
()
{
private
boolean
autoStartRecording
()
{
return
true
;
// 从配置读取
return
true
;
}
}
}
}
yd-communication-feign/src/main/java/com/yd/communication/feign/client/ApiCoSessionFeignClient.java
View file @
6cccf32b
...
@@ -7,6 +7,7 @@ import com.yd.communication.feign.response.*;
...
@@ -7,6 +7,7 @@ import com.yd.communication.feign.response.*;
import
org.springframework.cloud.openfeign.FeignClient
;
import
org.springframework.cloud.openfeign.FeignClient
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
javax.servlet.http.HttpServletRequest
;
/**
/**
...
@@ -37,6 +38,49 @@ public interface ApiCoSessionFeignClient {
...
@@ -37,6 +38,49 @@ public interface ApiCoSessionFeignClient {
Result
<
JoinResponse
>
join
(
@Validated
@RequestBody
JoinRequest
request
);
Result
<
JoinResponse
>
join
(
@Validated
@RequestBody
JoinRequest
request
);
/**
/**
* 根据房间号和密码获取会话详情
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return 完整会话信息
*/
@GetMapping
(
"/detail/roomIdAndPwd"
)
Result
<
SessionDetailResponse
>
get
(
@RequestParam
(
"roomId"
)
String
roomId
,
@RequestParam
(
"roomPwd"
)
String
roomPwd
);
/**
* 获取房间链接状态信息
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return
*/
@GetMapping
(
"/link/status"
)
Result
<
GetLinkStatusResponse
>
getLinkStatus
(
@RequestParam
(
"roomId"
)
String
roomId
,
@RequestParam
(
"roomPwd"
)
String
roomPwd
);
/**
* 设置房间链接状态为失效
*
* @param request 加入会话请求
* @return 会话详情
*/
@PostMapping
(
"/set/link/failure"
)
Result
<
SetLinkFailureResponse
>
setLinkFailure
(
@Validated
@RequestBody
SetLinkFailureRequest
request
);
/**
* 判断资源创建者和参与者是否是同一个人(供参与者调用)
*
* @param roomId 房间号
* @param roomPwd 房间密码
* @return true-是同一人 false-不是同一人
*/
@GetMapping
(
"/isMy"
)
Result
<
Boolean
>
isMy
(
@RequestParam
(
"roomId"
)
String
roomId
,
@RequestParam
(
"roomPwd"
)
String
roomPwd
,
HttpServletRequest
httpRequest
);
/**
* 获取会话状态
* 获取会话状态
* @param request
* @param request
* @return
* @return
...
...
yd-communication-feign/src/main/java/com/yd/communication/feign/dto/RoomLinkDTO.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
feign
.
dto
;
import
lombok.Data
;
import
java.io.Serializable
;
@Data
public
class
RoomLinkDTO
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
/**
* 纯链接
*/
private
String
roomLink
;
/**
* 二维码里面的链接
*/
private
String
qrCodeRoomLink
;
}
yd-communication-feign/src/main/java/com/yd/communication/feign/enums/RedisEnum.java
View file @
6cccf32b
...
@@ -10,9 +10,10 @@ import java.util.concurrent.TimeUnit;
...
@@ -10,9 +10,10 @@ import java.util.concurrent.TimeUnit;
public
enum
RedisEnum
{
public
enum
RedisEnum
{
//协同房间缓存信息redis参数
//协同房间缓存信息redis参数
ROOM
(
RedisConstants
.
ROOM_KEY_PREFIX
,
1
20
,
TimeUnit
.
MINUTE
S
),
ROOM
(
RedisConstants
.
ROOM_KEY_PREFIX
,
1
,
TimeUnit
.
DAY
S
),
//房间链接缓存信息redis参数
//房间链接缓存信息redis参数
ROOM_LINK
(
RedisConstants
.
ROOM_LINK_KEY_PREFIX
,
120
,
TimeUnit
.
MINUTES
),
ROOM_LINK
(
RedisConstants
.
ROOM_LINK_KEY_PREFIX
,
120
,
TimeUnit
.
MINUTES
),
//code置换资源创建者token的缓存信息
;
;
//缓存key前缀
//缓存key前缀
...
...
yd-communication-feign/src/main/java/com/yd/communication/feign/fallback/ApiCoSessionFeignFallbackFactory.java
View file @
6cccf32b
...
@@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j;
...
@@ -8,6 +8,8 @@ import lombok.extern.slf4j.Slf4j;
import
org.springframework.cloud.openfeign.FallbackFactory
;
import
org.springframework.cloud.openfeign.FallbackFactory
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
javax.servlet.http.HttpServletRequest
;
/**
/**
* 通信服务-协同会话信息Feign降级处理
* 通信服务-协同会话信息Feign降级处理
*/
*/
...
@@ -24,6 +26,26 @@ public class ApiCoSessionFeignFallbackFactory implements FallbackFactory<ApiCoSe
...
@@ -24,6 +26,26 @@ public class ApiCoSessionFeignFallbackFactory implements FallbackFactory<ApiCoSe
}
}
@Override
@Override
public
Result
<
SessionDetailResponse
>
get
(
String
roomId
,
String
roomPwd
)
{
return
null
;
}
@Override
public
Result
<
GetLinkStatusResponse
>
getLinkStatus
(
String
roomId
,
String
roomPwd
)
{
return
null
;
}
@Override
public
Result
<
SetLinkFailureResponse
>
setLinkFailure
(
SetLinkFailureRequest
request
)
{
return
null
;
}
@Override
public
Result
<
Boolean
>
isMy
(
String
roomId
,
String
roomPwd
,
HttpServletRequest
httpRequest
)
{
return
null
;
}
@Override
public
Result
<
JoinResponse
>
join
(
JoinRequest
request
)
{
public
Result
<
JoinResponse
>
join
(
JoinRequest
request
)
{
return
null
;
return
null
;
}
}
...
...
yd-communication-feign/src/main/java/com/yd/communication/feign/request/SetLinkFailureRequest.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
feign
.
request
;
import
lombok.Data
;
@Data
public
class
SetLinkFailureRequest
{
private
String
roomId
;
private
String
roomPwd
;
}
yd-communication-feign/src/main/java/com/yd/communication/feign/response/GetLinkStatusResponse.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
feign
.
response
;
import
lombok.Data
;
@Data
public
class
GetLinkStatusResponse
{
/**
* 报告归属人姓名
*/
private
String
reportOwnerName
;
/**
* 报告归属人手机号尾号四位
*/
private
String
reportOwnerMobileLast
;
}
yd-communication-feign/src/main/java/com/yd/communication/feign/response/JoinResponse.java
View file @
6cccf32b
...
@@ -57,4 +57,9 @@ public class JoinResponse {
...
@@ -57,4 +57,9 @@ public class JoinResponse {
* 手机号
* 手机号
*/
*/
private
String
mobile
;
private
String
mobile
;
/**
* 置换资源所有者token信息
*/
private
String
code
;
}
}
\ No newline at end of file
yd-communication-feign/src/main/java/com/yd/communication/feign/response/SetLinkFailureResponse.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
feign
.
response
;
import
lombok.Data
;
@Data
public
class
SetLinkFailureResponse
{
/**
* 报告归属人姓名
*/
private
String
reportOwnerName
;
}
yd-communication-feign/src/main/java/com/yd/communication/feign/response/http/QuerySfpUserResponse.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
feign
.
response
.
http
;
import
lombok.Data
;
import
java.util.Date
;
@Data
public
class
QuerySfpUserResponse
{
private
Long
id
;
//serial idPRIauto_increment
private
String
name
;
//userName
private
String
mobile
;
//手机号
private
Integer
gender
;
//性别,1,男,2,女
private
String
age
;
//年龄
private
String
manageMobile
;
//管理经纪人手机号(保单托管)
private
Date
loginDate
;
//登录时间(用于判断该用户是否登录过期 30天, 登录成功更新,退出或者切换账号更新)
private
Integer
loginState
;
//是否登录(0=No, 1=Yes)
private
String
customerSource
;
//客户来源
private
String
level
;
//用户等级
private
String
levelName
;
//用户等级名称
private
Integer
isVip
;
//是否vip
private
Date
vipExpireDate
;
//vip到期时间
private
Date
inactivateDate
;
//激活到期时间
private
Integer
remainingTimes
;
//剩余次数
private
Integer
isMax
;
//是否达到最大购买次数 0-否 1-是
private
Integer
userType
;
//用户类型
private
Long
roleId
;
//用户角色ID
private
String
systemType
;
//系统类型(tvm、sfp、policyManage)
private
String
tenantProjectRoleIds
;
//租户项目角色ID列表
private
String
flag
;
//标识
private
String
remark
;
//备注
private
String
wxNickname
;
//微信昵称
private
String
wxOpenId
;
//用户小程序登录的openid
private
String
wxOpenIdGzh
;
//用户公众号登录的openid
private
Integer
isBlacklist
;
//是否黑名单 0-否 1-是
private
Integer
isActive
;
//是否启用(0=No, 1=Yes)
private
Date
createdAt
;
//创建时间
private
String
createdBy
;
//创建人
private
Date
updatedAt
;
//修改时间
private
String
updatedBy
;
//修改人
/**
* 律家保-法税卡激活接口,请求⽅用户唯⼀识别号 (用于跳转到律家保页面的挂参)
*/
private
String
ljbRefId
;
}
yd-communication-service/src/main/java/com/yd/communication/service/utils/CffpTokenUtil.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
service
.
utils
;
import
io.jsonwebtoken.*
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.PostConstruct
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* CFFP 项目专用 JWT Token 工具类
* 完全在代码内部获取环境标识(System.getProperty),硬编码不同环境的配置
* 支持生成 Token 和解析 Token(获取 userId、cffpUserId 等)
*
* @author yourname
*/
@Slf4j
@Service
public
class
CffpTokenUtil
{
// JWT 标准声明 Key
private
static
final
String
CLAIM_KEY_SUBJECT
=
"sub"
;
private
static
final
String
CLAIM_KEY_CREATED
=
"created"
;
// 自定义声明 Key(与 CffpTokenFilter 保持一致)
private
static
final
String
CLAIM_KEY_USERID
=
"UserId"
;
private
static
final
String
CLAIM_KEY_CFFP_USERID
=
"cffpUserId"
;
// 静态配置字段(一套配置,根据环境加载不同的值)
private
static
String
seal
;
private
static
String
issuer
;
private
static
Long
expiration
;
/**
* 初始化:通过 System.getProperty 获取环境,硬编码对应的配置
* 该方法在 Spring 容器启动完成后自动执行
*/
@PostConstruct
public
void
init
()
{
// 从系统属性中获取 spring.profiles.active,如果获取不到则默认为 "default"
String
activeProfile
=
System
.
getProperty
(
"spring.profiles.active"
,
"default"
);
// 判断是否为生产环境
boolean
isProd
=
"prod"
.
equalsIgnoreCase
(
activeProfile
)
||
"production"
.
equalsIgnoreCase
(
activeProfile
)
||
activeProfile
.
toLowerCase
().
contains
(
"prod"
);
if
(
isProd
)
{
// 生产环境配置
seal
=
"zhb123!@#"
;
issuer
=
"cffpwealthcenter"
;
expiration
=
2592000L
;
log
.
info
(
"CffpTokenUtil 加载生产环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
else
{
// 测试/开发环境配置
seal
=
"zhb123!@#"
;
issuer
=
"zuihuibi"
;
expiration
=
86400000L
;
log
.
info
(
"CffpTokenUtil 加载测试环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
}
// ======================== 生成 Token ========================
/**
* 生成 JWT Token(自动添加 issuer 前缀,如 "zuihuibi {token}")
*
* @param ticket 用户标识(通常为登录名或唯一标识)
* @param userId 用户 ID(字符串)
* @param cffpUserId CFFP 用户 ID(可选)
* @return 完整 Token 字符串(含前缀)
*/
public
static
String
generateToken
(
String
ticket
,
String
userId
,
String
cffpUserId
)
{
Map
<
String
,
Object
>
claims
=
new
HashMap
<>();
claims
.
put
(
CLAIM_KEY_SUBJECT
,
ticket
);
claims
.
put
(
CLAIM_KEY_USERID
,
userId
);
if
(
cffpUserId
!=
null
)
{
claims
.
put
(
CLAIM_KEY_CFFP_USERID
,
cffpUserId
);
}
claims
.
put
(
CLAIM_KEY_CREATED
,
new
Date
());
String
token
=
Jwts
.
builder
()
.
setClaims
(
claims
)
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
expiration
*
1000
))
.
signWith
(
SignatureAlgorithm
.
HS512
,
seal
)
.
compact
();
return
issuer
+
" "
+
token
;
}
// ======================== 解析 Token ========================
/**
* 从 Token 中解析 Claims
*
* @param token 原始 Token(可能包含 issuer 前缀)
* @return Map, key 包含 "resultCode"(SUCCESS/EXPIRED/INVALID)和 "claims"(解析成功时为 Claims 对象)
*/
public
static
Map
<
String
,
Object
>
getClaimsFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
String
resultCode
=
"SUCCESS"
;
Claims
claims
=
null
;
if
(
token
==
null
||
token
.
isEmpty
())
{
map
.
put
(
"resultCode"
,
"INVALID"
);
map
.
put
(
"claims"
,
null
);
return
map
;
}
try
{
// 去除 issuer 前缀(如果存在)
String
realToken
=
token
;
if
(
token
.
startsWith
(
issuer
+
" "
))
{
realToken
=
token
.
substring
(
issuer
.
length
()
+
1
);
}
Jws
<
Claims
>
jwsClaims
=
Jwts
.
parser
()
.
setSigningKey
(
seal
)
.
parseClaimsJws
(
realToken
);
claims
=
jwsClaims
.
getBody
();
}
catch
(
ExpiredJwtException
e
)
{
resultCode
=
"EXPIRED"
;
}
catch
(
UnsupportedJwtException
|
MalformedJwtException
|
SignatureException
|
IllegalArgumentException
e
)
{
resultCode
=
"INVALID"
;
}
catch
(
Exception
e
)
{
resultCode
=
"INVALID"
;
}
map
.
put
(
"resultCode"
,
resultCode
);
map
.
put
(
"claims"
,
claims
);
return
map
;
}
/**
* 从 Token 中获取用户 ID(String 形式)
*
* @param token 原始 Token
* @return 用户 ID 字符串,解析失败返回 null
*/
public
static
String
getUserIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
userId
=
claims
.
get
(
CLAIM_KEY_USERID
);
return
userId
!=
null
?
userId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 从 Token 中获取 CFFP 用户 ID
*
* @param token 原始 Token
* @return CFFP 用户 ID 字符串,解析失败返回 null
*/
public
static
String
getCffpUserIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
cffpUserId
=
claims
.
get
(
CLAIM_KEY_CFFP_USERID
);
return
cffpUserId
!=
null
?
cffpUserId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 验证 Token 是否有效(未过期、格式正确)
*
* @param token 原始 Token
* @return true 表示有效,false 表示无效或过期
*/
public
static
boolean
validateToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
return
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
));
}
/**
* 检查 Token 是否过期
*
* @param token 原始 Token
* @return true 表示已过期,false 表示未过期或解析失败
*/
public
static
boolean
isTokenExpired
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
String
resultCode
=
(
String
)
map
.
get
(
"resultCode"
);
if
(
"EXPIRED"
.
equals
(
resultCode
))
{
return
true
;
}
if
(
"SUCCESS"
.
equals
(
resultCode
))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Date
expirationDate
=
claims
.
getExpiration
();
return
expirationDate
!=
null
&&
expirationDate
.
before
(
new
Date
());
}
}
return
false
;
}
}
\ No newline at end of file
yd-communication-service/src/main/java/com/yd/communication/service/utils/MyBatisPlusCodeGenerator.java
View file @
6cccf32b
...
@@ -5,11 +5,11 @@ import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
...
@@ -5,11 +5,11 @@ import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
public
class
MyBatisPlusCodeGenerator
{
public
class
MyBatisPlusCodeGenerator
{
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
FastAutoGenerator
.
create
(
"jdbc:mysql://139.224.145.34:3308/
yd_communication
?serverTimezone=GMT%2B8"
,
"root"
,
"Zxm7320017"
)
FastAutoGenerator
.
create
(
"jdbc:mysql://139.224.145.34:3308/
test
?serverTimezone=GMT%2B8"
,
"root"
,
"Zxm7320017"
)
.
globalConfig
(
builder
->
{
.
globalConfig
(
builder
->
{
builder
.
author
(
"zxm"
)
builder
.
author
(
"zxm"
)
//
.outputDir("src/main/java/com/yd/user/service");
.
outputDir
(
"src/main/java/com/yd/user/service"
);
.
outputDir
(
"D:/soft/ideaproject/v2/yd-communication/yd-communication-service/src/main/java"
);
//
.outputDir("D:/soft/ideaproject/v2/yd-communication/yd-communication-service/src/main/java");
})
})
.
packageConfig
(
builder
->
{
.
packageConfig
(
builder
->
{
builder
.
parent
(
"com.yd.communication.service"
)
builder
.
parent
(
"com.yd.communication.service"
)
...
@@ -21,7 +21,7 @@ public class MyBatisPlusCodeGenerator {
...
@@ -21,7 +21,7 @@ public class MyBatisPlusCodeGenerator {
})
})
.
strategyConfig
(
builder
->
{
.
strategyConfig
(
builder
->
{
builder
.
addInclude
(
builder
.
addInclude
(
"c
o_session"
,
"co_operation_log"
,
"recording_task"
,
"co_desensitization_rule
"
"c
lient_session
"
)
)
.
entityBuilder
()
.
entityBuilder
()
.
enableLombok
()
.
enableLombok
()
...
...
yd-communication-service/src/main/java/com/yd/communication/service/utils/SfpTokenUtil.java
0 → 100644
View file @
6cccf32b
package
com
.
yd
.
communication
.
service
.
utils
;
import
io.jsonwebtoken.*
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.PostConstruct
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* SFP 项目专用 JWT Token 工具类
* 完全在代码内部获取环境标识(System.getProperty),硬编码不同环境的配置
* 支持生成 Token 和解析 Token(获取 userId、customerId 等)
*
* @author yourname
*/
@Slf4j
@Service
public
class
SfpTokenUtil
{
// JWT 标准声明 Key
private
static
final
String
CLAIM_KEY_SUBJECT
=
"sub"
;
private
static
final
String
CLAIM_KEY_CREATED
=
"created"
;
// 自定义声明 Key(与 JwtTokenUtil 保持一致)
private
static
final
String
CLAIM_KEY_USERID
=
"UserId"
;
private
static
final
String
CLAIM_KEY_CUSTOMERID
=
"CustomerId"
;
// 静态配置字段
private
static
String
seal
;
private
static
String
issuer
;
private
static
Long
expiration
;
/**
* 初始化:通过 System.getProperty 获取环境,硬编码对应的配置
* 该方法在 Spring 容器启动完成后自动执行
*/
@PostConstruct
public
void
init
()
{
// 从系统属性中获取 spring.profiles.active,如果获取不到则默认为 "default"
String
activeProfile
=
System
.
getProperty
(
"spring.profiles.active"
,
"default"
);
// 判断是否为生产环境(可自定义判断规则,如包含 "prod" 或 "production")
boolean
isProd
=
"prod"
.
equalsIgnoreCase
(
activeProfile
)
||
"production"
.
equalsIgnoreCase
(
activeProfile
)
||
activeProfile
.
toLowerCase
().
contains
(
"prod"
);
if
(
isProd
)
{
// 生产环境配置(请替换为实际的生产密钥)
seal
=
"SFP2023!@#"
;
issuer
=
"sfpfamilyfinancialplanning"
;
expiration
=
2592000L
;
// 24小时
log
.
info
(
"SfpTokenUtil 加载生产环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
else
{
// 测试/开发环境配置(请替换为实际的测试密钥)
seal
=
"zhb123!@#"
;
issuer
=
"zuihuibi"
;
expiration
=
2592000L
;
log
.
info
(
"SfpTokenUtil 加载测试环境配置, issuer: {}, expiration: {} 秒"
,
issuer
,
expiration
);
}
}
// ======================== 生成 Token ========================
/**
* 生成 JWT Token(自动添加 issuer 前缀,如 "zuihuibi {token}")
*
* @param ticket 用户标识(通常为登录名或唯一标识)
* @param userId 用户 ID(字符串)
* @param customerId 客户 ID(可选)
* @return 完整 Token 字符串(含前缀)
*/
public
static
String
generateToken
(
String
ticket
,
String
userId
,
String
customerId
)
{
Map
<
String
,
Object
>
claims
=
new
HashMap
<>();
claims
.
put
(
CLAIM_KEY_SUBJECT
,
ticket
);
claims
.
put
(
CLAIM_KEY_USERID
,
userId
);
if
(
customerId
!=
null
)
{
claims
.
put
(
CLAIM_KEY_CUSTOMERID
,
customerId
);
}
claims
.
put
(
CLAIM_KEY_CREATED
,
new
Date
());
String
token
=
Jwts
.
builder
()
.
setClaims
(
claims
)
.
setExpiration
(
new
Date
(
System
.
currentTimeMillis
()
+
expiration
*
1000
))
.
signWith
(
SignatureAlgorithm
.
HS512
,
seal
)
.
compact
();
return
issuer
+
" "
+
token
;
}
// ======================== 解析 Token ========================
/**
* 从 Token 中解析 Claims(包含所有声明信息)
*
* @param token 原始 Token(可能包含 issuer 前缀)
* @return Map, key 包含 "resultCode"(SUCCESS/EXPIRED/INVALID)和 "claims"(解析成功时为 Claims 对象)
*/
public
static
Map
<
String
,
Object
>
getClaimsFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
String
resultCode
=
"SUCCESS"
;
Claims
claims
=
null
;
try
{
// 去除 issuer 前缀(如果存在)
String
realToken
=
token
;
if
(
token
.
startsWith
(
issuer
+
" "
))
{
realToken
=
token
.
substring
(
issuer
.
length
()
+
1
);
}
Jws
<
Claims
>
jwsClaims
=
Jwts
.
parser
()
.
setSigningKey
(
seal
)
.
parseClaimsJws
(
realToken
);
claims
=
jwsClaims
.
getBody
();
}
catch
(
ExpiredJwtException
e
)
{
resultCode
=
"EXPIRED"
;
}
catch
(
UnsupportedJwtException
|
MalformedJwtException
|
SignatureException
|
IllegalArgumentException
e
)
{
resultCode
=
"INVALID"
;
}
catch
(
Exception
e
)
{
resultCode
=
"INVALID"
;
}
map
.
put
(
"resultCode"
,
resultCode
);
map
.
put
(
"claims"
,
claims
);
return
map
;
}
/**
* 从 Token 中获取用户 ID(String 形式)
*
* @param token 原始 Token
* @return 用户 ID 字符串,解析失败返回 null
*/
public
static
String
getUserIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
userId
=
claims
.
get
(
CLAIM_KEY_USERID
);
return
userId
!=
null
?
userId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 从 Token 中获取客户 ID
*
* @param token 原始 Token
* @return 客户 ID 字符串,解析失败返回 null
*/
public
static
String
getCustomerIdFromToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
if
(
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
)))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Object
customerId
=
claims
.
get
(
CLAIM_KEY_CUSTOMERID
);
return
customerId
!=
null
?
customerId
.
toString
()
:
null
;
}
}
return
null
;
}
/**
* 验证 Token 是否有效(未过期、格式正确)
*
* @param token 原始 Token
* @return true 表示有效,false 表示无效或过期
*/
public
static
boolean
validateToken
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
return
"SUCCESS"
.
equals
(
map
.
get
(
"resultCode"
));
}
/**
* 检查 Token 是否过期
*
* @param token 原始 Token
* @return true 表示已过期,false 表示未过期或解析失败
*/
public
static
boolean
isTokenExpired
(
String
token
)
{
Map
<
String
,
Object
>
map
=
getClaimsFromToken
(
token
);
String
resultCode
=
(
String
)
map
.
get
(
"resultCode"
);
if
(
"EXPIRED"
.
equals
(
resultCode
))
{
return
true
;
}
if
(
"SUCCESS"
.
equals
(
resultCode
))
{
Claims
claims
=
(
Claims
)
map
.
get
(
"claims"
);
if
(
claims
!=
null
)
{
Date
expirationDate
=
claims
.
getExpiration
();
return
expirationDate
!=
null
&&
expirationDate
.
before
(
new
Date
());
}
}
return
false
;
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment