Merge branch 'feature-REQ/2129' into 'master'
Feature req/2129 See merge request universal/infrastructure/backend/im-center!43
This commit is contained in:
commit
ff5d29b499
@ -34,6 +34,17 @@
|
|||||||
<groupId>cn.axzo.framework</groupId>
|
<groupId>cn.axzo.framework</groupId>
|
||||||
<artifactId>axzo-common-web</artifactId>
|
<artifactId>axzo-common-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.axzo.basics</groupId>
|
||||||
|
<artifactId>basics-profiles-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.axzo.maokai</groupId>
|
||||||
|
<artifactId>maokai-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
|
|||||||
@ -0,0 +1,146 @@
|
|||||||
|
package cn.axzo.im.center.api.feign;
|
||||||
|
|
||||||
|
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiListResult;
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}")
|
||||||
|
public interface AccountRegisterApi {
|
||||||
|
|
||||||
|
@PostMapping("/api/im/account/register/page")
|
||||||
|
ApiPageResult<AccountRegisterDTO> page(@RequestBody PageAccountRegisterParam param);
|
||||||
|
|
||||||
|
@PostMapping("/api/im/account/register/list")
|
||||||
|
ApiListResult<AccountRegisterDTO> list(@RequestBody ListAccountRegisterParam param);
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class AccountRegisterDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账户 机器人robotId、普通用户userId
|
||||||
|
*/
|
||||||
|
private String accountId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通用户,通过appType和ouId包装
|
||||||
|
* 包装以后进行账户注册
|
||||||
|
*/
|
||||||
|
private String accountWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM账户
|
||||||
|
*/
|
||||||
|
private String imAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端类型
|
||||||
|
*
|
||||||
|
* @see AppTypeEnum
|
||||||
|
*/
|
||||||
|
private String appType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网易云信appKey
|
||||||
|
*/
|
||||||
|
private String appKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* channel 服务提供商
|
||||||
|
*/
|
||||||
|
private String channelProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账户类型:机器人、普通用户
|
||||||
|
*/
|
||||||
|
private String accountType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM注册 token
|
||||||
|
*/
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* organizational_unit表的id
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
private Date updateAt;
|
||||||
|
|
||||||
|
private PersonProfileDto personProfile;
|
||||||
|
|
||||||
|
private OrganizationalUnitVO organizationalUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListAccountRegisterParam {
|
||||||
|
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
private String appType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册用户ID唯一
|
||||||
|
* 普通用户personId、机器人robotId
|
||||||
|
*/
|
||||||
|
private String accountId;
|
||||||
|
|
||||||
|
private Set<String> accountIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册用户ID唯一
|
||||||
|
*/
|
||||||
|
private String imAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long organizationalUnitId;
|
||||||
|
|
||||||
|
private String accountType;
|
||||||
|
|
||||||
|
private boolean needOuInfo;
|
||||||
|
|
||||||
|
private boolean needUserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageAccountRegisterParam extends ListAccountRegisterParam {
|
||||||
|
Integer page;
|
||||||
|
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,22 @@
|
|||||||
package cn.axzo.im.center.api.feign;
|
package cn.axzo.im.center.api.feign;
|
||||||
|
|
||||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||||
|
import cn.axzo.im.center.api.vo.req.AsyncSendMessageParam;
|
||||||
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
|
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
|
||||||
import cn.axzo.im.center.api.vo.req.MessageInfo;
|
import cn.axzo.im.center.api.vo.req.MessageInfo;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendCustomMessageParam;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendMessageParam;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
||||||
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
|
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
|
||||||
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
|
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
|
||||||
import java.util.List;
|
import cn.axzo.im.center.api.vo.resp.MessageTaskResp;
|
||||||
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.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM消息管理API
|
* IM消息管理API
|
||||||
*
|
*
|
||||||
@ -22,17 +28,41 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}")
|
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}")
|
||||||
public interface MessageApi {
|
public interface MessageApi {
|
||||||
/**
|
/**
|
||||||
* 发送消息,单条消息、批量发送消息统一入口
|
* 发送消息时只是存储在messageTask中,通过xxlJob或者mq异步去处理
|
||||||
* 1.该接口一次请求,接收人支持最大2000人
|
* 因为:1、为了提高接口响应性能。2、第三方接口有限流控制,防止被限流后阻塞业务
|
||||||
* 2.网易云信一分钟支持120次调用,每次调用IM中心设置100个账户(能返回msgId最大支持100人)
|
* @param sendMessageParam 发送消息请求参数
|
||||||
* 3.IM中心接收人有工人端和管理端账户,故当接收人最大2000人时,需要调用网易云信发送4000条消息
|
* @return
|
||||||
* 4.按照每批次发送100条消息,需要发送40次。
|
*/
|
||||||
* 5.因此该接口一分钟内最大支持3次接收人为2000人的请求
|
@PostMapping("/api/im/message/async/send")
|
||||||
|
ApiResult<MessageTaskResp> sendMessageAsync(@RequestBody @Validated AsyncSendMessageParam sendMessageParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步发送消息,不建议使用,因为第三方接口有限流,会影响接口性能,只能给最多10个用户发送
|
||||||
|
* @param sendMessageParam
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("/api/im/message/send")
|
||||||
|
ApiResult<MessageTaskResp> sendMessage(@RequestBody @Validated SendMessageParam sendMessageParam);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过消息模板来发送消息
|
||||||
|
* 发送消息时只是存储在messageTask中,通过xxlJob或者mq异步去处理
|
||||||
|
* 因为:1、为了提高接口响应性能。2、第三方接口有限流控制,防止被限流后阻塞业务
|
||||||
|
* @param sendMessageParam
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@PostMapping("/api/im/template-message/async/send")
|
||||||
|
ApiResult<MessageTaskResp> sendTemplateMessageAsync(@RequestBody @Validated SendTemplateMessageParam sendMessageParam);
|
||||||
|
|
||||||
|
/**
|
||||||
*
|
*
|
||||||
|
* 接口已经作废,可以使用sendTemplateMessage来替换
|
||||||
* @param messageInfo 发送消息请求参数
|
* @param messageInfo 发送消息请求参数
|
||||||
* @return 发送消息请求响应
|
* @return 发送消息请求响应
|
||||||
*/
|
*/
|
||||||
@PostMapping("api/im/message/dispatch")
|
@PostMapping("api/im/message/dispatch")
|
||||||
|
@Deprecated
|
||||||
ApiResult<List<MessageDispatchResp>> sendMessage(@RequestBody @Validated MessageInfo messageInfo);
|
ApiResult<List<MessageDispatchResp>> sendMessage(@RequestBody @Validated MessageInfo messageInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,4 +71,5 @@ public interface MessageApi {
|
|||||||
@PostMapping("api/im/custom-message/send")
|
@PostMapping("api/im/custom-message/send")
|
||||||
ApiResult<List<MessageCustomResp>> sendCustomMessage(@RequestBody @Validated CustomMessageInfo messageInfo);
|
ApiResult<List<MessageCustomResp>> sendCustomMessage(@RequestBody @Validated CustomMessageInfo messageInfo);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,133 @@
|
|||||||
|
package cn.axzo.im.center.api.feign;
|
||||||
|
|
||||||
|
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiListResult;
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@FeignClient(name = "im-center", url = "${axzo.service.im-center:http://im-center:8080}")
|
||||||
|
public interface MessageHistoryApi {
|
||||||
|
|
||||||
|
@PostMapping("/api/im/message/history/page")
|
||||||
|
ApiPageResult<MessageHistoryDTO> page(@RequestBody PageMessageHistoryParam param);
|
||||||
|
|
||||||
|
@PostMapping("/api/im/message/history/list")
|
||||||
|
ApiListResult<MessageHistoryDTO> list(@RequestBody ListMessageHistoryParam param);
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListMessageHistoryParam {
|
||||||
|
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
private Long imMessageTaskId;
|
||||||
|
|
||||||
|
private Set<String> receivePersonIds;
|
||||||
|
|
||||||
|
private Set<String> toAccount;
|
||||||
|
|
||||||
|
private Set<String> appTypes;
|
||||||
|
|
||||||
|
private Set<String> statues;
|
||||||
|
|
||||||
|
private boolean needReceiveOuInfo;
|
||||||
|
|
||||||
|
private boolean needReceiveUserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageMessageHistoryParam extends ListMessageHistoryParam {
|
||||||
|
Integer page;
|
||||||
|
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class MessageHistoryDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上游业务请求ID
|
||||||
|
*/
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通用户,通过appType包装
|
||||||
|
* 包装以后进行账户注册
|
||||||
|
*/
|
||||||
|
private String messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送者IM账户
|
||||||
|
*/
|
||||||
|
private String fromAccount;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送者IM账户
|
||||||
|
*/
|
||||||
|
private String toAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 终端类型
|
||||||
|
*
|
||||||
|
* @see AppTypeEnum
|
||||||
|
*/
|
||||||
|
private String appType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* channel 网易云信
|
||||||
|
*/
|
||||||
|
private String channel;
|
||||||
|
|
||||||
|
|
||||||
|
private String messageBody;
|
||||||
|
|
||||||
|
private String result;
|
||||||
|
|
||||||
|
private Long imMessageTaskId;
|
||||||
|
|
||||||
|
private String receivePersonId;
|
||||||
|
|
||||||
|
private Long receiveOuId;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
private Date updateAt;
|
||||||
|
|
||||||
|
private PersonProfileDto receivePersonProfile;
|
||||||
|
|
||||||
|
private OrganizationalUnitVO receiveOrganizationalUnit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,13 @@ import cn.axzo.im.center.api.vo.req.RobotInfoReq;
|
|||||||
import cn.axzo.im.center.api.vo.req.RobotPageQuery;
|
import cn.axzo.im.center.api.vo.req.RobotPageQuery;
|
||||||
import cn.axzo.im.center.api.vo.req.UpdateRobotInfoReq;
|
import cn.axzo.im.center.api.vo.req.UpdateRobotInfoReq;
|
||||||
import cn.axzo.im.center.api.vo.resp.RobotInfoResp;
|
import cn.axzo.im.center.api.vo.resp.RobotInfoResp;
|
||||||
|
import cn.axzo.im.center.api.vo.resp.RobotTagResp;
|
||||||
|
import cn.axzo.im.center.common.enums.RobotStatusEnum;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
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.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -13,6 +20,7 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,6 +67,7 @@ public interface RobotInfoApi {
|
|||||||
* @return 机器人列表信息
|
* @return 机器人列表信息
|
||||||
*/
|
*/
|
||||||
@PostMapping("api/im/robot/basic/page")
|
@PostMapping("api/im/robot/basic/page")
|
||||||
|
@Deprecated
|
||||||
ApiPageResult<RobotInfoResp> queryRobotList(@RequestBody RobotPageQuery robotPageQuery);
|
ApiPageResult<RobotInfoResp> queryRobotList(@RequestBody RobotPageQuery robotPageQuery);
|
||||||
|
|
||||||
|
|
||||||
@ -71,5 +80,87 @@ public interface RobotInfoApi {
|
|||||||
@GetMapping("api/im/robot/enabled/list")
|
@GetMapping("api/im/robot/enabled/list")
|
||||||
ApiResult<List<RobotInfoResp>> queryRunningRobots();
|
ApiResult<List<RobotInfoResp>> queryRunningRobots();
|
||||||
|
|
||||||
|
@PostMapping("/api/im/robot-info/page")
|
||||||
|
ApiPageResult<RobotInfoDTO> page(@RequestBody PageRobotInfoParam param);
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListRobotInfoParam {
|
||||||
|
private String nickNameLike;
|
||||||
|
|
||||||
|
private RobotStatusEnum status;
|
||||||
|
|
||||||
|
private List<String> imAccounts;
|
||||||
|
|
||||||
|
private boolean needRobotTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageRobotInfoParam extends ListRobotInfoParam {
|
||||||
|
Integer pageNumber;
|
||||||
|
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class RobotInfoDTO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人ID
|
||||||
|
* 目的是用该字段进行账户注册,如果使用数据库主键,
|
||||||
|
* 那么注册就会出现账户重复问题
|
||||||
|
*/
|
||||||
|
private String robotId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人昵称
|
||||||
|
*/
|
||||||
|
private String nickName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人Tag列表
|
||||||
|
* 存放的是robotTag表的id
|
||||||
|
*/
|
||||||
|
private List<Long> tagNameList;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人头像链接
|
||||||
|
*/
|
||||||
|
private String headImageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人IM账户
|
||||||
|
*/
|
||||||
|
private String imAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器人状态
|
||||||
|
* @see cn.axzo.im.center.common.enums.RobotStatusEnum
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
private Date updateAt;
|
||||||
|
|
||||||
|
private List<RobotTagResp> robotTags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,4 +26,10 @@ public class AccountAbsentQuery {
|
|||||||
@NotNull(message = "注册用户personId不能为空")
|
@NotNull(message = "注册用户personId不能为空")
|
||||||
private String personId;
|
private String personId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据ouId获取账号
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,4 +36,10 @@ public class AccountQuery {
|
|||||||
*/
|
*/
|
||||||
private String imAccount;
|
private String imAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long organizationalUnitId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,111 @@
|
|||||||
|
package cn.axzo.im.center.api.vo.req;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AsyncSendMessageParam {
|
||||||
|
/**
|
||||||
|
* 发送者IM账号
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "sendImAccount不能为空")
|
||||||
|
private String sendImAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息接收用户信息
|
||||||
|
*/
|
||||||
|
private List<ReceivePerson> receivePersons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给全员发送
|
||||||
|
*/
|
||||||
|
private boolean allPerson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全员发送时需要指定发送消息到App端
|
||||||
|
* 工人端、企业端、服务器
|
||||||
|
* CM、CMP、SYSTEM
|
||||||
|
*
|
||||||
|
* @See cn.axzo.im.center.common.enums.AppTypeEnum
|
||||||
|
*/
|
||||||
|
private List<AppTypeEnum> appTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息标题
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息标题不能为空")
|
||||||
|
private String msgHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息内容不能为空")
|
||||||
|
private String msgContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转配置信息
|
||||||
|
*/
|
||||||
|
private List<SendMessageParam.JumpData> jumpData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封面图
|
||||||
|
*/
|
||||||
|
private String cardBannerUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息扩展信息
|
||||||
|
*/
|
||||||
|
private JSONObject ext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务的唯一ID,用于查询发送消息的记录和结果,不验证唯一
|
||||||
|
*/
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ReceivePerson {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收消息的personId
|
||||||
|
*/
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到App端
|
||||||
|
* 工人端、企业端、服务器
|
||||||
|
* CM、CMP、SYSTEM
|
||||||
|
*
|
||||||
|
* @See cn.axzo.im.center.common.enums.AppTypeEnum
|
||||||
|
*/
|
||||||
|
private AppTypeEnum appType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im账号,可以personId和imAccount二选一
|
||||||
|
*/
|
||||||
|
private String imAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 因为CMS端做消息跳转时需要这个字段做权限check
|
||||||
|
*/
|
||||||
|
private Long workspaceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,8 @@ package cn.axzo.im.center.api.vo.req;
|
|||||||
import cn.axzo.basics.common.page.PageRequest;
|
import cn.axzo.basics.common.page.PageRequest;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人信息
|
* 机器人信息
|
||||||
*
|
*
|
||||||
@ -34,5 +36,8 @@ public class RobotPageQuery extends PageRequest {
|
|||||||
*/
|
*/
|
||||||
private String imAccount;
|
private String imAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* todo 待优化替换成cn.axzo.im.center.api.feign.RobotInfoApi#page
|
||||||
|
*/
|
||||||
|
private String msgTemplateCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
package cn.axzo.im.center.api.vo.req;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.im.center.common.enums.BizTypeEnum;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author syl
|
||||||
|
* @date 2023/12/21
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SendCustomMessageParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息接收用户信息
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "消息接收用户信息不能为空")
|
||||||
|
private List<SendMessageParam.ReceivePerson> receivePersons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "业务类型不能为空")
|
||||||
|
private BizTypeEnum bizType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推送内容 - 业务数据,json格式
|
||||||
|
*/
|
||||||
|
private String payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务的唯一ID,用于查询发送消息的记录和结果
|
||||||
|
*/
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
static class ReceivePerson {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收消息的personId
|
||||||
|
*/
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到App端
|
||||||
|
* 工人端、企业端、服务器
|
||||||
|
* CM、CMP、SYSTEM
|
||||||
|
*
|
||||||
|
* @See cn.axzo.im.center.common.enums.AppTypeEnum
|
||||||
|
*/
|
||||||
|
private AppTypeEnum appType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
package cn.axzo.im.center.api.vo.req;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM消息信息
|
||||||
|
*
|
||||||
|
* @author zuoqinbo
|
||||||
|
* @version V1.0
|
||||||
|
* @date 2023/10/9 16:01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SendMessageParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送者IM账号
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "sendImAccount不能为空")
|
||||||
|
private String sendImAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息接收用户信息
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "消息接收用户信息不能为空")
|
||||||
|
@Valid
|
||||||
|
private List<ReceivePerson> receivePersons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息标题
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息标题不能为空")
|
||||||
|
private String msgHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息内容不能为空")
|
||||||
|
private String msgContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转配置信息
|
||||||
|
*/
|
||||||
|
private List<JumpData> jumpData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封面图
|
||||||
|
*/
|
||||||
|
private String cardBannerUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息扩展信息
|
||||||
|
*/
|
||||||
|
private JSONObject ext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务的唯一ID,用于查询发送消息的记录和结果,不验证唯一
|
||||||
|
*/
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class JumpData {
|
||||||
|
|
||||||
|
private JumpPlatform platform;
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum JumpPlatform {
|
||||||
|
PC(null, "WEB"),
|
||||||
|
CM_IOS(AppTypeEnum.CM, "IOS"),
|
||||||
|
CM_ANDROID(AppTypeEnum.CM, "ANDROID"),
|
||||||
|
CMP_IOS(AppTypeEnum.CMP, "IOS"),
|
||||||
|
CMP_ANDROID(AppTypeEnum.CMP, "ANDROID")
|
||||||
|
;
|
||||||
|
|
||||||
|
private AppTypeEnum appType;
|
||||||
|
private String oldPlatform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ReceivePerson {
|
||||||
|
/**
|
||||||
|
* im账号,可以personId和imAccount二选一
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "imAccount不能为空")
|
||||||
|
private String imAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package cn.axzo.im.center.api.vo.req;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SendTemplateMessageParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息接收用户信息
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "消息接收用户信息不能为空")
|
||||||
|
@Valid
|
||||||
|
private List<ReceivePerson> receivePersons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息标题
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息标题不能为空")
|
||||||
|
private String msgHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息内容不能为空")
|
||||||
|
private String msgContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板ID
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息模板ID不能为空")
|
||||||
|
private String msgTemplateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板内容
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "消息模板内容不能为空")
|
||||||
|
private String msgTemplateContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息扩展信息
|
||||||
|
*/
|
||||||
|
private JSONObject ext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务的唯一ID,用于查询发送消息的记录和结果,不验证唯一
|
||||||
|
*/
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ReceivePerson {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收消息的personId
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "personId不能为空")
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到App端
|
||||||
|
* 工人端、企业端、服务器
|
||||||
|
* CM、CMP、SYSTEM
|
||||||
|
*
|
||||||
|
* @See cn.axzo.im.center.common.enums.AppTypeEnum
|
||||||
|
*/
|
||||||
|
@NotNull(message = "appType不能为空")
|
||||||
|
private AppTypeEnum appType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,4 +51,9 @@ public class UserAccountReq {
|
|||||||
*/
|
*/
|
||||||
private Map<String, String> attachments;
|
private Map<String, String> attachments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long organizationalUnitId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,56 @@
|
|||||||
|
package cn.axzo.im.center.api.vo.resp;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MessageTaskResp {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务请求时可以带的排查问题的id
|
||||||
|
*/
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM消息发送personId
|
||||||
|
*/
|
||||||
|
private String sendPersonId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM消息接收人person信息
|
||||||
|
*/
|
||||||
|
private JSONArray receivePersons;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private JSONObject bizData;
|
||||||
|
|
||||||
|
private JSONObject ext;
|
||||||
|
|
||||||
|
private Date planStartTime;
|
||||||
|
|
||||||
|
private Date startedTime;
|
||||||
|
|
||||||
|
private Date finishedTime;
|
||||||
|
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
private Date updateAt;
|
||||||
|
}
|
||||||
@ -43,5 +43,9 @@ public class UserAccountResp {
|
|||||||
*/
|
*/
|
||||||
private String appType;
|
private String appType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,6 +98,11 @@
|
|||||||
<artifactId>axzo-common-rocketmq</artifactId>
|
<artifactId>axzo-common-rocketmq</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.axzo.maokai</groupId>
|
||||||
|
<artifactId>maokai-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
@ -107,6 +112,11 @@
|
|||||||
<groupId>cn.axzo.im.center</groupId>
|
<groupId>cn.axzo.im.center</groupId>
|
||||||
<artifactId>im-center-api</artifactId>
|
<artifactId>im-center-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.axzo.tyr</groupId>
|
||||||
|
<artifactId>tyr-api</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package cn.axzo.im;
|
package cn.axzo.im;
|
||||||
|
|
||||||
import cn.axzo.framework.data.mybatisplus.config.MybatisPlusAutoConfiguration;
|
import cn.axzo.framework.data.mybatisplus.config.MybatisPlusAutoConfiguration;
|
||||||
|
import cn.axzo.im.config.RocketMQEventConfiguration;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
@ -8,6 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|||||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -15,8 +17,10 @@ import org.springframework.core.env.Environment;
|
|||||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||||
@MapperScan(value = {"cn.axzo.im.dao.mapper"})
|
@MapperScan(value = {"cn.axzo.im.dao.mapper"})
|
||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
|
@Import(RocketMQEventConfiguration.class)
|
||||||
public class Application {
|
public class Application {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
|
ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
|
||||||
Environment env = run.getEnvironment();
|
Environment env = run.getEnvironment();
|
||||||
log.info(
|
log.info(
|
||||||
|
|||||||
@ -54,7 +54,7 @@ public class NimChannelService implements IMChannelProvider {
|
|||||||
|
|
||||||
private static final String NIM_MESSAGE_ATTACH_URL = "https://api.netease.im/nimserver/msg/sendAttachMsg.action";
|
private static final String NIM_MESSAGE_ATTACH_URL = "https://api.netease.im/nimserver/msg/sendAttachMsg.action";
|
||||||
|
|
||||||
private static final int SUCCESS_CODE = 200;
|
public static final int SUCCESS_CODE = 200;
|
||||||
|
|
||||||
private static final int NIM_ACCOUNT_ALREADY_REGISTER = 414;
|
private static final int NIM_ACCOUNT_ALREADY_REGISTER = 414;
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,12 @@ package cn.axzo.im.channel.netease.dto;
|
|||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static cn.axzo.im.channel.netease.NimChannelService.SUCCESS_CODE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量发送消息返回响应
|
* 批量发送消息返回响应
|
||||||
* 示例:
|
* 示例:
|
||||||
@ -37,4 +39,7 @@ public class MessageBatchDispatchResponse {
|
|||||||
|
|
||||||
private String desc;
|
private String desc;
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return Objects.equals(this.getCode(), SUCCESS_CODE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
package cn.axzo.im.config;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||||
|
import org.apache.ibatis.type.BaseTypeHandler;
|
||||||
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||||
|
import org.apache.ibatis.type.MappedTypes;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@MappedTypes({List.class})
|
||||||
|
@MappedJdbcTypes(JdbcType.VARCHAR)
|
||||||
|
public abstract class BaseListTypeHandler<T> extends BaseTypeHandler<List<T>> {
|
||||||
|
|
||||||
|
private Class<T> type = getGenericType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNonNullParameter(PreparedStatement preparedStatement, int i,
|
||||||
|
List<T> list, JdbcType jdbcType) throws SQLException {
|
||||||
|
preparedStatement.setString(i, JSONArray.toJSONString(list, SerializerFeature.WriteMapNullValue,
|
||||||
|
SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> getNullableResult(ResultSet resultSet, String s) throws SQLException {
|
||||||
|
return JSONArray.parseArray(resultSet.getString(s), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> getNullableResult(ResultSet resultSet, int i) throws SQLException {
|
||||||
|
return JSONArray.parseArray(resultSet.getString(i), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
|
||||||
|
return JSONArray.parseArray(callableStatement.getString(i), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<T> getGenericType() {
|
||||||
|
Type t = getClass().getGenericSuperclass();
|
||||||
|
Type[] params = ((ParameterizedType) t).getActualTypeArguments();
|
||||||
|
return (Class<T>) params[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package cn.axzo.im.config;
|
||||||
|
|
||||||
|
import cn.axzo.pokonyan.exception.ResultCode;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum BizResultCode implements ResultCode {
|
||||||
|
|
||||||
|
SEND_IM_ACCOUNT_NOT_FOUND("100", "发送者IM账号错误"),
|
||||||
|
SEND_IM_ACCOUNT_MAX("101", "同步接口只支持最多10个IM账号,请选择异步接口发送"),
|
||||||
|
SEND_PERSSON_ERROR("102", "接收人信息和全部接收人不能同时都为空"),
|
||||||
|
ALL_PERSSON_TYPE_NOT_EMPTY("103", "全员发送时,接收端不能为空"),
|
||||||
|
ACQUIRE_RATE_LIMITER_FAIL("104", "获取滑动窗口令牌失败"),
|
||||||
|
MESSAGE_TASK_STATUS_ERROR("105", "更新消息任务失败,状态异常"),
|
||||||
|
MESSAGE_TASK_NOT_FOUND("106", "消息任务不存在"),;
|
||||||
|
|
||||||
|
|
||||||
|
private String errorCode;
|
||||||
|
private String errorMessage;
|
||||||
|
}
|
||||||
@ -1,5 +1,9 @@
|
|||||||
package cn.axzo.im.config;
|
package cn.axzo.im.config;
|
||||||
|
|
||||||
|
import cn.axzo.pokonyan.client.RateLimiterClient;
|
||||||
|
import cn.axzo.pokonyan.client.impl.RateLimiterClientImpl;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -9,7 +13,7 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static cn.axzo.im.config.GlobalConfig.FeignClientConstant.*;
|
import static cn.axzo.im.config.GlobalConfig.FeignClientConstant.MSG_CENTER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局配置
|
* 全局配置
|
||||||
@ -45,4 +49,10 @@ public class GlobalConfig {
|
|||||||
executor.prestartCoreThread();
|
executor.prestartCoreThread();
|
||||||
return executor;
|
return executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RateLimiterClient rateLimiterClient(RedissonClient redissonClient) {
|
||||||
|
return RateLimiterClientImpl.builder().redissonClient(redissonClient).build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
package cn.axzo.im.config;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventProducer;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author yanglin
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RefreshScope
|
||||||
|
public class MqProducer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventProducer<?> eventProducer;
|
||||||
|
|
||||||
|
@Value("${sendMq}")
|
||||||
|
private Boolean sendMq;
|
||||||
|
|
||||||
|
public void send(Event event){
|
||||||
|
log.info(JSON.toJSONString(event));
|
||||||
|
if(sendMq != null && !sendMq){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//生产消息
|
||||||
|
eventProducer.send(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendBatch(List<Event> events){
|
||||||
|
events.forEach(this::send);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
package cn.axzo.im.config;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.BaseListener;
|
||||||
|
import cn.axzo.framework.rocketmq.DefaultEventConsumer;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.framework.rocketmq.EventHandlerRepository;
|
||||||
|
import cn.axzo.framework.rocketmq.EventProducer;
|
||||||
|
import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: liyong.tian
|
||||||
|
* @Date: 2023/7/25 14:43
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RocketMQEventConfiguration {
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
@Value("${topic}")
|
||||||
|
private String topic;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RocketMQTemplate ser(){
|
||||||
|
return new RocketMQTemplate();
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
EventProducer eventProducer(RocketMQTemplate rocketMQTemplate) {
|
||||||
|
return new RocketMQEventProducer(rocketMQTemplate,
|
||||||
|
"im-center",
|
||||||
|
appName,
|
||||||
|
EventProducer.Context.<RocketMQEventProducer.RocketMQMessageMeta>builder()
|
||||||
|
.meta(RocketMQEventProducer.RocketMQMessageMeta.builder()
|
||||||
|
.topic(topic)
|
||||||
|
.build())
|
||||||
|
.build(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) {
|
||||||
|
Consumer<EventConsumer.EventWrapper> callback = (eventWrapper) -> {
|
||||||
|
if (eventWrapper.isHandled()) {
|
||||||
|
// 只收集被App真正消费的消息.
|
||||||
|
//String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new DefaultEventConsumer(appName, eventHandlerRepository, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RocketMQMessageListener(topic = "topic_im_center_${spring.profiles.active}",
|
||||||
|
consumerGroup = "GID_topic_im_center_${spring.application.name}_${spring.profiles.active}",
|
||||||
|
consumeMode = ConsumeMode.ORDERLY,
|
||||||
|
nameServer = "${rocketmq.name-server}"
|
||||||
|
)
|
||||||
|
public static class DefaultListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventConsumer eventConsumer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(MessageExt message) {
|
||||||
|
super.onEvent(message, eventConsumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
EventHandlerRepository eventHandlerRepository() {
|
||||||
|
return new EventHandlerRepository((ex, logText) -> {
|
||||||
|
log.warn("MQ, handle warning {}", logText, ex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
package cn.axzo.im.controller;
|
||||||
|
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiListResult;
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||||
|
import cn.axzo.im.center.api.feign.AccountRegisterApi;
|
||||||
|
import cn.axzo.im.service.AccountRegisterService;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AccountRegisterController implements AccountRegisterApi {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountRegisterService accountRegisterService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiPageResult<AccountRegisterDTO> page(PageAccountRegisterParam param) {
|
||||||
|
AccountRegisterService.PageAccountRegisterParam pageAccountRegisterParam = AccountRegisterService.PageAccountRegisterParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, pageAccountRegisterParam);
|
||||||
|
|
||||||
|
Page<AccountRegisterService.AccountRegisterDTO> page = accountRegisterService.page(pageAccountRegisterParam);
|
||||||
|
|
||||||
|
return ApiPageResult.ok(page.convert(record -> {
|
||||||
|
AccountRegisterDTO accountRegisterDTO = AccountRegisterDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(record, accountRegisterDTO);
|
||||||
|
return accountRegisterDTO;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiListResult<AccountRegisterDTO> list(ListAccountRegisterParam param) {
|
||||||
|
AccountRegisterService.ListAccountRegisterParam listAccountRegisterParam = AccountRegisterService.ListAccountRegisterParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, listAccountRegisterParam);
|
||||||
|
|
||||||
|
List<AccountRegisterService.AccountRegisterDTO> list = accountRegisterService.list(listAccountRegisterParam);
|
||||||
|
return ApiListResult.ok(list.stream()
|
||||||
|
.map(e -> {
|
||||||
|
AccountRegisterDTO accountRegisterDTO = AccountRegisterDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(e, accountRegisterDTO);
|
||||||
|
return accountRegisterDTO;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,22 +1,52 @@
|
|||||||
package cn.axzo.im.controller;
|
package cn.axzo.im.controller;
|
||||||
|
|
||||||
|
import cn.axzo.basics.common.exception.ServiceException;
|
||||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||||
import cn.axzo.im.center.api.feign.MessageApi;
|
import cn.axzo.im.center.api.feign.MessageApi;
|
||||||
|
import cn.axzo.im.center.api.vo.req.AccountQuery;
|
||||||
|
import cn.axzo.im.center.api.vo.req.AsyncSendMessageParam;
|
||||||
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
|
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
|
||||||
import cn.axzo.im.center.api.vo.req.MessageInfo;
|
import cn.axzo.im.center.api.vo.req.MessageInfo;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendMessageParam;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam;
|
||||||
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
|
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
|
||||||
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
|
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
|
||||||
|
import cn.axzo.im.center.api.vo.resp.MessageTaskResp;
|
||||||
|
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import cn.axzo.im.entity.MessageTask;
|
||||||
|
import cn.axzo.im.service.AccountRegisterService;
|
||||||
|
import cn.axzo.im.service.AccountService;
|
||||||
|
import cn.axzo.im.service.MessageHistoryService;
|
||||||
import cn.axzo.im.service.MessageService;
|
import cn.axzo.im.service.MessageService;
|
||||||
|
import cn.axzo.im.service.MessageTaskService;
|
||||||
|
import cn.axzo.im.service.RobotMsgTemplateService;
|
||||||
|
import cn.axzo.pokonyan.exception.Aassert;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
|
||||||
import java.util.List;
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.axzo.im.config.BizResultCode.ALL_PERSSON_TYPE_NOT_EMPTY;
|
||||||
|
import static cn.axzo.im.config.BizResultCode.SEND_IM_ACCOUNT_MAX;
|
||||||
|
import static cn.axzo.im.config.BizResultCode.SEND_IM_ACCOUNT_NOT_FOUND;
|
||||||
|
import static cn.axzo.im.config.BizResultCode.SEND_PERSSON_ERROR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM消息派发相关
|
* IM消息派发相关
|
||||||
*
|
*
|
||||||
@ -29,13 +59,25 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MessageController implements MessageApi {
|
public class MessageController implements MessageApi {
|
||||||
|
|
||||||
@Resource
|
|
||||||
|
@Autowired
|
||||||
|
private MessageTaskService messageTaskService;
|
||||||
|
@Autowired
|
||||||
|
private AccountService accountService;
|
||||||
|
@Autowired
|
||||||
|
private RobotMsgTemplateService robotMsgTemplateService;
|
||||||
|
@Autowired
|
||||||
private MessageService messageService;
|
private MessageService messageService;
|
||||||
|
@Autowired
|
||||||
|
private AccountRegisterService accountRegisterService;
|
||||||
|
@Autowired
|
||||||
|
private MessageHistoryService messageHistoryService;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResult<List<MessageDispatchResp>> sendMessage(MessageInfo messageInfo) {
|
public ApiResult<List<MessageDispatchResp>> sendMessage(MessageInfo messageInfo) {
|
||||||
List<MessageDispatchResp> messageRespList = messageService.sendMessage(messageInfo);
|
// List<MessageDispatchResp> messageRespList = messageService.sendMessage(messageInfo);
|
||||||
return ApiResult.ok(messageRespList);
|
return ApiResult.ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,4 +91,169 @@ public class MessageController implements MessageApi {
|
|||||||
public ApiResult<String> handleRequestNotPermitted() {
|
public ApiResult<String> handleRequestNotPermitted() {
|
||||||
return ApiResult.err("服务器资源繁忙,请求被拒绝!");
|
return ApiResult.err("服务器资源繁忙,请求被拒绝!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息时只是存储在messageTask中,通过xxlJob或者mq异步去处理
|
||||||
|
* 因为:1、为了提高接口响应性能。2、第三方接口有限流控制,防止被限流后阻塞业务
|
||||||
|
* @param sendMessageParam 发送消息请求参数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ApiResult<MessageTaskResp> sendMessageAsync(AsyncSendMessageParam sendMessageParam) {
|
||||||
|
check(sendMessageParam);
|
||||||
|
MessageTask messageTask = messageTaskService.create(toMessageTask(sendMessageParam));
|
||||||
|
return ApiResult.ok(toMessageTaskResp(messageTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiResult<MessageTaskResp> sendMessage(SendMessageParam sendMessageParam) {
|
||||||
|
check(sendMessageParam);
|
||||||
|
MessageTask messageTask = messageTaskService.create(toMessageTask(sendMessageParam));
|
||||||
|
|
||||||
|
messageTaskService.createMessageHistory(messageTask);
|
||||||
|
List<MessageHistoryService.MessageHistoryDTO> messageHistories = messageHistoryService.list(MessageHistoryService.ListMessageHistoryParam.builder()
|
||||||
|
.imMessageTaskId(messageTask.getId())
|
||||||
|
.statues(Sets.newHashSet(MessageHistory.Status.PENDING.name()))
|
||||||
|
.build());
|
||||||
|
if (!CollectionUtils.isEmpty(messageHistories)) {
|
||||||
|
messageHistoryService.sendMessage(messageHistories);
|
||||||
|
}
|
||||||
|
return ApiResult.ok(toMessageTaskResp(messageTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiResult<MessageTaskResp> sendTemplateMessageAsync(SendTemplateMessageParam sendMessageParam) {
|
||||||
|
String sendImAccount = check(sendMessageParam);
|
||||||
|
MessageTask messageTask = messageTaskService.create(toMessageTask(sendMessageParam, sendImAccount));
|
||||||
|
return ApiResult.ok(toMessageTaskResp(messageTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(SendMessageParam sendMessageParam) {
|
||||||
|
List<AccountRegisterService.AccountRegisterDTO> accountRegisters = accountRegisterService.list(AccountRegisterService.ListAccountRegisterParam.builder()
|
||||||
|
.imAccount(sendMessageParam.getSendImAccount())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
Aassert.checkNotEmpty(accountRegisters, SEND_IM_ACCOUNT_NOT_FOUND);
|
||||||
|
|
||||||
|
Aassert.check(sendMessageParam.getReceivePersons().size() <= 10, SEND_IM_ACCOUNT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(AsyncSendMessageParam sendMessageParam) {
|
||||||
|
List<AccountRegisterService.AccountRegisterDTO> accountRegisters = accountRegisterService.list(AccountRegisterService.ListAccountRegisterParam.builder()
|
||||||
|
.imAccount(sendMessageParam.getSendImAccount())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
Aassert.checkNotEmpty(accountRegisters, SEND_IM_ACCOUNT_NOT_FOUND);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(sendMessageParam.getReceivePersons())
|
||||||
|
&& BooleanUtils.isNotTrue(sendMessageParam.isAllPerson())) {
|
||||||
|
throw SEND_PERSSON_ERROR.toException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BooleanUtils.isTrue(sendMessageParam.isAllPerson())) {
|
||||||
|
Aassert.checkNotEmpty(sendMessageParam.getAppTypes(), ALL_PERSSON_TYPE_NOT_EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String check(SendTemplateMessageParam sendMessageParam) {
|
||||||
|
List<String> robotIdList = robotMsgTemplateService.queryRobotIdByTemplate(sendMessageParam.getMsgTemplateId());
|
||||||
|
if (CollectionUtils.isEmpty(robotIdList)) {
|
||||||
|
throw new ServiceException("消息模板ID[" + sendMessageParam.getMsgTemplateId() + "],还未维护机器人账户!");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.size(robotIdList) > 1) {
|
||||||
|
throw new ServiceException("消息模板ID[" + sendMessageParam.getMsgTemplateId() + "],关联了多个机器人!");
|
||||||
|
}
|
||||||
|
AccountQuery accountQuery = new AccountQuery();
|
||||||
|
String robotId = robotIdList.get(0);
|
||||||
|
accountQuery.setAccountId(robotId);
|
||||||
|
accountQuery.setAppType(AppTypeEnum.SYSTEM.getCode());
|
||||||
|
List<UserAccountResp> robotImAccountList = accountService.queryAccountInfo(accountQuery);
|
||||||
|
if (CollectionUtils.isEmpty(robotImAccountList)) {
|
||||||
|
throw new ServiceException("消息模板ID[" + sendMessageParam.getMsgTemplateId() + "],机器人ID[" + robotId + "]," +
|
||||||
|
"未查询到机器人IM账户注册信息!");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(robotImAccountList) && robotImAccountList.size() > 1) {
|
||||||
|
throw new ServiceException("消息模板ID[" + sendMessageParam.getMsgTemplateId() + "],机器人ID[" + robotId + "],存在多个机器人IM账户!");
|
||||||
|
}
|
||||||
|
String robotImAccount = robotImAccountList.get(0).getImAccount();
|
||||||
|
if (StringUtils.isBlank(robotImAccount)) {
|
||||||
|
throw new ServiceException("消息模板ID[" + sendMessageParam.getMsgTemplateId() + "],机器人ID[" + robotId + "],还未生成IM账户!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return robotImAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageTaskResp toMessageTaskResp(MessageTask messageTask) {
|
||||||
|
MessageTaskResp messageTaskResp = MessageTaskResp.builder().build();
|
||||||
|
BeanUtils.copyProperties(messageTask, messageTaskResp);
|
||||||
|
return messageTaskResp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageTask toMessageTask(AsyncSendMessageParam sendMessageParam) {
|
||||||
|
|
||||||
|
MessageTask.BizData bizData = MessageTask.BizData.builder()
|
||||||
|
.jumpData(sendMessageParam.getJumpData())
|
||||||
|
// 全员发送是不常用的场景,不应该由业务处理,所以把配置放在bizData里面
|
||||||
|
.allPerson(sendMessageParam.isAllPerson())
|
||||||
|
.appTypes(sendMessageParam.getAppTypes())
|
||||||
|
.build();
|
||||||
|
Date now = new Date();
|
||||||
|
return MessageTask.builder()
|
||||||
|
.bizId(sendMessageParam.getBizId())
|
||||||
|
.sendImAccount(sendMessageParam.getSendImAccount())
|
||||||
|
.receivePersons(JSONArray.parseArray(JSONObject.toJSONString(sendMessageParam.getReceivePersons()), MessageTask.ReceivePerson.class))
|
||||||
|
.status(MessageTask.Status.PENDING)
|
||||||
|
.title(sendMessageParam.getMsgHeader())
|
||||||
|
.content(sendMessageParam.getMsgContent())
|
||||||
|
.bizData(bizData)
|
||||||
|
.ext(sendMessageParam.getExt())
|
||||||
|
.planStartTime(now)
|
||||||
|
.createAt(now)
|
||||||
|
.cardBannerUrl(sendMessageParam.getCardBannerUrl())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageTask toMessageTask(SendMessageParam sendMessageParam) {
|
||||||
|
|
||||||
|
MessageTask.BizData bizData = MessageTask.BizData.builder()
|
||||||
|
.jumpData(sendMessageParam.getJumpData())
|
||||||
|
.build();
|
||||||
|
Date now = new Date();
|
||||||
|
return MessageTask.builder()
|
||||||
|
.bizId(sendMessageParam.getBizId())
|
||||||
|
.sendImAccount(sendMessageParam.getSendImAccount())
|
||||||
|
.receivePersons(JSONArray.parseArray(JSONObject.toJSONString(sendMessageParam.getReceivePersons()), MessageTask.ReceivePerson.class))
|
||||||
|
.status(MessageTask.Status.PENDING)
|
||||||
|
.title(sendMessageParam.getMsgHeader())
|
||||||
|
.content(sendMessageParam.getMsgContent())
|
||||||
|
.bizData(bizData)
|
||||||
|
.ext(sendMessageParam.getExt())
|
||||||
|
.planStartTime(now)
|
||||||
|
.createAt(now)
|
||||||
|
.cardBannerUrl(sendMessageParam.getCardBannerUrl())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageTask toMessageTask(SendTemplateMessageParam sendMessageParam,
|
||||||
|
String sendImAccount) {
|
||||||
|
|
||||||
|
MessageTask.BizData bizData = MessageTask.BizData.builder()
|
||||||
|
.msgTemplateContent(sendMessageParam.getMsgTemplateContent())
|
||||||
|
.msgTemplateId(sendMessageParam.getMsgTemplateId())
|
||||||
|
.build();
|
||||||
|
Date now = new Date();
|
||||||
|
return MessageTask.builder()
|
||||||
|
.bizId(sendMessageParam.getBizId())
|
||||||
|
.sendImAccount(sendImAccount)
|
||||||
|
.receivePersons(JSONArray.parseArray(JSONObject.toJSONString(sendMessageParam.getReceivePersons()), MessageTask.ReceivePerson.class))
|
||||||
|
.status(MessageTask.Status.PENDING)
|
||||||
|
.title(sendMessageParam.getMsgHeader())
|
||||||
|
.content(sendMessageParam.getMsgContent())
|
||||||
|
.bizData(bizData)
|
||||||
|
.ext(sendMessageParam.getExt())
|
||||||
|
.planStartTime(now)
|
||||||
|
.createAt(now)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,55 @@
|
|||||||
|
package cn.axzo.im.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiListResult;
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||||
|
import cn.axzo.im.center.api.feign.MessageHistoryApi;
|
||||||
|
import cn.axzo.im.service.MessageHistoryService;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MessageHistoryController implements MessageHistoryApi {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageHistoryService messageHistoryService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiPageResult<MessageHistoryDTO> page(PageMessageHistoryParam param) {
|
||||||
|
MessageHistoryService.PageMessageHistoryParam pageMessageHistoryParam = MessageHistoryService.PageMessageHistoryParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, pageMessageHistoryParam);
|
||||||
|
|
||||||
|
Page<MessageHistoryService.MessageHistoryDTO> page = messageHistoryService.page(pageMessageHistoryParam);
|
||||||
|
|
||||||
|
return ApiPageResult.ok(page.convert(record -> {
|
||||||
|
MessageHistoryDTO messageHistoryDTO = MessageHistoryDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(record, messageHistoryDTO);
|
||||||
|
messageHistoryDTO.setStatus(record.getStatus().name());
|
||||||
|
return messageHistoryDTO;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiListResult<MessageHistoryDTO> list(ListMessageHistoryParam param) {
|
||||||
|
MessageHistoryService.ListMessageHistoryParam listMessageHistoryParam = MessageHistoryService.ListMessageHistoryParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, listMessageHistoryParam);
|
||||||
|
|
||||||
|
List<MessageHistoryService.MessageHistoryDTO> list = messageHistoryService.list(listMessageHistoryParam);
|
||||||
|
return ApiListResult.ok(list.stream()
|
||||||
|
.map(e -> {
|
||||||
|
MessageHistoryDTO messageHistoryDTO = MessageHistoryDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(e, messageHistoryDTO);
|
||||||
|
return messageHistoryDTO;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,16 @@
|
|||||||
package cn.axzo.im.controller;
|
package cn.axzo.im.controller;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendMessageParam;
|
||||||
import cn.axzo.im.channel.netease.client.NimClient;
|
import cn.axzo.im.channel.netease.client.NimClient;
|
||||||
import cn.axzo.im.channel.netease.dto.QueryEventRequest;
|
import cn.axzo.im.channel.netease.dto.QueryEventRequest;
|
||||||
import cn.axzo.im.channel.netease.dto.QueryMessageRequest;
|
import cn.axzo.im.channel.netease.dto.QueryMessageRequest;
|
||||||
import cn.axzo.im.channel.netease.dto.RevokeMessageRequest;
|
import cn.axzo.im.channel.netease.dto.RevokeMessageRequest;
|
||||||
|
import cn.axzo.im.job.CreateMessageHistoryJob;
|
||||||
import cn.axzo.im.job.RevokeAllMessagesJob;
|
import cn.axzo.im.job.RevokeAllMessagesJob;
|
||||||
|
import cn.axzo.im.job.SendMessageJob;
|
||||||
|
import cn.axzo.im.job.UpdateImAccountOuIdJob;
|
||||||
|
import cn.axzo.im.service.AccountRegisterService;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@ -22,6 +28,11 @@ public class PrivateController {
|
|||||||
|
|
||||||
private final NimClient nimClient;
|
private final NimClient nimClient;
|
||||||
private final RevokeAllMessagesJob revokeAllMessagesJob;
|
private final RevokeAllMessagesJob revokeAllMessagesJob;
|
||||||
|
private final UpdateImAccountOuIdJob updateImAccountOuIdJob;
|
||||||
|
private final AccountRegisterService accountRegisterService;
|
||||||
|
private final SendMessageJob sendMessageJob;
|
||||||
|
private final CreateMessageHistoryJob createMessageHistoryJob;
|
||||||
|
private final MessageController messageController;
|
||||||
|
|
||||||
@PostMapping("/private/revoke")
|
@PostMapping("/private/revoke")
|
||||||
public Object revoke(@Valid @RequestBody RevokeMessageRequest request) {
|
public Object revoke(@Valid @RequestBody RevokeMessageRequest request) {
|
||||||
@ -43,4 +54,28 @@ public class PrivateController {
|
|||||||
return revokeAllMessagesJob.execute(param);
|
return revokeAllMessagesJob.execute(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/private/im-account/ou-id/update")
|
||||||
|
public Object updateImAccountOuId(@RequestBody UpdateImAccountOuIdJob.UpdateImAccountOuIdParam param) throws Exception {
|
||||||
|
return updateImAccountOuIdJob.execute(JSONObject.toJSONString(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/private/account-register/page")
|
||||||
|
public Object pageAccountRegister(@RequestBody AccountRegisterService.PageAccountRegisterParam param) throws Exception {
|
||||||
|
return accountRegisterService.page(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/private/message/history/job/do")
|
||||||
|
public Object doMessageHistory(@RequestBody CreateMessageHistoryJob.CreateMessageHistoryParam param) throws Exception {
|
||||||
|
return createMessageHistoryJob.execute(JSONObject.toJSONString(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/private/message/job/do")
|
||||||
|
public Object doMessageJob(@RequestBody SendMessageJob.SendMessageParam param) throws Exception {
|
||||||
|
return sendMessageJob.execute(JSONObject.toJSONString(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/private/message/send")
|
||||||
|
public Object sendMessage(@RequestBody SendMessageParam param) throws Exception {
|
||||||
|
return messageController.sendMessage(param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -10,8 +10,13 @@ import cn.axzo.im.center.api.vo.req.UpdateRobotInfoReq;
|
|||||||
import cn.axzo.im.center.api.vo.resp.RobotInfoResp;
|
import cn.axzo.im.center.api.vo.resp.RobotInfoResp;
|
||||||
import cn.axzo.im.channel.netease.INotifyService;
|
import cn.axzo.im.channel.netease.INotifyService;
|
||||||
import cn.axzo.im.service.RobotInfoService;
|
import cn.axzo.im.service.RobotInfoService;
|
||||||
|
import cn.axzo.im.service.RobotInfoV2Service;
|
||||||
|
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@ -35,6 +40,9 @@ public class RobotInfoController implements RobotInfoApi {
|
|||||||
@Resource
|
@Resource
|
||||||
private INotifyService iNotifyService;
|
private INotifyService iNotifyService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RobotInfoV2Service robotInfoV2Service;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResult<RobotInfoResp> saveRobotInfo(RobotInfoReq robotInfoReq) {
|
public ApiResult<RobotInfoResp> saveRobotInfo(RobotInfoReq robotInfoReq) {
|
||||||
RobotInfoResp robotTagResp = infoService.saveRobotInfo(robotInfoReq);
|
RobotInfoResp robotTagResp = infoService.saveRobotInfo(robotInfoReq);
|
||||||
@ -54,6 +62,7 @@ public class RobotInfoController implements RobotInfoApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public ApiPageResult<RobotInfoResp> queryRobotList(RobotPageQuery robotQuery) {
|
public ApiPageResult<RobotInfoResp> queryRobotList(RobotPageQuery robotQuery) {
|
||||||
PageResp<RobotInfoResp> robotTagRespPage = infoService.queryRobotInfoList(robotQuery);
|
PageResp<RobotInfoResp> robotTagRespPage = infoService.queryRobotInfoList(robotQuery);
|
||||||
return ApiPageResult.ok(robotTagRespPage);
|
return ApiPageResult.ok(robotTagRespPage);
|
||||||
@ -64,4 +73,18 @@ public class RobotInfoController implements RobotInfoApi {
|
|||||||
List<RobotInfoResp> robotTagResp = infoService.queryRunningRobotList();
|
List<RobotInfoResp> robotTagResp = infoService.queryRunningRobotList();
|
||||||
return ApiResult.ok(robotTagResp);
|
return ApiResult.ok(robotTagResp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiPageResult<RobotInfoDTO> page(PageRobotInfoParam param) {
|
||||||
|
RobotInfoV2Service.PageRobotInfoParam pageRobotInfoParam = RobotInfoV2Service.PageRobotInfoParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, pageRobotInfoParam);
|
||||||
|
Page<RobotInfoV2Service.RobotInfoDTO> page = robotInfoV2Service.page(pageRobotInfoParam);
|
||||||
|
|
||||||
|
Page<RobotInfoDTO> result = PageConverter.convert(page, (record) -> {
|
||||||
|
RobotInfoDTO robotInfoDTO = RobotInfoDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(record, robotInfoDTO);
|
||||||
|
return robotInfoDTO;
|
||||||
|
});
|
||||||
|
return ApiPageResult.ok(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package cn.axzo.im.dao.mapper;
|
|||||||
import cn.axzo.im.entity.AccountRegister;
|
import cn.axzo.im.entity.AccountRegister;
|
||||||
import cn.axzo.im.entity.RobotInfo;
|
import cn.axzo.im.entity.RobotInfo;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,6 +13,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
* @version V1.0
|
* @version V1.0
|
||||||
* @date 2023/10/10 10:06
|
* @date 2023/10/10 10:06
|
||||||
*/
|
*/
|
||||||
|
@Repository
|
||||||
public interface AccountRegisterMapper extends BaseMapper<AccountRegister> {
|
public interface AccountRegisterMapper extends BaseMapper<AccountRegister> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
package cn.axzo.im.dao.mapper;
|
||||||
|
|
||||||
|
import cn.axzo.im.entity.MessageTask;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface MessageTaskMapper extends BaseMapper<MessageTask> {
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ package cn.axzo.im.dao.mapper;
|
|||||||
|
|
||||||
import cn.axzo.im.entity.RobotInfo;
|
import cn.axzo.im.entity.RobotInfo;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RobotInfoMapper
|
* RobotInfoMapper
|
||||||
@ -10,6 +11,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
* @version V1.0
|
* @version V1.0
|
||||||
* @date 2023/10/10 10:06
|
* @date 2023/10/10 10:06
|
||||||
*/
|
*/
|
||||||
|
@Repository
|
||||||
public interface RobotInfoMapper extends BaseMapper<RobotInfo> {
|
public interface RobotInfoMapper extends BaseMapper<RobotInfo> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,8 @@ public class RobotInfoDao extends ServiceImpl<RobotInfoMapper, RobotInfo> {
|
|||||||
* @param robotInfoQuery 机器人标签分页查询条件
|
* @param robotInfoQuery 机器人标签分页查询条件
|
||||||
* @return 机器人分页查询结果
|
* @return 机器人分页查询结果
|
||||||
*/
|
*/
|
||||||
public IPage<RobotInfo> queryRobotInfoOfPage(RobotPageQuery robotInfoQuery) {
|
public IPage<RobotInfo> queryRobotInfoOfPage(RobotPageQuery robotInfoQuery,
|
||||||
|
List<String> robotIds) {
|
||||||
return lambdaQuery().eq(RobotInfo::getIsDelete, 0)
|
return lambdaQuery().eq(RobotInfo::getIsDelete, 0)
|
||||||
.like(StringUtils.isNoneBlank(robotInfoQuery.getNickName()),
|
.like(StringUtils.isNoneBlank(robotInfoQuery.getNickName()),
|
||||||
RobotInfo::getNickName,
|
RobotInfo::getNickName,
|
||||||
@ -37,6 +38,7 @@ public class RobotInfoDao extends ServiceImpl<RobotInfoMapper, RobotInfo> {
|
|||||||
RobotInfo::getStatus, robotInfoQuery.getStatus())
|
RobotInfo::getStatus, robotInfoQuery.getStatus())
|
||||||
.eq(StringUtils.isNoneBlank(robotInfoQuery.getImAccount()),
|
.eq(StringUtils.isNoneBlank(robotInfoQuery.getImAccount()),
|
||||||
RobotInfo::getImAccount, robotInfoQuery.getImAccount())
|
RobotInfo::getImAccount, robotInfoQuery.getImAccount())
|
||||||
|
.in(!CollectionUtils.isEmpty(robotIds), RobotInfo::getRobotId, robotIds)
|
||||||
.orderByDesc(RobotInfo::getUpdateAt)
|
.orderByDesc(RobotInfo::getUpdateAt)
|
||||||
.page(robotInfoQuery.toPage());
|
.page(robotInfoQuery.toPage());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
package cn.axzo.im.entity;
|
package cn.axzo.im.entity;
|
||||||
|
|
||||||
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
|
||||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM账户表
|
* IM账户表
|
||||||
@ -19,12 +23,17 @@ import java.io.Serializable;
|
|||||||
*/
|
*/
|
||||||
@TableName("im_account_register")
|
@TableName("im_account_register")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@SuperBuilder
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class AccountRegister extends BaseEntity<AccountRegister> implements Serializable {
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AccountRegister implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账户 机器人robotId、普通用户userId
|
* 账户 机器人robotId、普通用户userId
|
||||||
*/
|
*/
|
||||||
@ -32,7 +41,7 @@ public class AccountRegister extends BaseEntity<AccountRegister> implements Ser
|
|||||||
private String accountId;
|
private String accountId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 普通用户,通过appType包装
|
* 普通用户,通过appType和ouId包装
|
||||||
* 包装以后进行账户注册
|
* 包装以后进行账户注册
|
||||||
*/
|
*/
|
||||||
@TableField("account_wrapper")
|
@TableField("account_wrapper")
|
||||||
@ -76,4 +85,19 @@ public class AccountRegister extends BaseEntity<AccountRegister> implements Ser
|
|||||||
*/
|
*/
|
||||||
@TableField("token")
|
@TableField("token")
|
||||||
private String token;
|
private String token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* organizational_unit表的id
|
||||||
|
*/
|
||||||
|
@TableField("ou_id")
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date updateAt;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,19 @@ package cn.axzo.im.entity;
|
|||||||
|
|
||||||
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
||||||
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM消息模历史表
|
* IM消息模历史表
|
||||||
@ -19,12 +25,17 @@ import java.io.Serializable;
|
|||||||
*/
|
*/
|
||||||
@TableName("im_message_history")
|
@TableName("im_message_history")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@SuperBuilder
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class MessageHistory extends BaseEntity<MessageHistory> implements Serializable {
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MessageHistory implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上游业务请求ID
|
* 上游业务请求ID
|
||||||
*/
|
*/
|
||||||
@ -70,4 +81,33 @@ public class MessageHistory extends BaseEntity<MessageHistory> implements Seria
|
|||||||
@TableField("message_body")
|
@TableField("message_body")
|
||||||
private String messageBody;
|
private String messageBody;
|
||||||
|
|
||||||
|
@TableField("result")
|
||||||
|
private String result;
|
||||||
|
|
||||||
|
@TableField("im_message_task_id")
|
||||||
|
private Long imMessageTaskId;
|
||||||
|
|
||||||
|
@TableField("receive_person_id")
|
||||||
|
private String receivePersonId;
|
||||||
|
|
||||||
|
@TableField("receive_ou_id")
|
||||||
|
private Long receiveOuId;
|
||||||
|
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date updateAt;
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
PENDING,
|
||||||
|
SUCCEED,
|
||||||
|
FAILED,
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,223 @@
|
|||||||
|
package cn.axzo.im.entity;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendMessageParam;
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.im.center.common.enums.BizTypeEnum;
|
||||||
|
import cn.axzo.im.config.BaseListTypeHandler;
|
||||||
|
import cn.axzo.maokai.api.client.OrganizationalTeamOuRelationApi;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalTeamOuRelationResp;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||||
|
import com.google.common.collect.HashBasedTable;
|
||||||
|
import com.google.common.collect.Table;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.cglib.beans.BeanMap;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static cn.axzo.im.config.BizResultCode.MESSAGE_TASK_STATUS_ERROR;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@TableName(value = "`im_message_task`", autoResultMap = true)
|
||||||
|
public class MessageTask {
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务请求时可以带的排查问题的id
|
||||||
|
*/
|
||||||
|
@TableField(value = "biz_id")
|
||||||
|
private String bizId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM消息发送者IM的账号
|
||||||
|
*/
|
||||||
|
@TableField(value = "send_im_account")
|
||||||
|
private String sendImAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM消息接收人person信息
|
||||||
|
*/
|
||||||
|
@TableField(typeHandler = ListReceivePersonTypeHandler.class)
|
||||||
|
private List<ReceivePerson> receivePersons;
|
||||||
|
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
@TableField(value = "title")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@TableField(value = "content")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@TableField(value = "card_banner_url")
|
||||||
|
private String cardBannerUrl;
|
||||||
|
|
||||||
|
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||||
|
private BizData bizData;
|
||||||
|
|
||||||
|
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||||
|
private JSONObject ext;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date planStartTime;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date startedTime;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date finishedTime;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date updateAt;
|
||||||
|
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
PENDING,
|
||||||
|
SUCCEED,
|
||||||
|
FAILED,
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject mergeBizData(BizData param) {
|
||||||
|
JSONObject bizData = JSONObject.parseObject(JSONObject.toJSONString(Optional.ofNullable(this.getBizData())
|
||||||
|
.orElseGet(BizData::new)));
|
||||||
|
if (param == null) {
|
||||||
|
return bizData;
|
||||||
|
}
|
||||||
|
return bizData.fluentPutAll(BeanMap.create(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class BizData {
|
||||||
|
private String msgTemplateId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板内容
|
||||||
|
*/
|
||||||
|
private String msgTemplateContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网易云信-自定义消息使用
|
||||||
|
*/
|
||||||
|
private BizTypeEnum bizType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网易云信-自定义消息使用
|
||||||
|
* 推送内容 - 业务数据,json格式
|
||||||
|
*/
|
||||||
|
private String payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转信息
|
||||||
|
*/
|
||||||
|
private List<SendMessageParam.JumpData> jumpData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给全员发送
|
||||||
|
*/
|
||||||
|
private boolean allPerson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全员发送时需要指定发送消息到App端
|
||||||
|
* 工人端、企业端、服务器
|
||||||
|
* CM、CMP、SYSTEM
|
||||||
|
*
|
||||||
|
* @See cn.axzo.im.center.common.enums.AppTypeEnum
|
||||||
|
*/
|
||||||
|
private List<AppTypeEnum> appTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ReceivePerson {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接收消息的personId
|
||||||
|
*/
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据organizationalUnitId获取账号
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到App端
|
||||||
|
* 工人端、企业端、服务器
|
||||||
|
* CM、CMP、SYSTEM
|
||||||
|
*
|
||||||
|
* @See cn.axzo.im.center.common.enums.AppTypeEnum
|
||||||
|
*/
|
||||||
|
private AppTypeEnum appType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* im账号,可以personId和imAccount二选一
|
||||||
|
*/
|
||||||
|
private String imAccount;
|
||||||
|
|
||||||
|
private Long workspaceId;
|
||||||
|
|
||||||
|
public String buildKey(Map<Long, Long> ouIdMap) {
|
||||||
|
if (StringUtils.isNotBlank(this.getImAccount())) {
|
||||||
|
return this.getImAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 因为模板消息发给工人端的时候会带ouId
|
||||||
|
if (appType == AppTypeEnum.CM) {
|
||||||
|
return this.getPersonId() + "_" + this.getAppType().getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getPersonId() + "_" + this.getAppType().getCode() + "_" + ouIdMap.getOrDefault(this.getOuId(), this.getOuId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ListReceivePersonTypeHandler extends BaseListTypeHandler<ReceivePerson> {}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ActionEnum {
|
||||||
|
SUCCESS,
|
||||||
|
;
|
||||||
|
|
||||||
|
private static final Table<Status, ActionEnum, Status> STATUS_FLOWS = HashBasedTable.create();
|
||||||
|
|
||||||
|
static {
|
||||||
|
STATUS_FLOWS.put(Status.PENDING, SUCCESS, Status.SUCCEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getNextStatus(Status oldStatus) {
|
||||||
|
return Optional.ofNullable(STATUS_FLOWS.get(oldStatus, this)).orElseThrow(MESSAGE_TASK_STATUS_ERROR::toException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,19 @@
|
|||||||
package cn.axzo.im.entity;
|
package cn.axzo.im.entity;
|
||||||
|
|
||||||
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
import cn.axzo.framework.data.mybatisplus.type.BaseListTypeHandler;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,13 +25,17 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@TableName(value = "im_robot_info",autoResultMap = true)
|
@TableName(value = "im_robot_info",autoResultMap = true)
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@SuperBuilder
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
|
@NoArgsConstructor
|
||||||
public class RobotInfo extends BaseEntity<RobotInfo> implements Serializable {
|
@AllArgsConstructor
|
||||||
|
public class RobotInfo implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人ID
|
* 机器人ID
|
||||||
* 目的是用该字段进行账户注册,如果使用数据库主键,
|
* 目的是用该字段进行账户注册,如果使用数据库主键,
|
||||||
@ -43,8 +52,9 @@ public class RobotInfo extends BaseEntity<RobotInfo> implements Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人Tag列表
|
* 机器人Tag列表
|
||||||
|
* 存放的是robotTag表的id
|
||||||
*/
|
*/
|
||||||
@TableField(value = "tag_name_list",typeHandler = JacksonTypeHandler.class)
|
@TableField(value = "tag_name_list",typeHandler = ListLongTypeHandler.class)
|
||||||
private List<Long> tagNameList;
|
private List<Long> tagNameList;
|
||||||
|
|
||||||
|
|
||||||
@ -67,4 +77,17 @@ public class RobotInfo extends BaseEntity<RobotInfo> implements Serializable {
|
|||||||
@TableField("status")
|
@TableField("status")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Integer isDelete;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
@TableField
|
||||||
|
private Date updateAt;
|
||||||
|
|
||||||
|
/** 使用FastjsonTypeHandler, 因为没有指定类型,有可能反序列化成List<Integer>,引起后续类型转换异常 */
|
||||||
|
public static class ListLongTypeHandler extends BaseListTypeHandler<Long> {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
package cn.axzo.im.event.inner;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname EventTypeEnum
|
||||||
|
* @Date 2021/2/7 6:05 下午
|
||||||
|
* @Created by lilong
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum EventTypeEnum {
|
||||||
|
|
||||||
|
MESSAGE_HISTORY_CREATED("message-history", "message-history-created", "发送记录创建"),
|
||||||
|
MESSAGE_HISTORY_UPDATED("message-history", "message-history-updated", "发送记录修改")
|
||||||
|
;
|
||||||
|
|
||||||
|
EventTypeEnum(String model, String name, String desc) {
|
||||||
|
this.eventCode = Event.EventCode.builder()
|
||||||
|
.module(model)
|
||||||
|
.name(name)
|
||||||
|
.build();
|
||||||
|
this.model = model;
|
||||||
|
this.name = name;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String model;
|
||||||
|
private String name;
|
||||||
|
private String desc;
|
||||||
|
private Event.EventCode eventCode;
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package cn.axzo.im.event.payload;
|
||||||
|
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MessageHistoryCreatedPayload implements Serializable {
|
||||||
|
|
||||||
|
private MessageHistory messageHistory;
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package cn.axzo.im.event.payload;
|
||||||
|
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MessageHistoryUpdatedPayload implements Serializable {
|
||||||
|
|
||||||
|
private MessageHistory newMessageHistory;
|
||||||
|
private MessageHistory oldMessageHistory;
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package cn.axzo.im.exception;
|
package cn.axzo.im.exception;
|
||||||
|
|
||||||
import cn.axzo.basics.common.exception.ServiceException;
|
import cn.axzo.basics.common.exception.ServiceException;
|
||||||
|
import cn.axzo.pokonyan.exception.BusinessException;
|
||||||
import cn.azxo.framework.common.model.CommonResponse;
|
import cn.azxo.framework.common.model.CommonResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
@ -36,6 +37,12 @@ public class ExceptionAdviceHandler {
|
|||||||
return CommonResponse.fail(e.getMessage());
|
return CommonResponse.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(BusinessException.class)
|
||||||
|
public CommonResponse<Void> businessExceptionHandler(BusinessException e) {
|
||||||
|
log.warn("业务异常", e);
|
||||||
|
return CommonResponse.fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(BindException.class)
|
@ExceptionHandler(BindException.class)
|
||||||
public CommonResponse<Void> bindExceptionHandler(BindException e) {
|
public CommonResponse<Void> bindExceptionHandler(BindException e) {
|
||||||
log.warn("业务异常", e);
|
log.warn("业务异常", e);
|
||||||
|
|||||||
@ -0,0 +1,83 @@
|
|||||||
|
package cn.axzo.im.job;
|
||||||
|
|
||||||
|
import cn.axzo.im.entity.MessageTask;
|
||||||
|
import cn.axzo.im.service.MessageTaskService;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
|
import com.xxl.job.core.handler.IJobHandler;
|
||||||
|
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询ImMessageTask中的PEDING数据,添加到messageHistory
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CreateMessageHistoryJob extends IJobHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageTaskService messageTaskService;
|
||||||
|
|
||||||
|
private static final Integer DEFAULT_PAGE_SIZE = 500;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@XxlJob("createMessageHistoryJob")
|
||||||
|
public ReturnT<String> execute(String s) throws Exception {
|
||||||
|
|
||||||
|
log.info("start createMessageHistoryJob,s:{}", s);
|
||||||
|
CreateMessageHistoryParam createMessageHistoryParam = Optional.ofNullable(s)
|
||||||
|
.map(e -> JSONObject.parseObject(e, CreateMessageHistoryParam.class))
|
||||||
|
.orElseGet(() -> CreateMessageHistoryParam.builder().build());
|
||||||
|
Integer pageNumber = 1;
|
||||||
|
Date now = new Date();
|
||||||
|
while (true) {
|
||||||
|
MessageTaskService.PageMessageTaskParam req = MessageTaskService.PageMessageTaskParam.builder()
|
||||||
|
.ids(createMessageHistoryParam.getIds())
|
||||||
|
.planStartTimeLE(now)
|
||||||
|
.status(MessageTask.Status.PENDING)
|
||||||
|
.page(pageNumber)
|
||||||
|
.pageSize(DEFAULT_PAGE_SIZE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Page<MessageTask> page = messageTaskService.page(req);
|
||||||
|
if (CollectionUtils.isNotEmpty(page.getRecords())) {
|
||||||
|
page.getRecords().forEach(messageTask -> {
|
||||||
|
try {
|
||||||
|
messageTaskService.createMessageHistory(messageTask);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.warn("messageTask 执行失败,{}, ex", messageTask.getId(), exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!page.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("end createMessageHistoryJob");
|
||||||
|
return ReturnT.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class CreateMessageHistoryParam {
|
||||||
|
private List<Long> ids;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
package cn.axzo.im.job;
|
||||||
|
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import cn.axzo.im.service.MessageHistoryService;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
|
import com.xxl.job.core.handler.IJobHandler;
|
||||||
|
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SendMessageJob extends IJobHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageHistoryService messageHistoryService;
|
||||||
|
|
||||||
|
private static final Integer DEFAULT_PAGE_SIZE = 100;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@XxlJob("sendMessageJob")
|
||||||
|
public ReturnT<String> execute(String s) throws Exception {
|
||||||
|
log.info("start sendMessageJob,s:{}", s);
|
||||||
|
SendMessageParam sendMessageParam = Optional.ofNullable(s)
|
||||||
|
.map(e -> JSONObject.parseObject(e, SendMessageParam.class))
|
||||||
|
.orElseGet(() -> SendMessageParam.builder().build());
|
||||||
|
Integer pageNumber = 1;
|
||||||
|
Date now = new Date();
|
||||||
|
while (true) {
|
||||||
|
MessageHistoryService.PageMessageHistoryParam req = MessageHistoryService.PageMessageHistoryParam.builder()
|
||||||
|
.ids(sendMessageParam.getIds())
|
||||||
|
.statues(Sets.newHashSet(MessageHistory.Status.PENDING.name()))
|
||||||
|
.page(pageNumber)
|
||||||
|
.pageSize(DEFAULT_PAGE_SIZE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Page<MessageHistoryService.MessageHistoryDTO> page = messageHistoryService.page(req);
|
||||||
|
if (CollectionUtils.isNotEmpty(page.getRecords())) {
|
||||||
|
Map<Long, List<MessageHistoryService.MessageHistoryDTO>> messageHistories = page.getRecords().stream()
|
||||||
|
.collect(Collectors.groupingBy(MessageHistoryService.MessageHistoryDTO::getImMessageTaskId));
|
||||||
|
|
||||||
|
messageHistories.values().forEach(messageHistoryService::sendMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!page.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("end sendMessageJob");
|
||||||
|
return ReturnT.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class SendMessageParam {
|
||||||
|
private List<Long> ids;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
package cn.axzo.im.job;
|
||||||
|
|
||||||
|
import cn.axzo.basics.common.constant.enums.OrganizationalUnitTypeEnum;
|
||||||
|
import cn.axzo.im.center.common.enums.AccountTypeEnum;
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.im.entity.AccountRegister;
|
||||||
|
import cn.axzo.im.service.AccountRegisterService;
|
||||||
|
import cn.axzo.maokai.api.client.OrganizationalUnitApi;
|
||||||
|
import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import cn.axzo.tyr.client.feign.TyrSaasRoleUserApi;
|
||||||
|
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserDTO;
|
||||||
|
import cn.axzo.tyr.client.model.roleuser.req.RoleUserParam;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.xxl.job.core.biz.model.ReturnT;
|
||||||
|
import com.xxl.job.core.handler.IJobHandler;
|
||||||
|
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把appType = CMP、accountType = 'user'的账号的ouId更新成用户最后加入的企业id
|
||||||
|
* 因为用户在管理版的IM云信消息要按照企业隔离,历史的账号是跟企业没绑定,要保持数据不丢失
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UpdateImAccountOuIdJob extends IJobHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountRegisterService accountRegisterService;
|
||||||
|
@Autowired
|
||||||
|
private TyrSaasRoleUserApi tyrSaasRoleUserApi;
|
||||||
|
@Autowired
|
||||||
|
private OrganizationalUnitApi organizationalUnitApi;
|
||||||
|
|
||||||
|
private static final Integer DEFAULT_PAGE_SIZE = 500;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@XxlJob("updateImAccountOuIdJob")
|
||||||
|
public ReturnT<String> execute(String s) throws Exception {
|
||||||
|
|
||||||
|
log.info("start updateImAccountOuIdJob,s:{}", s);
|
||||||
|
UpdateImAccountOuIdParam updateImAccountOuIdParam = Optional.ofNullable(s)
|
||||||
|
.map(e -> JSONObject.parseObject(e, UpdateImAccountOuIdParam.class))
|
||||||
|
.orElseGet(() -> UpdateImAccountOuIdParam.builder().build());
|
||||||
|
Integer pageNumber = 1;
|
||||||
|
while (true) {
|
||||||
|
AccountRegisterService.PageAccountRegisterParam req = AccountRegisterService.PageAccountRegisterParam.builder()
|
||||||
|
.ids(updateImAccountOuIdParam.getIds())
|
||||||
|
.appType(AppTypeEnum.CMP.getCode())
|
||||||
|
.accountType(AccountTypeEnum.USER.getCode())
|
||||||
|
.accountWrapperEW("cmp")
|
||||||
|
.page(pageNumber++)
|
||||||
|
.pageSize(DEFAULT_PAGE_SIZE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Page<AccountRegisterService.AccountRegisterDTO> page = accountRegisterService.page(req);
|
||||||
|
if (CollectionUtils.isNotEmpty(page.getRecords())) {
|
||||||
|
|
||||||
|
Map<String, Long> nodeUsers = listNodeUsers(page.getRecords());
|
||||||
|
|
||||||
|
updateAccountRegister(page.getRecords(), nodeUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!page.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("end updateImAccountOuIdJob");
|
||||||
|
return ReturnT.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAccountRegister(List<AccountRegisterService.AccountRegisterDTO> accountRegisters, Map<String, Long> nodeUsers) {
|
||||||
|
List<AccountRegister> update = accountRegisters.stream()
|
||||||
|
.filter(accountRegister -> nodeUsers.get(accountRegister.getAccountId()) != null)
|
||||||
|
.map(accountRegister -> {
|
||||||
|
Long ouId = nodeUsers.get(accountRegister.getAccountId());
|
||||||
|
|
||||||
|
if (ouId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AccountRegister result = new AccountRegister();
|
||||||
|
result.setId(accountRegister.getId());
|
||||||
|
result.setOuId(ouId);
|
||||||
|
result.setUpdateAt(new Date());
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(accountRegisters)) {
|
||||||
|
log.info("updateImAccountOuIdJob: no data update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
accountRegisterService.updateBatchById(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Long> listNodeUsers(List<AccountRegisterService.AccountRegisterDTO> accountRegisters) {
|
||||||
|
if (CollectionUtils.isEmpty(accountRegisters)) {
|
||||||
|
return Collections.EMPTY_MAP;
|
||||||
|
}
|
||||||
|
Set<Long> accountIds = accountRegisters.stream()
|
||||||
|
.map(AccountRegister::getAccountId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(StringUtils::isNumeric)
|
||||||
|
.map(Long::valueOf)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (CollectionUtils.isEmpty(accountIds)) {
|
||||||
|
return Collections.EMPTY_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SaasRoleUserDTO> saasRoleUsers = accountIds.stream()
|
||||||
|
.flatMap(e -> tyrSaasRoleUserApi.roleUserList(RoleUserParam.builder().personId(e).build()).getData().stream())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<Long> ouIds = Lists.transform(saasRoleUsers, SaasRoleUserDTO::getOuId);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(ouIds)) {
|
||||||
|
return Collections.EMPTY_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Long> effectOuIds = organizationalUnitApi.list(OrganizationalUnitQuery.builder().unitIds(ouIds).build()).getData()
|
||||||
|
.stream()
|
||||||
|
.filter(e -> !Objects.equals(e.getType(), OrganizationalUnitTypeEnum.PROJECT_OUT_TEAM.getValue()))
|
||||||
|
.map(OrganizationalUnitVO::getId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return saasRoleUsers.stream()
|
||||||
|
.filter(e -> effectOuIds.contains(e.getOuId()))
|
||||||
|
.collect(Collectors.toMap(e -> e.getNaturalPersonId().toString(), SaasRoleUserDTO::getOuId, (f, s) -> f));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class UpdateImAccountOuIdParam {
|
||||||
|
private List<Long> ids;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
package cn.axzo.im.service;
|
||||||
|
|
||||||
|
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||||
|
import cn.axzo.im.entity.AccountRegister;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import cn.axzo.pokonyan.dao.page.IPageParam;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.Operator;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface AccountRegisterService extends IService<AccountRegister> {
|
||||||
|
|
||||||
|
Page<AccountRegisterDTO> page(PageAccountRegisterParam param);
|
||||||
|
|
||||||
|
List<AccountRegisterDTO> list(ListAccountRegisterParam param);
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListAccountRegisterParam {
|
||||||
|
|
||||||
|
@CriteriaField(field = "id", operator = Operator.IN)
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
@CriteriaField(field = "appType", operator = Operator.EQ)
|
||||||
|
private String appType;
|
||||||
|
|
||||||
|
@CriteriaField(field = "appType", operator = Operator.IN)
|
||||||
|
private Set<String> appTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册用户ID唯一
|
||||||
|
* 普通用户personId、机器人robotId
|
||||||
|
*/
|
||||||
|
@CriteriaField(field = "accountId", operator = Operator.EQ)
|
||||||
|
private String accountId;
|
||||||
|
|
||||||
|
@CriteriaField(field = "accountId", operator = Operator.IN)
|
||||||
|
private Set<String> accountIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册用户ID唯一
|
||||||
|
*/
|
||||||
|
@CriteriaField(field = "imAccount", operator = Operator.EQ)
|
||||||
|
private String imAccount;
|
||||||
|
|
||||||
|
@CriteriaField(field = "imAccount", operator = Operator.IN)
|
||||||
|
private Set<String> imAccounts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号,
|
||||||
|
* 所以需要根据ouId获取账号
|
||||||
|
*/
|
||||||
|
@CriteriaField(field = "ouId", operator = Operator.EQ)
|
||||||
|
private Long ouId;
|
||||||
|
|
||||||
|
@CriteriaField(field = "accountType", operator = Operator.EQ)
|
||||||
|
private String accountType;
|
||||||
|
|
||||||
|
@CriteriaField(field = "accountWrapper", operator = Operator.EW)
|
||||||
|
private String accountWrapperEW;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
private boolean needOuInfo;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
private boolean needUserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageAccountRegisterParam extends ListAccountRegisterParam implements IPageParam {
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer page;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class AccountRegisterDTO extends AccountRegister {
|
||||||
|
|
||||||
|
private PersonProfileDto personProfile;
|
||||||
|
|
||||||
|
private OrganizationalUnitVO organizationalUnit;
|
||||||
|
|
||||||
|
public static AccountRegisterDTO from(AccountRegister accountRegister,
|
||||||
|
Map<String, PersonProfileDto> personProfiles,
|
||||||
|
Map<Long, OrganizationalUnitVO> organizationals) {
|
||||||
|
AccountRegisterDTO accountRegisterDTO = AccountRegisterDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(accountRegister, accountRegisterDTO);
|
||||||
|
|
||||||
|
accountRegisterDTO.setPersonProfile(personProfiles.get(accountRegisterDTO.getAccountId()));
|
||||||
|
accountRegisterDTO.setOrganizationalUnit(organizationals.get(accountRegisterDTO.getOuId()));
|
||||||
|
return accountRegisterDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,24 +25,24 @@ import cn.axzo.im.entity.bo.AccountQueryParam;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM账户服务
|
* IM账户服务
|
||||||
@ -56,6 +56,9 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AccountService {
|
public class AccountService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountRegisterService accountRegisterService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IMChannelProvider imChannelProvider;
|
private IMChannelProvider imChannelProvider;
|
||||||
|
|
||||||
@ -116,10 +119,10 @@ public class AccountService {
|
|||||||
if (appTypeEnum == null) {
|
if (appTypeEnum == null) {
|
||||||
throw new ServiceException("当前appType,服务器不支持该类型!!");
|
throw new ServiceException("当前appType,服务器不支持该类型!!");
|
||||||
}
|
}
|
||||||
String userIdWrapper = buildUserIdWrapper(userAccountReq.getUserId(), userAccountReq.getAppType());
|
String userIdWrapper = buildUserIdWrapper(userAccountReq.getUserId(), userAccountReq.getAppType(), userAccountReq.getOrganizationalUnitId());
|
||||||
//后续AppKey可能会更换,普通用户通过userId、appType、appKey维度来保证数据库唯一性
|
//后续AppKey可能会更换,普通用户通过userId、appType、appKey维度来保证数据库唯一性
|
||||||
UserAccountResp userAccountResp = createAccountRegister(userAccountReq.getUserId(), userIdWrapper, appType,
|
UserAccountResp userAccountResp = createAccountRegister(userAccountReq.getUserId(), userIdWrapper, appType,
|
||||||
AccountTypeEnum.USER.getCode(), userAccountReq.getHeadImageUrl(), userAccountReq.getNickName());
|
AccountTypeEnum.USER.getCode(), userAccountReq.getHeadImageUrl(), userAccountReq.getNickName(), userAccountReq.getOrganizationalUnitId());
|
||||||
|
|
||||||
if (iNotifyService != null && userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
|
if (iNotifyService != null && userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
|
||||||
iNotifyService.notifyUserAccountChange(userAccountResp.getImAccount(), userAccountReq.getNickName(), null);
|
iNotifyService.notifyUserAccountChange(userAccountResp.getImAccount(), userAccountReq.getNickName(), null);
|
||||||
@ -127,13 +130,17 @@ public class AccountService {
|
|||||||
return userAccountResp;
|
return userAccountResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildUserIdWrapper(String userId, String appType) {
|
private String buildUserIdWrapper(String userId, String appType, Long organizationalUnitId) {
|
||||||
String env = environment.getProperty("spring.profiles.active");
|
String env = environment.getProperty("spring.profiles.active");
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
if (StringUtils.isNotBlank(liveEnvPrefix)) {
|
if (StringUtils.isNotBlank(liveEnvPrefix)) {
|
||||||
buf.append(liveEnvPrefix).append("_");
|
buf.append(liveEnvPrefix).append("_");
|
||||||
}
|
}
|
||||||
buf.append(env).append(userId).append("_").append(appType);
|
buf.append(env).append(userId).append("_").append(appType);
|
||||||
|
// 新的用户在使用管理版时,如果有企业,则只能根据企业产生唯一账号
|
||||||
|
if (organizationalUnitId != null) {
|
||||||
|
buf.append("_").append(organizationalUnitId);
|
||||||
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +154,7 @@ public class AccountService {
|
|||||||
if (appTypeEnum == null) {
|
if (appTypeEnum == null) {
|
||||||
throw new ServiceException("当前appType,服务器不支持该类型!!");
|
throw new ServiceException("当前appType,服务器不支持该类型!!");
|
||||||
}
|
}
|
||||||
String userIdWrapper = buildUserIdWrapper(userAccountReq.getUserId(), appTypeEnum.getCode());
|
String userIdWrapper = buildUserIdWrapper(userAccountReq.getUserId(), appTypeEnum.getCode(), userAccountReq.getOrganizationalUnitId());
|
||||||
|
|
||||||
String appKey = imChannelProvider.getProviderAppKey();
|
String appKey = imChannelProvider.getProviderAppKey();
|
||||||
AccountRegister customAccountRegister = queryCustomAccount(AccountTypeEnum.CUSTOM,
|
AccountRegister customAccountRegister = queryCustomAccount(AccountTypeEnum.CUSTOM,
|
||||||
@ -163,7 +170,8 @@ public class AccountService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UserAccountResp userAccountResp = createAccountRegister(userAccountReq.getUserId(), userIdWrapper, appType,
|
UserAccountResp userAccountResp = createAccountRegister(userAccountReq.getUserId(), userIdWrapper, appType,
|
||||||
AccountTypeEnum.CUSTOM.getCode(), userAccountReq.getHeadImageUrl(), userAccountReq.getNickName());
|
AccountTypeEnum.CUSTOM.getCode(), userAccountReq.getHeadImageUrl(), userAccountReq.getNickName(),
|
||||||
|
userAccountReq.getOrganizationalUnitId());
|
||||||
|
|
||||||
if (iNotifyService != null && userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
|
if (iNotifyService != null && userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
|
||||||
iNotifyService.notifyUserAccountChange(userAccountResp.getImAccount(), userAccountReq.getNickName(), null);
|
iNotifyService.notifyUserAccountChange(userAccountResp.getImAccount(), userAccountReq.getNickName(), null);
|
||||||
@ -192,7 +200,7 @@ public class AccountService {
|
|||||||
throw new ServiceException("该机器人robotId:{} 还未创建信息!");
|
throw new ServiceException("该机器人robotId:{} 还未创建信息!");
|
||||||
}
|
}
|
||||||
UserAccountResp userAccountResp = createAccountRegister(robotId, robotId, AppTypeEnum.SYSTEM.getCode(),
|
UserAccountResp userAccountResp = createAccountRegister(robotId, robotId, AppTypeEnum.SYSTEM.getCode(),
|
||||||
AccountTypeEnum.ROBOT.getCode(), robotAccountReq.getHeadImageUrl(), robotAccountReq.getNickName());
|
AccountTypeEnum.ROBOT.getCode(), robotAccountReq.getHeadImageUrl(), robotAccountReq.getNickName(), null);
|
||||||
if (userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
|
if (userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
|
||||||
//生成后更新机器人状态和IM账户
|
//生成后更新机器人状态和IM账户
|
||||||
robotInfoService.updateRobotStatus(robotId, userAccountResp.getImAccount(), RobotStatusEnum.UN_ENABLE);
|
robotInfoService.updateRobotStatus(robotId, userAccountResp.getImAccount(), RobotStatusEnum.UN_ENABLE);
|
||||||
@ -204,7 +212,8 @@ public class AccountService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public UserAccountResp createAccountRegister(String userId, String userIdWrapper, String appType,
|
public UserAccountResp createAccountRegister(String userId, String userIdWrapper, String appType,
|
||||||
String accountType, String headImageUrl, String nickName) {
|
String accountType, String headImageUrl, String nickName,
|
||||||
|
Long ouId) {
|
||||||
//1.检查账户是否已经创建
|
//1.检查账户是否已经创建
|
||||||
String appKey = imChannelProvider.getProviderAppKey();
|
String appKey = imChannelProvider.getProviderAppKey();
|
||||||
UserAccountResp userAccountResp = new UserAccountResp();
|
UserAccountResp userAccountResp = new UserAccountResp();
|
||||||
@ -230,6 +239,7 @@ public class AccountService {
|
|||||||
accountRegister.setChannelProvider(imChannelProvider.getProviderType());
|
accountRegister.setChannelProvider(imChannelProvider.getProviderType());
|
||||||
accountRegister.setCreateAt(new Date());
|
accountRegister.setCreateAt(new Date());
|
||||||
accountRegister.setUpdateAt(new Date());
|
accountRegister.setUpdateAt(new Date());
|
||||||
|
accountRegister.setOuId(ouId);
|
||||||
accountRegisterDao.saveOrUpdate(accountRegister);
|
accountRegisterDao.saveOrUpdate(accountRegister);
|
||||||
} else {
|
} else {
|
||||||
//2.1注册出现异常
|
//2.1注册出现异常
|
||||||
@ -237,6 +247,7 @@ public class AccountService {
|
|||||||
userAccountResp.setDesc(accountResp.getDesc());
|
userAccountResp.setDesc(accountResp.getDesc());
|
||||||
return userAccountResp;
|
return userAccountResp;
|
||||||
}
|
}
|
||||||
|
userAccountResp.setOuId(ouId);
|
||||||
accountResp.setAppType(appType);
|
accountResp.setAppType(appType);
|
||||||
return accountResp;
|
return accountResp;
|
||||||
}
|
}
|
||||||
@ -245,6 +256,7 @@ public class AccountService {
|
|||||||
userAccountResp.setUserId(userId);
|
userAccountResp.setUserId(userId);
|
||||||
userAccountResp.setAppType(appType);
|
userAccountResp.setAppType(appType);
|
||||||
userAccountResp.setToken(accountRegister.getToken());
|
userAccountResp.setToken(accountRegister.getToken());
|
||||||
|
userAccountResp.setOuId(ouId);
|
||||||
return userAccountResp;
|
return userAccountResp;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -267,11 +279,18 @@ public class AccountService {
|
|||||||
return userAccountResp;
|
return userAccountResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建议用更通用的AccountRegisterService.page解耦
|
||||||
|
* @param accountQuery
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public List<UserAccountResp> queryAccountInfo(@Valid AccountQuery accountQuery) {
|
public List<UserAccountResp> queryAccountInfo(@Valid AccountQuery accountQuery) {
|
||||||
//如果存在多个appKey,一个账户会有多条数据,分别对应不同的appKey
|
//如果存在多个appKey,一个账户会有多条数据,分别对应不同的appKey
|
||||||
//机器人的账户 不进行wapper判断
|
//机器人的账户 不进行wapper判断
|
||||||
|
// TODO 这块逻辑不通用,新的数据userIdWrapper会增加ouId,历史的数据只会补ouId,不会把userIdWrapper补上ouId,不应该放在通用的query里面
|
||||||
if (!AppTypeEnum.SYSTEM.getCode().equals(accountQuery.getAppType()) && StringUtils.isEmpty(accountQuery.getImAccount())) {
|
if (!AppTypeEnum.SYSTEM.getCode().equals(accountQuery.getAppType()) && StringUtils.isEmpty(accountQuery.getImAccount())) {
|
||||||
String userIdWrapper = buildUserIdWrapper(accountQuery.getAccountId(), accountQuery.getAppType());
|
String userIdWrapper = buildUserIdWrapper(accountQuery.getAccountId(), accountQuery.getAppType(), null);
|
||||||
accountQuery.setImAccount(userIdWrapper);
|
accountQuery.setImAccount(userIdWrapper);
|
||||||
}
|
}
|
||||||
List<AccountRegister> accountRegisterList = accountRegisterDao.lambdaQuery().eq(AccountRegister::getIsDelete, 0)
|
List<AccountRegister> accountRegisterList = accountRegisterDao.lambdaQuery().eq(AccountRegister::getIsDelete, 0)
|
||||||
@ -316,13 +335,29 @@ public class AccountService {
|
|||||||
} else {
|
} else {
|
||||||
target = AppTypeEnum.values();
|
target = AppTypeEnum.values();
|
||||||
}
|
}
|
||||||
|
// TODO 待优化,兼容移动端,因为原接口会返回cm、cmp两个端的账号,但是cmp这个端查询的时候,如果有传ouId,则返回对应ouId的账号
|
||||||
for (AppTypeEnum appTypeEnum : target) {
|
for (AppTypeEnum appTypeEnum : target) {
|
||||||
AccountQuery accountQuery = new AccountQuery();
|
AccountRegisterService.ListAccountRegisterParam listAccountRegisterParam = AccountRegisterService.ListAccountRegisterParam.builder()
|
||||||
accountQuery.setAppType(appTypeEnum.getCode());
|
.appType(appTypeEnum.getCode())
|
||||||
accountQuery.setAccountId(accountAbsentQuery.getPersonId());
|
.accountId(accountAbsentQuery.getPersonId())
|
||||||
List<UserAccountResp> userAccountRespList = queryAccountInfo(accountQuery);
|
.build();
|
||||||
if (CollectionUtils.isNotEmpty(userAccountRespList)) {
|
if (appTypeEnum == AppTypeEnum.CMP && accountAbsentQuery.getOuId() != null && accountAbsentQuery.getOuId() != 0) {
|
||||||
userAccountAll.addAll(userAccountRespList);
|
listAccountRegisterParam.setOuId(accountAbsentQuery.getOuId());
|
||||||
|
}
|
||||||
|
List<AccountRegisterService.AccountRegisterDTO> accountRegisters = accountRegisterService.list(listAccountRegisterParam);
|
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(accountRegisters)) {
|
||||||
|
userAccountAll.addAll(accountRegisters.stream()
|
||||||
|
.map(accountRegister -> {
|
||||||
|
UserAccountResp userAccountResp = new UserAccountResp();
|
||||||
|
userAccountResp.setImAccount(accountRegister.getImAccount());
|
||||||
|
userAccountResp.setUserId(accountRegister.getAccountId());
|
||||||
|
userAccountResp.setAppType(accountRegister.getAppType());
|
||||||
|
userAccountResp.setToken(accountRegister.getToken());
|
||||||
|
userAccountResp.setOuId(accountRegister.getOuId());
|
||||||
|
return userAccountResp;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList()));
|
||||||
} else {
|
} else {
|
||||||
if (appTypeEnum == AppTypeEnum.SYSTEM) {
|
if (appTypeEnum == AppTypeEnum.SYSTEM) {
|
||||||
//log.warn("PersonId=[" + accountAbsentQuery.getPersonId() + "],不允许创建AppType=[system]账户!");
|
//log.warn("PersonId=[" + accountAbsentQuery.getPersonId() + "],不允许创建AppType=[system]账户!");
|
||||||
@ -332,6 +367,10 @@ public class AccountService {
|
|||||||
userAccountReq.setAppType(appTypeEnum.getCode());
|
userAccountReq.setAppType(appTypeEnum.getCode());
|
||||||
userAccountReq.setUserId(accountAbsentQuery.getPersonId());
|
userAccountReq.setUserId(accountAbsentQuery.getPersonId());
|
||||||
userAccountReq.setNickName(DEFAULT_NICK_NAME + accountAbsentQuery.getPersonId());
|
userAccountReq.setNickName(DEFAULT_NICK_NAME + accountAbsentQuery.getPersonId());
|
||||||
|
// 管理版需要根据ou注册IM账号,做数据隔离
|
||||||
|
if (appTypeEnum == AppTypeEnum.CMP && accountAbsentQuery.getOuId() != null && accountAbsentQuery.getOuId() != 0) {
|
||||||
|
userAccountReq.setOrganizationalUnitId(accountAbsentQuery.getOuId());
|
||||||
|
}
|
||||||
UserAccountResp accountResp = generateAccount(userAccountReq, iNotifyService);
|
UserAccountResp accountResp = generateAccount(userAccountReq, iNotifyService);
|
||||||
if (StringUtils.isEmpty(accountResp.getToken())) {
|
if (StringUtils.isEmpty(accountResp.getToken())) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -0,0 +1,102 @@
|
|||||||
|
package cn.axzo.im.service;
|
||||||
|
|
||||||
|
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import cn.axzo.pokonyan.dao.page.IPageParam;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.Operator;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface MessageHistoryService extends IService<MessageHistory> {
|
||||||
|
|
||||||
|
Page<MessageHistoryDTO> page(PageMessageHistoryParam param);
|
||||||
|
|
||||||
|
List<MessageHistoryDTO> list(ListMessageHistoryParam param);
|
||||||
|
|
||||||
|
void sendMessage(List<MessageHistoryService.MessageHistoryDTO> messageHistories);
|
||||||
|
|
||||||
|
void createBatch(List<MessageHistory> messageHistories);
|
||||||
|
|
||||||
|
void updateBatch(List<MessageHistory> messageHistories);
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListMessageHistoryParam {
|
||||||
|
|
||||||
|
@CriteriaField(field = "id", operator = Operator.IN)
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
@CriteriaField(field = "imMessageTaskId", operator = Operator.EQ)
|
||||||
|
private Long imMessageTaskId;
|
||||||
|
|
||||||
|
@CriteriaField(field = "receivePersonId", operator = Operator.IN)
|
||||||
|
private Set<String> receivePersonIds;
|
||||||
|
|
||||||
|
@CriteriaField(field = "toAccount", operator = Operator.IN)
|
||||||
|
private Set<String> toAccount;
|
||||||
|
|
||||||
|
@CriteriaField(field = "appType", operator = Operator.IN)
|
||||||
|
private Set<String> appTypes;
|
||||||
|
|
||||||
|
@CriteriaField(field = "status", operator = Operator.IN)
|
||||||
|
private Set<String> statues;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
private boolean needReceiveOuInfo;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
private boolean needReceiveUserInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageMessageHistoryParam extends ListMessageHistoryParam implements IPageParam {
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer page;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class MessageHistoryDTO extends MessageHistory {
|
||||||
|
private PersonProfileDto receivePersonProfile;
|
||||||
|
|
||||||
|
private OrganizationalUnitVO receiveOrganizationalUnit;
|
||||||
|
|
||||||
|
public static MessageHistoryDTO from(MessageHistory messageHistory,
|
||||||
|
Map<String, PersonProfileDto> personProfiles,
|
||||||
|
Map<Long, OrganizationalUnitVO> organizationals) {
|
||||||
|
MessageHistoryDTO messageHistoryDTO = MessageHistoryDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(messageHistory, messageHistoryDTO);
|
||||||
|
|
||||||
|
messageHistoryDTO.setReceivePersonProfile(personProfiles.get(messageHistoryDTO.getReceivePersonId()));
|
||||||
|
messageHistoryDTO.setReceiveOrganizationalUnit(organizationals.get(messageHistoryDTO.getReceiveOuId()));
|
||||||
|
return messageHistoryDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,8 @@ import cn.axzo.basics.common.exception.ServiceException;
|
|||||||
import cn.axzo.basics.common.util.AssertUtil;
|
import cn.axzo.basics.common.util.AssertUtil;
|
||||||
import cn.axzo.im.center.api.vo.req.AccountQuery;
|
import cn.axzo.im.center.api.vo.req.AccountQuery;
|
||||||
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
|
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
|
||||||
import cn.axzo.im.center.api.vo.req.MessageInfo;
|
import cn.axzo.im.center.api.vo.req.SendCustomMessageParam;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendMessageParam;
|
||||||
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
|
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
|
||||||
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
|
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
|
||||||
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
|
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
|
||||||
@ -35,6 +36,7 @@ import org.apache.commons.collections.CollectionUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cglib.beans.BeanMap;
|
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
@ -105,32 +107,40 @@ public class MessageService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
/**
|
||||||
public List<MessageDispatchResp> sendMessage(MessageInfo messageInfo) {
|
* 使用xxlJob异步发送第三方接口消息
|
||||||
String msgTemplateId = messageInfo.getMsgTemplateId();
|
* 1、第三方接口有限流
|
||||||
MessageDispatchRequest messageRequest = buildMessageDispatchRequest(messageInfo);
|
* 2、提高接口的性能
|
||||||
buildMsgFromAccount(messageRequest, msgTemplateId);
|
* @param sendMessageParam
|
||||||
//设置IM消息发送者账号
|
* @return
|
||||||
if (messageInfo.getToPersonIdList().size() > msgReceiverLimit) {
|
*/
|
||||||
throw new ServiceException("IM消息接收用户数量超过上限:[" + msgReceiverLimit + "]!");
|
// @Transactional(rollbackFor = Exception.class)
|
||||||
}
|
// public List<MessageDispatchResp> sendMessage(SendMessageParam sendMessageParam) {
|
||||||
List<MessageDispatchResp> messageDispatchRespList;
|
// String msgTemplateId = sendMessageParam.getMsgTemplateId();
|
||||||
log.info("sendMessage发送消息,msgReceiverLimit:{},msgReceiverThreshold:{},msgSendPersonOfOneBatch:{}"
|
// MessageDispatchRequest messageRequest = buildMessageDispatchRequest(sendMessageParam);
|
||||||
, msgReceiverLimit, msgReceiverThreshold, msgSendPersonOfOneBatch);
|
// buildMsgFromAccount(messageRequest, msgTemplateId);
|
||||||
int personCount = messageInfo.getToPersonIdList().size();
|
// //设置IM消息发送者账号
|
||||||
//小于阈值就走单个IM消息发送接口
|
// if (sendMessageParam.getToPersonIdList().size() > msgReceiverLimit) {
|
||||||
if (personCount <= msgReceiverThreshold) {
|
// throw new ServiceException("IM消息接收用户数量超过上限:[" + msgReceiverLimit + "]!");
|
||||||
messageDispatchRespList = sendOneByOneMessage(messageInfo, messageRequest);
|
// }
|
||||||
} else {
|
// List<MessageDispatchResp> messageDispatchRespList;
|
||||||
log.info("sendBatchMessage批量发送消息:" + JSONUtil.toJsonStr(messageInfo));
|
// log.info("sendMessage发送消息,msgReceiverLimit:{},msgReceiverThreshold:{},msgSendPersonOfOneBatch:{}"
|
||||||
messageDispatchRespList = sendBatchMessage(messageInfo, messageRequest);
|
// , msgReceiverLimit, msgReceiverThreshold, msgSendPersonOfOneBatch);
|
||||||
}
|
// // 异步发送消息,1、同步发送接口性能不好;2、第三方接口有接口限流处理
|
||||||
List<MessageDispatchResp> saveRespList = messageDispatchRespList.stream()
|
// int personCount = sendMessageParam.getToPersonIdList().size();
|
||||||
.filter(i -> StringUtils.isBlank(i.getSendFailCause()))
|
// //小于阈值就走单个IM消息发送接口
|
||||||
.collect(toList());
|
// if (personCount <= msgReceiverThreshold) {
|
||||||
insertImMessage(saveRespList, messageRequest.getBody());
|
// messageDispatchRespList = sendOneByOneMessage(sendMessageParam, messageRequest);
|
||||||
return messageDispatchRespList;
|
// } else {
|
||||||
}
|
// log.info("sendBatchMessage批量发送消息:" + JSONUtil.toJsonStr(sendMessageParam));
|
||||||
|
// messageDispatchRespList = sendBatchMessage(sendMessageParam, messageRequest);
|
||||||
|
// }
|
||||||
|
// List<MessageDispatchResp> saveRespList = messageDispatchRespList.stream()
|
||||||
|
// .filter(i -> StringUtils.isBlank(i.getSendFailCause()))
|
||||||
|
// .collect(toList());
|
||||||
|
// insertImMessage(saveRespList, messageRequest.getBody());
|
||||||
|
// return messageDispatchRespList;
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置IM消息发送者账户,目前只支持机器人账户发送
|
* 设置IM消息发送者账户,目前只支持机器人账户发送
|
||||||
@ -171,115 +181,115 @@ public class MessageService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MessageDispatchRequest buildMessageDispatchRequest(MessageInfo messageInfo) {
|
// private MessageDispatchRequest buildMessageDispatchRequest(SendMessageParam sendMessageParam) {
|
||||||
MessageDispatchRequest messageRequest = new MessageDispatchRequest();
|
// MessageDispatchRequest messageRequest = new MessageDispatchRequest();
|
||||||
MessageBody messageBody = new MessageBody();
|
// MessageBody messageBody = new MessageBody();
|
||||||
messageBody.setMsgType(NimMsgTypeEnum.TEMPLATE.getCode());
|
// messageBody.setMsgType(NimMsgTypeEnum.TEMPLATE.getCode());
|
||||||
messageBody.setMsgContent(messageInfo.getMsgContent());
|
// messageBody.setMsgContent(sendMessageParam.getMsgContent());
|
||||||
messageBody.setMsgHeader(messageInfo.getMsgHeader());
|
// messageBody.setMsgHeader(sendMessageParam.getMsgHeader());
|
||||||
messageBody.setMsgBody(messageInfo.getMsgTemplateContent());
|
// messageBody.setMsgBody(sendMessageParam.getMsgTemplateContent());
|
||||||
Map<String, String> defaultExtMap = Maps.newHashMap();
|
// Map<String, String> defaultExtMap = Maps.newHashMap();
|
||||||
defaultExtMap.put("msgTemplateId", messageInfo.getMsgTemplateId());
|
// defaultExtMap.put("msgTemplateId", sendMessageParam.getMsgTemplateId());
|
||||||
if (messageInfo.getExtendsInfo() != null) {
|
// if (sendMessageParam.getExt() != null) {
|
||||||
defaultExtMap.putAll(messageInfo.getExtendsInfo());
|
// defaultExtMap.putAll(BeanMap.create(sendMessageParam.getExt()));
|
||||||
}
|
// }
|
||||||
messageBody.setMessageExtension(defaultExtMap);
|
// messageBody.setMessageExtension(defaultExtMap);
|
||||||
String body = JSONUtil.toJsonStr(messageBody);
|
// String body = JSONUtil.toJsonStr(messageBody);
|
||||||
messageRequest.setBody(body);
|
// messageRequest.setBody(body);
|
||||||
return messageRequest;
|
// return messageRequest;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private List<MessageDispatchResp> sendBatchMessage(MessageInfo messageInfo, MessageDispatchRequest messageRequest) {
|
// private List<MessageDispatchResp> sendBatchMessage(SendMessageParam sendMessageParam, MessageDispatchRequest messageRequest) {
|
||||||
//消息模板是针对多App端,则单个用户有多个IM账户,需要分开进行发送消息
|
// //消息模板是针对多App端,则单个用户有多个IM账户,需要分开进行发送消息
|
||||||
List<AppTypeEnum> appTypeList = messageInfo.getAppTypeList();
|
// List<AppTypeEnum> appTypeList = sendMessageParam.getAppTypeList();
|
||||||
String fromAccId = messageRequest.getFrom();
|
// String fromAccId = messageRequest.getFrom();
|
||||||
List<MessageDispatchResp> messageDispatchRespList = Lists.newArrayList();
|
// List<MessageDispatchResp> messageDispatchRespList = Lists.newArrayList();
|
||||||
//1.首先自动添加IM账户进行批量发送,返回其中IM账户未注册部分
|
// //1.首先自动添加IM账户进行批量发送,返回其中IM账户未注册部分
|
||||||
//2.如下是默认IM账户规则
|
// //2.如下是默认IM账户规则
|
||||||
//TODO 批量这里的账户生成判断有问题,生产环境有两种类型的数据123_cm和master123_cm
|
// //TODO 批量这里的账户生成判断有问题,生产环境有两种类型的数据123_cm和master123_cm
|
||||||
//TODO 先去数据库里面查询判断是否有IM账户
|
// //TODO 先去数据库里面查询判断是否有IM账户
|
||||||
//消息接收者分页,然后进行批量发送
|
// //消息接收者分页,然后进行批量发送
|
||||||
for (AppTypeEnum appTypeEnum : appTypeList) {
|
// for (AppTypeEnum appTypeEnum : appTypeList) {
|
||||||
String appType = appTypeEnum.getCode();
|
// String appType = appTypeEnum.getCode();
|
||||||
if (appType == null || AppTypeEnum.isValidAppType(appType) == null) {
|
// if (appType == null || AppTypeEnum.isValidAppType(appType) == null) {
|
||||||
throw new ServiceException("当前服务器不支持该appType类型!");
|
// throw new ServiceException("当前服务器不支持该appType类型!");
|
||||||
}
|
// }
|
||||||
Set<String> sourcePersonList = messageInfo.getToPersonIdList();
|
// Set<String> sourcePersonList = sendMessageParam.getToPersonIdList();
|
||||||
List<String> toPersonIMList = Lists.newArrayList();
|
// List<String> toPersonIMList = Lists.newArrayList();
|
||||||
HashMap<String, String> imAccount2PersonId = new HashMap<>();
|
// HashMap<String, String> imAccount2PersonId = new HashMap<>();
|
||||||
for (String sourcePersonId : sourcePersonList) {
|
// for (String sourcePersonId : sourcePersonList) {
|
||||||
AccountQuery accountQuery = new AccountQuery();
|
// AccountQuery accountQuery = new AccountQuery();
|
||||||
accountQuery.setAppType(appType);
|
// accountQuery.setAppType(appType);
|
||||||
accountQuery.setAccountId(sourcePersonId);
|
// accountQuery.setAccountId(sourcePersonId);
|
||||||
List<UserAccountResp> userAccountRespList = accountService.queryAccountInfo(accountQuery);
|
// List<UserAccountResp> userAccountRespList = accountService.queryAccountInfo(accountQuery);
|
||||||
if (CollectionUtils.isNotEmpty(userAccountRespList)) {
|
// if (CollectionUtils.isNotEmpty(userAccountRespList)) {
|
||||||
userAccountRespList.forEach(userAccountResp -> {
|
// userAccountRespList.forEach(userAccountResp -> {
|
||||||
if (StringUtils.isNotEmpty(userAccountResp.getImAccount())
|
// if (StringUtils.isNotEmpty(userAccountResp.getImAccount())
|
||||||
&& StringUtils.isNotEmpty(userAccountResp.getToken())) {
|
// && StringUtils.isNotEmpty(userAccountResp.getToken())) {
|
||||||
toPersonIMList.add(userAccountResp.getImAccount());
|
// toPersonIMList.add(userAccountResp.getImAccount());
|
||||||
imAccount2PersonId.put(userAccountResp.getImAccount(), sourcePersonId);
|
// imAccount2PersonId.put(userAccountResp.getImAccount(), sourcePersonId);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
log.warn("发送IM消息异常,不存在personId=[" + sourcePersonId + "]的IM账户");
|
// log.warn("发送IM消息异常,不存在personId=[" + sourcePersonId + "]的IM账户");
|
||||||
MessageDispatchResp resp = new MessageDispatchResp();
|
// MessageDispatchResp resp = new MessageDispatchResp();
|
||||||
resp.setAppType(appType);
|
// resp.setAppType(appType);
|
||||||
resp.setTimetag(System.currentTimeMillis());
|
// resp.setTimetag(System.currentTimeMillis());
|
||||||
resp.setFromImAccount(messageRequest.getFrom());
|
// resp.setFromImAccount(messageRequest.getFrom());
|
||||||
resp.setToImAccount(messageRequest.getTo());
|
// resp.setToImAccount(messageRequest.getTo());
|
||||||
resp.setPersonId(sourcePersonId);
|
// resp.setPersonId(sourcePersonId);
|
||||||
resp.setSendFailCause("personId=" + sourcePersonId + ", 未注册IM账户");
|
// resp.setSendFailCause("personId=" + sourcePersonId + ", 未注册IM账户");
|
||||||
messageDispatchRespList.add(resp);
|
// messageDispatchRespList.add(resp);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
List<List<String>> personPage = Lists.partition(toPersonIMList, msgSendPersonOfOneBatch);
|
// List<List<String>> personPage = Lists.partition(toPersonIMList, msgSendPersonOfOneBatch);
|
||||||
MessageBatchDispatchRequest batchDispatchRequest = new MessageBatchDispatchRequest();
|
// MessageBatchDispatchRequest batchDispatchRequest = new MessageBatchDispatchRequest();
|
||||||
batchDispatchRequest.setBody(messageRequest.getBody());
|
// batchDispatchRequest.setBody(messageRequest.getBody());
|
||||||
batchDispatchRequest.setFromAccid(fromAccId);
|
// batchDispatchRequest.setFromAccid(fromAccId);
|
||||||
personPage.forEach(imAccountList -> {
|
// personPage.forEach(imAccountList -> {
|
||||||
batchDispatchRequest.setToAccids(imAccountList);
|
// batchDispatchRequest.setToAccids(imAccountList);
|
||||||
MessageBatchDispatchResponse batchResponse = imChannel.dispatchBatchMessage(batchDispatchRequest);
|
// MessageBatchDispatchResponse batchResponse = imChannel.dispatchBatchMessage(batchDispatchRequest);
|
||||||
if (batchResponse != null) {
|
// if (batchResponse != null) {
|
||||||
Map<String, Long> userMsgResponseMap = batchResponse.getMsgids();
|
// Map<String, Long> userMsgResponseMap = batchResponse.getMsgids();
|
||||||
if (userMsgResponseMap != null) {
|
// if (userMsgResponseMap != null) {
|
||||||
//遍历批量返回中每一个账户对应的MessageId
|
// //遍历批量返回中每一个账户对应的MessageId
|
||||||
userMsgResponseMap.forEach((imAccount, messageId) -> {
|
// userMsgResponseMap.forEach((imAccount, messageId) -> {
|
||||||
String personId = imAccount2PersonId.get(imAccount);
|
// String personId = imAccount2PersonId.get(imAccount);
|
||||||
MessageDispatchResp messageDispatchResp =
|
// MessageDispatchResp messageDispatchResp =
|
||||||
buildMessageDispatchResp(String.valueOf(messageId), fromAccId,
|
// buildMessageDispatchResp(String.valueOf(messageId), fromAccId,
|
||||||
imAccount, personId, appType, batchResponse.getTimetag(), null);
|
// imAccount, personId, appType, batchResponse.getTimetag(), null);
|
||||||
messageDispatchRespList.add(messageDispatchResp);
|
// messageDispatchRespList.add(messageDispatchResp);
|
||||||
});
|
// });
|
||||||
} else if (StringUtils.isNotBlank(batchResponse.getDesc())) {
|
// } else if (StringUtils.isNotBlank(batchResponse.getDesc())) {
|
||||||
for (String imAccount : imAccountList) {
|
// for (String imAccount : imAccountList) {
|
||||||
String personId = imAccount2PersonId.get(imAccount);
|
// String personId = imAccount2PersonId.get(imAccount);
|
||||||
MessageDispatchResp messageDispatchResp =
|
// MessageDispatchResp messageDispatchResp =
|
||||||
buildMessageDispatchResp(null, fromAccId,
|
// buildMessageDispatchResp(null, fromAccId,
|
||||||
imAccount, personId, appType, batchResponse.getTimetag(), batchResponse.getDesc());
|
// imAccount, personId, appType, batchResponse.getTimetag(), batchResponse.getDesc());
|
||||||
messageDispatchRespList.add(messageDispatchResp);
|
// messageDispatchRespList.add(messageDispatchResp);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
log.error("dispatchBatchMessage请求返回出现异常:{}", JSONUtil.toJsonStr(batchResponse));
|
// log.error("dispatchBatchMessage请求返回出现异常:{}", JSONUtil.toJsonStr(batchResponse));
|
||||||
}
|
// }
|
||||||
//返回未注册的IM账户
|
// //返回未注册的IM账户
|
||||||
Set<String> unregisterAccountSets = batchResponse.getUnregister();
|
// Set<String> unregisterAccountSets = batchResponse.getUnregister();
|
||||||
//字符串转义字符处理
|
// //字符串转义字符处理
|
||||||
if (CollectionUtils.isNotEmpty(unregisterAccountSets)) {
|
// if (CollectionUtils.isNotEmpty(unregisterAccountSets)) {
|
||||||
unregisterAccountSets = unregisterAccountSets.stream()
|
// unregisterAccountSets = unregisterAccountSets.stream()
|
||||||
.map(account -> account.replace("\"", "")).collect(Collectors.toSet());
|
// .map(account -> account.replace("\"", "")).collect(Collectors.toSet());
|
||||||
unregisterAccountSets.forEach(unregisterAccount -> {
|
// unregisterAccountSets.forEach(unregisterAccount -> {
|
||||||
MessageDispatchResp messageDispatchResp = buildMessageDispatchResp(null, fromAccId,
|
// MessageDispatchResp messageDispatchResp = buildMessageDispatchResp(null, fromAccId,
|
||||||
unregisterAccount, null, appType, batchResponse.getTimetag(), null);
|
// unregisterAccount, null, appType, batchResponse.getTimetag(), null);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
log.error("dispatchBatchMessage请求返回出现异常");
|
// log.error("dispatchBatchMessage请求返回出现异常");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
return messageDispatchRespList;
|
// return messageDispatchRespList;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private MessageDispatchResp buildMessageDispatchResp(String messageId, String fromImAccount, String toImAccount, String personId,
|
private MessageDispatchResp buildMessageDispatchResp(String messageId, String fromImAccount, String toImAccount, String personId,
|
||||||
String appType, Long timeTag, String desc) {
|
String appType, Long timeTag, String desc) {
|
||||||
@ -304,62 +314,62 @@ public class MessageService {
|
|||||||
return messageDispatchResp;
|
return messageDispatchResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MessageDispatchResp> sendOneByOneMessage(MessageInfo messageInfo, MessageDispatchRequest messageRequest) {
|
// private List<MessageDispatchResp> sendOneByOneMessage(SendMessageParam sendMessageParam, MessageDispatchRequest messageRequest) {
|
||||||
//如果消息模板是针对多App端,则分开进行发送消息
|
// //如果消息模板是针对多App端,则分开进行发送消息
|
||||||
List<AppTypeEnum> appTypeList = messageInfo.getAppTypeList();
|
// List<AppTypeEnum> appTypeList = sendMessageParam.getAppTypeList();
|
||||||
List<MessageDispatchResp> messageDispatchRespList = Lists.newArrayList();
|
// List<MessageDispatchResp> messageDispatchRespList = Lists.newArrayList();
|
||||||
appTypeList.forEach(appType -> {
|
// appTypeList.forEach(appType -> {
|
||||||
if (appType == null || AppTypeEnum.isValidAppType(appType.getCode()) == null) {
|
// if (appType == null || AppTypeEnum.isValidAppType(appType.getCode()) == null) {
|
||||||
throw new ServiceException("当前服务器不支持该appType类型!");
|
// throw new ServiceException("当前服务器不支持该appType类型!");
|
||||||
}
|
// }
|
||||||
List<String> toPersonList = Lists.newArrayList(messageInfo.getToPersonIdList());
|
// List<String> toPersonList = Lists.newArrayList(sendMessageParam.getToPersonIdList());
|
||||||
//进行接收用户IM账户校验 目前支持单个用户进行IM消息发送,多个IM用户进行消息接收
|
// //进行接收用户IM账户校验 目前支持单个用户进行IM消息发送,多个IM用户进行消息接收
|
||||||
for (String personId : toPersonList) {
|
// for (String personId : toPersonList) {
|
||||||
List<AccountRegister> accountRegisterList = accountRegisterDao.lambdaQuery().eq(AccountRegister::getIsDelete, 0)
|
// List<AccountRegister> accountRegisterList = accountRegisterDao.lambdaQuery().eq(AccountRegister::getIsDelete, 0)
|
||||||
.eq(AccountRegister::getAccountId, personId)
|
// .eq(AccountRegister::getAccountId, personId)
|
||||||
.eq(AccountRegister::getAppKey, imChannel.getProviderAppKey())
|
// .eq(AccountRegister::getAppKey, imChannel.getProviderAppKey())
|
||||||
.isNotNull(AccountRegister::getToken)
|
// .isNotNull(AccountRegister::getToken)
|
||||||
.eq(AccountRegister::getAppType, appType.getCode()).list();
|
// .eq(AccountRegister::getAppType, appType.getCode()).list();
|
||||||
if (CollectionUtils.isEmpty(accountRegisterList)) {
|
// if (CollectionUtils.isEmpty(accountRegisterList)) {
|
||||||
//返回未注册的IM账户信息
|
// //返回未注册的IM账户信息
|
||||||
MessageDispatchResp messageDispatchResp = buildMessageDispatchResp(null,
|
// MessageDispatchResp messageDispatchResp = buildMessageDispatchResp(null,
|
||||||
messageRequest.getFrom(), null,
|
// messageRequest.getFrom(), null,
|
||||||
personId, appType.getCode(), 0L, "unregistered");
|
// personId, appType.getCode(), 0L, "unregistered");
|
||||||
log.warn("用户personId=[" + personId + "],appType[" + appType.getCode() + "],未注册IM账户,不进行消息发送!");
|
// log.warn("用户personId=[" + personId + "],appType[" + appType.getCode() + "],未注册IM账户,不进行消息发送!");
|
||||||
MessageDispatchResp resp = new MessageDispatchResp();
|
// MessageDispatchResp resp = new MessageDispatchResp();
|
||||||
resp.setAppType(appType.getCode());
|
// resp.setAppType(appType.getCode());
|
||||||
resp.setTimetag(System.currentTimeMillis());
|
// resp.setTimetag(System.currentTimeMillis());
|
||||||
resp.setFromImAccount(messageRequest.getFrom());
|
// resp.setFromImAccount(messageRequest.getFrom());
|
||||||
resp.setToImAccount(messageRequest.getTo());
|
// resp.setToImAccount(messageRequest.getTo());
|
||||||
resp.setPersonId(personId);
|
// resp.setPersonId(personId);
|
||||||
resp.setSendFailCause("personId=" + personId + ",未注册IM账户");
|
// resp.setSendFailCause("personId=" + personId + ",未注册IM账户");
|
||||||
messageDispatchRespList.add(resp);
|
// messageDispatchRespList.add(resp);
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
accountRegisterList.forEach(accountRegister -> {
|
// accountRegisterList.forEach(accountRegister -> {
|
||||||
if (StringUtils.isNotEmpty(accountRegister.getImAccount()) &&
|
// if (StringUtils.isNotEmpty(accountRegister.getImAccount()) &&
|
||||||
StringUtils.isNotEmpty(accountRegister.getToken())) {
|
// StringUtils.isNotEmpty(accountRegister.getToken())) {
|
||||||
messageRequest.setTo(accountRegister.getImAccount());
|
// messageRequest.setTo(accountRegister.getImAccount());
|
||||||
messageRequest.setType(ChannelMsgTypeEnum.CUSTOM.getCode());
|
// messageRequest.setType(ChannelMsgTypeEnum.CUSTOM.getCode());
|
||||||
MessageDispatchResponse response = imChannel.dispatchMessage(messageRequest);
|
// MessageDispatchResponse response = imChannel.dispatchMessage(messageRequest);
|
||||||
MessageDispatchResp messageDispatchResp = BeanMapper.map(response.getData(), MessageDispatchResp.class);
|
// MessageDispatchResp messageDispatchResp = BeanMapper.map(response.getData(), MessageDispatchResp.class);
|
||||||
if (messageDispatchResp == null) {
|
// if (messageDispatchResp == null) {
|
||||||
messageDispatchResp = new MessageDispatchResp();
|
// messageDispatchResp = new MessageDispatchResp();
|
||||||
}
|
// }
|
||||||
if (StringUtils.isNotBlank(response.getDesc())) {
|
// if (StringUtils.isNotBlank(response.getDesc())) {
|
||||||
messageDispatchResp.setDesc(response.getDesc());
|
// messageDispatchResp.setDesc(response.getDesc());
|
||||||
}
|
// }
|
||||||
messageDispatchResp.setAppType(appType.getCode());
|
// messageDispatchResp.setAppType(appType.getCode());
|
||||||
messageDispatchResp.setFromImAccount(messageRequest.getFrom());
|
// messageDispatchResp.setFromImAccount(messageRequest.getFrom());
|
||||||
messageDispatchResp.setToImAccount(accountRegister.getImAccount());
|
// messageDispatchResp.setToImAccount(accountRegister.getImAccount());
|
||||||
messageDispatchResp.setPersonId(personId);
|
// messageDispatchResp.setPersonId(personId);
|
||||||
messageDispatchRespList.add(messageDispatchResp);
|
// messageDispatchRespList.add(messageDispatchResp);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
return messageDispatchRespList;
|
// return messageDispatchRespList;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void insertImMessage(List<MessageDispatchResp> messageRespList, String messageBody) {
|
private void insertImMessage(List<MessageDispatchResp> messageRespList, String messageBody) {
|
||||||
if (CollectionUtils.isEmpty(messageRespList)) {
|
if (CollectionUtils.isEmpty(messageRespList)) {
|
||||||
@ -487,7 +497,7 @@ public class MessageService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static MessageCustomBody wrapperCustomMessage(String toImAccount,
|
public static MessageCustomBody wrapperCustomMessage(String toImAccount,
|
||||||
CustomMessageInfo customMessage) {
|
CustomMessageInfo customMessage) {
|
||||||
return MessageCustomBody.builder()
|
return MessageCustomBody.builder()
|
||||||
.toImAccount(toImAccount)
|
.toImAccount(toImAccount)
|
||||||
.personId(customMessage.getToPersonId())
|
.personId(customMessage.getToPersonId())
|
||||||
|
|||||||
@ -0,0 +1,85 @@
|
|||||||
|
package cn.axzo.im.service;
|
||||||
|
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import cn.axzo.im.entity.MessageTask;
|
||||||
|
import cn.axzo.pokonyan.dao.page.IPageParam;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.Operator;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MessageTaskService extends IService<MessageTask> {
|
||||||
|
|
||||||
|
MessageTask create(MessageTask param);
|
||||||
|
|
||||||
|
Page<MessageTask> page(PageMessageTaskParam param);
|
||||||
|
|
||||||
|
void createMessageHistory(MessageTask messageTask);
|
||||||
|
|
||||||
|
void update(UpdateMessageTaskParam param);
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class UpdateMessageTaskParam {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private MessageTask.ActionEnum action;
|
||||||
|
|
||||||
|
private Date startedTime;
|
||||||
|
|
||||||
|
private Date finishedTime;
|
||||||
|
|
||||||
|
public MessageTask to() {
|
||||||
|
return MessageTask.builder()
|
||||||
|
.id(this.getId())
|
||||||
|
.startedTime(this.getStartedTime())
|
||||||
|
.finishedTime(this.getFinishedTime())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListMessageTaskParam {
|
||||||
|
|
||||||
|
@CriteriaField(field = "id", operator = Operator.IN)
|
||||||
|
private List<Long> ids;
|
||||||
|
|
||||||
|
@CriteriaField(field = "planStartTime", operator = Operator.LE)
|
||||||
|
private Date planStartTimeLE;
|
||||||
|
|
||||||
|
@CriteriaField(field = "status", operator = Operator.EQ)
|
||||||
|
private MessageTask.Status status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageMessageTaskParam extends ListMessageTaskParam implements IPageParam {
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer page;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -153,7 +154,14 @@ public class RobotInfoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PageResp<RobotInfoResp> queryRobotInfoList(RobotPageQuery robotInfoQuery) {
|
public PageResp<RobotInfoResp> queryRobotInfoList(RobotPageQuery robotInfoQuery) {
|
||||||
IPage<RobotInfo> robotInfoPage = robotInfoDao.queryRobotInfoOfPage(robotInfoQuery);
|
|
||||||
|
List<String> robotIds = resolveRobotIds(robotInfoQuery);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(robotInfoQuery.getMsgTemplateCode()) && CollectionUtils.isEmpty(robotIds)) {
|
||||||
|
return PageResp.zero(robotInfoQuery.getPage(), robotInfoQuery.getPageSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
IPage<RobotInfo> robotInfoPage = robotInfoDao.queryRobotInfoOfPage(robotInfoQuery, robotIds);
|
||||||
List<RobotInfoResp> robotInfoRespList = BeanMapper.copyList(robotInfoPage.getRecords(), RobotInfoResp.class);
|
List<RobotInfoResp> robotInfoRespList = BeanMapper.copyList(robotInfoPage.getRecords(), RobotInfoResp.class);
|
||||||
PageResp<RobotInfoResp> pageOfRobotInfoResp = PageResp.list(robotInfoPage.getCurrent(), robotInfoPage.getSize(),
|
PageResp<RobotInfoResp> pageOfRobotInfoResp = PageResp.list(robotInfoPage.getCurrent(), robotInfoPage.getSize(),
|
||||||
robotInfoPage.getTotal(), robotInfoRespList);
|
robotInfoPage.getTotal(), robotInfoRespList);
|
||||||
@ -178,6 +186,14 @@ public class RobotInfoService {
|
|||||||
return pageOfRobotInfoResp;
|
return pageOfRobotInfoResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> resolveRobotIds(RobotPageQuery robotInfoQuery) {
|
||||||
|
if (StringUtils.isBlank(robotInfoQuery.getMsgTemplateCode())) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
// todo 这里查询也需要优化,现在是把所有数据查询出来过滤的,数据量过大的情况下会有性能和内存影响
|
||||||
|
return templateService.queryRobotIdByTemplate(robotInfoQuery.getMsgTemplateCode());
|
||||||
|
}
|
||||||
|
|
||||||
public List<RobotInfoResp> queryRunningRobotList() {
|
public List<RobotInfoResp> queryRunningRobotList() {
|
||||||
List<RobotInfo> runningRobots = robotInfoDao.queryRunningRobotList();
|
List<RobotInfo> runningRobots = robotInfoDao.queryRunningRobotList();
|
||||||
if (CollectionUtils.isEmpty(runningRobots)) {
|
if (CollectionUtils.isEmpty(runningRobots)) {
|
||||||
|
|||||||
@ -0,0 +1,89 @@
|
|||||||
|
package cn.axzo.im.service;
|
||||||
|
|
||||||
|
import cn.axzo.im.center.api.vo.resp.RobotTagResp;
|
||||||
|
import cn.axzo.im.center.common.enums.RobotStatusEnum;
|
||||||
|
import cn.axzo.im.entity.RobotInfo;
|
||||||
|
import cn.axzo.pokonyan.dao.page.IPageParam;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
|
||||||
|
import cn.axzo.pokonyan.dao.wrapper.Operator;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public interface RobotInfoV2Service extends IService<RobotInfo> {
|
||||||
|
|
||||||
|
Page<RobotInfoDTO> page(PageRobotInfoParam param);
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListRobotInfoParam {
|
||||||
|
|
||||||
|
@CriteriaField(field = "nickName", operator = Operator.LIKE)
|
||||||
|
private String nickNameLike;
|
||||||
|
|
||||||
|
@CriteriaField(field = "status", operator = Operator.EQ)
|
||||||
|
private RobotStatusEnum status;
|
||||||
|
|
||||||
|
@CriteriaField(field = "imAccount", operator = Operator.IN)
|
||||||
|
private List<String> imAccounts;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
private boolean needRobotTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class PageRobotInfoParam extends ListRobotInfoParam implements IPageParam {
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer pageNumber;
|
||||||
|
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
Integer pageSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序:使用示例,createTime__DESC
|
||||||
|
*/
|
||||||
|
@CriteriaField(ignore = true)
|
||||||
|
List<String> sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class RobotInfoDTO extends RobotInfo {
|
||||||
|
|
||||||
|
private List<RobotTagResp> robotTags;
|
||||||
|
|
||||||
|
public static RobotInfoDTO from(RobotInfo robotInfo,
|
||||||
|
Map<Long, RobotTagResp> robotTags) {
|
||||||
|
RobotInfoDTO robotInfoDTO = RobotInfoDTO.builder().build();
|
||||||
|
BeanUtils.copyProperties(robotInfo, robotInfoDTO);
|
||||||
|
|
||||||
|
|
||||||
|
List<RobotTagResp> robotTagResps = Optional.ofNullable(robotInfoDTO.getTagNameList())
|
||||||
|
.map(tagIds ->
|
||||||
|
tagIds.stream()
|
||||||
|
.map(robotTags::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
).orElse(null);
|
||||||
|
robotInfoDTO.setRobotTags(robotTagResps);
|
||||||
|
return robotInfoDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
package cn.axzo.im.service.impl;
|
||||||
|
|
||||||
|
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
|
||||||
|
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||||
|
import cn.axzo.im.center.common.enums.AccountTypeEnum;
|
||||||
|
import cn.axzo.im.channel.IMChannelProvider;
|
||||||
|
import cn.axzo.im.dao.mapper.AccountRegisterMapper;
|
||||||
|
import cn.axzo.im.entity.AccountRegister;
|
||||||
|
import cn.axzo.im.service.AccountRegisterService;
|
||||||
|
import cn.axzo.maokai.api.client.OrganizationalUnitApi;
|
||||||
|
import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||||
|
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class AccountRegisterServiceImpl extends ServiceImpl<AccountRegisterMapper, AccountRegister>
|
||||||
|
implements AccountRegisterService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMChannelProvider imChannelProvider;
|
||||||
|
@Autowired
|
||||||
|
private OrganizationalUnitApi organizationalUnitApi;
|
||||||
|
@Autowired
|
||||||
|
private UserProfileServiceApi userProfileServiceApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<AccountRegisterDTO> page(PageAccountRegisterParam param) {
|
||||||
|
QueryWrapper<AccountRegister> wrapper = QueryWrapperHelper.fromBean(param, AccountRegister.class);
|
||||||
|
// 只能取配置的appKey的数据,防止接口使用方没传appKey导致获取错乱的数据
|
||||||
|
wrapper.eq("app_key", imChannelProvider.getProviderAppKey());
|
||||||
|
wrapper.eq("is_delete", 0);
|
||||||
|
|
||||||
|
Page<AccountRegister> page = this.page(PageConverter.convertToMybatis(param, AccountRegister.class), wrapper);
|
||||||
|
|
||||||
|
Map<String, PersonProfileDto> personProfiles = listUserPersonProfile(param, page.getRecords());
|
||||||
|
|
||||||
|
Map<Long, OrganizationalUnitVO> organizationals = listOrganizational(param, page.getRecords());
|
||||||
|
|
||||||
|
return PageConverter.convert(page, (record) -> AccountRegisterDTO.from(record,
|
||||||
|
personProfiles,
|
||||||
|
organizationals));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AccountRegisterDTO> list(ListAccountRegisterParam param) {
|
||||||
|
return PageConverter.drainAll(pageNumber -> {
|
||||||
|
PageAccountRegisterParam pageParam = PageAccountRegisterParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, pageParam);
|
||||||
|
pageParam.setPage(pageNumber);
|
||||||
|
pageParam.setPageSize(500);
|
||||||
|
return page(pageParam);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, PersonProfileDto> listUserPersonProfile(PageAccountRegisterParam param,
|
||||||
|
List<AccountRegister> accountRegisters) {
|
||||||
|
if (CollectionUtils.isEmpty(accountRegisters) || BooleanUtils.isNotTrue(param.isNeedUserInfo())) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> personIds = accountRegisters.stream()
|
||||||
|
.filter(e -> Objects.equals(e.getAccountType(), AccountTypeEnum.USER.getCode()))
|
||||||
|
.map(AccountRegister::getAccountId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(StringUtils::isNumeric)
|
||||||
|
.map(Long::valueOf)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(personIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return userProfileServiceApi.postPersonProfiles(personIds).getData()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(e -> e.getId().toString(), Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, OrganizationalUnitVO> listOrganizational(PageAccountRegisterParam param,
|
||||||
|
List<AccountRegister> accountRegisters) {
|
||||||
|
if (CollectionUtils.isEmpty(accountRegisters) || BooleanUtils.isNotTrue(param.isNeedOuInfo())) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> ouIds = accountRegisters.stream()
|
||||||
|
.map(AccountRegister::getOuId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(ouIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return organizationalUnitApi.page(OrganizationalUnitQuery.builder().unitIds(ouIds).build())
|
||||||
|
.getData()
|
||||||
|
.getList()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(OrganizationalUnitVO::getId, Function.identity(), (f, s) -> f));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,278 @@
|
|||||||
|
package cn.axzo.im.service.impl;
|
||||||
|
|
||||||
|
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
|
||||||
|
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.im.channel.IMChannelProvider;
|
||||||
|
import cn.axzo.im.channel.netease.dto.MessageBatchDispatchRequest;
|
||||||
|
import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse;
|
||||||
|
import cn.axzo.im.config.MqProducer;
|
||||||
|
import cn.axzo.im.dao.mapper.MessageHistoryMapper;
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import cn.axzo.im.event.payload.MessageHistoryCreatedPayload;
|
||||||
|
import cn.axzo.im.event.payload.MessageHistoryUpdatedPayload;
|
||||||
|
import cn.axzo.im.service.MessageHistoryService;
|
||||||
|
import cn.axzo.maokai.api.client.OrganizationalUnitApi;
|
||||||
|
import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||||
|
import cn.axzo.pokonyan.client.RateLimiter;
|
||||||
|
import cn.axzo.pokonyan.client.RateLimiterClient;
|
||||||
|
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||||
|
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.axzo.im.config.BizResultCode.ACQUIRE_RATE_LIMITER_FAIL;
|
||||||
|
import static cn.axzo.im.event.inner.EventTypeEnum.MESSAGE_HISTORY_CREATED;
|
||||||
|
import static cn.axzo.im.event.inner.EventTypeEnum.MESSAGE_HISTORY_UPDATED;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MessageHistoryServiceImpl extends ServiceImpl<MessageHistoryMapper, MessageHistory>
|
||||||
|
implements MessageHistoryService, InitializingBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrganizationalUnitApi organizationalUnitApi;
|
||||||
|
@Autowired
|
||||||
|
private UserProfileServiceApi userProfileServiceApi;
|
||||||
|
@Autowired
|
||||||
|
private RateLimiterClient rateLimiterClient;
|
||||||
|
@Autowired
|
||||||
|
private IMChannelProvider imChannelProvider;
|
||||||
|
@Autowired
|
||||||
|
private MqProducer mqProducer;
|
||||||
|
|
||||||
|
@Value("${send.message.limiter.permits}")
|
||||||
|
private int permits;
|
||||||
|
|
||||||
|
@Value("${send.message.limiter.seconds}")
|
||||||
|
private long seconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网易云信IM批量发送-每批次发送给多少用户
|
||||||
|
*/
|
||||||
|
@Value("${im-center.message.batch.receiver.once:10}")
|
||||||
|
public int msgSendPersonOfOneBatch;
|
||||||
|
|
||||||
|
private RateLimiter rateLimiter;
|
||||||
|
|
||||||
|
private static final String LIMITER_KEY = "im-center:sendMessage";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认超时时间(毫秒)
|
||||||
|
*/
|
||||||
|
private static final long DEFAULT_TIME_OUT_MILLIS = 60 * 1000;
|
||||||
|
|
||||||
|
private static final String TARGET_TYPE = "messageHistoryId";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<MessageHistoryDTO> page(PageMessageHistoryParam param) {
|
||||||
|
QueryWrapper<MessageHistory> wrapper = QueryWrapperHelper.fromBean(param, MessageHistory.class);
|
||||||
|
// 只能取配置的appKey的数据,防止接口使用方没传appKey导致获取错乱的数据
|
||||||
|
wrapper.eq("is_delete", 0);
|
||||||
|
|
||||||
|
Page<MessageHistory> page = this.page(PageConverter.convertToMybatis(param, MessageHistory.class), wrapper);
|
||||||
|
|
||||||
|
Map<String, PersonProfileDto> personProfiles = listReceiveUserPersonProfile(param, page.getRecords());
|
||||||
|
|
||||||
|
Map<Long, OrganizationalUnitVO> organizationals = listReceiveOrganizational(param, page.getRecords());
|
||||||
|
|
||||||
|
return PageConverter.convert(page, (record) -> MessageHistoryDTO.from(record,
|
||||||
|
personProfiles,
|
||||||
|
organizationals));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MessageHistoryDTO> list(ListMessageHistoryParam param) {
|
||||||
|
return PageConverter.drainAll(pageNumber -> {
|
||||||
|
PageMessageHistoryParam pageParam = PageMessageHistoryParam.builder().build();
|
||||||
|
BeanUtils.copyProperties(param, pageParam);
|
||||||
|
pageParam.setPage(pageNumber);
|
||||||
|
pageParam.setPageSize(500);
|
||||||
|
return page(pageParam);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void createBatch(List<MessageHistory> messageHistories) {
|
||||||
|
|
||||||
|
this.saveBatch(messageHistories);
|
||||||
|
|
||||||
|
List<Event> events = this.listByIds(Lists.transform(messageHistories, MessageHistory::getId))
|
||||||
|
.stream()
|
||||||
|
.map(messageHistory ->
|
||||||
|
Event.builder()
|
||||||
|
.targetId(String.valueOf(messageHistory.getId()))
|
||||||
|
.targetType(TARGET_TYPE)
|
||||||
|
.eventCode(MESSAGE_HISTORY_CREATED.getEventCode())
|
||||||
|
.data(MessageHistoryCreatedPayload.builder()
|
||||||
|
.messageHistory(messageHistory)
|
||||||
|
.build())
|
||||||
|
.build())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
mqProducer.sendBatch(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateBatch(List<MessageHistory> messageHistories) {
|
||||||
|
|
||||||
|
Map<Long, MessageHistory> oldMessageHistories = this.listByIds(Lists.transform(messageHistories, MessageHistory::getId))
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(MessageHistory::getId, Function.identity()));
|
||||||
|
|
||||||
|
this.updateBatchById(messageHistories);
|
||||||
|
|
||||||
|
List<Event> events = this.listByIds(Lists.transform(messageHistories, MessageHistory::getId))
|
||||||
|
.stream()
|
||||||
|
.map(messageHistory -> Event.builder()
|
||||||
|
.targetId(String.valueOf(messageHistory.getId()))
|
||||||
|
.targetType(TARGET_TYPE)
|
||||||
|
.eventCode(MESSAGE_HISTORY_UPDATED.getEventCode())
|
||||||
|
.data(MessageHistoryUpdatedPayload.builder()
|
||||||
|
.newMessageHistory(messageHistory)
|
||||||
|
.oldMessageHistory(oldMessageHistories.get(messageHistory.getId()))
|
||||||
|
.build())
|
||||||
|
.build())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
mqProducer.sendBatch(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void sendMessage(List<MessageHistoryService.MessageHistoryDTO> messageHistories) {
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(messageHistories)) {
|
||||||
|
log.info("发送的消息记录为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 三方接口调用频率120次/分,超限将限制1分钟使用,所以抛出异常,等待下一次xxlJob做重试补偿
|
||||||
|
if (!rateLimiter.tryAcquire(DEFAULT_TIME_OUT_MILLIS)) {
|
||||||
|
log.info("未获得令牌");
|
||||||
|
throw ACQUIRE_RATE_LIMITER_FAIL.toException();
|
||||||
|
}
|
||||||
|
log.info("获得令牌");
|
||||||
|
MessageHistoryDTO messageHistoryDTO = messageHistories.stream().findFirst().get();
|
||||||
|
MessageBatchDispatchRequest batchDispatchRequest = new MessageBatchDispatchRequest();
|
||||||
|
batchDispatchRequest.setBody(messageHistoryDTO.getMessageBody());
|
||||||
|
batchDispatchRequest.setFromAccid(messageHistoryDTO.getFromAccount());
|
||||||
|
batchDispatchRequest.setToAccids(Lists.transform(messageHistories, MessageHistoryService.MessageHistoryDTO::getToAccount));
|
||||||
|
MessageBatchDispatchResponse response = imChannelProvider.dispatchBatchMessage(batchDispatchRequest);
|
||||||
|
|
||||||
|
if (response.isSuccess()) {
|
||||||
|
// 发送成功的IMAccountId -> msgId
|
||||||
|
Map<String, Long> msgids = response.getMsgids();
|
||||||
|
// unregister的账号
|
||||||
|
Set<String> unregister = Optional.ofNullable(response.getUnregister())
|
||||||
|
.orElseGet(Sets::newHashSet);
|
||||||
|
|
||||||
|
List<MessageHistory> updateMessageHistories = messageHistories.stream()
|
||||||
|
.map(e -> {
|
||||||
|
MessageHistory messageHistory = MessageHistory.builder()
|
||||||
|
.id(e.getId())
|
||||||
|
.build();
|
||||||
|
if (unregister.contains(e.getToAccount())) {
|
||||||
|
messageHistory.setStatus(MessageHistory.Status.FAILED);
|
||||||
|
messageHistory.setResult("IM账号未在网易云信注册");
|
||||||
|
} else {
|
||||||
|
messageHistory.setStatus(MessageHistory.Status.SUCCEED);
|
||||||
|
messageHistory.setMessageId(msgids.get(e.getToAccount()).toString());
|
||||||
|
}
|
||||||
|
return messageHistory;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
this.updateBatch(updateMessageHistories);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MessageHistory> failedMessageHistories = messageHistories.stream()
|
||||||
|
.map(e -> MessageHistory.builder()
|
||||||
|
.id(e.getId())
|
||||||
|
.result(response.getDesc())
|
||||||
|
.status(MessageHistory.Status.FAILED)
|
||||||
|
.build())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
this.updateBatch(failedMessageHistories);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, PersonProfileDto> listReceiveUserPersonProfile(PageMessageHistoryParam param,
|
||||||
|
List<MessageHistory> messageHistories) {
|
||||||
|
if (CollectionUtils.isEmpty(messageHistories) || BooleanUtils.isNotTrue(param.isNeedReceiveUserInfo())) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> personIds = messageHistories.stream()
|
||||||
|
.map(MessageHistory::getReceivePersonId)
|
||||||
|
.filter(StringUtils::isNumeric)
|
||||||
|
.map(Long::valueOf)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(personIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return userProfileServiceApi.postPersonProfiles(personIds).getData()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(e -> e.getId().toString(), Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, OrganizationalUnitVO> listReceiveOrganizational(PageMessageHistoryParam param,
|
||||||
|
List<MessageHistory> messageHistories) {
|
||||||
|
if (CollectionUtils.isEmpty(messageHistories) || BooleanUtils.isNotTrue(param.isNeedReceiveOuInfo())) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> ouIds = messageHistories.stream()
|
||||||
|
.map(MessageHistory::getReceiveOuId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(ouIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return organizationalUnitApi.page(OrganizationalUnitQuery.builder().unitIds(ouIds).build())
|
||||||
|
.getData()
|
||||||
|
.getList()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(OrganizationalUnitVO::getId, Function.identity(), (f, s) -> f));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
rateLimiter = rateLimiterClient.build(RateLimiterClient.RateLimiterReq.builder()
|
||||||
|
.windowType(RateLimiter.WindowType.SLIDING)
|
||||||
|
.limiterKey(LIMITER_KEY)
|
||||||
|
.rule(RateLimiter.LimitRule.builder()
|
||||||
|
.permits(permits)
|
||||||
|
.seconds(seconds)
|
||||||
|
.build())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,389 @@
|
|||||||
|
package cn.axzo.im.service.impl;
|
||||||
|
|
||||||
|
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||||
|
import cn.axzo.im.center.api.vo.req.SendMessageParam;
|
||||||
|
import cn.axzo.im.center.common.enums.AccountTypeEnum;
|
||||||
|
import cn.axzo.im.center.common.enums.AppTypeEnum;
|
||||||
|
import cn.axzo.im.channel.IMChannelProvider;
|
||||||
|
import cn.axzo.im.channel.netease.NimMsgTypeEnum;
|
||||||
|
import cn.axzo.im.channel.netease.dto.MessageBody;
|
||||||
|
import cn.axzo.im.dao.mapper.MessageTaskMapper;
|
||||||
|
import cn.axzo.im.entity.AccountRegister;
|
||||||
|
import cn.axzo.im.entity.MessageHistory;
|
||||||
|
import cn.axzo.im.entity.MessageTask;
|
||||||
|
import cn.axzo.im.service.AccountRegisterService;
|
||||||
|
import cn.axzo.im.service.MessageHistoryService;
|
||||||
|
import cn.axzo.im.service.MessageTaskService;
|
||||||
|
import cn.axzo.maokai.api.client.OrganizationalTeamOuRelationApi;
|
||||||
|
import cn.axzo.maokai.api.vo.request.OrganizationalTeamOuRelationReq;
|
||||||
|
import cn.axzo.maokai.api.vo.response.OrganizationalTeamOuRelationResp;
|
||||||
|
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||||
|
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
|
||||||
|
import cn.axzo.pokonyan.exception.Aassert;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.axzo.im.config.BizResultCode.MESSAGE_TASK_NOT_FOUND;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MessageTaskServiceImpl extends ServiceImpl<MessageTaskMapper, MessageTask>
|
||||||
|
implements MessageTaskService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMChannelProvider imChannelProvider;
|
||||||
|
@Autowired
|
||||||
|
private AccountRegisterService accountRegisterService;
|
||||||
|
@Autowired
|
||||||
|
private MessageHistoryService messageHistoryService;
|
||||||
|
@Autowired
|
||||||
|
private OrganizationalTeamOuRelationApi organizationalTeamOuRelationApi;
|
||||||
|
|
||||||
|
private static final Integer DEFAULT_PAGE_SIZE = 500;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public MessageTask create(MessageTask param) {
|
||||||
|
// 未设置计划执行时间,则计划时间为当前时间,xxlJob可立即执行
|
||||||
|
if (param.getPlanStartTime() == null) {
|
||||||
|
param.setPlanStartTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.save(param);
|
||||||
|
return this.getById(param.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<MessageTask> page(PageMessageTaskParam param) {
|
||||||
|
QueryWrapper<MessageTask> wrapper = QueryWrapperHelper.fromBean(param, MessageTask.class);
|
||||||
|
wrapper.eq("is_delete", 0);
|
||||||
|
|
||||||
|
return this.page(PageConverter.convertToMybatis(param, MessageTask.class), wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createMessageHistory(MessageTask messageTask) {
|
||||||
|
|
||||||
|
this.update(UpdateMessageTaskParam.builder()
|
||||||
|
.id(messageTask.getId())
|
||||||
|
.startedTime(new Date())
|
||||||
|
.build());
|
||||||
|
|
||||||
|
MessageTask.BizData bizData = messageTask.getBizData();
|
||||||
|
if (bizData.isAllPerson()) {
|
||||||
|
log.info("发送全员消息");
|
||||||
|
doSendAll(messageTask, bizData);
|
||||||
|
} else {
|
||||||
|
log.info("发送非全员消息");
|
||||||
|
doSendNotAll(messageTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update(UpdateMessageTaskParam.builder()
|
||||||
|
.id(messageTask.getId())
|
||||||
|
.action(MessageTask.ActionEnum.SUCCESS)
|
||||||
|
.finishedTime(new Date())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(UpdateMessageTaskParam param) {
|
||||||
|
MessageTask oldMessageTask = this.lambdaQuery()
|
||||||
|
.eq(MessageTask::getId, param.getId())
|
||||||
|
.last("for update")
|
||||||
|
.one();
|
||||||
|
Aassert.notNull(oldMessageTask, MESSAGE_TASK_NOT_FOUND);;
|
||||||
|
|
||||||
|
|
||||||
|
MessageTask updateMessageTask = param.to();
|
||||||
|
if (param.getAction() != null) {
|
||||||
|
updateMessageTask.setStatus(param.getAction().getNextStatus(oldMessageTask.getStatus()));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateById(updateMessageTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSendAll(MessageTask messageTask, MessageTask.BizData bizData) {
|
||||||
|
Integer pageNumber = 1;
|
||||||
|
while (true) {
|
||||||
|
Page<AccountRegisterService.AccountRegisterDTO> page = accountRegisterService.page(AccountRegisterService.PageAccountRegisterParam.builder()
|
||||||
|
.accountType(AccountTypeEnum.USER.getCode())
|
||||||
|
.appTypes(bizData.getAppTypes().stream().map(AppTypeEnum::getCode).collect(Collectors.toSet()))
|
||||||
|
.page(pageNumber++)
|
||||||
|
.pageSize(DEFAULT_PAGE_SIZE)
|
||||||
|
.build());
|
||||||
|
if (!CollectionUtils.isEmpty(page.getRecords())) {
|
||||||
|
List<MessageTask.ReceivePerson> receivePersons = page.getRecords().stream()
|
||||||
|
.map(e -> MessageTask.ReceivePerson.builder().imAccount(e.getImAccount()).build())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
saveMessageHistory(receivePersons, messageTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!page.hasNext()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSendNotAll(MessageTask messageTask) {
|
||||||
|
// 防止sql过长
|
||||||
|
List<List<MessageTask.ReceivePerson>> receivePersons = Lists.partition(messageTask.getReceivePersons(), DEFAULT_PAGE_SIZE);
|
||||||
|
receivePersons.forEach(e -> saveMessageHistory(e, messageTask));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveMessageHistory(List<MessageTask.ReceivePerson> receivePersons,
|
||||||
|
MessageTask messageTask) {
|
||||||
|
// 排除已经发送成功的记录,防止重复发送
|
||||||
|
Set<String> existPersons = listExistPerson(receivePersons, messageTask);
|
||||||
|
Set<String> existImAccounts = listExistImAccount(receivePersons, messageTask);
|
||||||
|
|
||||||
|
Map<Long, Long> ouIdMap = resolveOuId(receivePersons.stream()
|
||||||
|
.map(MessageTask.ReceivePerson::getOuId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
List<MessageTask.ReceivePerson> absentReceivePersons = receivePersons.stream()
|
||||||
|
.filter(e -> {
|
||||||
|
String key = e.buildKey(ouIdMap);
|
||||||
|
return !existPersons.contains(key) && !existImAccounts.contains(key);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(absentReceivePersons)) {
|
||||||
|
log.info("messageTask,{}, receivePersons,{},已经存在", JSONObject.toJSONString(messageTask),
|
||||||
|
JSONObject.toJSONString(receivePersons));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> accountRegisters = listAccountRegisters(absentReceivePersons);
|
||||||
|
|
||||||
|
Map<String, AccountRegisterService.AccountRegisterDTO> imAccounts = listImAccount(absentReceivePersons);
|
||||||
|
|
||||||
|
List<MessageHistory> messageHistories = absentReceivePersons.stream()
|
||||||
|
.map(receivePerson -> resolveMessageHistory(messageTask, receivePerson, imAccounts, accountRegisters, ouIdMap))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
messageHistoryService.createBatch(messageHistories);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageHistory resolveMessageHistory(MessageTask messageTask,
|
||||||
|
MessageTask.ReceivePerson receivePerson,
|
||||||
|
Map<String, AccountRegisterService.AccountRegisterDTO> imAccounts,
|
||||||
|
Map<String, String> accountRegisters,
|
||||||
|
Map<Long, Long> ouIdMap) {
|
||||||
|
MessageHistory messageHistory = new MessageHistory();
|
||||||
|
messageHistory.setBizId(Optional.ofNullable(messageTask.getBizId()).orElseGet(() -> messageTask.getId().toString()));
|
||||||
|
messageHistory.setImMessageTaskId(messageTask.getId());
|
||||||
|
messageHistory.setFromAccount(messageTask.getSendImAccount());
|
||||||
|
messageHistory.setChannel(imChannelProvider.getProviderType());
|
||||||
|
messageHistory.setCreateAt(new Date());
|
||||||
|
messageHistory.setStatus(MessageHistory.Status.PENDING);
|
||||||
|
if (StringUtils.isNotBlank(receivePerson.getImAccount())) {
|
||||||
|
AccountRegisterService.AccountRegisterDTO imAccount = imAccounts.get(receivePerson.getImAccount());
|
||||||
|
if (imAccount == null) {
|
||||||
|
messageHistory.setToAccount(receivePerson.getImAccount());
|
||||||
|
messageHistory.setResult("IM账号未在IM-CENTER注册");
|
||||||
|
messageHistory.setStatus(MessageHistory.Status.FAILED);
|
||||||
|
// 因为appType不能为空,所以随便填写一个
|
||||||
|
messageHistory.setAppType(AppTypeEnum.CM.getCode());
|
||||||
|
} else {
|
||||||
|
messageHistory.setReceiveOuId(imAccount.getOuId());
|
||||||
|
messageHistory.setReceivePersonId(imAccount.getAccountId());
|
||||||
|
messageHistory.setAppType(imAccount.getAppType());
|
||||||
|
messageHistory.setToAccount(receivePerson.getImAccount());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String key = receivePerson.buildKey(ouIdMap);
|
||||||
|
String imAccount = accountRegisters.get(key);
|
||||||
|
messageHistory.setReceiveOuId(ouIdMap.getOrDefault(receivePerson.getOuId(), receivePerson.getOuId()));
|
||||||
|
messageHistory.setReceivePersonId(receivePerson.getPersonId());
|
||||||
|
messageHistory.setAppType(receivePerson.getAppType().getCode());
|
||||||
|
messageHistory.setToAccount(imAccount);
|
||||||
|
if (StringUtils.isBlank(imAccount)) {
|
||||||
|
messageHistory.setToAccount("未找到IM账号");
|
||||||
|
messageHistory.setResult("未找到IM账号");
|
||||||
|
messageHistory.setStatus(MessageHistory.Status.FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messageHistory.setMessageBody(resolveBody(receivePerson, messageTask, messageHistory.getAppType()));
|
||||||
|
return messageHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> listExistImAccount(List<MessageTask.ReceivePerson> receivePersons,
|
||||||
|
MessageTask messageTask) {
|
||||||
|
Set<String> imAccounts = receivePersons.stream()
|
||||||
|
.map(MessageTask.ReceivePerson::getImAccount)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(imAccounts)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageHistoryService.list(MessageHistoryService.ListMessageHistoryParam.builder()
|
||||||
|
.imMessageTaskId(messageTask.getId())
|
||||||
|
.toAccount(imAccounts)
|
||||||
|
.build())
|
||||||
|
.stream()
|
||||||
|
.map(MessageHistory::getToAccount)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> listExistPerson(List<MessageTask.ReceivePerson> receivePersons,
|
||||||
|
MessageTask messageTask) {
|
||||||
|
Set<String> personIds = receivePersons.stream()
|
||||||
|
.map(MessageTask.ReceivePerson::getPersonId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (CollectionUtils.isEmpty(personIds)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageHistoryService.list(MessageHistoryService.ListMessageHistoryParam.builder()
|
||||||
|
.imMessageTaskId(messageTask.getId())
|
||||||
|
.receivePersonIds(personIds)
|
||||||
|
.build())
|
||||||
|
.stream()
|
||||||
|
.map(e -> e.getReceivePersonId() + "_" + e.getAppType() + "_" + e.getReceiveOuId())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> listAccountRegisters(List<MessageTask.ReceivePerson> receivePersons) {
|
||||||
|
Set<String> personIds = receivePersons.stream()
|
||||||
|
.filter(receivePerson -> StringUtils.isNotBlank(receivePerson.getPersonId())
|
||||||
|
&& StringUtils.isBlank(receivePerson.getImAccount()))
|
||||||
|
.map(MessageTask.ReceivePerson::getPersonId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (CollectionUtils.isEmpty(personIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountRegisterService.list(AccountRegisterService.ListAccountRegisterParam.builder()
|
||||||
|
.accountIds(personIds)
|
||||||
|
.build())
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(accountRegister -> {
|
||||||
|
if (Objects.equals(accountRegister.getAppType(), AppTypeEnum.CM.getCode())) {
|
||||||
|
return accountRegister.getAccountId() +
|
||||||
|
"_" + accountRegister.getAppType();
|
||||||
|
}
|
||||||
|
return accountRegister.getAccountId() +
|
||||||
|
"_" + accountRegister.getAppType() + "_" + accountRegister.getOuId();
|
||||||
|
}, AccountRegister::getImAccount, (f, s) -> f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, AccountRegisterService.AccountRegisterDTO> listImAccount(List<MessageTask.ReceivePerson> receivePersons) {
|
||||||
|
Set<String> imAccounts = receivePersons.stream()
|
||||||
|
.filter(receivePerson -> StringUtils.isNotBlank(receivePerson.getImAccount()))
|
||||||
|
.map(MessageTask.ReceivePerson::getImAccount)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (CollectionUtils.isEmpty(imAccounts)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountRegisterService.list(AccountRegisterService.ListAccountRegisterParam.builder()
|
||||||
|
.imAccounts(imAccounts)
|
||||||
|
.build())
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(AccountRegisterService.AccountRegisterDTO::getImAccount, Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveBody(MessageTask.ReceivePerson receivePerson, MessageTask messageTask, String appType) {
|
||||||
|
|
||||||
|
MessageBody messageBody = new MessageBody();
|
||||||
|
messageBody.setMsgType(NimMsgTypeEnum.TEMPLATE.getCode());
|
||||||
|
messageBody.setMsgContent(messageTask.getContent());
|
||||||
|
messageBody.setMsgHeader(messageTask.getTitle());
|
||||||
|
|
||||||
|
Map<String, String> defaultExtMap = Maps.newHashMap();
|
||||||
|
MessageTask.BizData bizData = messageTask.getBizData();
|
||||||
|
if (StringUtils.isNotBlank(bizData.getMsgTemplateContent())) {
|
||||||
|
messageBody.setMsgBody(bizData.getMsgTemplateContent());
|
||||||
|
defaultExtMap.put("msgTemplateId", bizData.getMsgTemplateId());
|
||||||
|
} else {
|
||||||
|
JSONObject msgBody = new JSONObject()
|
||||||
|
.fluentPut("cardTitle", messageTask.getTitle())
|
||||||
|
.fluentPut("cardContent", messageTask.getContent())
|
||||||
|
.fluentPut("cardBannerUrl", messageTask.getCardBannerUrl());
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(bizData.getJumpData())) {
|
||||||
|
List<JSONObject> actionPaths = bizData.getJumpData().stream()
|
||||||
|
.map(e -> {
|
||||||
|
String platform;
|
||||||
|
if (e.getPlatform() == SendMessageParam.JumpPlatform.PC) {
|
||||||
|
platform = SendMessageParam.JumpPlatform.PC.getOldPlatform();
|
||||||
|
} else if (Objects.equals(e.getPlatform().getAppType().getCode(), appType)) {
|
||||||
|
platform = e.getPlatform().getOldPlatform();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JSONObject()
|
||||||
|
.fluentPut("platform", platform)
|
||||||
|
.fluentPut("url", e.getUrl());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
msgBody.fluentPut("cardDetailButton", new JSONObject()
|
||||||
|
.fluentPut("title", "查看详情")
|
||||||
|
.fluentPut("action", "JUMP")
|
||||||
|
// 必填字段,非模板消息的业务没有这个参数
|
||||||
|
.fluentPut("isHighlight", false)
|
||||||
|
.fluentPut("actionPaths", actionPaths));
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBody.setMsgBody(msgBody.toJSONString());
|
||||||
|
}
|
||||||
|
if (messageTask.getExt() != null) {
|
||||||
|
defaultExtMap.putAll((Map) JSON.parseObject(JSONObject.toJSONString(messageTask.getExt())));
|
||||||
|
}
|
||||||
|
// 传入app版本号,保证消息能被正常打开
|
||||||
|
defaultExtMap.putIfAbsent("minAppVersion", "2.1.0");
|
||||||
|
// CMS端收到消息后会根据workspaceId做check
|
||||||
|
if (receivePerson.getWorkspaceId() != null) {
|
||||||
|
defaultExtMap.putIfAbsent("workspaceId", receivePerson.getWorkspaceId().toString());
|
||||||
|
}
|
||||||
|
messageBody.setMessageExtension(defaultExtMap);
|
||||||
|
|
||||||
|
return JSONUtil.toJsonStr(messageBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要根据接收方的ouId转成真正的ouId,因为平台班组的需要转企业团队的ouId
|
||||||
|
* 特殊逻辑
|
||||||
|
* @param ouIds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Map<Long, Long> resolveOuId(Set<Long> ouIds) {
|
||||||
|
if (CollectionUtils.isEmpty(ouIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
OrganizationalTeamOuRelationReq organizationalTeamOuRelationReq = new OrganizationalTeamOuRelationReq();
|
||||||
|
organizationalTeamOuRelationReq.setTeamOuIds(ouIds);
|
||||||
|
List<OrganizationalTeamOuRelationResp> ouRelationResps = organizationalTeamOuRelationApi.relationListByParam(organizationalTeamOuRelationReq).getData();
|
||||||
|
|
||||||
|
return ouRelationResps.stream()
|
||||||
|
.collect(Collectors.toMap(OrganizationalTeamOuRelationResp::getTeamOuId, OrganizationalTeamOuRelationResp::getOuId, (f, s) -> f));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
package cn.axzo.im.service.impl;
|
||||||
|
|
||||||
|
import cn.axzo.basics.common.BeanMapper;
|
||||||
|
import cn.axzo.im.center.api.vo.resp.RobotTagResp;
|
||||||
|
import cn.axzo.im.dao.mapper.RobotInfoMapper;
|
||||||
|
import cn.axzo.im.dao.repository.RobotTagDao;
|
||||||
|
import cn.axzo.im.entity.RobotInfo;
|
||||||
|
import cn.axzo.im.entity.RobotTag;
|
||||||
|
import cn.axzo.im.service.RobotInfoV2Service;
|
||||||
|
import cn.axzo.pokonyan.dao.converter.PageConverter;
|
||||||
|
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class RobotInfoV2ServiceImpl extends ServiceImpl<RobotInfoMapper, RobotInfo> implements RobotInfoV2Service {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RobotTagDao robotTagDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<RobotInfoDTO> page(PageRobotInfoParam param) {
|
||||||
|
QueryWrapper<RobotInfo> wrapper = QueryWrapperHelper.fromBean(param, RobotInfo.class);
|
||||||
|
wrapper.eq("is_delete", 0);
|
||||||
|
Page<RobotInfo> page = this.page(PageConverter.convertToMybatis(param, RobotInfo.class), wrapper);
|
||||||
|
|
||||||
|
Map<Long, RobotTagResp> robotTags = listRobotTag(param, page.getRecords());
|
||||||
|
return PageConverter.convert(page, (record) -> RobotInfoDTO.from(record, robotTags));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, RobotTagResp> listRobotTag(PageRobotInfoParam param, List<RobotInfo> robotInfos) {
|
||||||
|
|
||||||
|
if (BooleanUtils.isNotTrue(param.isNeedRobotTag()) || CollectionUtils.isEmpty(robotInfos)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> tagIds = robotInfos.stream()
|
||||||
|
.map(RobotInfo::getTagNameList)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(tagIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
List<RobotTag> robotTags = robotTagDao.queryRobotTagValidList(tagIds);
|
||||||
|
List<RobotTagResp> robotTagsResp = BeanMapper.copyList(robotTags, RobotTagResp.class);
|
||||||
|
return robotTagsResp.stream()
|
||||||
|
.collect(Collectors.toMap(RobotTagResp::getId, Function.identity()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package cn.axzo.im.service;
|
||||||
|
|
||||||
|
import cn.axzo.im.Application;
|
||||||
|
import cn.axzo.im.controller.AccountController;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@TestPropertySource(properties = {
|
||||||
|
"NACOS_HOST=https://dev-nacos.axzo.cn",
|
||||||
|
"xxl.job.admin.addresses=http://dev-xxl-job.axzo.cn/xxl-job-admin",
|
||||||
|
"xxl.job.executor.appName=im-center",
|
||||||
|
"xxl.job.executor.port=8990"
|
||||||
|
})
|
||||||
|
@SpringBootTest(classes = Application.class)
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
class AccountServiceTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountController accountController;
|
||||||
|
@Autowired
|
||||||
|
protected MockMvc mockMvc;
|
||||||
|
@Autowired
|
||||||
|
private AccountRegisterService accountRegisterService;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void registerAccountIfAbsent() {
|
||||||
|
|
||||||
|
AccountRegisterService.ListAccountRegisterParam listAccountRegisterParam = AccountRegisterService.ListAccountRegisterParam.builder()
|
||||||
|
.build();
|
||||||
|
List<AccountRegisterService.AccountRegisterDTO> accountRegisters = accountRegisterService.list(listAccountRegisterParam);
|
||||||
|
System.out.println(accountRegisters);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
sql/init.sql
35
sql/init.sql
@ -98,3 +98,38 @@ CREATE TABLE IF NOT EXISTS im_message_history
|
|||||||
create index idx_im_from_account
|
create index idx_im_from_account
|
||||||
on im_message_history (from_account);
|
on im_message_history (from_account);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE im_account_register ADD COLUMN `ou_id` bigint not null default 0 comment 'organizational_unit表的id';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS im_message_task
|
||||||
|
(
|
||||||
|
id bigint auto_increment comment '主键',
|
||||||
|
biz_id varchar(200) not null default '' comment '业务请求时可以带的排查问题的id',
|
||||||
|
send_im_account varchar(100) not null comment '发送者的三方平台账号id',
|
||||||
|
send_person_id varchar(100) not null default '' comment 'IM消息发送personId,自定义消息没有personId',
|
||||||
|
receive_persons json not null comment 'IM消息接收人person列表',
|
||||||
|
status varchar(32) not null default 'PENDING' comment '消息状态:PENDING、SUCCEED、FAILED',
|
||||||
|
title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '标题',
|
||||||
|
content VARCHAR(512) NOT NULL DEFAULT '' COMMENT '内容',
|
||||||
|
card_banner_url VARCHAR(512) NOT NULL DEFAULT '' COMMENT '封面图',
|
||||||
|
biz_data json not null comment '消息业务数据,JSON格式,不同的第三方格式不同',
|
||||||
|
ext VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '其它额外信息',
|
||||||
|
plan_start_time DATETIME(3) NOT NULL COMMENT '任务计划开始时间,时间大于改时间会对未完成的任务进行执行操作',
|
||||||
|
started_time DATETIME(3) null comment '实际开始时间',
|
||||||
|
finished_time DATETIME(3) null comment '实际完成时间',
|
||||||
|
is_delete tinyint default 0 not null comment '未删除0,删除1',
|
||||||
|
create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间',
|
||||||
|
update_at datetime default CURRENT_TIMESTAMP not null comment '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
key idx_message_task_biz_id (`biz_id`),
|
||||||
|
key idx_message_task_plan_start_time (`plan_start_time`)
|
||||||
|
) ENGINE = InnoDB
|
||||||
|
DEFAULT CHARSET = utf8 comment '消息推送任务';
|
||||||
|
|
||||||
|
ALTER TABLE im_message_history ADD COLUMN `result` varchar(1024) NULL COMMENT 'result';
|
||||||
|
ALTER TABLE im_message_history ADD COLUMN `im_message_task_id` bigint NULL COMMENT '消息推送任务的id';
|
||||||
|
ALTER TABLE im_message_history ADD COLUMN status varchar(32) not null default 'SUCCEED' comment '消息状态:PENDING、SUCCEED、FAILED';
|
||||||
|
ALTER TABLE im_message_history ADD COLUMN receive_person_id varchar(100) not null default '' comment 'IM消息接收personId';
|
||||||
|
ALTER TABLE im_message_history ADD COLUMN receive_ou_id bigint comment 'organizational_unit表的id';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user