发送文本消息

这个提交包含在:
xuqm 2023-05-31 11:03:19 +08:00
父节点 96da12992b
当前提交 f2d3ed21af
共有 19 个文件被更改,包括 770 次插入24 次删除

10
pom.xml
查看文件

@ -39,6 +39,16 @@
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>

查看文件

@ -1,5 +1,6 @@
package cn.org.bjca.trust.java.imserver;
import cn.org.bjca.trust.java.imserver.im.ImManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@ -10,6 +11,7 @@ public class ImServerApplication {
public static void main(String[] args) {
SpringApplication.run(ImServerApplication.class, args);
ImManager.getInstance().connect();
}
}

查看文件

@ -0,0 +1,98 @@
package cn.org.bjca.trust.java.imserver.common;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component
public class SpringUtilsAuTo implements BeanFactoryPostProcessor {
/**
* Spring应用上下文环境
*/
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtilsAuTo.beanFactory = beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws BeansException
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws BeansException
*/
public static <T> T getBean(Class<T> clz) throws BeansException {
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype 如果与给定名字相应的bean定义没有被找到将会抛出一个异常NoSuchBeanDefinitionException
*
* @param name
* @return boolean
* @throws NoSuchBeanDefinitionException
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws NoSuchBeanDefinitionException
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名则返回这些别名
*
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getAliases(name);
}
/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) AopContext.currentProxy();
}
}

查看文件

@ -0,0 +1,54 @@
package cn.org.bjca.trust.java.imserver.common.json;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Created by xuqm on 2016/6/3.
*/
public class GsonImplHelp extends Json {
private final Gson gson = new Gson();
@Override
public String toJson(Object src) {
return gson.toJson(src);
}
@Override
public <T> T toObject(String json, Class<T> claxx) {
return gson.fromJson(json, claxx);
}
@Override
public <T> T toObject(byte[] bytes, Class<T> claxx) {
return gson.fromJson(new String(bytes), claxx);
}
public <T> List<T> toList(String json, Class<T> clazz) {
JsonArray jsonArray = JsonParser.parseString(json).getAsJsonArray();
List<T> list = new ArrayList<>();
for (JsonElement jsonElement : jsonArray) {
list.add(gson.fromJson(jsonElement, clazz)); //cls
}
return list;
}
public static <T> List<T> stringToArray(String s, Class<T[]> cls) {
T[] array = new Gson().fromJson(s, cls);
return Arrays.asList(array);
}
}

查看文件

@ -0,0 +1,29 @@
package cn.org.bjca.trust.java.imserver.common.json;
import java.util.List;
/**
* Created by xuqm on 2016/6/3.
*/
public abstract class Json {
private static Json json;
Json() {
}
public static Json get() {
if (json == null) {
json = new GsonImplHelp();
}
return json;
}
public abstract String toJson(Object src);
public abstract <T> T toObject(String json, Class<T> claxx);
public abstract <T> T toObject(byte[] bytes, Class<T> claxx);
public abstract <T> List<T> toList(String json, Class<T> claxx);
}

查看文件

