feat:消息发送、账户注册功能开发

This commit is contained in:
zuoqinbo 2023-10-11 09:37:41 +08:00
parent 72e4eefafe
commit cb32de27ed
21 changed files with 441 additions and 62 deletions

View File

@ -13,6 +13,11 @@
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>

View File

@ -1,5 +1,6 @@
package cn.axzo.im.center.api.feign;
import cn.axzo.im.center.api.vo.req.RobotAccountReq;
import cn.axzo.im.center.api.vo.req.UserAccountReq;
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
import cn.azxo.framework.common.model.CommonResponse;
@ -17,21 +18,24 @@ import org.springframework.web.bind.annotation.RequestBody;
*/
@FeignClient(name = "im", url = "${axzo.service.im:http://im:8080}")
public interface UserAccountApi {
public interface AccountApi {
/**
* 生成网易云信IM账户
* 普通用户生成网易云信IM账户
* 因多终端场景同一个普通用户会申请多个云信账户用于不同的app终端
* 例如工人端一个IM账户企业端一个IM账户,根据不同的appType来区分
* @param userAccountReq 生成云信账户参数
* @return 返回云信IM账户
*/
@PostMapping("api/im/user/account/generate")
CommonResponse<UserAccountResp> generateAccount(@RequestBody @Validated UserAccountReq userAccountReq);
/**
* 生成网易云信IM账户
* @param userAccountReq 生成云信账户参数
* 生成机器人网易云信IM账户,机器人只有一个PC端不需要appType来区分
* @param robotAccountReq 生成云信账户参数
* @return 返回云信IM账户
*/
@PostMapping("api/im/robot/account/generate")
CommonResponse<UserAccountResp> generateRobotAccount(@RequestBody @Validated UserAccountReq userAccountReq);
CommonResponse<UserAccountResp> generateRobotAccount(@RequestBody @Validated RobotAccountReq robotAccountReq);
}

View File

@ -16,25 +16,15 @@ import org.springframework.web.bind.annotation.RequestBody;
* @date 2023/10/9 16:01
*/
@FeignClient(name = "im", url = "${axzo.service.im:http://im:8080}")
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im:8080}")
public interface MessageApi {
/**
* 创建机器人
* 发送消息
*
* @param messageInfo 机器人请求参数
* @param messageInfo 消息请求参数
* @return 机器人成功创建信息
*/
@PostMapping("api/im/message/dispatch")
CommonResponse<RobotInfoResp> sendMessage(@RequestBody @Validated MessageInfo messageInfo);
CommonResponse<MessageResp> sendMessage(@RequestBody @Validated MessageInfo messageInfo);
/**
* 创建机器人
*
* @param messageInfo 机器人请求参数
* @return 机器人成功创建信息
*/
@PostMapping("api/im/account/register")
CommonResponse<RobotInfoResp> registerMessage(@RequestBody @Validated MessageInfo messageInfo);
}

View File

@ -3,6 +3,7 @@ package cn.axzo.im.center.api.feign;
import cn.axzo.framework.domain.page.Page;
import cn.axzo.im.center.api.vo.req.RobotInfoReq;
import cn.axzo.im.center.api.vo.req.RobotQuery;
import cn.axzo.im.center.api.vo.req.UpdateRobotInfoReq;
import cn.axzo.im.center.api.vo.resp.RobotInfoResp;
import cn.azxo.framework.common.model.CommonResponse;
import org.springframework.cloud.openfeign.FeignClient;
@ -12,6 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* 机器人管理API
*
@ -20,7 +23,7 @@ import org.springframework.web.bind.annotation.RequestBody;
* @date 2023/10/9 16:01
*/
@FeignClient(name = "im", url = "${axzo.service.im:http://im:8080}")
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im:8080}")
public interface RobotInfoApi {
/**
@ -33,11 +36,11 @@ public interface RobotInfoApi {
/**
* 更新机器人信息
* @param robotInfoReq 机器人请求参数
* @param updateRobotInfoReq 更新机器人请求参数
* @return 机器人成功更新信息
*/
@PostMapping("api/im/robot/basic/update")
CommonResponse<RobotInfoResp> updateRobotInfo(@RequestBody @Validated RobotInfoReq robotInfoReq);
CommonResponse<RobotInfoResp> updateRobotInfo(@RequestBody @Validated UpdateRobotInfoReq updateRobotInfoReq);
/**
* 查询机器人信息
@ -50,14 +53,13 @@ public interface RobotInfoApi {
/**
* 查询机器人列表
* OMS-PC端-查询机器人列表
* @param robotQuery 机器人查询条件
* @return 机器人列表信息
*/
@GetMapping("api/im/robot/basic/list")
CommonResponse<Page<RobotInfoResp>> queryRobotList(@RequestBody RobotQuery robotQuery);
/**
* 生成网易云信IM账户
* @param robotInfoRequest 生成云信账户参数
@ -66,4 +68,13 @@ public interface RobotInfoApi {
@PostMapping("api/im/robot/account/generate")
CommonResponse<RobotInfoResp> generateAccount(@RequestBody @Validated RobotInfoReq robotInfoRequest);
/**
* Mobile移动端-查询所有运行中的机器人列表
* @return 所有机器人的列表信息包含标签以及消息模板信息
*/
@GetMapping("api/im/robot/msgTemplate/list")
CommonResponse<List<RobotMsgTemplateResp>> queryRunningRobots();
}

