feat:聊天第三方接口对接
This commit is contained in:
1 parent
f23dc0412c
commit
6a8aed3c96
11 files changed
+445
-5
No files matched your search
+24
@@ -0,0 +1,24 @@
|
||||
package cn.iocoder.yudao.module.member.client.service;
|
||||
|
||||
import cn.iocoder.yudao.module.member.client.vo.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
public interface ChatApi {
|
||||
|
||||
/**
|
||||
* 聊天用户登录
|
||||
*/
|
||||
ChatLoginRespVo login(@Valid ChatLoginReqVO dto);
|
||||
|
||||
/**
|
||||
* 创建或者更新聊天用户
|
||||
*/
|
||||
boolean createOrUpdate(@Valid ChatCreateOrUpdateUserReqVo dto);
|
||||
|
||||
/**
|
||||
* 根据userId查询用户详情
|
||||
*/
|
||||
ChatGetUserByUserIdRespVo getUserByUserId(@Valid ChatGetUserByUserIdReqVo dto);
|
||||
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
package cn.iocoder.yudao.module.member.client.service;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.module.member.client.tool.ChatApiTool;
|
||||
import cn.iocoder.yudao.module.member.client.vo.*;
|
||||
import cn.iocoder.yudao.module.member.client.vo.base.ChatBaseRespVo;
|
||||
import cn.iocoder.yudao.module.member.framework.web.config.ChatProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ChatApiImpl implements ChatApi {
|
||||
|
||||
@Resource
|
||||
private ChatProperties chatProperties;
|
||||
|
||||
/**
|
||||
* 聊天用户登录
|
||||
*/
|
||||
@Override
|
||||
public ChatLoginRespVo login(ChatLoginReqVO dto) {
|
||||
ChatApiTool.API api = setApiConfig(ChatApiTool.USER_LOGIN);
|
||||
try {
|
||||
String body = JSONUtil.toJsonStr(dto);
|
||||
String res = HttpRequest.post(api.getFullPath()).header(apiCountersign(body)).body(body).execute().body();
|
||||
log.debug("聊天用户登录,res:{}", res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("聊天用户登录,res为空");
|
||||
return null;
|
||||
}
|
||||
ChatBaseRespVo baseRes = JSONUtil.toBean(res, ChatBaseRespVo.class);
|
||||
if (ObjectUtil.isEmpty(baseRes) || !baseRes.isSuccess()) {
|
||||
log.error("聊天用户登录,返回错误");
|
||||
return null;
|
||||
}
|
||||
ChatLoginRespVo vo = JSONUtil.toBean(baseRes.getData(), ChatLoginRespVo.class);
|
||||
if (ObjectUtil.isEmpty(vo)) {
|
||||
log.error("聊天用户登录,返回json解析错误");
|
||||
return null;
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("聊天用户登录,意外的错误", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或者更新聊天用户
|
||||
*/
|
||||
@Override
|
||||
public boolean createOrUpdate(ChatCreateOrUpdateUserReqVo dto) {
|
||||
ChatApiTool.API api = setApiConfig(ChatApiTool.USER_SAVE_OR_UPDATE);
|
||||
try {
|
||||
String body = JSONUtil.toJsonStr(dto);
|
||||
String res = HttpRequest.post(api.getFullPath()).header(apiCountersign(body)).body(body).execute().body();
|
||||
log.debug("创建或者更新聊天用户,res:{}", res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("创建或者更新聊天用户,res为空");
|
||||
return false;
|
||||
}
|
||||
ChatBaseRespVo baseRes = JSONUtil.toBean(res, ChatBaseRespVo.class);
|
||||
if (ObjectUtil.isEmpty(baseRes) || !baseRes.isSuccess()) {
|
||||
log.error("创建或者更新聊天用户,返回错误");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("创建或者更新聊天用户,意外的错误", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据userId查询用户详情
|
||||
*/
|
||||
@Override
|
||||
public ChatGetUserByUserIdRespVo getUserByUserId(ChatGetUserByUserIdReqVo dto) {
|
||||
ChatApiTool.API api = setApiConfig(ChatApiTool.USER_GET);
|
||||
try {
|
||||
String body = JSONUtil.toJsonStr(dto);
|
||||
String res = HttpRequest.post(api.getFullPath()).header(apiCountersign(body)).body(body).execute().body();
|
||||
log.debug("根据userId查询用户详情,res:{}", res);
|
||||
if (ObjectUtil.isEmpty(res)) {
|
||||
log.error("根据userId查询用户详情,res为空");
|
||||
return null;
|
||||
}
|
||||
ChatBaseRespVo baseRes = JSONUtil.toBean(res, ChatBaseRespVo.class);
|
||||
if (ObjectUtil.isEmpty(baseRes) || !baseRes.isSuccess()) {
|
||||
log.error("根据userId查询用户详情,返回错误");
|
||||
return null;
|
||||
}
|
||||
ChatGetUserByUserIdRespVo vo = JSONUtil.toBean(baseRes.getData(), ChatGetUserByUserIdRespVo.class);
|
||||
if (ObjectUtil.isEmpty(vo)) {
|
||||
log.error("根据userId查询用户详情,返回json解析错误");
|
||||
return null;
|
||||
}
|
||||
return vo;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("根据userId查询用户详情,意外的错误", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ChatApiTool.API setApiConfig(ChatApiTool.API api) {
|
||||
if (ObjectUtil.isNotEmpty(api)) {
|
||||
api.setHost(chatProperties.getBaseUrl());
|
||||
}
|
||||
api.init();
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接口加签
|
||||
*/
|
||||
private Map<String, List<String>> apiCountersign(String body) {
|
||||
String appKey = chatProperties.getAppKey();
|
||||
String appSecret = chatProperties.getAppSecret();
|
||||
String bizType = "10";
|
||||
String timestamp = String.valueOf(Instant.now().getEpochSecond());
|
||||
|
||||
String signStr = String.format("%s%s%s%s%s", appKey, appSecret, bizType, timestamp, body);
|
||||
String successSignMd5 = DigestUtils.md5Hex(signStr);
|
||||
|
||||
Map<String, List<String>> header = new LinkedHashMap<>();
|
||||
header.put("APP-KEY", new ArrayList<String>() {{
|
||||
add(appKey);
|
||||
}});
|
||||
header.put("BIZ-TYPE", new ArrayList<String>() {{
|
||||
add(bizType);
|
||||
}});
|
||||
header.put("TIMESTAMP", new ArrayList<String>() {{
|
||||
add(timestamp);
|
||||
}});
|
||||
header.put("SIGN", new ArrayList<String>() {{
|
||||
add(successSignMd5);
|
||||
}});
|
||||
return header;
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package cn.iocoder.yudao.module.member.client.tool;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 聊天接口工具类
|
||||
*/
|
||||
public class ChatApiTool {
|
||||
|
||||
public static final API USER_LOGIN = API.builder().summary("用户登录").url("/third/user/login").method(HttpMethod.POST).build();
|
||||
public static final API USER_GET = API.builder().summary("根据userId查询用户详情").url("/third/user/getUserByUserId").method(HttpMethod.POST).build();
|
||||
public static final API USER_SAVE_OR_UPDATE = API.builder().summary("创建或者更新用户").url("/third/user/createOrUpdate").method(HttpMethod.POST).build();
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
static public class API {
|
||||
|
||||
private String summary;
|
||||
|
||||
private String host;
|
||||
|
||||
private String url;
|
||||
|
||||
private String fullPath;
|
||||
|
||||
private HttpMethod method;
|
||||
|
||||
private Map<String, Object> paramsMap;
|
||||
|
||||
public String getParamsString() throws UnsupportedEncodingException {
|
||||
if (ObjectUtil.isEmpty(this.paramsMap)) return "";
|
||||
StringBuilder query = new StringBuilder();
|
||||
for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
|
||||
if (ObjectUtil.isNotEmpty(entry.getValue())) {
|
||||
if (ObjectUtil.isNotEmpty(query)) query.append("&");
|
||||
query.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name())).append("=").append(URLEncoder.encode(String.valueOf(entry.getValue()), StandardCharsets.UTF_8.name()));
|
||||
}
|
||||
}
|
||||
return "?" + query;
|
||||
}
|
||||
|
||||
public API setParamsMap(Map<String, Object> paramsMap) {
|
||||
this.paramsMap = paramsMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String init() {
|
||||
String apiPath = host + url;
|
||||
fullPath = apiPath;
|
||||
return apiPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.member.client.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
@Data
|
||||
@Schema(description = "chat用户注册req")
|
||||
public class ChatCreateOrUpdateUserReqVo {
|
||||
|
||||
@NotEmpty(message = "用户id不可为空")
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
@Length(max = 20, message = "用户名不能大于20字符")
|
||||
@NotEmpty(message = "用户名不可为空")
|
||||
@Schema(description = "用户名")
|
||||
private String userName;
|
||||
|
||||
@NotEmpty(message = "用户手机号不可为空")
|
||||
@Schema(description = "用户手机号")
|
||||
private String phone;
|
||||
|
||||
@Length(min = 5, max = 20, message = "密码长度必须在5-20个字符之间")
|
||||
@NotEmpty(message = "用户密码不可为空")
|
||||
@Schema(description = "用户密码")
|
||||
private String password;
|
||||
|
||||
@Length(max = 20, message = "昵称不能大于20字符")
|
||||
@Schema(description = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
@Schema(description = "用户头像")
|
||||
private String avatar;
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.module.member.client.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@Schema(description = "chat根据userId查询用户详情")
|
||||
public class ChatGetUserByUserIdReqVo {
|
||||
|
||||
@NotNull(message = "用户id不能为空")
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package cn.iocoder.yudao.module.member.client.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@Schema(description = "chat根据userId查询用户详情resp")
|
||||
public class ChatGetUserByUserIdRespVo {
|
||||
|
||||
@NotNull(message = "用户id不能为空")
|
||||
@Schema(description = "id")
|
||||
private Long id;
|
||||
|
||||
@NotEmpty(message = "用户名不能为空")
|
||||
@Length(max = 20, message = "用户名不能大于20字符")
|
||||
@Schema(description = "用户名")
|
||||
private String userName;
|
||||
|
||||
@NotEmpty(message = "用户昵称不能为空")
|
||||
@Length(max = 20, message = "昵称不能大于20字符")
|
||||
@Schema(description = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
@Schema(description = "性别")
|
||||
private Integer sex;
|
||||
|
||||
@Schema(description = "用户类型 1:普通用户 2:审核账户")
|
||||
private Integer type;
|
||||
|
||||
@Length(max = 128, message = "个性签名不能大于128个字符")
|
||||
@Schema(description = "个性签名")
|
||||
private String signature;
|
||||
|
||||
@Schema(description = "头像")
|
||||
private String headImage;
|
||||
|
||||
@Schema(description = "头像缩略图")
|
||||
private String headImageThumb;
|
||||
|
||||
@Schema(description = "是否在线")
|
||||
private Boolean online;
|
||||
|
||||
@Schema(description = "账号是否被封禁")
|
||||
private Boolean isBanned;
|
||||
|
||||
@Schema(description = "被封禁原因")
|
||||
private String reason;
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.member.client.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@Schema(description = "chat用户登录DTO")
|
||||
public class ChatLoginReqVO {
|
||||
|
||||
@Max(value = 2, message = "登录终端类型取值范围:0,2")
|
||||
@Min(value = 0, message = "登录终端类型取值范围:0,2")
|
||||
@NotNull(message = "登录终端类型不可为空")
|
||||
@Schema(description = "登录终端 0:web 1:app 2:pc")
|
||||
private Integer terminal;
|
||||
|
||||
@NotEmpty(message = "用户id不存在")
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.member.client.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "chat用户登录resp")
|
||||
public class ChatLoginRespVo {
|
||||
|
||||
@Schema(description = "每次请求都必须在header中携带accessToken")
|
||||
private String accessToken;
|
||||
|
||||
@Schema(description = "accessToken过期时间(秒)")
|
||||
private Integer accessTokenExpiresIn;
|
||||
|
||||
@Schema(description = "accessToken过期后,通过refreshToken换取新的token")
|
||||
private String refreshToken;
|
||||
|
||||
@Schema(description = "refreshToken过期时间(秒)")
|
||||
private Integer refreshTokenExpiresIn;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.member.client.vo.base;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChatBaseRespVo {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String message;
|
||||
|
||||
private String data;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return ObjUtil.equal(code, 200);
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.member.framework.web.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties("chat")
|
||||
@Data
|
||||
public class ChatProperties {
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private String appKey;
|
||||
|
||||
private String appSecret;
|
||||
|
||||
}
|
||||
@@ -4,10 +4,10 @@ server:
|
||||
--- #################### 数据库相关配置 ####################
|
||||
|
||||
spring:
|
||||
# autoconfigure:
|
||||
# exclude:
|
||||
# - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
|
||||
# - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
|
||||
# autoconfigure:
|
||||
# exclude:
|
||||
# - org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStoreAutoConfiguration # 禁用 AI 模块的 Qdrant,手动创建
|
||||
# - org.springframework.ai.autoconfigure.vectorstore.milvus.MilvusVectorStoreAutoConfiguration # 禁用 AI 模块的 Milvus,手动创建
|
||||
# 数据源配置项
|
||||
autoconfigure:
|
||||
exclude:
|
||||
@@ -225,4 +225,9 @@ iot:
|
||||
|
||||
# 插件配置
|
||||
pf4j:
|
||||
pluginsDir: ${user.home}/plugins # 插件目录
|
||||
pluginsDir: ${user.home}/plugins # 插件目录
|
||||
|
||||
chat:
|
||||
base-url: http://127.0.0.1:8888
|
||||
api-key: 4H2HkBLygMsxaQKO
|
||||
app-secret: JIizm84av3TK5xaQdsng7X5mqLPjbeQ0
|
||||
Reference in new issue
Block a user