@ -1,19 +1,19 @@
package cn.org.bjca.trust.java.imserver.controller.user.v1;
import cn.org.bjca.trust.java.imserver.entitys.UserInfo;
public class LoginData {
private String host;
private String port;
private String clientId;
private String token;
private UserInfo userInfo;
public LoginData() {
}
public LoginData(String host, String port, String clientId, String token) {
public LoginData(String host, String port, UserInfo userInfo) {
this.host = host;
this.port = port;
this.clientId = clientId;
this.token = token;
this.userInfo = userInfo;
}
public String getHost() {
@ -32,19 +32,11 @@ public class LoginData {
this.port = port;
}
public String getClientId() {
return clientId;
public UserInfo getUserInfo() {
return userInfo;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
}

查看文件

@ -24,8 +24,8 @@ public class UserV1Controller {
@Autowired
private ApplicationRepository applicationRepository;
@PostMapping("/login")
public HttpResult<LoginData> login(@RequestBody LoginBean user, @RequestHeader HttpHeaders headers) throws Exception {
@PostMapping("/register")
public HttpResult<LoginData> register(@RequestBody LoginBean user, @RequestHeader HttpHeaders headers) throws Exception {
String appid = headers.getFirst("appid");
String userid = headers.getFirst("userid");
String ostype = headers.getFirst("ostype");
@ -39,6 +39,7 @@ public class UserV1Controller {
System.out.println("-----------------用户不存在------------------");
userInfo = new UserInfo();
userInfo.setUserId(userid);
userInfo.setNickName(userid);
userInfo.setUserName(UUID.randomUUID().toString());
userInfo.setAppId(appid);
userInfo.setOsType(ostype);
@ -52,7 +53,7 @@ public class UserV1Controller {
}
return new HttpResult<>(200, "成功", new LoginData("114.115.203.60", "18883", userInfo.getUserName(), userInfo.getPassword()));
return new HttpResult<>(200, "成功", new LoginData("114.115.203.60", "18883", userInfo));
} else {
return new HttpResult<>(201, "参数错误", new LoginData());
}

查看文件

@ -27,8 +27,8 @@ public abstract class AbstractBaseTimeEntity {
@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createTime;
private transient LocalDateTime createTime;
@LastModifiedDate
@Column()
private LocalDateTime updateTime;
private transient LocalDateTime updateTime;
}

查看文件

@ -0,0 +1,40 @@
package cn.org.bjca.trust.java.imserver.enums;
public enum PacketType {
//连接请求
CONNECT(10),
CONNECTED(11),
//发送消息
SEND(20),
SEND_ACK(21),
ARRIVE(30),
ARRIVE_ACK(31),
//心跳包
PING(40),
PANG(41),
//数据请求
REQUEST(50),
RESULT(51),
//系统通知
SYSTEM(60),
SYSTEM_ACK(61),
UNKNOWN(-1);
private int type = -1;
PacketType(final int type) {
this.type = type;
}
public int type() {
return this.type;
}
public static PacketType getType(final int type) {
for (final PacketType value : PacketType.values()) {
if (value.type == type) {
return value;
}
}
return UNKNOWN;
}
}

查看文件

@ -0,0 +1,153 @@
package cn.org.bjca.trust.java.imserver.im;
import cn.org.bjca.trust.java.imserver.common.SpringUtilsAuTo;
import cn.org.bjca.trust.java.imserver.common.json.GsonImplHelp;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
import cn.org.bjca.trust.java.imserver.im.msg.ConnectMessage;
import cn.org.bjca.trust.java.imserver.im.msg.ConnectedMessage;
import cn.org.bjca.trust.java.imserver.im.msg.msg.SZYXMessage;
import cn.org.bjca.trust.java.imserver.im.msg.msg.SendAckMessage;
import cn.org.bjca.trust.java.imserver.repository.UserRepository;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import java.nio.charset.StandardCharsets;
public class ImManager {
private final UserRepository userRepository = SpringUtilsAuTo.getBean(UserRepository.class);
public static ImManager getInstance() {
return ImManagerHolder.instance;
}
private static final class ImManagerHolder {
static final ImManager instance = new ImManager();
}
private MqttClient mqttClient;
private final MqttConnectOptions connectOptions;
public ImManager() {
connectOptions = new MqttConnectOptions();
connectOptions.setCleanSession(false);
connectOptions.setUserName("server");
connectOptions.setPassword("server".toCharArray());
connectOptions.setConnectionTimeout(30);
connectOptions.setKeepAliveInterval(10);
connectOptions.setAutomaticReconnect(true);
try {
mqttClient = new MqttClient("tcp://114.115.203.60:18883",
"server" + System.currentTimeMillis(), new MemoryPersistence());
mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
System.out.println("======>connectComplete:reconnect?" + reconnect + "::" + serverURI);
if (reconnect) return;
try {
mqttClient.subscribe("server" + PacketType.CONNECT, 2);
mqttClient.subscribe("server" + PacketType.SEND, 2);
mqttClient.subscribe("server" + PacketType.PING, 2);
mqttClient.subscribe("server" + PacketType.REQUEST, 2);
} catch (MqttException ignored) {
}
}
@Override
public void connectionLost(Throwable cause) {
System.out.println("======>connectionLost" + cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String msg = new String(message.getPayload());
if (topic.equals("server" + PacketType.CONNECT)) {
sendConnectedMsg(GsonImplHelp.get().toObject(msg, ConnectMessage.class));
} else if (topic.equals("server" + PacketType.SEND)) {
SZYXMessage szyxMessage = GsonImplHelp.get().toObject(msg, SZYXMessage.class);
if (!szyxMessage.isGroup()) {
// List<UserInfo> userInfoList = userRepository.findAllByUserIdAndAppId(szyxMessage.getToClientId(), szyxMessage.getAppId());
// for (UserInfo userInfo : userInfoList) {
SZYXMessage message1 = szyxMessage.copy();
message1.setUserName(szyxMessage.getToClientId());
message1.setArrive(true);
message1.setStatus(0);
// sendPacketMessage(szyxMessage.getPacketType(), message1);
// }
sendPacketMessage(szyxMessage.getPacketType(), message1);
}
// TODO: 这里应该有计时器判断转发消息是否送达如果没送达则ack返回失败状态
sendAckMsg(szyxMessage);
} else
System.out.println("======>messageArrived:\n" + topic + "::" + msg);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
});
} catch (MqttException e) {
System.out.println("======>MqttException" + e.getMessage());
}
}
public void connect() {
new Thread(() -> {
try {
if (!mqttClient.isConnected()) {
mqttClient.connect(connectOptions);
}
} catch (MqttException e) {
System.out.println("======>connect" + e.getMessage());
}
}
).start();
}
private void sendConnectedMsg(ConnectMessage connectMessage) {
ConnectedMessage message = new ConnectedMessage();
message.setStatus(200);
message.setAppId(connectMessage.getAppId());
message.setUserName(connectMessage.getUserName());
sendPacketMessage(PacketType.CONNECTED, message);
System.out.println("======>登录成功\n" + GsonImplHelp.get().toJson(message));
}
private void sendAckMsg(SZYXMessage szyxMessage) {
SendAckMessage message = new SendAckMessage();
message.setAckId(szyxMessage.getMsgId());
message.setAckStatus(0);
message.setAppId(szyxMessage.getAppId());
message.setUserName(szyxMessage.getUserName());
sendPacketMessage(PacketType.SEND_ACK, message);
}
private void sendPacketMessage(PacketType packetType, PacketMessage message) {
if (null == connectOptions) {
return;
}
String msg = GsonImplHelp.get().toJson(message);
try {
String topic = message.getAppId() + "/" + packetType + message.getUserName();
mqttClient.publish(topic, msg.getBytes(StandardCharsets.UTF_8), 2, false);
System.out.println("======>发送消息:\n" + topic + "\n" + msg);
} catch (MqttException ignored) {
}
}
}

查看文件

@ -0,0 +1,61 @@
package cn.org.bjca.trust.java.imserver.im.bean;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import java.util.UUID;
public abstract class PacketMessage {
/**
* 消息id
*/
private String msgId = UUID.randomUUID().toString();
private PacketType packetType;
private long timestamp = System.currentTimeMillis();
private String appId;
private String userName;
public PacketMessage(PacketType packetType) {
this.packetType = packetType;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public PacketType getPacketType() {
return packetType;
}
public void setPacketType(PacketType packetType) {
this.packetType = packetType;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}

查看文件

@ -0,0 +1,26 @@
package cn.org.bjca.trust.java.imserver.im.msg;
import cn.org.bjca.trust.java.imserver.entitys.DeviceEntity;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
public class ConnectMessage extends PacketMessage {
public ConnectMessage() {
super(PacketType.CONNECT);
}
private DeviceEntity device;
public ConnectMessage(DeviceEntity device) {
super(PacketType.CONNECT);
this.device = device;
}
public DeviceEntity getDevice() {
return device;
}
public void setDevice(DeviceEntity device) {
this.device = device;
}
}

查看文件

@ -0,0 +1,30 @@
package cn.org.bjca.trust.java.imserver.im.msg;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
public class ConnectedMessage extends PacketMessage {
public ConnectedMessage() {
super(PacketType.CONNECTED);
}
private int status;
private String msg;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

查看文件

@ -0,0 +1,26 @@
package cn.org.bjca.trust.java.imserver.im.msg.msg;
import cn.org.bjca.trust.java.imserver.entitys.DeviceEntity;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
public class ConnectMessage extends PacketMessage {
public ConnectMessage() {
super(PacketType.CONNECT);
}
private DeviceEntity device;
public ConnectMessage(DeviceEntity device) {
super(PacketType.CONNECT);
this.device = device;
}
public DeviceEntity getDevice() {
return device;
}
public void setDevice(DeviceEntity device) {
this.device = device;
}
}

查看文件

@ -0,0 +1,30 @@
package cn.org.bjca.trust.java.imserver.im.msg.msg;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
public class ConnectedMessage extends PacketMessage {
public ConnectedMessage() {
super(PacketType.CONNECTED);
}
private int status;
private String msg;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

查看文件

@ -0,0 +1,142 @@
package cn.org.bjca.trust.java.imserver.im.msg.msg;
import cn.org.bjca.trust.java.imserver.entitys.UserInfo;
import cn.org.bjca.trust.java.imserver.enums.MsgType;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
import cn.org.bjca.trust.java.imserver.im.msg.msg.message.SZYXTextMessage;
public class SZYXMessage extends PacketMessage {
public SZYXMessage(MsgType msgType) {
super(PacketType.SEND);
this.msgType = msgType;
}
/**
* 发送者信息
*/
private UserInfo fromClient;
/**
* 接收者信息
*/
private String toClientId;
/**
* 群id
*/
private String groupID;
/**
* 自定义信息(备注信息描述信息)
*/
private String describe;
/**
* 是不是群消息
*/
private boolean isGroup;
/**
* 是不是接收消息
*/
private boolean isArrive;
/**
* 消息发送状态 -1=失败0=成功1=发送中
*/
private int status;
/**
* 消息类型
*/
private MsgType msgType;
private SZYXTextMessage textMessage;
public UserInfo getFromClient() {
return fromClient;
}
public void setFromClient(UserInfo fromClient) {
this.fromClient = fromClient;
}
public String getToClientId() {
return toClientId;
}
public void setToClientId(String toClientId) {
this.toClientId = toClientId;
}
public String getGroupID() {
return groupID;
}
public void setGroupID(String groupID) {
this.groupID = groupID;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
public boolean isGroup() {
return isGroup;
}
public void setGroup(boolean group) {
isGroup = group;
}
public boolean isArrive() {
return isArrive;
}
public void setArrive(boolean arrive) {
isArrive = arrive;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public MsgType getMsgType() {
return msgType;
}
public void setMsgType(MsgType msgType) {
this.msgType = msgType;
}
public SZYXTextMessage getTextMessage() {
return textMessage;
}
public void setTextMessage(SZYXTextMessage textMessage) {
this.textMessage = textMessage;
}
public SZYXMessage copy(){
SZYXMessage szyxMessage = new SZYXMessage(this.msgType);
szyxMessage.setMsgId(this.getMsgId());
szyxMessage.setPacketType(this.getPacketType());
szyxMessage.setTimestamp(this.getTimestamp());
szyxMessage.setUserName(this.getUserName());
szyxMessage.setAppId(this.getAppId());
szyxMessage.setArrive(this.isArrive());
szyxMessage.setDescribe(this.getDescribe());
szyxMessage.setMsgType(this.getMsgType());
szyxMessage.setToClientId(this.getToClientId());
szyxMessage.setFromClient(this.getFromClient());
szyxMessage.setGroup(this.isGroup());
szyxMessage.setStatus(this.getStatus());
szyxMessage.setGroupID(this.getGroupID());
return szyxMessage;
}
}

查看文件

@ -0,0 +1,32 @@
package cn.org.bjca.trust.java.imserver.im.msg.msg;
import cn.org.bjca.trust.java.imserver.enums.PacketType;
import cn.org.bjca.trust.java.imserver.im.bean.PacketMessage;
public class SendAckMessage extends PacketMessage {
public SendAckMessage() {
super(PacketType.SEND_ACK);
}
private String ackId;
/**
* 0-成功-1-失败;
*/
private int ackStatus;
public String getAckId() {
return ackId;
}
public void setAckId(String ackId) {
this.ackId = ackId;
}
public int getAckStatus() {
return ackStatus;
}
public void setAckStatus(int ackStatus) {
this.ackStatus = ackStatus;
}
}

查看文件

@ -0,0 +1,17 @@
package cn.org.bjca.trust.java.imserver.im.msg.msg.message;
public class SZYXTextMessage {
private String text;
public SZYXTextMessage(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}

查看文件

@ -2,11 +2,14 @@ package cn.org.bjca.trust.java.imserver.repository;
import cn.org.bjca.trust.java.imserver.entitys.UserInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<UserInfo,Long> {
public interface UserRepository extends JpaRepository<UserInfo, Long> {
UserInfo findUserInfoByUserIdAndOsTypeAndAppId(String userId, String osType, String appId);
List<UserInfo> findAllByUserIdAndAppId(String userId, String appId);
}