View File

@ -2,6 +2,7 @@ package cn.axzo.im.center.api.feign;
import cn.axzo.im.center.api.vo.req.RobotTagQuery;
import cn.axzo.im.center.api.vo.req.RobotTagReq;
import cn.axzo.im.center.api.vo.req.UpdateRobotTagReq;
import cn.axzo.im.center.api.vo.resp.RobotTagResp;
import cn.azxo.framework.common.model.CommonResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -19,7 +20,7 @@ import org.springframework.web.bind.annotation.RequestBody;
* @author zuoqinbo
* @date 2023/10/9 16:01
*/
@FeignClient(name = "im", url = "${axzo.service.im:http://im:8080}")
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im:8080}")
public interface RobotTagApi {
/**
@ -38,7 +39,7 @@ public interface RobotTagApi {
* @return 机器人标签更新完成信息
*/
@PostMapping("api/im/robot/tag/update")
CommonResponse<RobotTagResp> updateRobotTag(@RequestBody @Validated RobotTagReq robotTagRequest);
CommonResponse<RobotTagResp> updateRobotTag(@RequestBody @Validated UpdateRobotTagReq robotTagRequest);
/**
* 查询机器人标签信息

View File

@ -0,0 +1,51 @@
package cn.axzo.im.center.api.vo.nim;
import java.security.MessageDigest;
/**
* 文档地址:https://doc.yunxin.163.com/messaging/docs/jk3MzY2MTI?platform=server
* 网易云信接口鉴权
* @version V1.0
* @author zuoqinbo
* @date 2023/10/10 18:38
*/
public class CheckSumUtil {
// 计算并获取CheckSum
public static String getCheckSum(String appSecret, String nonce, String curTime) {
return encode("sha1", appSecret + nonce + curTime);
}
// 计算并获取md5值
public static String getMD5(String requestBody) {
return encode("md5", requestBody);
}
private static String encode(String algorithm, String value) {
if (value == null) {
return null;
}
try {
MessageDigest messageDigest
= MessageDigest.getInstance(algorithm);
messageDigest.update(value.getBytes());
return getFormattedText(messageDigest.digest());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
}

View File

@ -0,0 +1,89 @@
package cn.axzo.im.center.api.vo.nim;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* im-center
*
* @author zuoqinbo
* @version V1.0
* @date 2023/10/10 18:46
*/
@Service
public class NimService {
private static final String NIM_ACCOUNT_CREATE_URL = " https://api.netease.im/nimserver/user/create.action";
private static final String NIM_MESSAGE_DISPATCH_URL = "https://api.netease.im/nimserver/msg/sendMsg.action";
private static final int SUCCESS_CODE = 200;
public static String sendMessage(Message message) {
if(message == null){
}
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("from", message.getFrom());
paramMap.put("from", message.getFrom());
paramMap.put("body", message.getBody());
paramMap.put("ope", message.getOpe());
paramMap.put("to", message.getTo());
paramMap.put("type", message.getType());
String appKey = "9e1160e993e2249dc054bfb2c9dcb422";
Map<String, String> authHeaderMap = buildAuthHeader(appKey);
HttpResponse response = HttpRequest.post(NIM_MESSAGE_DISPATCH_URL).addHeaders(authHeaderMap)
.form(paramMap).timeout(5000).execute();
if (response.getStatus() == SUCCESS_CODE) {
} else {
}
String result = response.body();
return result;
}
public static String registerAccount(Register register) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("accid", register.getAccid());
paramMap.put("icon", register.getIcon());
paramMap.put("name", register.getName());
String appKey = "9e1160e993e2249dc054bfb2c9dcb422";
Map<String, String> authHeaderMap = buildAuthHeader(appKey);
HttpResponse response = HttpRequest.post(NIM_ACCOUNT_CREATE_URL).addHeaders(authHeaderMap)
.form(paramMap).timeout(5000).execute();
if (response.getStatus() == SUCCESS_CODE) {
} else {
}
String result = response.body();
return result;
}
/**
* 构建公共的鉴权信息
* 文档地址: https://doc.yunxin.163.com/messaging/docs/jk3MzY2MTI?platform=server
*
* @return
*/
private static Map<String, String> buildAuthHeader(String appKey) {
String nonce = UUID.randomUUID().toString();
String curTime = String.valueOf(System.currentTimeMillis() / 1000);
String checkSum = CheckSumUtil.getCheckSum(appKey, nonce, curTime);
HashMap<String, String> commonAuthMap = new HashMap<>();
commonAuthMap.put("AppKey", appKey);
commonAuthMap.put("Nonce", nonce);
commonAuthMap.put("CurTime", curTime);
commonAuthMap.put("CheckSum", checkSum);
commonAuthMap.put("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
return commonAuthMap;
}
}

View File

@ -0,0 +1,38 @@
package cn.axzo.im.center.api.vo.nim;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 云信账户注册其他字段暂时不需要
* 文档地址:https://doc.yunxin.163.com/messaging/docs/DQ3Nzk1MTY?platform=server
* @author zuoqinbo
* @version V1.0
* @date 2023/10/10 18:41
*/
@Data
public class Register {
/**
* AppKey 唯一标识
*/
@NotNull
private String appKey;
/**
* 云信账号必须保证唯一性若涉及字母传参时请一律小写处理只允许字母数字半角下划线_@半角点以及半角-请注意以此接口返回结果中的accid为准
*/
@NotNull
private String accid;
/**
* 用户昵称
*/
private String name;
/**
* 用户头像 URL
*/
private String icon;
}

View File

@ -21,7 +21,7 @@ public class MessageInfo {
* 工人端企业端ALL
* WORKERENTERPRISEALL
*/
@NotNull(message = "发送者身份信息")
@NotNull(message = "消息接收端类型")
private String appType;
/**

View File

@ -16,18 +16,18 @@ import java.util.Map;
public class RobotAccountReq {
/**
* robotId
* 机器人robotId
*/
@NotNull(message = "robotId不能为空")
private String robotId;
/**
* 用户头像链接
* 机器人头像链接
*/
private String headImageUrl;
/**
* 用户账户扩展信息
* 机器人账户扩展信息
*/
private Map<String, String> attachments;
}

View File

@ -15,11 +15,6 @@ import java.util.List;
@Data
public class RobotInfoReq {
/**
* 机器人ID
*/
private Integer robotId;
/**
* 机器人昵称
*/
@ -41,8 +36,9 @@ public class RobotInfoReq {
/**
* 机器人状态
* @see cn.axzo.maokai.common.enums.RobotStatusEnum
*/
private String status;
private String status = "creating";
}

View File

@ -10,9 +10,9 @@ import javax.validation.constraints.NotNull;
/**
* 机器人标签创建请求
*
* @author zuoqinbo
* @version V1.0
* @author zuoqinbo
* @date 2023/10/9 18:07
* @date 2023/10/9 18:07
*/
@Accessors(chain = true)
@Builder
@ -23,11 +23,6 @@ import javax.validation.constraints.NotNull;
@ToString
public class RobotTagReq {
/**
* 机器人TagID
*/
private Integer tagId;
/**
* 机器人Tag名称
* 对外展示 不允许重复
@ -38,15 +33,16 @@ public class RobotTagReq {
/**
* 机器人Tag排序权重
* 新增默认1
*/
@Min(1)
private Integer weight ;
private Integer weight = 1;
/**
* 机器人Tag状态 0表示关闭1表示开启
* 新增默认开启
*/
private Integer status ;
private Integer status = 1;
/**

View File

@ -0,0 +1,49 @@
package cn.axzo.im.center.api.vo.req;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 机器人信息
*
* @author zuoqinbo
* @version V1.0
* @date 2023/10/9 16:01
*/
@Data
public class UpdateRobotInfoReq {
/**
* 机器人ID
*/
@NotNull(message = "机器人ID不能为空")
private Integer robotId;
/**
* 机器人昵称
*/
@NotNull(message = "机器人昵称不能为空")
private String nickName;
/**
* 机器人Tag列表
*/
@NotNull(message = "机器人标签不能为空")
private List<String> tagNameList;
/**
* 机器人头像链接
*/
private String headImageUrl;
/**
* 机器人状态
*/
private String status;
}

View File

@ -0,0 +1,54 @@
package cn.axzo.im.center.api.vo.req;
import lombok.*;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
/**
* 机器人标签创建请求
*
* @version V1.0
* @author zuoqinbo
* @date 2023/10/9 18:07
*/
@Accessors(chain = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class UpdateRobotTagReq {
/**
* 机器人TagID
*/
@NotNull(message = "机器人TagID不能为空")
private Integer tagId;
/**
* 机器人Tag名称
* 对外展示 不允许重复
*/
private String tagName;
/**
* 机器人Tag排序权重
* 如果是0则不进行更新
*/
private Integer weight ;
/**
* 机器人Tag状态 0表示关闭1表示开启
*/
private Integer status ;
/**
* 机器人Tag颜色
*/
private String color;
}

View File

@ -16,7 +16,16 @@ import java.util.Map;
public class UserAccountReq {
/**
* 用户userId
* 发送消息到端
* 工人端企业端ALL
* WORKERENTERPRISEALL
*/
@NotNull(message = "消息接收端类型")
private String appType;
/**
* 用户userId 唯一
*/
@NotNull(message = "userId不能为空")
private String userId;

View File

@ -0,0 +1,26 @@
package cn.axzo.im.center.api.vo.resp;
/**
* im-center
*
* @author zuoqinbo
* @version V1.0
* @date 2023/10/11 9:10
*/
@Data
public class MessageResp {
/**
* 消息ID
*/
private String msgid;
/**
* 消息发送的时间戳
*/
private long timetag;
/**
* 消息是否被反垃圾内容审核拦截如未被拦截则值为 false
*/
private boolean antispam;
}

View File

@ -0,0 +1,12 @@
package cn.axzo.im.center.api.vo.resp;
/**
* im-center
*
* @author zuoqinbo
* @version V1.0
* @date 2023/10/11 9:34
*/
public class MessageTemplateResp {
}

View File

@ -25,8 +25,9 @@ public class RobotInfoResp {
/**
* 机器人Tag列表
* 已开启的标签列表
*/
private List<String> tagNameList;
private List<RobotTagResp> robotTagList;
/**
@ -47,12 +48,12 @@ public class RobotInfoResp {
/**
* 消息模板失效数量
*/
private String msgTemplateInvalidCount;
private Integer msgTemplateInvalidCount = 5;
/**
* 消息模板数量
*/
private String msgTemplateCount;
private Integer msgTemplateCount = 10;
}

View File

@ -0,0 +1,53 @@
package cn.axzo.im.center.api.vo.resp;
import lombok.Data;
import java.util.List;
/**
* 机器人页面显示信息
*
* @version V1.0
* @author zuoqinbo
* @date 2023/10/9 16:01
*/
@Data
public class RobotMsgTemplateResp {
/**
* 机器人ID
*/
private Integer robotId;
/**
* 机器人昵称
*/
private String nickName;
/**
* 机器人Tag列表
* 已开启的标签列表
*/
private List<RobotTagResp> robotTagList;
/**
* 机器人头像链接
*/
private String headImageUrl;
/**
* 机器人IM云信账户
*/
private String imAccount;
/**
* 机器人状态
*/
private String status;
/**
* 机器人关联的消息模板
*/
private List<MessageTemplateResp> messageTemplates;
}

View File

@ -38,4 +38,10 @@ public class RobotTagResp {
* 机器人Tag颜色
*/
private String color;
/**
* 机器人使用数量
*/
private Integer robotUseCount;
}

View File

@ -1,12 +0,0 @@
package cn.axzo.im.utils;
/**
* im-center
*
* @author zuoqinbo
* @version V1.0
* @date 2023/10/10 14:33
*/
public class HttpClientUtil {
}