1.0
This commit is contained in:
41
旧的java项目/itcast/client/ChatClient.java
Normal file
41
旧的java项目/itcast/client/ChatClient.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package cn.itcast.client;
|
||||
|
||||
import cn.itcast.protocol.MessageCodecSharable;
|
||||
import cn.itcast.protocol.ProcotolFrameDecoder;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class ChatClient {
|
||||
public static void main(String[] args) {
|
||||
NioEventLoopGroup group = new NioEventLoopGroup();
|
||||
LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
|
||||
MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
|
||||
try {
|
||||
Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
bootstrap.group(group);
|
||||
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new ProcotolFrameDecoder());
|
||||
ch.pipeline().addLast(LOGGING_HANDLER);
|
||||
ch.pipeline().addLast(MESSAGE_CODEC);
|
||||
}
|
||||
});
|
||||
Channel channel = bootstrap.connect("localhost", 9020).sync().channel();
|
||||
channel.closeFuture().sync();
|
||||
} catch (Exception e) {
|
||||
// log.error("client error", e);
|
||||
} finally {
|
||||
group.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
19
旧的java项目/itcast/message/AbstractResponseMessage.java
Normal file
19
旧的java项目/itcast/message/AbstractResponseMessage.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public abstract class AbstractResponseMessage extends Message {
|
||||
private boolean success;
|
||||
private String reason;
|
||||
|
||||
public AbstractResponseMessage() {
|
||||
}
|
||||
|
||||
public AbstractResponseMessage(boolean success, String reason) {
|
||||
this.success = success;
|
||||
this.reason = reason;
|
||||
}
|
||||
}
|
||||
26
旧的java项目/itcast/message/ChatRequestMessage.java
Normal file
26
旧的java项目/itcast/message/ChatRequestMessage.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ChatRequestMessage extends Message {
|
||||
private String content;
|
||||
private String to;
|
||||
private String from;
|
||||
|
||||
public ChatRequestMessage() {
|
||||
}
|
||||
|
||||
public ChatRequestMessage(String from, String to, String content) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return ChatRequestMessage;
|
||||
}
|
||||
}
|
||||
26
旧的java项目/itcast/message/ChatResponseMessage.java
Normal file
26
旧的java项目/itcast/message/ChatResponseMessage.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ChatResponseMessage extends AbstractResponseMessage {
|
||||
|
||||
private String from;
|
||||
private String content;
|
||||
|
||||
public ChatResponseMessage(boolean success, String reason) {
|
||||
super(success, reason);
|
||||
}
|
||||
|
||||
public ChatResponseMessage(String from, String content) {
|
||||
this.from = from;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return ChatResponseMessage;
|
||||
}
|
||||
}
|
||||
23
旧的java项目/itcast/message/GroupChatRequestMessage.java
Normal file
23
旧的java项目/itcast/message/GroupChatRequestMessage.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupChatRequestMessage extends Message {
|
||||
private String content;
|
||||
private String groupName;
|
||||
private String from;
|
||||
|
||||
public GroupChatRequestMessage(String from, String groupName, String content) {
|
||||
this.content = content;
|
||||
this.groupName = groupName;
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupChatRequestMessage;
|
||||
}
|
||||
}
|
||||
24
旧的java项目/itcast/message/GroupChatResponseMessage.java
Normal file
24
旧的java项目/itcast/message/GroupChatResponseMessage.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupChatResponseMessage extends AbstractResponseMessage {
|
||||
private String from;
|
||||
private String content;
|
||||
|
||||
public GroupChatResponseMessage(boolean success, String reason) {
|
||||
super(success, reason);
|
||||
}
|
||||
|
||||
public GroupChatResponseMessage(String from, String content) {
|
||||
this.from = from;
|
||||
this.content = content;
|
||||
}
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupChatResponseMessage;
|
||||
}
|
||||
}
|
||||
23
旧的java项目/itcast/message/GroupCreateRequestMessage.java
Normal file
23
旧的java项目/itcast/message/GroupCreateRequestMessage.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupCreateRequestMessage extends Message {
|
||||
private String groupName;
|
||||
private Set<String> members;
|
||||
|
||||
public GroupCreateRequestMessage(String groupName, Set<String> members) {
|
||||
this.groupName = groupName;
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupCreateRequestMessage;
|
||||
}
|
||||
}
|
||||
18
旧的java项目/itcast/message/GroupCreateResponseMessage.java
Normal file
18
旧的java项目/itcast/message/GroupCreateResponseMessage.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupCreateResponseMessage extends AbstractResponseMessage {
|
||||
|
||||
public GroupCreateResponseMessage(boolean success, String reason) {
|
||||
super(success, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupCreateResponseMessage;
|
||||
}
|
||||
}
|
||||
22
旧的java项目/itcast/message/GroupJoinRequestMessage.java
Normal file
22
旧的java项目/itcast/message/GroupJoinRequestMessage.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupJoinRequestMessage extends Message {
|
||||
private String groupName;
|
||||
|
||||
private String username;
|
||||
|
||||
public GroupJoinRequestMessage(String username, String groupName) {
|
||||
this.groupName = groupName;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupJoinRequestMessage;
|
||||
}
|
||||
}
|
||||
18
旧的java项目/itcast/message/GroupJoinResponseMessage.java
Normal file
18
旧的java项目/itcast/message/GroupJoinResponseMessage.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupJoinResponseMessage extends AbstractResponseMessage {
|
||||
|
||||
public GroupJoinResponseMessage(boolean success, String reason) {
|
||||
super(success, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupJoinResponseMessage;
|
||||
}
|
||||
}
|
||||
19
旧的java项目/itcast/message/GroupMembersRequestMessage.java
Normal file
19
旧的java项目/itcast/message/GroupMembersRequestMessage.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupMembersRequestMessage extends Message {
|
||||
private String groupName;
|
||||
|
||||
public GroupMembersRequestMessage(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupMembersRequestMessage;
|
||||
}
|
||||
}
|
||||
22
旧的java项目/itcast/message/GroupMembersResponseMessage.java
Normal file
22
旧的java项目/itcast/message/GroupMembersResponseMessage.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupMembersResponseMessage extends Message {
|
||||
|
||||
private Set<String> members;
|
||||
|
||||
public GroupMembersResponseMessage(Set<String> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupMembersResponseMessage;
|
||||
}
|
||||
}
|
||||
22
旧的java项目/itcast/message/GroupQuitRequestMessage.java
Normal file
22
旧的java项目/itcast/message/GroupQuitRequestMessage.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupQuitRequestMessage extends Message {
|
||||
private String groupName;
|
||||
|
||||
private String username;
|
||||
|
||||
public GroupQuitRequestMessage(String username, String groupName) {
|
||||
this.groupName = groupName;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupQuitRequestMessage;
|
||||
}
|
||||
}
|
||||
17
旧的java项目/itcast/message/GroupQuitResponseMessage.java
Normal file
17
旧的java项目/itcast/message/GroupQuitResponseMessage.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class GroupQuitResponseMessage extends AbstractResponseMessage {
|
||||
public GroupQuitResponseMessage(boolean success, String reason) {
|
||||
super(success, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return GroupQuitResponseMessage;
|
||||
}
|
||||
}
|
||||
26
旧的java项目/itcast/message/LoginRequestMessage.java
Normal file
26
旧的java项目/itcast/message/LoginRequestMessage.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class LoginRequestMessage extends Message {
|
||||
private String username;
|
||||
private String password;
|
||||
private String nickname;
|
||||
|
||||
public LoginRequestMessage() {
|
||||
}
|
||||
|
||||
public LoginRequestMessage(String username, String password, String nickname) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return LoginRequestMessage;
|
||||
}
|
||||
}
|
||||
13
旧的java项目/itcast/message/LoginResponseMessage.java
Normal file
13
旧的java项目/itcast/message/LoginResponseMessage.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class LoginResponseMessage extends AbstractResponseMessage {
|
||||
@Override
|
||||
public int getMessageType() {
|
||||
return LoginResponseMessage;
|
||||
}
|
||||
}
|
||||
54
旧的java项目/itcast/message/Message.java
Normal file
54
旧的java项目/itcast/message/Message.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package cn.itcast.message;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public abstract class Message implements Serializable {
|
||||
|
||||
public static Class<?> getMessageClass(int messageType) {
|
||||
return messageClasses.get(messageType);
|
||||
}
|
||||
|
||||
private int sequenceId;
|
||||
|
||||
private int messageType;
|
||||
|
||||
public abstract int getMessageType();
|
||||
|
||||
public static final int LoginRequestMessage = 0;
|
||||
public static final int LoginResponseMessage = 1;
|
||||
public static final int ChatRequestMessage = 2;
|
||||
public static final int ChatResponseMessage = 3;
|
||||
public static final int GroupCreateRequestMessage = 4;
|
||||
public static final int GroupCreateResponseMessage = 5;
|
||||
public static final int GroupJoinRequestMessage = 6;
|
||||
public static final int GroupJoinResponseMessage = 7;
|
||||
public static final int GroupQuitRequestMessage = 8;
|
||||
public static final int GroupQuitResponseMessage = 9;
|
||||
public static final int GroupChatRequestMessage = 10;
|
||||
public static final int GroupChatResponseMessage = 11;
|
||||
public static final int GroupMembersRequestMessage = 12;
|
||||
public static final int GroupMembersResponseMessage = 13;
|
||||
private static final Map<Integer, Class<?>> messageClasses = new HashMap<>();
|
||||
|
||||
static {
|
||||
messageClasses.put(LoginRequestMessage, LoginRequestMessage.class);
|
||||
messageClasses.put(LoginResponseMessage, LoginResponseMessage.class);
|
||||
messageClasses.put(ChatRequestMessage, ChatRequestMessage.class);
|
||||
messageClasses.put(ChatResponseMessage, ChatResponseMessage.class);
|
||||
messageClasses.put(GroupCreateRequestMessage, GroupCreateRequestMessage.class);
|
||||
messageClasses.put(GroupCreateResponseMessage, GroupCreateResponseMessage.class);
|
||||
messageClasses.put(GroupJoinRequestMessage, GroupJoinRequestMessage.class);
|
||||
messageClasses.put(GroupJoinResponseMessage, GroupJoinResponseMessage.class);
|
||||
messageClasses.put(GroupQuitRequestMessage, GroupQuitRequestMessage.class);
|
||||
messageClasses.put(GroupQuitResponseMessage, GroupQuitResponseMessage.class);
|
||||
messageClasses.put(GroupChatRequestMessage, GroupChatRequestMessage.class);
|
||||
messageClasses.put(GroupChatResponseMessage, GroupChatResponseMessage.class);
|
||||
messageClasses.put(GroupMembersRequestMessage, GroupMembersRequestMessage.class);
|
||||
messageClasses.put(GroupMembersResponseMessage, GroupMembersResponseMessage.class);
|
||||
}
|
||||
}
|
||||
62
旧的java项目/itcast/protocol/MessageCodec.java
Normal file
62
旧的java项目/itcast/protocol/MessageCodec.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package cn.itcast.protocol;
|
||||
|
||||
import cn.itcast.message.Message;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageCodec;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@ChannelHandler.Sharable
|
||||
public class MessageCodec extends ByteToMessageCodec<Message> {
|
||||
|
||||
@Override
|
||||
public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
|
||||
// // 1. 4 字节的魔数
|
||||
// out.writeBytes(new byte[]{1, 2, 3, 4});
|
||||
// // 2. 1 字节的版本,
|
||||
// out.writeByte(1);
|
||||
// // 3. 1 字节的序列化方式 jdk 0 , json 1
|
||||
// out.writeByte(0);
|
||||
// // 4. 1 字节的指令类型
|
||||
// out.writeByte(msg.getMessageType());
|
||||
// // 5. 4 个字节
|
||||
//// out.writeInt(msg.getSequenceId());
|
||||
// // 无意义,对齐填充
|
||||
// out.writeByte(0xff);
|
||||
// // 6. 获取内容的字节数组
|
||||
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
// ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||
// oos.writeObject(msg);
|
||||
// byte[] bytes = bos.toByteArray();
|
||||
// // 7. 长度
|
||||
// out.writeInt(bytes.length);
|
||||
// // 8. 写入内容
|
||||
// out.writeBytes(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
int magicNum = in.readInt();
|
||||
byte version = in.readByte();
|
||||
byte serializerType = in.readByte();
|
||||
byte messageType = in.readByte();
|
||||
int sequenceId = in.readInt();
|
||||
in.readByte();
|
||||
int length = in.readInt();
|
||||
byte[] bytes = new byte[length];
|
||||
in.readBytes(bytes, 0, length);
|
||||
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
Message message = (Message) ois.readObject();
|
||||
// log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
|
||||
// log.debug("{}", message);
|
||||
out.add(message);
|
||||
}
|
||||
}
|
||||
66
旧的java项目/itcast/protocol/MessageCodecSharable.java
Normal file
66
旧的java项目/itcast/protocol/MessageCodecSharable.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package cn.itcast.protocol;
|
||||
|
||||
import cn.itcast.message.Message;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@ChannelHandler.Sharable
|
||||
/**
|
||||
* 必须和 LengthFieldBasedFrameDecoder 一起使用,确保接到的 ByteBuf 消息是完整的
|
||||
*/
|
||||
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {
|
||||
// ByteBuf out = ctx.alloc().buffer();
|
||||
// // 1. 4 字节的魔数
|
||||
// out.writeBytes(new byte[]{1, 2, 3, 4});
|
||||
// // 2. 1 字节的版本,
|
||||
// out.writeByte(1);
|
||||
// // 3. 1 字节的序列化方式 jdk 0 , json 1
|
||||
// out.writeByte(0);
|
||||
// // 4. 1 字节的指令类型
|
||||
// out.writeByte(msg.getMessageType());
|
||||
// // 5. 4 个字节
|
||||
// out.writeInt(msg.getSequenceId());
|
||||
// // 无意义,对齐填充
|
||||
// out.writeByte(0xff);
|
||||
// // 6. 获取内容的字节数组
|
||||
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
// ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||
// oos.writeObject(msg);
|
||||
// byte[] bytes = bos.toByteArray();
|
||||
// // 7. 长度
|
||||
// out.writeInt(bytes.length);
|
||||
// // 8. 写入内容
|
||||
// out.writeBytes(bytes);
|
||||
// outList.add(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
int magicNum = in.readInt();
|
||||
byte version = in.readByte();
|
||||
byte serializerType = in.readByte();
|
||||
byte messageType = in.readByte();
|
||||
int sequenceId = in.readInt();
|
||||
in.readByte();
|
||||
int length = in.readInt();
|
||||
byte[] bytes = new byte[length];
|
||||
in.readBytes(bytes, 0, length);
|
||||
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
||||
Message message = (Message) ois.readObject();
|
||||
// log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
|
||||
// log.debug("{}", message);
|
||||
out.add(message);
|
||||
}
|
||||
}
|
||||
14
旧的java项目/itcast/protocol/ProcotolFrameDecoder.java
Normal file
14
旧的java项目/itcast/protocol/ProcotolFrameDecoder.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package cn.itcast.protocol;
|
||||
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
|
||||
public class ProcotolFrameDecoder extends LengthFieldBasedFrameDecoder {
|
||||
|
||||
public ProcotolFrameDecoder() {
|
||||
this(1024, 12, 4, 0, 0);
|
||||
}
|
||||
|
||||
public ProcotolFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
|
||||
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
|
||||
}
|
||||
}
|
||||
44
旧的java项目/itcast/server/ChatServer.java
Normal file
44
旧的java项目/itcast/server/ChatServer.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package cn.itcast.server;
|
||||
|
||||
import cn.itcast.protocol.MessageCodecSharable;
|
||||
import cn.itcast.protocol.ProcotolFrameDecoder;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class ChatServer {
|
||||
public static void main(String[] args) {
|
||||
NioEventLoopGroup boss = new NioEventLoopGroup();
|
||||
NioEventLoopGroup worker = new NioEventLoopGroup();
|
||||
LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
|
||||
MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
|
||||
try {
|
||||
ServerBootstrap serverBootstrap = new ServerBootstrap();
|
||||
serverBootstrap.channel(NioServerSocketChannel.class);
|
||||
serverBootstrap.group(boss, worker);
|
||||
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new ProcotolFrameDecoder());
|
||||
ch.pipeline().addLast(LOGGING_HANDLER);
|
||||
ch.pipeline().addLast(MESSAGE_CODEC);
|
||||
}
|
||||
});
|
||||
Channel channel = serverBootstrap.bind(9020).sync().channel();
|
||||
channel.closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
// log.error("server error", e);
|
||||
} finally {
|
||||
boss.shutdownGracefully();
|
||||
worker.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
旧的java项目/itcast/server/service/UserService.java
Normal file
15
旧的java项目/itcast/server/service/UserService.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package cn.itcast.server.service;
|
||||
|
||||
/**
|
||||
* 用户管理接口
|
||||
*/
|
||||
public interface UserService {
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @return 登录成功返回 true, 否则返回 false
|
||||
*/
|
||||
boolean login(String username, String password);
|
||||
}
|
||||
10
旧的java项目/itcast/server/service/UserServiceFactory.java
Normal file
10
旧的java项目/itcast/server/service/UserServiceFactory.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package cn.itcast.server.service;
|
||||
|
||||
public abstract class UserServiceFactory {
|
||||
|
||||
private static UserService userService = new UserServiceMemoryImpl();
|
||||
|
||||
public static UserService getUserService() {
|
||||
return userService;
|
||||
}
|
||||
}
|
||||
25
旧的java项目/itcast/server/service/UserServiceMemoryImpl.java
Normal file
25
旧的java项目/itcast/server/service/UserServiceMemoryImpl.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package cn.itcast.server.service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class UserServiceMemoryImpl implements UserService {
|
||||
private Map<String, String> allUserMap = new ConcurrentHashMap<>();
|
||||
|
||||
{
|
||||
allUserMap.put("zhangsan", "123");
|
||||
allUserMap.put("lisi", "123");
|
||||
allUserMap.put("wangwu", "123");
|
||||
allUserMap.put("zhaoliu", "123");
|
||||
allUserMap.put("qianqi", "123");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean login(String username, String password) {
|
||||
String pass = allUserMap.get(username);
|
||||
if (pass == null) {
|
||||
return false;
|
||||
}
|
||||
return pass.equals(password);
|
||||
}
|
||||
}
|
||||
24
旧的java项目/itcast/server/session/Group.java
Normal file
24
旧的java项目/itcast/server/session/Group.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
/**
|
||||
* 聊天组,即聊天室
|
||||
*/
|
||||
public class Group {
|
||||
// 聊天室名称
|
||||
private String name;
|
||||
// 聊天室成员
|
||||
private Set<String> members;
|
||||
|
||||
public static final Group EMPTY_GROUP = new Group("empty", Collections.emptySet());
|
||||
|
||||
public Group(String name, Set<String> members) {
|
||||
this.name = name;
|
||||
this.members = members;
|
||||
}
|
||||
}
|
||||
57
旧的java项目/itcast/server/session/GroupSession.java
Normal file
57
旧的java项目/itcast/server/session/GroupSession.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 聊天组会话管理接口
|
||||
*/
|
||||
public interface GroupSession {
|
||||
|
||||
/**
|
||||
* 创建一个聊天组, 如果不存在才能创建成功, 否则返回 null
|
||||
* @param name 组名
|
||||
* @param members 成员
|
||||
* @return 成功时返回组对象, 失败返回 null
|
||||
*/
|
||||
Group createGroup(String name, Set<String> members);
|
||||
|
||||
/**
|
||||
* 加入聊天组
|
||||
* @param name 组名
|
||||
* @param member 成员名
|
||||
* @return 如果组不存在返回 null, 否则返回组对象
|
||||
*/
|
||||
Group joinMember(String name, String member);
|
||||
|
||||
/**
|
||||
* 移除组成员
|
||||
* @param name 组名
|
||||
* @param member 成员名
|
||||
* @return 如果组不存在返回 null, 否则返回组对象
|
||||
*/
|
||||
Group removeMember(String name, String member);
|
||||
|
||||
/**
|
||||
* 移除聊天组
|
||||
* @param name 组名
|
||||
* @return 如果组不存在返回 null, 否则返回组对象
|
||||
*/
|
||||
Group removeGroup(String name);
|
||||
|
||||
/**
|
||||
* 获取组成员
|
||||
* @param name 组名
|
||||
* @return 成员集合, 没有成员会返回 empty set
|
||||
*/
|
||||
Set<String> getMembers(String name);
|
||||
|
||||
/**
|
||||
* 获取组成员的 channel 集合, 只有在线的 channel 才会返回
|
||||
* @param name 组名
|
||||
* @return 成员 channel 集合
|
||||
*/
|
||||
List<Channel> getMembersChannel(String name);
|
||||
}
|
||||
10
旧的java项目/itcast/server/session/GroupSessionFactory.java
Normal file
10
旧的java项目/itcast/server/session/GroupSessionFactory.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
public abstract class GroupSessionFactory {
|
||||
|
||||
private static GroupSession session = new GroupSessionMemoryImpl();
|
||||
|
||||
public static GroupSession getGroupSession() {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
55
旧的java项目/itcast/server/session/GroupSessionMemoryImpl.java
Normal file
55
旧的java项目/itcast/server/session/GroupSessionMemoryImpl.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GroupSessionMemoryImpl implements GroupSession {
|
||||
private final Map<String, Group> groupMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Group createGroup(String name, Set<String> members) {
|
||||
Group group = new Group(name, members);
|
||||
return groupMap.putIfAbsent(name, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group joinMember(String name, String member) {
|
||||
return groupMap.computeIfPresent(name, (key, value) -> {
|
||||
// value.getMembers().add(member);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group removeMember(String name, String member) {
|
||||
return groupMap.computeIfPresent(name, (key, value) -> {
|
||||
// value.getMembers().remove(member);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group removeGroup(String name) {
|
||||
return groupMap.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getMembers(String name) {
|
||||
// return groupMap.getOrDefault(name, Group.EMPTY_GROUP).getMembers();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Channel> getMembersChannel(String name) {
|
||||
return getMembers(name).stream()
|
||||
.map(member -> SessionFactory.getSession().getChannel(member))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
46
旧的java项目/itcast/server/session/Session.java
Normal file
46
旧的java项目/itcast/server/session/Session.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* 会话管理接口
|
||||
*/
|
||||
public interface Session {
|
||||
|
||||
/**
|
||||
* 绑定会话
|
||||
* @param channel 哪个 channel 要绑定会话
|
||||
* @param username 会话绑定用户
|
||||
*/
|
||||
void bind(Channel channel, String username);
|
||||
|
||||
/**
|
||||
* 解绑会话
|
||||
* @param channel 哪个 channel 要解绑会话
|
||||
*/
|
||||
void unbind(Channel channel);
|
||||
|
||||
/**
|
||||
* 获取属性
|
||||
* @param channel 哪个 channel
|
||||
* @param name 属性名
|
||||
* @return 属性值
|
||||
*/
|
||||
Object getAttribute(Channel channel, String name);
|
||||
|
||||
/**
|
||||
* 设置属性
|
||||
* @param channel 哪个 channel
|
||||
* @param name 属性名
|
||||
* @param value 属性值
|
||||
*/
|
||||
void setAttribute(Channel channel, String name, Object value);
|
||||
|
||||
/**
|
||||
* 根据用户名获取 channel
|
||||
* @param username 用户名
|
||||
* @return channel
|
||||
*/
|
||||
Channel getChannel(String username);
|
||||
}
|
||||
10
旧的java项目/itcast/server/session/SessionFactory.java
Normal file
10
旧的java项目/itcast/server/session/SessionFactory.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
public abstract class SessionFactory {
|
||||
|
||||
private static Session session = new SessionMemoryImpl();
|
||||
|
||||
public static Session getSession() {
|
||||
return session;
|
||||
}
|
||||
}
|
||||
47
旧的java项目/itcast/server/session/SessionMemoryImpl.java
Normal file
47
旧的java项目/itcast/server/session/SessionMemoryImpl.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package cn.itcast.server.session;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SessionMemoryImpl implements Session {
|
||||
|
||||
private final Map<String, Channel> usernameChannelMap = new ConcurrentHashMap<>();
|
||||
private final Map<Channel, String> channelUsernameMap = new ConcurrentHashMap<>();
|
||||
private final Map<Channel,Map<String,Object>> channelAttributesMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void bind(Channel channel, String username) {
|
||||
usernameChannelMap.put(username, channel);
|
||||
channelUsernameMap.put(channel, username);
|
||||
channelAttributesMap.put(channel, new ConcurrentHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind(Channel channel) {
|
||||
String username = channelUsernameMap.remove(channel);
|
||||
usernameChannelMap.remove(username);
|
||||
channelAttributesMap.remove(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(Channel channel, String name) {
|
||||
return channelAttributesMap.get(channel).get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(Channel channel, String name, Object value) {
|
||||
channelAttributesMap.get(channel).put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getChannel(String username) {
|
||||
return usernameChannelMap.get(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return usernameChannelMap.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user