This commit is contained in:
dute7liang
2024-01-01 03:52:14 +08:00
parent 248d0271b1
commit 3aa29bcefc
31 changed files with 407 additions and 92 deletions

View File

@@ -310,7 +310,11 @@
<artifactId>ruoyi-sms</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-yunxin</artifactId>
<version>${ruoyi-vue-plus.version}</version>
</dependency>
<!-- demo模块 -->
<dependency>
@@ -331,6 +335,7 @@
<module>ruoyi-oss</module>
<module>ruoyi-sms</module>
<module>ruoyi-cai</module>
<module>ruoyi-yunxin</module>
</modules>
<packaging>pom</packaging>

View File

@@ -26,14 +26,13 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-yunxin</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -3,6 +3,8 @@ package com.ruoyi.cai.auth;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.cai.domain.*;
@@ -242,6 +244,7 @@ public class CaiLoginManager {
add.setGender(user.getGender());
add.setCity(user.getCity());
add.setInviteId(user.getInviteId());
add.setImToken(IdUtil.simpleUUID());
userService.save(add);
String clientIP = ServletUtils.getClientIP();
UserInfo userInfo = new UserInfo();

View File

@@ -2,7 +2,7 @@ package com.ruoyi.cai.trd;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.util.RestTemplateUtil;
import com.ruoyi.yunxin.util.RestTemplateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;

View File

@@ -1,76 +0,0 @@
package com.ruoyi.cai.trd;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.util.RestTemplateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class Yunxin {
@Autowired
private YunxinProperties yunxinProperties;
private final static String SEND_URL = "https://api.netease.im/nimserver/msg/sendMsg.action";
private final static String SEND_ATTR_URL = "https://api.netease.im/nimserver/msg/sendAttachMsg.action";
public void sendTo(Long toUid,Object data,Long fromUid){
Map<String,Object> option = new HashMap<>();
option.put("push",true); // 该消息是否需要APNS推送或安卓系统通知栏推送
option.put("roam",false); // 该消息是否需要漫游需要app开通漫游消息功能
option.put("history",false); // 该消息是否存云端历史
option.put("sendersync",false); // 该消息是否需要发送方多端同步
option.put("route",false); // 该消息是否需要抄送第三方 (需要app开通消息抄送功能)
Map<String,Object> bodyData = new HashMap<>();
bodyData.put("from", fromUid == null ? yunxinProperties.getDefaultFromUid() :fromUid);
bodyData.put("ope", 0);
bodyData.put("to", toUid);
bodyData.put("type", 100);
bodyData.put("body", JSON.toJSONString(data));
bodyData.put("option", JSON.toJSONString(option));
String nonce = UUID.fastUUID().toString();
String curTime = DateUtil.currentSeconds() + "";
HttpHeaders headers = new HttpHeaders();
headers.add("AppKey",yunxinProperties.getAppKey());
headers.add("Nonce", nonce);
headers.add("CurTime", curTime);
headers.add("CheckSum", yunxinProperties.getAppSecret()+nonce+curTime);
HttpEntity httpEntity = new HttpEntity<>(bodyData, headers);
RestTemplateUtil.restTemplate.postForObject(SEND_URL,httpEntity, JSONObject.class);
}
public void sendAttachMsg(Long toUid,Object data,Long fromUid){
Map<String,Object> option = new HashMap<>();
option.put("push",true); // 该消息是否需要APNS推送或安卓系统通知栏推送
option.put("roam",false); // 该消息是否需要漫游需要app开通漫游消息功能
option.put("history",false); // 该消息是否存云端历史
option.put("sendersync",false); // 该消息是否需要发送方多端同步
option.put("route",false); // 该消息是否需要抄送第三方 (需要app开通消息抄送功能)
Map<String,Object> bodyData = new HashMap<>();
bodyData.put("from", fromUid == null ? yunxinProperties.getDefaultFromUid() :fromUid);
bodyData.put("ope", 0);
bodyData.put("to", toUid);
bodyData.put("type", 100);
bodyData.put("body", JSON.toJSONString(data));
bodyData.put("option", JSON.toJSONString(option));
String nonce = UUID.fastUUID().toString();
String curTime = DateUtil.currentSeconds() + "";
HttpHeaders headers = new HttpHeaders();
headers.add("AppKey",yunxinProperties.getAppKey());
headers.add("Nonce", nonce);
headers.add("CurTime", curTime);
headers.add("CheckSum", yunxinProperties.getAppSecret()+nonce+curTime);
HttpEntity httpEntity = new HttpEntity<>(bodyData, headers);
RestTemplateUtil.restTemplate.postForObject(SEND_ATTR_URL,httpEntity, JSONObject.class);
}
}

View File

@@ -6,7 +6,7 @@ import com.ruoyi.cai.domain.UserCall;
import com.ruoyi.cai.service.UserCallService;
import com.ruoyi.cai.trd.ImDataRes;
import com.ruoyi.cai.trd.ImMsgGen;
import com.ruoyi.cai.trd.Yunxin;
import com.ruoyi.yunxin.Yunxin;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.constant.HangUpEnums;
@@ -46,7 +46,7 @@ public class CancelMessageHandler extends AbstractMessageHandle implements IMess
Long receiverId = room.getReceiverUserData().getId();
Long callerId = room.getCallUserData().getId();
ImDataRes imDataRes = ImMsgGen.callNotice(1, callerId, receiverId, 0);
yunxin.sendTo(receiverId,imDataRes,callerId);
yunxin.sendTo(receiverId,callerId,imDataRes);
// 更新房间状态
userCallService.update(Wrappers.lambdaUpdate(UserCall.class)
.eq(UserCall::getId,roomId)

View File

@@ -6,7 +6,7 @@ import com.ruoyi.cai.domain.UserCall;
import com.ruoyi.cai.service.UserCallService;
import com.ruoyi.cai.trd.ImDataRes;
import com.ruoyi.cai.trd.ImMsgGen;
import com.ruoyi.cai.trd.Yunxin;
import com.ruoyi.yunxin.Yunxin;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.RoomDataCache;
@@ -49,7 +49,7 @@ public class RefuseMessageHandler extends AbstractMessageHandle implements IMess
Long receiverId = room.getReceiverUserData().getId();
Long callerId = room.getCallUserData().getId();
ImDataRes imDataRes = ImMsgGen.callNotice(1, callerId, receiverId, 0);
yunxin.sendTo(receiverId,imDataRes,callerId);
yunxin.sendTo(receiverId,callerId,imDataRes);
// 更新房间状态
userCallService.update(Wrappers.lambdaUpdate(UserCall.class)

View File

@@ -5,7 +5,7 @@ import com.ruoyi.cai.domain.Account;
import com.ruoyi.cai.service.AccountService;
import com.ruoyi.cai.trd.ImDataRes;
import com.ruoyi.cai.trd.ImMsgGen;
import com.ruoyi.cai.trd.Yunxin;
import com.ruoyi.yunxin.Yunxin;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.bean.RoomData;
import com.ruoyi.cai.ws.bean.UserData;
@@ -67,7 +67,7 @@ public class SettleService {
Long callUserId = room.getCallUserData().getId();
if(callTime > 0){
ImDataRes imDataRes = ImMsgGen.callNotice(4, receiverUserId, callUserId, callTime);
yunxin.sendTo(room.getCallUserData().getId(),imDataRes,room.getReceiverUserData().getId());
yunxin.sendTo(room.getCallUserData().getId(),room.getReceiverUserData().getId(),imDataRes);
}
// 收入通知
if(room != null){ // TODO修改数据

View File

@@ -170,7 +170,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
</dependencies>
</project>

32
ruoyi-yunxin/pom.xml Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-yunxin</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-framework</artifactId>
</dependency>
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>1.5.33</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,32 @@
package com.ruoyi.yunxin;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.yunxin.client.ImMessageClient;
import com.ruoyi.yunxin.config.YunxinProperties;
import com.ruoyi.yunxin.req.Option;
import com.ruoyi.yunxin.req.SendMsgReq;
import com.ruoyi.yunxin.resp.SendMsgResp;
import com.ruoyi.yunxin.resp.YxDataR;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class Yunxin {
@Autowired
private YunxinProperties yunxinProperties;
@Resource
private ImMessageClient messageClient;
public YxDataR<SendMsgResp> sendTo(Long toUid,Long fromUid,Object data){
SendMsgReq req = new SendMsgReq();
req.setFrom(fromUid == null ? yunxinProperties.getDefaultFromUid() : fromUid+"");
req.setTo(toUid+"");
req.setBody(JSON.toJSONString(data));
req.setOption(JSON.toJSONString(new Option()));
return messageClient.sendMsg(req);
}
}

View File

@@ -0,0 +1,18 @@
package com.ruoyi.yunxin.client;
import com.dtflys.forest.annotation.BaseRequest;
import com.dtflys.forest.annotation.Post;
import com.ruoyi.yunxin.interceptor.GlodonTokenInterceptor;
import com.ruoyi.yunxin.req.SendMsgReq;
import com.ruoyi.yunxin.resp.SendMsgResp;
import com.ruoyi.yunxin.resp.YxDataR;
@BaseRequest(baseURL = "${baseUrl}", interceptor = GlodonTokenInterceptor.class)
public interface ImMessageClient {
@Post(url = "/nimserver/msg/sendMsg.action")
YxDataR<SendMsgResp> sendMsg(SendMsgReq req);
// @Post(url = "/nimserver/msg/sendAttachMsg.action")
// YxR<SendMsgResp> sendAttachMsg(SendMsgReq req);
}

View File

@@ -0,0 +1,29 @@
package com.ruoyi.yunxin.client;
import com.dtflys.forest.annotation.BaseRequest;
import com.dtflys.forest.annotation.Body;
import com.dtflys.forest.annotation.Post;
import com.ruoyi.yunxin.interceptor.GlodonTokenInterceptor;
import com.ruoyi.yunxin.req.BlockReq;
import com.ruoyi.yunxin.req.CreateUserReq;
import com.ruoyi.yunxin.req.UnblockReq;
import com.ruoyi.yunxin.req.UpdateTokenReq;
import com.ruoyi.yunxin.resp.YxCommonR;
@BaseRequest(baseURL = "${baseUrl}", interceptor = GlodonTokenInterceptor.class)
public interface ImUserClient {
@Post(url = "/nimserver/user/create.action")
YxCommonR createUser(@Body CreateUserReq req);
@Post(url = "/nimserver/user/update.action")
YxCommonR updateToken(@Body UpdateTokenReq req);
@Post(url = "/nimserver/user/block.action")
YxCommonR block(@Body BlockReq req);
@Post(url = "/nimserver/user/unblock.action")
YxCommonR unblock(@Body UnblockReq req);
}

View File

@@ -0,0 +1,19 @@
package com.ruoyi.yunxin.client;
import com.dtflys.forest.annotation.BaseRequest;
import com.dtflys.forest.annotation.Body;
import com.dtflys.forest.annotation.Post;
import com.ruoyi.yunxin.interceptor.GlodonTokenInterceptor;
import com.ruoyi.yunxin.req.CreateUserReq;
import com.ruoyi.yunxin.req.UpdateUinfoReq;
import com.ruoyi.yunxin.resp.YxCommonR;
import com.ruoyi.yunxin.resp.YxInfoR;
@BaseRequest(baseURL = "${baseUrl}", interceptor = GlodonTokenInterceptor.class)
public interface ImUserRefClient {
@Post(url = "/nimserver/user/updateUinfo.action")
YxCommonR updateUinfo(@Body UpdateUinfoReq query);
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.yunxin.config;
import com.dtflys.forest.converter.json.ForestJacksonConverter;
import com.dtflys.forest.converter.json.ForestJsonConverter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ForestConfig {
@Bean
public ForestJsonConverter forestJacksonConverter() {
ForestJacksonConverter converter = new ForestJacksonConverter();
ObjectMapper mapper = converter.getMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// converter.setDateFormat("yyyy-MM-dd HH:mm:ss");
return converter;
}
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.yunxin.config;
import com.dtflys.forest.Forest;
import com.dtflys.forest.config.ForestConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class ForestInit {
@Autowired
private YunxinProperties yunxinProperties;
@PostConstruct
public void init(){
ForestConfiguration configuration = Forest.config();
configuration.setVariableValue("baseUrl", (method) -> yunxinProperties.getBaseUrl());
}
}

View File

@@ -1,4 +1,4 @@
package com.ruoyi.cai.trd;
package com.ruoyi.yunxin.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "yunxin")
public class YunxinProperties {
private String baseUrl = "https://api.netease.im/nimserver";
private String appKey;
private String appSecret;

View File

@@ -0,0 +1,56 @@
package com.ruoyi.yunxin.interceptor;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dtflys.forest.exceptions.ForestRuntimeException;
import com.dtflys.forest.http.ForestRequest;
import com.dtflys.forest.http.ForestResponse;
import com.dtflys.forest.interceptor.Interceptor;
import com.ruoyi.yunxin.config.YunxinProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class GlodonTokenInterceptor implements Interceptor {
@Autowired
private YunxinProperties yunxinProperties;
@Override
public boolean beforeExecute(ForestRequest request) {
String nonce = UUID.fastUUID().toString();
String curTime = DateUtil.currentSeconds() + "";
request.addHeader("AppKey",yunxinProperties.getAppKey());
request.addHeader("Nonce", nonce);
request.addHeader("CurTime", curTime);
request.addHeader("CheckSum", yunxinProperties.getAppSecret()+nonce+curTime);
return true;
}
@Override
public void onSuccess(Object data, ForestRequest request, ForestResponse response) {
log.info("onSuccess URI:{},QueryValues:{},耗时:{}ms,Param:{},RespStatus:{},Response:{}",
request.getURI(),
JSON.toJSONString(request.getQueryValues()),
response.getTimeAsMillisecond(),
JSONObject.toJSONString(request.getArguments()),
response.getStatusCode(),
response.getContent());
}
@Override
public void onError(ForestRuntimeException ex, ForestRequest request, ForestResponse response) {
log.info("onError URI:{},QueryValues:{},耗时:{}ms,Param:{},RespStatus:{},Response:{}",
request.getURI(),
JSON.toJSONString(request.getQueryValues()),
response.getTimeAsMillisecond(),
JSONObject.toJSONString(request.getArguments()),
response.getStatusCode(),
response.getContent());
}
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class BlockReq {
private String accid;
private boolean needkick = true;
}

View File

@@ -0,0 +1,11 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class CreateUserReq {
private String accid;
private String token;
private String name;
}

View File

@@ -0,0 +1,27 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class Option {
/**
* 该消息是否需要APNS推送或安卓系统通知栏推送
*/
private boolean push = true;
/**
* 该消息是否需要漫游需要app开通漫游消息功能
*/
private boolean roam = false;
/**
* 该消息是否存云端历史
*/
private boolean history = false;
/**
* 该消息是否需要发送方多端同步
*/
private boolean sendersync = false;
/**
* 该消息是否需要抄送第三方 (需要app开通消息抄送功能)
*/
private boolean route = false;
}

View File

@@ -0,0 +1,8 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class SendAttachMsgReq {
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class SendMsgReq {
private String from;
private int ope = 0;
private String to;
private int type = 100;
private String body;
private String option;
}

View File

@@ -0,0 +1,8 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class UnblockReq {
private String accid;
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class UpdateTokenReq {
private String accid;
private String token;
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.yunxin.req;
import lombok.Data;
@Data
public class UpdateUinfoReq {
private String accid;
private String name;
private String icon;
private String birth;
private String mobile;
private String gender;
}

View File

@@ -0,0 +1,10 @@
package com.ruoyi.yunxin.resp;
import lombok.Data;
@Data
public class SendMsgResp {
private Long msgid;
private Long timetag;
private Boolean antispam;
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.yunxin.resp;
import lombok.Data;
@Data
public class YxCommonR {
private Integer code;
private String desc;
public boolean isSuccess(){
return code != null && code == 200;
}
}

View File

@@ -0,0 +1,15 @@
package com.ruoyi.yunxin.resp;
import lombok.Data;
import java.io.Serializable;
@Data
public class YxDataR<T> implements Serializable {
private Integer code;
private T data;
public boolean isSuccess(){
return code != null && code == 200;
}
}

View File

@@ -0,0 +1,13 @@
package com.ruoyi.yunxin.resp;
import lombok.Data;
@Data
public class YxInfoR<T> {
private Integer code;
private T info;
public boolean isSuccess(){
return code != null && code == 200;
}
}

View File

@@ -1,4 +1,4 @@
package com.ruoyi.cai.util;
package com.ruoyi.yunxin.util;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;