package com.ruoyi.web.controller.hanler;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.google.gson.Gson;
|
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.smartor.domain.*;
|
import com.smartor.mapper.IvrLibaExtemplatescriptMapper;
|
import com.smartor.service.IIvrLibaTemplateService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
import org.springframework.web.socket.BinaryMessage;
|
import org.springframework.web.socket.CloseStatus;
|
import org.springframework.web.socket.TextMessage;
|
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
|
|
import java.io.IOException;
|
import java.nio.charset.StandardCharsets;
|
import java.util.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.TimeUnit;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
@Slf4j
|
@Component
|
public class ChatWebSocketHandler extends AbstractWebSocketHandler {
|
|
private static RedisCache redisCache;
|
|
private static IIvrLibaTemplateService ivrLibaTemplateService;
|
|
private static IvrLibaExtemplatescriptMapper ivrLibaExtemplatescriptMapper;
|
|
// 用于存储用户ID和WebSocketSession的映射关系
|
private static Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
|
|
@Autowired
|
public void setIEMapper(IvrLibaExtemplatescriptMapper ivrLibaExtemplatescriptMapper) {
|
ChatWebSocketHandler.ivrLibaExtemplatescriptMapper = ivrLibaExtemplatescriptMapper;
|
}
|
|
@Autowired
|
public void setTodayReaderService(IIvrLibaTemplateService ivrLibaTemplateService) {
|
ChatWebSocketHandler.ivrLibaTemplateService = ivrLibaTemplateService;
|
}
|
|
@Autowired
|
public void setRedisCache(RedisCache redisCache) {
|
ChatWebSocketHandler.redisCache = redisCache;
|
}
|
|
@Override
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
// 获取用户ID,可以从session中获取或者通过其他方式获取
|
String userId = extractUserId(session);
|
|
// 将用户ID和WebSocketSession存储到映射表中
|
sessions.put(userId, session);
|
|
}
|
|
@Override
|
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
// 处理收到的消息
|
String userId = extractUserId(session);
|
String payload = message.getPayload().toString();
|
log.info("-----------------:{}", payload);
|
// 解析消息类型
|
ObjectMapper mapper = new ObjectMapper();
|
SocketMessage parsedMessage = mapper.readValue(payload, SocketMessage.class);
|
if (parsedMessage != null) {
|
sendMessageToUser(parsedMessage.getUserId(), parsedMessage);
|
}
|
|
}
|
|
@Override
|
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
|
log.info("发送二进制");
|
}
|
|
@Override
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
// 关闭连接时,从映射表中移除对应的用户ID和WebSocketSession
|
String userId = extractUserId(session);
|
sessions.remove(userId);
|
}
|
|
@Override
|
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
// 处理传输错误,例如连接断开或发生异常
|
String userId = extractUserId(session);
|
sessions.remove(userId);
|
}
|
|
@Override
|
public boolean supportsPartialMessages() {
|
// 支持部分消息处理
|
return false;
|
}
|
|
private String extractUserId(WebSocketSession session) {
|
// 在实际情况下,你可以根据需要从session中提取用户ID,可以直接拿当前登际人的userId
|
String userId = session.getUri().getQuery().split("=")[1];
|
// return session.getAttributes().get("userId").toString();
|
return userId;
|
}
|
|
private void sendMessageToUser(String userId, SocketMessage socketMessage) throws IOException {
|
WebSocketSession session = sessions.get(userId);
|
if (session != null && session.isOpen()) {
|
if (socketMessage.getTemplateId() != null) {
|
//通过模板ID获取模板问题
|
IvrLibaTemplateVO ivrLibaTemplateVO = new IvrLibaTemplateVO();
|
ivrLibaTemplateVO.setID(socketMessage.getTemplateId());
|
IvrLibaTemplateVO ivrLibaTemplateVO1 = ivrLibaTemplateService.selectInfoByCondition(ivrLibaTemplateVO);
|
redisCache.setCacheObject(userId + "ivrLibaTemplateVO1", ivrLibaTemplateVO1, 120, TimeUnit.MINUTES);
|
//将查出来的问题,放到全局变量中去
|
List<IvrLibaTemplateScriptVO> ivrLibaTemplateScriptVOList = ivrLibaTemplateVO1.getIvrLibaTemplateScriptVOList();
|
//根据序号进行排序
|
Collections.sort(ivrLibaTemplateScriptVOList, Comparator.comparing(IvrLibaTemplateScriptVO::getTargetid));
|
|
//将查出来的数据放到redis中
|
redisCache.setCacheObject(userId + "ivrLibaTemplateScriptVOList", ivrLibaTemplateScriptVOList, 120, TimeUnit.MINUTES);
|
//用来返回调查的总结果
|
redisCache.setCacheObject(userId + "backQuset", new ArrayList<>(), 120, TimeUnit.MINUTES);
|
//用来记录无声响应次数
|
redisCache.setCacheObject(userId + "noVoice", 0, 120, TimeUnit.MINUTES);
|
//用来记录无匹配次数
|
redisCache.setCacheObject(userId + "mateNum", 0, 120, TimeUnit.MINUTES);
|
//用来记录整个问卷是否结束 0 :未结束 1:结束
|
redisCache.setCacheObject(userId + "isOver", 0, 120, TimeUnit.MINUTES);
|
|
//用来返回当前需要问的问题信息
|
QuestionMessage returnQues = new QuestionMessage();
|
|
for (IvrLibaTemplateScriptVO ivrLibaTemplateScriptVO : ivrLibaTemplateScriptVOList) {
|
if (ivrLibaTemplateScriptVO.getTargetid() == ivrLibaTemplateVO1.getFirstQuestionNum().intValue())
|
//获取第一题的问题
|
returnQues.setNowQuestion(ivrLibaTemplateScriptVO);
|
// returnQues.setCode(ivrLibaTemplateScriptVO.getTargetid() + 1);
|
}
|
// returnQues.setKcb("你好,大傻狗,我们是某某某医院,现在需要做一次随访;");
|
returnQues.setKcb(ivrLibaTemplateVO1.getRevisitBefore());
|
|
//记录响应
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
} else {
|
//获取socketMessage里的QuestionMessage,对答案进行处理然后,再问下一道
|
Gson gson = new Gson();
|
if (!StringUtils.isEmpty(socketMessage.getContent())) {
|
socketMessage.setQuestionMessage(gson.fromJson(socketMessage.getContent(), QuestionMessage.class));
|
}
|
|
QuestionMessage questionMessage = socketMessage.getQuestionMessage();
|
List<IvrLibaTemplateScriptVO> ivrLibaTemplateScriptVOList = redisCache.getCacheObject(userId + "ivrLibaTemplateScriptVOList");
|
//根据前端传回的条件,获取当前题目
|
IvrLibaTemplateScriptVO ivrLibaTemplateScriptVO = questionMessage.getNowQuestion();
|
if (ivrLibaTemplateScriptVO.getID() == null) {
|
QuestionMessage returnQues = redisCache.getCacheObject(userId + "returnQues");
|
ivrLibaTemplateScriptVO = returnQues.getNowQuestion();
|
}
|
//获取模板信息
|
IvrLibaTemplateVO ivrLibaTemplateVO1 = redisCache.getCacheObject(userId + "ivrLibaTemplateVO1");
|
|
if (StringUtils.isEmpty(questionMessage.getContent())) {
|
//调用ivrLibaTemplateScriptVO中的slienceText(静默话术)
|
Integer noVoice = redisCache.getCacheObject(userId + "noVoice");
|
//实际静默次数是否 等于 模板中配置的次数
|
if (noVoice == ivrLibaTemplateVO1.getNoVoiceNum().intValue()) {
|
//用来返回调查的总结果
|
List<IvrLibaTemplateScriptVO> backQuset = new ArrayList<>();
|
backQuset.add(ivrLibaTemplateScriptVO);
|
redisCache.setCacheObject(userId + "backQuset", backQuset, 120, TimeUnit.MINUTES);
|
|
//如果几次都没响应,就下一题(需要先判断是否有下一题)
|
if (ivrLibaTemplateScriptVO.getTargetid() == ivrLibaTemplateScriptVOList.size()) {
|
//如果下一题没有了,就结束了
|
QuestionMessage returnQues = new QuestionMessage();
|
// returnQues.setCode(null);
|
List<IvrLibaTemplateScriptVO> backQusetRedis = redisCache.getCacheObject(userId + "backQuset");
|
returnQues.setContent(JSON.toJSONString(backQusetRedis));
|
returnQues.setJsy(ivrLibaTemplateVO1.getRevisitAfter());
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
redisCache.setCacheObject(userId + "isOver", 1, 120, TimeUnit.MINUTES);
|
|
} else {
|
//如果有下一题,就根据当前teagetID+1 获取下一题
|
QuestionMessage returnQues = getNextQuestion(ivrLibaTemplateScriptVOList, ivrLibaTemplateScriptVO);
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
redisCache.setCacheObject(userId + "noVoice", 0, 120, TimeUnit.MINUTES);
|
}
|
} else {
|
//实际静默次数是否 不等于 模板中配置的次数
|
// QuestionMessage returnQues = redisCache.getCacheObject(userId + "returnQues");
|
// returnQues.setContent(null);
|
// redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
|
Integer noVoice2 = redisCache.getCacheObject(userId + "noVoice");
|
noVoice2 = noVoice2 + 1;
|
redisCache.setCacheObject(userId + "noVoice", noVoice2, 120, TimeUnit.MINUTES);
|
}
|
} else {
|
//对回答的问题,进行正则匹配(这里只针对选择题,其它题型不行)x
|
for (int j = 0; j < ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().size(); j++) {
|
//包含
|
Matcher matcher = null;
|
if (StringUtils.isNotEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex())) {
|
Pattern pattern = Pattern.compile(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex());
|
matcher = pattern.matcher(questionMessage.getContent());
|
}
|
//不包含
|
Matcher matcher2 = null;
|
if (StringUtils.isNotEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex2())) {
|
Pattern pattern2 = Pattern.compile(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex2());
|
matcher2 = pattern2.matcher(questionMessage.getContent());
|
}
|
log.info("==============================Targetregex的值为:{}, Targetregex2的值为:{}", ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex(), ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex2());
|
|
if (StringUtils.isNotEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex()) && matcher.matches() && StringUtils.isNotEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex2()) && matcher2.matches() || StringUtils.isEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex()) && StringUtils.isNotEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex2()) && matcher2.matches() || StringUtils.isEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex2()) && StringUtils.isNotEmpty(ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getTargetregex()) && matcher.matches()) {
|
//说明匹配正确了
|
ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).setIsUserOperation(true);
|
List<IvrLibaTemplateScriptVO> backQuset = redisCache.getCacheObject(userId + "backQuset");
|
//匹配完成后,将结果保存到新的数组
|
backQuset.add(ivrLibaTemplateScriptVO);
|
redisCache.setCacheObject(userId + "backQuset", backQuset, 120, TimeUnit.MINUTES);
|
//将静默置为0
|
redisCache.setCacheObject(userId + "noVoice", 0, 120, TimeUnit.MINUTES);
|
//获取下一题
|
Integer nextQuestion = ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().get(j).getNextQuestion();
|
if (nextQuestion > ivrLibaTemplateScriptVOList.size()) {
|
//如果下一题没有了,就结束了
|
QuestionMessage returnQues = new QuestionMessage();
|
List<IvrLibaTemplateScriptVO> backQusetRedis = redisCache.getCacheObject(userId + "backQuset");
|
returnQues.setContent(JSON.toJSONString(backQusetRedis));
|
returnQues.setJsy(ivrLibaTemplateVO1.getRevisitAfter());
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
redisCache.setCacheObject(userId + "isOver", 1, 120, TimeUnit.MINUTES);
|
} else {
|
for (IvrLibaTemplateScriptVO script : ivrLibaTemplateScriptVOList) {
|
if (script.getTargetid() == nextQuestion) {
|
QuestionMessage returnQues = new QuestionMessage();
|
returnQues.setNowQuestion(script);
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
break;
|
}
|
}
|
}
|
break;
|
} else {
|
//没有匹配到
|
Integer mateNum = redisCache.getCacheObject(userId + "mateNum");
|
|
//无匹配次数去判断是否到最大询问次数,并且所有的选项都匹配完了
|
if (mateNum == ivrLibaTemplateVO1.getMateNum().intValue() && j == ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().size() - 1) {
|
//问了最大询问次数后,还是没有匹配上,将结果保存到新的数组
|
List<IvrLibaTemplateScriptVO> backQuset = redisCache.getCacheObject(userId + "backQuset");
|
backQuset.add(ivrLibaTemplateScriptVO);
|
redisCache.setCacheObject(userId + "backQuset", backQuset, 120, TimeUnit.MINUTES);
|
|
//如果下一题为空.则新的数据返回,并加上感谢语
|
if (ivrLibaTemplateScriptVO.getTargetid() < ivrLibaTemplateScriptVOList.size()) {
|
QuestionMessage returnQues = getNextQuestion(ivrLibaTemplateScriptVOList, ivrLibaTemplateScriptVO);
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
redisCache.setCacheObject(userId + "mateNum", 0, 120, TimeUnit.MINUTES);
|
} else {
|
QuestionMessage returnQues2 = new QuestionMessage();
|
// returnQues2.setCode(null);
|
List<IvrLibaTemplateScriptVO> backQusetRedis = redisCache.getCacheObject(userId + "backQuset");
|
returnQues2.setQuestionList(backQusetRedis);
|
returnQues2.setJsy("感谢您的耐心回答,再见");
|
redisCache.setCacheObject(userId + "returnQues", returnQues2, 120, TimeUnit.MINUTES);
|
redisCache.setCacheObject(userId + "isOver", 1, 120, TimeUnit.MINUTES);
|
break;
|
}
|
} else if (mateNum < ivrLibaTemplateVO1.getMateNum().intValue() && j == ivrLibaTemplateScriptVO.getIvrLibaScriptTargetoptionList().size() - 1) {
|
//没有问到规定次数
|
mateNum = mateNum + 1;
|
redisCache.setCacheObject(userId + "mateNum", mateNum, 120, TimeUnit.MINUTES);
|
}
|
}
|
}
|
//选项匹配完成后,需要再去通过库再进行匹配一次
|
String extemplateID = ivrLibaTemplateVO1.getSubmoduleID();
|
String[] split = extemplateID.split(",");
|
List<String> list = Arrays.asList(split);
|
List<Long> list1 = new ArrayList<>();
|
if (StringUtils.isNotEmpty(extemplateID)) {
|
for (String str : list) {
|
list1.add(Long.valueOf(str));
|
}
|
List<IvrLibaExtemplatescript> ivrLibaExtemplatescripts = ivrLibaExtemplatescriptMapper.queryIvrLibaExtemplatescriptList(list1);
|
for (IvrLibaExtemplatescript ivrLibaExtemplatescript : ivrLibaExtemplatescripts) {
|
Matcher matcher = null;
|
if (StringUtils.isNotEmpty(ivrLibaExtemplatescript.getSelfRegex())) {
|
Pattern pattern = Pattern.compile(ivrLibaExtemplatescript.getSelfRegex());
|
matcher = pattern.matcher(questionMessage.getContent());
|
}
|
|
Matcher matcher2 = null;
|
if (StringUtils.isNotEmpty(ivrLibaExtemplatescript.getSelfRegex2())) {
|
Pattern pattern2 = Pattern.compile(ivrLibaExtemplatescript.getSelfRegex2());
|
matcher2 = pattern2.matcher(questionMessage.getContent());
|
}
|
log.info("++++++++++++++++++++++++++通用库是否为空:selfRegex : {} , selfRegex2 : {}", ivrLibaExtemplatescript.getSelfRegex(), ivrLibaExtemplatescript.getSelfRegex2());
|
|
if (StringUtils.isNotEmpty(ivrLibaExtemplatescript.getSelfRegex()) && matcher.matches() && StringUtils.isNotEmpty(ivrLibaExtemplatescript.getSelfRegex2()) && matcher2.matches() || StringUtils.isEmpty(ivrLibaExtemplatescript.getSelfRegex()) && StringUtils.isNotEmpty(ivrLibaExtemplatescript.getSelfRegex2()) && matcher2.matches() || StringUtils.isEmpty(ivrLibaExtemplatescript.getSelfRegex2()) && StringUtils.isNotEmpty(ivrLibaExtemplatescript.getSelfRegex()) && matcher.matches()) {
|
QuestionMessage returnQues = redisCache.getCacheObject(userId + "returnQues");
|
IvrLibaTemplateScriptVO nowQuestion = returnQues.getNowQuestion();
|
nowQuestion.setSubmoduleText(ivrLibaExtemplatescript.getSwitchText());
|
nowQuestion.setSubmoduleVoice(ivrLibaExtemplatescript.getSwitchWav());
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
if (ivrLibaExtemplatescript.getIsEnd() == 1) {
|
//将问题置空
|
IvrLibaTemplateScriptVO nowQuestion1 = returnQues.getNowQuestion();
|
nowQuestion1.setQuestionText(null);
|
nowQuestion1.setQuestionVoice(null);
|
returnQues.setNowQuestion(nowQuestion1);
|
redisCache.setCacheObject(userId + "returnQues", returnQues, 120, TimeUnit.MINUTES);
|
|
redisCache.setCacheObject(userId + "isOver", 1, 120, TimeUnit.MINUTES);
|
}
|
}
|
break;
|
}
|
}
|
}
|
}
|
QuestionMessage returnQues = redisCache.getCacheObject(userId + "returnQues");
|
List<IvrLibaTemplateScriptVO> backQusetRedis = redisCache.getCacheObject(userId + "backQuset");
|
returnQues.setQuestionList(backQusetRedis);
|
session.sendMessage(new TextMessage(JSON.toJSONString(returnQues).getBytes(StandardCharsets.UTF_8)));
|
|
//整个流程是否结束,将redis中的该userId下的数据删除;
|
Integer isOver = redisCache.getCacheObject(userId + "isOver");
|
if (isOver == 1) {
|
redisCache.deleteObject(userId + "ivrLibaTemplateScriptVOList");
|
redisCache.deleteObject(userId + "backQuset");
|
redisCache.deleteObject(userId + "noVoice");
|
redisCache.deleteObject(userId + "returnQues");
|
redisCache.deleteObject(userId + "isOver");
|
redisCache.deleteObject(userId + "ivrLibaTemplateVO1");
|
try {
|
//断开链接
|
afterConnectionClosed(session, null);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
}
|
|
//获取下一题(这个方法不适合选项中的nextQuestion)
|
private QuestionMessage getNextQuestion(List<IvrLibaTemplateScriptVO> ivrLibaTemplateScriptVOList, IvrLibaTemplateScriptVO ivrLibaTemplateScriptVO) {
|
QuestionMessage returnQues = new QuestionMessage();
|
for (int j = 0; j < ivrLibaTemplateScriptVOList.size(); j++) {
|
if (ivrLibaTemplateScriptVOList.get(j).getTargetid() == ivrLibaTemplateScriptVO.getTargetid() + 1) {
|
// 对该条templateScriptVO进行处理
|
returnQues.setNowQuestion(ivrLibaTemplateScriptVOList.get(j));
|
}
|
}
|
return returnQues;
|
}
|
|
}
|