Commit 68e5444b authored by shiyu's avatar shiyu

IM

parent 93d6514f
package com.wwdz.ch.core.consts;
/**
* IM对话枚举
*/
public class IMEnum {
public enum MsgTypeEnum {
TIMTextElem(1, "文本消息", "TIMTextElem"),
TIMLocationElem(2, "位置消息", "TIMLocationElem"),
TIMFaceElem(3, "表情消息", "TIMFaceElem"),
TIMCustomElem(4, "自定义消息", "TIMCustomElem"),
TIMSoundElem(5, "语音消息", "TIMSoundElem"),
TIMImageElem(6, "图像消息", "TIMImageElem"),
TIMFileElem(7, "文件消息", "TIMFileElem"),
TIMVideoFileElem(8, "视频消息", "TIMVideoFileElem"),
;
private int code;
private String des;
private String value;
MsgTypeEnum(int code, String des, String value) {
this.code = code;
this.des = des;
this.value = value;
}
public static String getValueByCode(int code) {
for (IMEnum.MsgTypeEnum msgTypeEnum : IMEnum.MsgTypeEnum.values()) {
if (code == msgTypeEnum.getCode()) {
return msgTypeEnum.getValue();
}
}
return null;
}
public int getCode() {
return code;
}
public String getDes() {
return des;
}
public String getValue() {
return value;
}
}
public enum SyncOtherMachineEnum {
SYNC(1, "消息同步至发送方"),
NOT_SYNC(2, "消息不S同步至发送方"),
;
private int code;
private String des;
SyncOtherMachineEnum(int code, String des) {
this.code = code;
this.des = des;
}
public static String getNameByCode(int code) {
for (IMEnum.SyncOtherMachineEnum syncOtherMachineEnum : IMEnum.SyncOtherMachineEnum.values()) {
if (code == syncOtherMachineEnum.getCode()) {
return syncOtherMachineEnum.getDes();
}
}
return null;
}
public int getCode() {
return code;
}
public String getDes() {
return des;
}
}
}
package com.wwdz.ch.core.entity.im;
import com.wwdz.ch.core.consts.IMEnum;
import com.xxdxxs.entity.Entity;
import lombok.Data;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
public class IMChatMsg implements Entity {
/**
* 1:把消息同步到 From_Account 在线终端和漫游上
* 2:消息不同步至 From_Account
* 若不填写默认情况下会将消息存 From_Account 漫游
*/
private Integer SyncOtherMachine;
/**
* 消息发送方 UserID(用于指定发送消息方账号)
*/
private String From_Account;
/**
* 消息接收方 UserID
*/
private String To_Account;
/**
* 消息离线保存时长(单位:秒),最长为7天(604800秒)
* 若设置该字段为0,则消息只发在线用户,不保存离线
* 若设置该字段超过7天(604800秒),仍只保存7天
* 若不设置该字段,则默认保存7天
*/
private Integer MsgLifeTime;
/**
* 消息序列号(32位无符号整数),后台会根据该字段去重及进行同秒内消息的排序,
* 详细规则请看本接口的功能说明。若不填该字段,则由后台填入随机数
*/
private Integer MsgSeq;
/**
* 消息随机数(32位无符号整数),后台用于同一秒内的消息去重。请确保该字段填的是随机
*/
private Integer MsgRandom;
/**
* 消息主体
* 其中包含
* MsgType 消息类型
* MsgContent 消息内容
*/
private List MsgBody;
}
package com.wwdz.ch.core.entity.im;
import com.wwdz.ch.db.dto.request.BaseRequestDto;
import com.xxdxxs.entity.Entity;
import lombok.Data;
@Data
public class IMChatRequestDto extends BaseRequestDto implements Entity {
private Long userId;
/**
* 普通会话的起始时间,第一页填 0。
*/
private Integer timeStamp;
/**
* 普通会话的起始位置,第一页填 0。
*/
private Integer startIndex;
/**
* 置顶会话的起始时间,第一页填 0。
*/
private Integer topTimeStamp;
/**
* 置顶会话的起始位置,第一页填 0。
*/
private Integer topStartIndex;
}
package com.wwdz.ch.core.entity.im;
import com.xxdxxs.entity.Entity;
import lombok.Data;
/**
* 历史聊天记录请求参数类
*/
@Data
public class IMHistoryMsgRequestDto implements Entity {
/**
* 历史聊天记录查询的发起方
*/
private String operatorAccount;
/**
* 会话的另一方
*/
private String peerAccount;
/**
* 请求的消息条数
*/
private Integer maxCnt;
/**
* 请求的消息时间范围的最小值(单位:秒)
*/
private Integer minTime;
/**
* 请求的消息时间范围的最大值(单位:秒)
*/
private Integer maxTime;
/**
* 上一次拉取到的最后一条消息的 MsgKey,续拉时需要填该字段
*/
private String LastMsgKey;
}
package com.wwdz.ch.core.entity.im;
import com.xxdxxs.entity.Entity;
import lombok.Data;
@Data
public class IMUser implements Entity {
/**
* 用户id
*/
private String userId;
/**
* 昵称
*/
private String nick;
/**
* 头像
*/
private String faceUrl;
}
package com.wwdz.ch.core.entity.im;
import com.xxdxxs.entity.Entity;
import lombok.Data;
@Data
public class SendChatMsgRequestDto implements Entity {
/**
* 1:把消息同步到 From_Account 在线终端和漫游上
* 2:消息不同步至 From_Account
* 若不填写默认情况下会将消息存 From_Account 漫游
*/
private Integer SyncOtherMachine;
/**
* 消息发送方 UserID(用于指定发送消息方账号)
*/
private String From_Account;
/**
* 消息接收方 UserID
*/
private String To_Account;
/**
* 消息离线保存时长(单位:秒),最长为7天(604800秒)
* 若设置该字段为0,则消息只发在线用户,不保存离线
* 若设置该字段超过7天(604800秒),仍只保存7天
* 若不设置该字段,则默认保存7天
*/
private Integer MsgLifeTime;
/**
* 消息序列号(32位无符号整数),后台会根据该字段去重及进行同秒内消息的排序,
* 详细规则请看本接口的功能说明。若不填该字段,则由后台填入随机数
*/
private Integer MsgSeq;
/**
* 消息随机数(32位无符号整数),后台用于同一秒内的消息去重。请确保该字段填的是随机
*/
private Integer MsgRandom;
/**
* 消息对象类型
* 枚举转换成字符串文本
*/
private Integer MsgType;
/**
* 消息内容
*/
private Object MsgContent;
}
package com.wwdz.ch.core.entity.im.vo;
import com.xxdxxs.entity.Entity;
import lombok.Data;
@Data
public class IMChatVo implements Entity {
}
package com.wwdz.ch.wx.im.ussrSig;
package com.wwdz.ch.core.im;
import org.json.JSONObject;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.security.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.zip.Deflater;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.json.JSONObject;
public class TLSSigAPIv2 {
final private long sdkappid;
......
package com.wwdz.ch.core.im.api;
import com.wwdz.ch.core.entity.AbstractSubscribeMsg;
import com.wwdz.ch.core.entity.im.IMUser;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.core.util.IMUtil;
import com.wwdz.ch.core.util.OkHttpUtil;
import com.wwdz.ch.core.util.RedisUtils;
import com.wwdz.ch.db.dao.UserDao;
import com.wwdz.ch.db.domain.User;
import com.xxdxxs.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* 对话用户管理
*/
@Component
public class ChatUserApi {
private static final Logger logger = LoggerFactory.getLogger(ChatUserApi.class);
private static final String ACCOUNT_URL = "https://console.tim.qq.com/v4/im_open_login_svc/account_import";
@Value("${dts.im.adminid}")
private String ADMIN_ID;
@Value("${dts.im.SDKAppID}")
private Long SDKAppID;
@Value("${dts.im.secret}")
private String SECRET;
@Autowired
TLSSigApi tlsSigApi;
@Autowired
IMUtil imUtil;
@Autowired
UserDao userDao;
/**
* 导入用户信息到IM中
* @return
*/
public Result importUser(User user) {
String userSig = tlsSigApi.getUserSig(ADMIN_ID);
Random random = new Random(4294967295L);
long randomNum = random.nextInt();
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("?sdkappid=" + SDKAppID);
stringBuffer.append("&identifier=" + ADMIN_ID);
stringBuffer.append("&usersig=" + userSig);
stringBuffer.append("&random=" + randomNum);
stringBuffer.append("&contenttype=json");
String url = ACCOUNT_URL + stringBuffer.toString();
logger.info("============== IM导入用户请求url : {}", url);
OkHttpUtil okHttpUtil = OkHttpUtil.builder().url(url);
Map<String, Object> map = new HashMap<>();
map.put("UserID", imUtil.formatUserId(user.getId() + ""));
map.put("Nick", user.getNickname());
map.put("FaceUrl", user.getAvatar());
logger.info("============ IM导入用户内容 : {}", JsonUtils.fromMap(map));
okHttpUtil.addParams(map);
okHttpUtil.post(true);
String responseStr = okHttpUtil.async();
logger.info("用户id : {}, IM导入用户 response :{}", user.getId(), responseStr);
String actionStatus = JsonUtils.getValueByPath(responseStr, "ActionStatus");
String errorCode = JsonUtils.getValueByPath(responseStr, "ErrorCode");
String errorInfo = JsonUtils.getValueByPath(responseStr, "ErrorInfo");
if (!"OK".equals(actionStatus)) {
logger.error("用户id : {}, IM导入用户失败, errorCode : {}, errmsg : {} ", user.getId(), errorCode, errorInfo);
return Result.failed(errorInfo);
}
logger.info("============= IM导入用户成功 ===========");
return Result.success();
}
/**
* IM用户初始化
* 导入表中已有全部的用户
* @return
*/
public void initUser() {
List<User> userList = userDao.queryAll();
userList.forEach(user -> {
importUser(user);
});
}
}
package com.wwdz.ch.core.im.api;
import com.wwdz.ch.core.consts.IMEnum;
import com.wwdz.ch.core.entity.im.IMChatRequestDto;
import com.wwdz.ch.core.entity.im.SendChatMsgRequestDto;
import com.wwdz.ch.core.entity.im.IMChatMsg;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.core.util.IMUtil;
import com.wwdz.ch.core.util.OkHttpUtil;
import com.xxdxxs.utils.EntityMapper;
import com.xxdxxs.utils.JsonUtils;
import com.xxdxxs.utils.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 会话api
*/
@Component
public class ConversationApi {
private static final Logger logger = LoggerFactory.getLogger(ConversationApi.class);
private static final String ACCOUNT_URL = "https://console.tim.qq.com/v4/openim/sendmsg";
private static final String GET_CHAT_LIST_URL = "https://console.tim.qq.com/v4/recentcontact/get_list";
@Value("${dts.im.adminid}")
private String ADMIN_ID;
@Value("${dts.im.SDKAppID}")
private Long SDKAppID;
@Autowired
TLSSigApi tlsSigApi;
@Autowired
IMUtil imUtil;
/**
* 发送对话信息
* @param sendChatMsgRequestDto
* @return
*/
public Result sendChatMsg(SendChatMsgRequestDto sendChatMsgRequestDto) {
String userSig = tlsSigApi.getUserSig(ADMIN_ID);
Random random = new Random(4294967295L);
int randomNum = random.nextInt();
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("?sdkappid=" + SDKAppID);
stringBuffer.append("&identifier=" + ADMIN_ID);
stringBuffer.append("&usersig=" + userSig);
stringBuffer.append("&random=" + randomNum);
stringBuffer.append("&contenttype=json");
String url = ACCOUNT_URL + stringBuffer.toString();
OkHttpUtil okHttpUtil = OkHttpUtil.builder().url(url);
IMChatMsg imChatMsg = imUtil.convert(sendChatMsgRequestDto);
//消息同步至发送方
imChatMsg.setSyncOtherMachine(IMEnum.SyncOtherMachineEnum.SYNC.getCode());
imChatMsg.setMsgRandom(randomNum);
logger.info("============ 发送对话信息内容 : {}", JsonUtils.from(imChatMsg));
okHttpUtil.addParams(MapUtils.fromEntity(imChatMsg));
okHttpUtil.post(true);
String responseStr = okHttpUtil.async();
logger.info("发送对话信息 response :{}", responseStr);
String actionStatus = JsonUtils.getValueByPath(responseStr, "ActionStatus");
String errorCode = JsonUtils.getValueByPath(responseStr, "ErrorCode");
String errorInfo = JsonUtils.getValueByPath(responseStr, "ErrorInfo");
if (!"OK".equals(actionStatus)) {
logger.error("用户id : {}, 发送对话信息失败, errorCode : {}, errmsg : {} ", imChatMsg.getFrom_Account(), errorCode, errorInfo);
return Result.failed(errorInfo);
}
logger.info("============= 发送对话信息成功 ===========");
return Result.success();
}
/**
* 拉取会话列表
* @param imChatRequestDto
* @return
*/
public Result getChatList(IMChatRequestDto imChatRequestDto) {
String userSig = tlsSigApi.getUserSig(ADMIN_ID);
Random random = new Random(4294967295L);
int randomNum = random.nextInt();
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("?sdkappid=" + SDKAppID);
stringBuffer.append("&identifier=" + ADMIN_ID);
stringBuffer.append("&usersig=" + userSig);
stringBuffer.append("&random=" + randomNum);
stringBuffer.append("&contenttype=json");
String url = GET_CHAT_LIST_URL + stringBuffer.toString();
OkHttpUtil okHttpUtil = OkHttpUtil.builder().url(url);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("From_Account", imUtil.formatUserId(imChatRequestDto.getUserId() + ""));
paramMap.put("TimeStamp", 0);
paramMap.put("StartIndex", 0);
paramMap.put("TopTimeStamp", 0);
paramMap.put("TopStartIndex", 0);
paramMap.put("AssistFlags", 15);
logger.info("============ 拉取会话列表参数 : {}", JsonUtils.fromMap(paramMap));
okHttpUtil.addParams(paramMap);
okHttpUtil.post(true);
String responseStr = okHttpUtil.async();
logger.info("拉取会话列表 response :{}", responseStr);
String actionStatus = JsonUtils.getValueByPath(responseStr, "ActionStatus");
String errorCode = JsonUtils.getValueByPath(responseStr, "ErrorCode");
String errorInfo = JsonUtils.getValueByPath(responseStr, "ErrorInfo");
if (!"OK".equals(actionStatus)) {
logger.error("用户id : {}, 拉取会话列表, errorCode : {}, errmsg : {} ", imChatRequestDto.getUserId(), errorCode, errorInfo);
return Result.failed(errorInfo);
}
logger.info("============= 拉取会话列表成功 ===========");
return Result.success();
}
}
package com.wwdz.ch.core.im.api;
import com.wwdz.ch.core.im.TLSSigAPIv2;
import com.wwdz.ch.core.util.IMUtil;
import com.wwdz.ch.core.util.RedisUtils;
import com.xxdxxs.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 用户签名
*/
@Component
public class TLSSigApi {
private static final Logger logger = LoggerFactory.getLogger(TLSSigApi.class);
private final static String USERSIG_KEY= "IM:USERSIG:";
/**
* 30天有效期
*/
private final Long EXPIRE = 86400 * 30L;
@Value("${dts.im.SDKAppID}")
private Long SDKAppID;
@Value("${dts.im.secret}")
private String SECRET;
@Value("${dts.im.adminid}")
private String ADMIN_ID;
@Autowired
RedisUtils redisUtils;
@Autowired
IMUtil imUtil;
/**
* 获取用户签名
* @param userId
* @return
*/
public String getUserSig(String userId) {
//根据商户的appid从redis中获取商户的token
String userSig = redisUtils.hasKey(getUserSigKey(userId))? redisUtils.get(getUserSigKey(userId)).toString() : null;
if (StringUtils.isEmpty(userSig)) {
userSig = refreshUserSig(userId);
}
return userSig;
}
/**
* 用户签名存在redis中的key
* @param userId
* @return
*/
private String getUserSigKey(String userId) {
return USERSIG_KEY + imUtil.formatUserId(userId);
}
/**
* 刷新签名
* 有效期为24小时
* @param userId
* @return
*/
public String refreshUserSig(String userId) {
TLSSigAPIv2 api = new TLSSigAPIv2(SDKAppID, SECRET);
String userSig = api.genUserSig(userId, EXPIRE);
logger.info("IM刷新签名 : {}", userSig);
redisUtils.set(getUserSigKey(userId), userSig, EXPIRE - 10, TimeUnit.SECONDS);
return userSig;
}
}
package com.wwdz.ch.core.util;
import com.wwdz.ch.core.consts.IMEnum;
import com.wwdz.ch.core.entity.im.SendChatMsgRequestDto;
import com.wwdz.ch.core.entity.im.IMChatMsg;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Component
public class IMUtil {
@Value("${dts.im.prefix}")
private String PREFIX;
/**
* 格式化用户id
* 转换为im对话中的用户id
* @param userId
* @return
*/
public String formatUserId(String userId) {
return PREFIX + userId;
}
/**
* 参数userId格式为XX_userid
* 还原成系统中的userid,去除前缀
* @param userId
* @return
*/
public long getAppletUserId(String userId) {
String appletUserId = userId.split("_")[1];
return Long.valueOf(appletUserId);
}
/**
* SendChatMsgRequestDto 转换成 IMChatMsg
* @param dto
* @return
*/
public IMChatMsg convert(SendChatMsgRequestDto dto) {
IMChatMsg imChatMsg = new IMChatMsg();
//userid需要转换成IM的用户ID
imChatMsg.setTo_Account(formatUserId(dto.getTo_Account()));
imChatMsg.setFrom_Account(formatUserId(dto.getFrom_Account()));
Map<String, Object> msgContentMap = new HashMap<>();
msgContentMap.put("MsgType", IMEnum.MsgTypeEnum.getValueByCode(dto.getMsgType()));
msgContentMap.put("MsgContent", new HashMap(){{put("Text", dto.getMsgContent());}});
imChatMsg.setMsgBody(Arrays.asList(msgContentMap));
return imChatMsg;
}
}
......@@ -22,6 +22,13 @@ dts:
officialaccount-key: noeN1amYRvzrVmE2GnC5VnsIfgPEmv6bhX54wJOARlM
get-officialaccount-accesstoken-url: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential
#腾讯IM配置
im:
SDKAppID: 1400489950
secret: b5873a44e46efd086015a51e171e6e09fdeb4dce778752c891e63ed17aa1a81e
prefix: cjxc-applet-dev_
adminid: cjxc
#通知相关配置
notify:
mail:
......
......@@ -21,6 +21,13 @@ dts:
officialaccount-key: noeN1amYRvzrVmE2GnC5VnsIfgPEmv6bhX54wJOARlM
get-officialaccount-accesstoken-url: https://api.weixin.qq.com/cgi-bin/stable_token?grant_type=client_credential
#腾讯IM配置
im:
SDKAppID: 1400489950
secret: b5873a44e46efd086015a51e171e6e09fdeb4dce778752c891e63ed17aa1a81e
prefix: cjxc-applet_
adminid: cjxc
#通知相关配置
notify:
mail:
......
......@@ -7,4 +7,6 @@ import java.util.List;
public interface AiAssistantDao {
List<AiAssistant> findList (AiAssistantRequestDto dto);
AiAssistant findByCode (String code);
}
......@@ -2,6 +2,8 @@ package com.wwdz.ch.db.dao;
import com.wwdz.ch.db.domain.User;
import java.util.List;
public interface UserDao {
/**
* 通过oid查询未删除的记录
......@@ -71,4 +73,7 @@ public interface UserDao {
boolean isExistedByMobile(String beforeMobile, String afterMobile);
List<User> queryAll();
}
package com.wwdz.ch.db.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
......@@ -9,12 +10,17 @@ import lombok.Data;
/**
* @author shiyu
* @date 2023/10/16
* @date 2023/10/18
*/
@Data
public class AiAssistant implements Entity {
private Integer id;
/**
* 编号
*/
private String code;
/**
* 头像
*/
......@@ -49,6 +55,7 @@ public class AiAssistant implements Entity {
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", code=").append(code);
sb.append(", avatar=").append(avatar);
sb.append(", name=").append(name);
sb.append(", profile=").append(profile);
......@@ -72,6 +79,7 @@ public class AiAssistant implements Entity {
}
AiAssistant other = (AiAssistant) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getCode() == null ? other.getCode() == null : this.getCode().equals(other.getCode()))
&& (this.getAvatar() == null ? other.getAvatar() == null : this.getAvatar().equals(other.getAvatar()))
&& (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName()))
&& (this.getProfile() == null ? other.getProfile() == null : this.getProfile().equals(other.getProfile()))
......@@ -84,6 +92,7 @@ public class AiAssistant implements Entity {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getCode() == null) ? 0 : getCode().hashCode());
result = prime * result + ((getAvatar() == null) ? 0 : getAvatar().hashCode());
result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
result = prime * result + ((getProfile() == null) ? 0 : getProfile().hashCode());
......@@ -101,6 +110,7 @@ public class AiAssistant implements Entity {
*/
public enum Column {
id("id", "id", "INTEGER", false),
code("code", "code", "VARCHAR", false),
avatar("avatar", "avatar", "VARCHAR", false),
name("name", "name", "VARCHAR", true),
profile("profile", "profile", "VARCHAR", false),
......
......@@ -280,6 +280,148 @@ public class AiAssistantExample {
return (Criteria) this;
}
public Criteria andCodeIsNull() {
addCriterion("code is null");
return (Criteria) this;
}
public Criteria andCodeIsNotNull() {
addCriterion("code is not null");
return (Criteria) this;
}
public Criteria andCodeEqualTo(String value) {
addCriterion("code =", value, "code");
return (Criteria) this;
}
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table ai_assistant
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
public Criteria andCodeEqualToColumn(AiAssistant.Column column) {
addCriterion(new StringBuilder("code = ").append(column.getEscapedColumnName()).toString());
return (Criteria) this;
}
public Criteria andCodeNotEqualTo(String value) {
addCriterion("code <>", value, "code");
return (Criteria) this;
}
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table ai_assistant
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
public Criteria andCodeNotEqualToColumn(AiAssistant.Column column) {
addCriterion(new StringBuilder("code <> ").append(column.getEscapedColumnName()).toString());
return (Criteria) this;
}
public Criteria andCodeGreaterThan(String value) {
addCriterion("code >", value, "code");
return (Criteria) this;
}
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table ai_assistant
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
public Criteria andCodeGreaterThanColumn(AiAssistant.Column column) {
addCriterion(new StringBuilder("code > ").append(column.getEscapedColumnName()).toString());
return (Criteria) this;
}
public Criteria andCodeGreaterThanOrEqualTo(String value) {
addCriterion("code >=", value, "code");
return (Criteria) this;
}
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table ai_assistant
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
public Criteria andCodeGreaterThanOrEqualToColumn(AiAssistant.Column column) {
addCriterion(new StringBuilder("code >= ").append(column.getEscapedColumnName()).toString());
return (Criteria) this;
}
public Criteria andCodeLessThan(String value) {
addCriterion("code <", value, "code");
return (Criteria) this;
}
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table ai_assistant
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
public Criteria andCodeLessThanColumn(AiAssistant.Column column) {
addCriterion(new StringBuilder("code < ").append(column.getEscapedColumnName()).toString());
return (Criteria) this;
}
public Criteria andCodeLessThanOrEqualTo(String value) {
addCriterion("code <=", value, "code");
return (Criteria) this;
}
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table ai_assistant
*
* @mbg.generated
* @project https://github.com/itfsw/mybatis-generator-plugin
*/
public Criteria andCodeLessThanOrEqualToColumn(AiAssistant.Column column) {
addCriterion(new StringBuilder("code <= ").append(column.getEscapedColumnName()).toString());
return (Criteria) this;
}
public Criteria andCodeLike(String value) {
addCriterion("code like", value, "code");
return (Criteria) this;
}
public Criteria andCodeNotLike(String value) {
addCriterion("code not like", value, "code");
return (Criteria) this;
}
public Criteria andCodeIn(List<String> values) {
addCriterion("code in", values, "code");
return (Criteria) this;
}
public Criteria andCodeNotIn(List<String> values) {
addCriterion("code not in", values, "code");
return (Criteria) this;
}
public Criteria andCodeBetween(String value1, String value2) {
addCriterion("code between", value1, value2, "code");
return (Criteria) this;
}
public Criteria andCodeNotBetween(String value1, String value2) {
addCriterion("code not between", value1, value2, "code");
return (Criteria) this;
}
public Criteria andAvatarIsNull() {
addCriterion("avatar is null");
return (Criteria) this;
......
......@@ -9,6 +9,11 @@ public class AiAssistantRequestDto extends BaseRequestDto implements Entity {
private Integer id;
/**
* 编号
*/
private String code;
/**
* 名称
*/
......
......@@ -24,4 +24,11 @@ public class AiAssistantDaoImpl implements AiAssistantDao {
PageHelper.startPage(dto.getPage(), dto.getLimit());
return aiAssistantMapper.selectByExample(aiAssistantExample);
}
@Override
public AiAssistant findByCode(String code) {
AiAssistantExample aiAssistantExample = new AiAssistantExample();
aiAssistantExample.createCriteria().andCodeEqualTo(code);
return aiAssistantMapper.selectOneByExample(aiAssistantExample);
}
}
......@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
@Repository
public class UserDaoImpl implements UserDao {
......@@ -72,4 +73,11 @@ public class UserDaoImpl implements UserDao {
criteria.andDeletedEqualTo(false);
return userMapper.countByExample(example) > 0;
}
@Override
public List<User> queryAll() {
UserExample example = new UserExample();
example.createCriteria().andDeletedEqualTo(false);
return userMapper.selectByExample(example);
}
}
......@@ -3,6 +3,7 @@
<mapper namespace="com.wwdz.ch.db.mapper.AiAssistantMapper">
<resultMap id="BaseResultMap" type="com.wwdz.ch.db.domain.AiAssistant">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="code" jdbcType="VARCHAR" property="code" />
<result column="avatar" jdbcType="VARCHAR" property="avatar" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="profile" jdbcType="VARCHAR" property="profile" />
......@@ -68,7 +69,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, avatar, `name`, profile, `type`, create_time
id, code, avatar, `name`, profile, `type`, create_time
</sql>
<select id="selectByExample" parameterType="com.wwdz.ch.db.domain.AiAssistantExample" resultMap="BaseResultMap">
select
......@@ -103,7 +104,7 @@
</foreach>
</when>
<otherwise>
id, avatar, `name`, profile, `type`, create_time
id, code, avatar, `name`, profile, `type`, create_time
</otherwise>
</choose>
from ai_assistant
......@@ -134,7 +135,7 @@
</foreach>
</when>
<otherwise>
id, avatar, `name`, profile, `type`, create_time
id, code, avatar, `name`, profile, `type`, create_time
</otherwise>
</choose>
from ai_assistant
......@@ -154,10 +155,12 @@
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into ai_assistant (avatar, `name`, profile,
`type`, create_time)
values (#{avatar,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{profile,jdbcType=VARCHAR},
#{type,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP})
insert into ai_assistant (code, avatar, `name`,
profile, `type`, create_time
)
values (#{code,jdbcType=VARCHAR}, #{avatar,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{profile,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP}
)
</insert>
<insert id="insertSelective" parameterType="com.wwdz.ch.db.domain.AiAssistant">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
......@@ -165,6 +168,9 @@
</selectKey>
insert into ai_assistant
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="code != null">
code,
</if>
<if test="avatar != null">
avatar,
</if>
......@@ -182,6 +188,9 @@
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="code != null">
#{code,jdbcType=VARCHAR},
</if>
<if test="avatar != null">
#{avatar,jdbcType=VARCHAR},
</if>
......@@ -211,6 +220,9 @@
<if test="record.id != null">
id = #{record.id,jdbcType=INTEGER},
</if>
<if test="record.code != null">
code = #{record.code,jdbcType=VARCHAR},
</if>
<if test="record.avatar != null">
avatar = #{record.avatar,jdbcType=VARCHAR},
</if>
......@@ -234,6 +246,7 @@
<update id="updateByExample" parameterType="map">
update ai_assistant
set id = #{record.id,jdbcType=INTEGER},
code = #{record.code,jdbcType=VARCHAR},
avatar = #{record.avatar,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
profile = #{record.profile,jdbcType=VARCHAR},
......@@ -246,6 +259,9 @@
<update id="updateByPrimaryKeySelective" parameterType="com.wwdz.ch.db.domain.AiAssistant">
update ai_assistant
<set>
<if test="code != null">
code = #{code,jdbcType=VARCHAR},
</if>
<if test="avatar != null">
avatar = #{avatar,jdbcType=VARCHAR},
</if>
......@@ -266,7 +282,8 @@
</update>
<update id="updateByPrimaryKey" parameterType="com.wwdz.ch.db.domain.AiAssistant">
update ai_assistant
set avatar = #{avatar,jdbcType=VARCHAR},
set code = #{code,jdbcType=VARCHAR},
avatar = #{avatar,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
profile = #{profile,jdbcType=VARCHAR},
`type` = #{type,jdbcType=INTEGER},
......@@ -306,7 +323,7 @@
</foreach>
</when>
<otherwise>
id, avatar, `name`, profile, `type`, create_time
id, code, avatar, `name`, profile, `type`, create_time
</otherwise>
</choose>
from ai_assistant
......@@ -319,4 +336,5 @@
limit 1
</select>
</mapper>
\ No newline at end of file
......@@ -41,7 +41,8 @@ public class WebMvcConfiguration implements WebMvcConfigurer {
, "/wx/user/loginByWx", "/wx/user/loginByMobile", "/wx/user/loginRegCaptcha", "/wx/user/updateRegCaptcha", "/wx/user/login", "/wx/user/fillCode",
"/officialAccountCallback/**",
"/wx/officialAccount/**",
"/wx/item/**"
"/wx/item/**",
"/wx/aiAssistant/**"
);
}
}
package com.wwdz.ch.wx.impl;
import com.wwdz.ch.core.consts.IMEnum;
import com.wwdz.ch.core.entity.im.SendChatMsgRequestDto;
import com.wwdz.ch.core.entity.im.IMChatRequestDto;
import com.wwdz.ch.core.im.api.ConversationApi;
import com.wwdz.ch.core.im.api.TLSSigApi;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.db.dao.AiAssistantDao;
import com.wwdz.ch.db.domain.AiAssistant;
import com.wwdz.ch.wx.service.IMService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* 会话
*/
@Service
public class IMServiceImpl implements IMService {
private static final Logger logger = LoggerFactory.getLogger(IMServiceImpl.class);
@Autowired
ConversationApi conversationApi;
@Autowired
AiAssistantDao aiAssistantDao;
@Autowired
TLSSigApi tlsSigApi;
/**
* 新增ai会话,发送默认打招呼的消息
* @param dto
* @return
*/
@Override
public Result addAiChat(SendChatMsgRequestDto dto) {
try {
AiAssistant aiAssistant = aiAssistantDao.findByCode(dto.getFrom_Account());
String msgContent = aiAssistant.getProfile();
dto.setMsgContent(msgContent);
dto.setMsgType(IMEnum.MsgTypeEnum.TIMTextElem.getCode());
Result sendResult = conversationApi.sendChatMsg(dto);
if (!sendResult.getSuccess()) {
return Result.failed("新增会话失败");
}
return Result.success();
} catch (Exception e) {
logger.info("新增ai会话失败 error:{}",e );
}
return Result.failed();
}
@Override
public Result findChatList(IMChatRequestDto dto) {
try {
Result result = conversationApi.getChatList(dto);
} catch (Exception e) {
logger.error("获取会话列表失败:{}", e);
}
return Result.failed();
}
@Override
public Result getUserSig(IMChatRequestDto dto) {
try {
String userSig = tlsSigApi.getUserSig(String.valueOf(dto.getUserId()));
Map<String, String> map = new HashMap<>();
map.put("userSig", userSig);
return Result.success(map);
} catch (Exception e) {
logger.error("获取用户签名失败:{}", e);
}
return Result.failed();
}
}
package com.wwdz.ch.wx.service;
import com.wwdz.ch.core.entity.im.SendChatMsgRequestDto;
import com.wwdz.ch.core.entity.im.IMChatRequestDto;
import com.wwdz.ch.core.type.Result;
public interface IMService {
/**
* 新增ai会话
* 发送默认打招呼的消息
*/
Result addAiChat(SendChatMsgRequestDto dto);
/**
* 查询会话列表
* @param dto
* @return
*/
Result findChatList(IMChatRequestDto dto);
/**
* 获取用户签名
* @param dto
* @return
*/
Result getUserSig(IMChatRequestDto dto);
}
......@@ -49,4 +49,6 @@ public class AiAssistantController {
}
}
package com.wwdz.ch.wx.web;
import com.alibaba.fastjson.JSON;
import com.wwdz.ch.core.consts.ResultCode;
import com.wwdz.ch.core.entity.im.SendChatMsgRequestDto;
import com.wwdz.ch.core.entity.im.IMChatRequestDto;
import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.wx.service.AiAssistantService;
import com.wwdz.ch.wx.service.AiDefaultQuestionService;
import com.wwdz.ch.wx.service.IMService;
import com.xxdxxs.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/wx/im")
public class IMController {
private static final Logger logger = LoggerFactory.getLogger(IMController.class);
@Autowired
AiAssistantService aiAssistantService;
@Autowired
AiDefaultQuestionService aiDefaultQuestionService;
@Autowired
IMService imService;
@ApiOperation(value = "查询会话列表")
@PostMapping("/findChatList")
public Result findList(@RequestBody IMChatRequestDto dto) {
logger.info("【请求开始】查询会话列表,请求参数:{}", JSON.toJSONString(dto));
return imService.findChatList(dto);
}
@ApiOperation(value = "新增AI会话")
@PostMapping("/addChat")
public Result addChat(@RequestBody SendChatMsgRequestDto dto) {
logger.info("【请求开始】新增AI会话,请求参数:{}", JSON.toJSONString(dto));
if (!StringUtils.isAllNotEmpty(dto.getFrom_Account(), dto.getTo_Account())) {
return Result.failed(ResultCode.PARAM_ERROR);
}
return imService.addAiChat(dto);
}
@ApiOperation(value = "获取用户签名")
@PostMapping("/getUserSig")
public Result getUserSig(@RequestBody IMChatRequestDto dto) {
logger.info("【请求开始】获取用户签名,请求参数:{}", JSON.toJSONString(dto));
if (StringUtils.isEmpty(dto.getUserId())) {
return Result.failed(ResultCode.PARAM_ERROR);
}
return imService.getUserSig(dto);
}
}
package com.wwdz.ch.wx.api;
import com.wwdz.ch.core.consts.IMEnum;
import com.wwdz.ch.core.entity.im.IMChatRequestDto;
import com.wwdz.ch.core.entity.im.SendChatMsgRequestDto;
import com.wwdz.ch.core.im.api.ChatUserApi;
import com.wwdz.ch.core.im.api.ConversationApi;
import com.wwdz.ch.core.im.api.TLSSigApi;
import com.wwdz.ch.db.dao.UserDao;
import com.wwdz.ch.db.domain.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
......@@ -15,12 +22,71 @@ public class ChatApiTest {
@Autowired
ChatApi chatApi;
@Autowired
ChatUserApi chatUserApi;
@Autowired
ConversationApi conversationApi;
@Autowired
UserDao userDao;
@Autowired
TLSSigApi tlsSigApi;
@Test
public void chatWithModel() {
String question = "刀币的由来";
chatApi.chatWithModel(question);
}
@Test
public void getUserSig() {
tlsSigApi.refreshUserSig("cjxc");
}
/**
* 导入IM用户
*/
@Test
public void importUser() {
User user = userDao.queryById(251L);
chatUserApi.importUser(user);
}
/**
* 导入系统所有用户
*/
@Test
public void initAllUser() {
chatUserApi.initUser();
}
/**
* 发送IM消息
*/
@Test
public void sendChatMsg() {
SendChatMsgRequestDto sendChatMsgRequestDto = new SendChatMsgRequestDto();
sendChatMsgRequestDto.setTo_Account("241");
sendChatMsgRequestDto.setFrom_Account("251");
sendChatMsgRequestDto.setMsgType(IMEnum.MsgTypeEnum.TIMTextElem.getCode());
String msgContent = "测试消息4444444的数据, 是否可以接收到";
sendChatMsgRequestDto.setMsgContent(msgContent);
conversationApi.sendChatMsg(sendChatMsgRequestDto);
}
/**
* 拉取会话列表
*/
@Test
public void getChatList() {
IMChatRequestDto imChatRequestDto = new IMChatRequestDto();
imChatRequestDto.setUserId(251L);
conversationApi.getChatList(imChatRequestDto);
}
}
\ No newline at end of file
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