写在前面:
上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块——Common模块记录一下。Common的设计如下:
功能说明:
Common模块主要是数据交互,这里使用JSON数据进行交互,common模块定义了各类交互信息,SendHelper实现的socket信息的传送,I18N是语言话,ConstantValue是系统中的配置以及常量(这里常量都是用接口,这个可能不太好),对于ReturnMessage拥有一系列的DTO作为其content属性。
具体实现:
[SendHelper.java]
SendHelper负责发送socket数据,不管是服务端还是客户端,都由SendHelper来发送数据,SendHelper的具体实现如下:
1 public class SendHelper { 2 3 private SendHelper() { 4 } 5 6 public synchronized static void send(Socket socket, BaseMessage message) { 7 if (socket != null && !socket.isClosed()) { 8 try { 9 PrintWriter out = new PrintWriter(socket.getOutputStream()); 10 LoggerUtil.trach(" [" + JSON.toJSON(message) + "] SEND AT " + new Date()); 11 out.println(JSON.toJSON(message)); 12 out.flush(); // ?? 13 Thread.sleep(ConstantValue.MESSAGE_PERIOD); 14 } catch (Exception ignore) { 15 LoggerUtil.debug("Message send faild !" + ignore.getMessage(), ignore); 16 } 17 } 18 } 19 20 public synchronized static void upload(Socket socket, File file) { 21 if (socket != null && !socket.isClosed()) { 22 InputStream is = null; 23 try { 24 OutputStream os = socket.getOutputStream(); 25 is = new FileInputStream(file); 26 byte[] buff = new byte[ConstantValue.BUFF_SIZE]; 27 int len = -1; 28 while ((len = is.read(buff)) != -1) { 29 os.write(buff, 0, len); 30 } 31 os.flush(); 32 Thread.sleep(ConstantValue.MESSAGE_PERIOD); 33 } catch (Exception ignore) { 34 LoggerUtil.debug("File upload faild !" + ignore.getMessage(), ignore); 35 } finally { 36 if (is != null) { 37 try { 38 is.close(); 39 } catch (Exception ignore) { 40 } 41 is = null; 42 } 43 } 44 } 45 } 46 }
[BaseMessage.java...]
这里使用JSON数据进行交互,所有的消息数据传输对象对应的类都继承BaseMessage,BaseMessage的设计以及其他Message的设计如下(这里为了缩小篇幅,将其他Messaged类的代码收起来):
1 /** 2 * BaseMessage 3 * @author yaolin 4 * 5 */ 6 public class BaseMessage { 7 8 protected String from; 9 protected String to; 10 protected String owner; 11 protected int type; 12 13 public String getFrom() { 14 return from; 15 } 16 public BaseMessage setFrom(String from) { 17 this.from = from; // which tab will be select 18 return this; 19 } 20 public String getTo() { 21 return to; 22 } 23 public BaseMessage setTo(String to) { 24 this.to = to; 25 return this; 26 } 27 public String getOwner() { 28 return owner; 29 } 30 public BaseMessage setOwner(String owner) { 31 this.owner = owner; // display 32 return this; 33 } 34 public int getType() { 35 return type; 36 } 37 public BaseMessage setType(int type) { 38 this.type = type; 39 return this; 40 } 41 42 }
1 public class AliveMessage extends BaseMessage { 2 3 private final int type = MessageType.ALIVE; 4 5 public int getType() { 6 return type; 7 } 8 }
1 public class ChatMessage extends BaseMessage { 2 3 private final int type = MessageType.CHAT; 4 private String content; 5 6 public int getType() { 7 return type; 8 } 9 10 public String getContent() { 11 return content; 12 } 13 14 public ChatMessage setContent(String content) { 15 this.content = content; 16 return this; 17 } 18 }
1 public class FileMessage extends BaseMessage { 2 3 private final int type = MessageType.FILE; 4 5 private String name; 6 private long size; 7 private String ext; 8 9 public String getName() { 10 return name; 11 } 12 13 public FileMessage setName(String name) { 14 this.name = name; 15 return this; 16 } 17 18 public long getSize() { 19 return size; 20 } 21 22 public FileMessage setSize(long size) { 23 this.size = size; 24 return this; 25 } 26 27 public String getExt() { 28 return ext; 29 } 30 31 public FileMessage setExt(String ext) { 32 this.ext = ext; 33 return this; 34 } 35 36 public int getType() { 37 return type; 38 } 39 }
1 public class LoginMessage extends BaseMessage{ 2 3 private final int type = MessageType.LOGIN; 4 private String username; 5 private String password; 6 7 public int getType() { 8 return type; 9 } 10 public String getUsername() { 11 return username; 12 } 13 public LoginMessage setUsername(String username) { 14 this.username = username; 15 return this; 16 } 17 public String getPassword() { 18 return password; 19 } 20 public LoginMessage setPassword(String password) { 21 this.password = password; 22 return this; 23 } 24 }
1 public class LogoutMessage extends BaseMessage { 2 3 private final int type = MessageType.LOGOUT; 4 private String username; 5 public String getUsername() { 6 return username; 7 } 8 public LogoutMessage setUsername(String username) { 9 this.username = username; 10 return this; 11 } 12 public int getType() { 13 return type; 14 } 15 }
1 public class RegisterMessage extends BaseMessage{ 2 3 private final int type = MessageType.REGISTER; 4 private String username; 5 private String password; 6 private String confirm; 7 8 public String getUsername() { 9 return username; 10 } 11 public RegisterMessage setUsername(String username) { 12 this.username = username; 13 return this; 14 } 15 public String getPassword() { 16 return password; 17 } 18 public RegisterMessage setPassword(String password) { 19 this.password = password; 20 return this; 21 } 22 public String getConfirm() { 23 return confirm; 24 } 25 public RegisterMessage setConfirm(String confirm) { 26 this.confirm = confirm; 27 return this; 28 } 29 public int getType() { 30 return type; 31 } 32 }
1 public class ReturnMessage extends BaseMessage { 2 3 private final int type = MessageType.RETURN; 4 private boolean success; 5 // success 6 private String key; 7 private Object content; 8 // error 9 private String message; 10 private String code; 11 12 13 public int getType() { 14 return type; 15 } 16 public boolean isSuccess() { 17 return success; 18 } 19 public ReturnMessage setSuccess(boolean success) { 20 this.success = success; 21 return this; 22 } 23 public String getKey() { 24 return key; 25 } 26 public ReturnMessage setKey(String key) { 27 this.key = key; 28 return this; 29 } 30 public Object getContent() { 31 return content; 32 } 33 public ReturnMessage setContent(Object content) { 34 this.content = content; 35 return this; 36 } 37 public String getMessage() { 38 return message; 39 } 40 public ReturnMessage setMessage(String message) { 41 this.message = message; 42 return this; 43 } 44 public String getCode() { 45 return code; 46 } 47 public ReturnMessage setCode(String code) { 48 this.code = code; 49 return this; 50 } 51 }
对于ReturnMessage,其他Content属性可以是各种DTO,目前有两个,由KEY指定是那种DTO:
1 public interface Key { 2 /** 3 * 登陆 4 */ 5 String LOGIN = "LOGIN"; 6 /** 7 * 注册 8 */ 9 String REGISTER = "REGISTER"; 10 /** 11 * Client 上线 / 离线 通知 12 */ 13 String NOTIFY = "NOTIFY"; 14 /** 15 * 拉去在线 Client 列表 16 */ 17 String LISTUSER = "LISTUSER"; 18 /** 19 * TIP 提示 20 */ 21 String TIP = "TIP"; 22 }
1 public class ClientListUserDTO { 2 3 private Set<String> listUser; 4 5 public Set<String> getListUser() { 6 return listUser; 7 } 8 public void setListUser(Set<String> listUser) { 9 this.listUser = listUser; 10 } 11 }
1 public class ClientNotifyDTO { 2 3 private boolean flag; // true:online,false:offline 4 private String username; // hostname 5 6 public ClientNotifyDTO() { 7 } 8 public ClientNotifyDTO(boolean flag, String username) { 9 this.flag = flag; 10 this.username = username; 11 } 12 public boolean isFlag() { 13 return flag; 14 } 15 public void setFlag(boolean flag) { 16 this.flag = flag; 17 } 18 public String getUsername() { 19 return username; 20 } 21 public void setUsername(String username) { 22 this.username = username; 23 } 24 }
另外几个常量也给出:
1 public interface ConstantValue { 2 /** 3 * 缓冲区大小 4 */ 5 int BUFF_SIZE = 1024; 6 /** 7 * 调试模式 8 */ 9 int DEBUG_LEVEL = 0; 10 /** 11 * 客户端接收文件的存储路径 12 */ 13 String CLIENT_RECEIVE_DIR = "./file"; 14 /** 15 * KEEPALIVE PERIOD‘second 16 */ 17 int KEEP_ALIVE_PERIOD = 20; 18 /** 19 * 最大socket线程处理数 20 */ 21 int MAX_POOL_SIZE = PropertiesUtil.getInt("server-thread-pool-size", 30); 22 /** 23 * <pre> 24 * 检测是否有新的数据时间间隔‘ms 25 * (server.SocketDispatch,client.ReceiveListener,SendHelper) 26 * 使用同一个Thread.sleep时间保证数据能正确接收到,同时降低CPU的使用率 27 * !!!!! -非常重要- !!!!! 28 * </pre> 29 */ 30 int MESSAGE_PERIOD = 500; 31 /** 32 * 服务器IP地址 33 */ 34 String SERVER_IP = PropertiesUtil.get("server-ip", "127.0.0.1"); 35 /** 36 * 服务器名称,用户注册不能使用此用户名 37 */ 38 String SERVER_NAME = "niloay"; 39 /** 40 * 服务器端口 41 */ 42 int SERVER_PORT = PropertiesUtil.getInt("server-port", 8888); 43 /** 44 * SOCKET超时时间‘second 45 */ 46 int TIME_OUT = 120; 47 /** 48 * 群发标识TO:ALL,用户注册不能使用此用户名 49 */ 50 String TO_ALL = "TO_ALL"; 51 }
1 public interface I18N { 2 3 //--------------------------------- 4 // TEXT 5 //--------------------------------- 6 /** 7 * APP_NAME 8 */ 9 String TEXT_APP_NAME = "NILOAY-CHAT v1.0.0"; 10 /** 11 * 登陆 12 */ 13 String TEXT_LOGIN = "登陆"; 14 /** 15 * 注册 16 */ 17 String TEXT_REGISTER = "注册"; 18 /** 19 * 账号 20 */ 21 String TEXT_USERNAME = "账号"; 22 /** 23 * 密码 24 */ 25 String TEXT_PASSWORD = "密码"; 26 27 //--------------------------------- 28 // BTN 29 //--------------------------------- 30 /** 31 * 注册 32 */ 33 String BTN_REGISTER = "注册"; 34 /** 35 * 登陆 36 */ 37 String BTN_LOGIN = "登陆"; 38 /** 39 * 退出 40 */ 41 String BTN_EXIT = "退出"; 42 /** 43 * 发送 44 */ 45 String BTN_SEND = "发送"; 46 /** 47 * 发送文件 48 */ 49 String BTN_SEND_FILE = "发送文件"; 50 51 //--------------------------------- 52 // INFO 53 //--------------------------------- 54 /** 55 * 请填写注册账号和密码 56 */ 57 String INFO_REGISTER_EMPTY_DATA = "请填写注册账号和密码"; 58 /** 59 * 用户已存在 60 */ 61 String INFO_REGISTER_CLIENT_EXIST = "用户已存在"; 62 /** 63 * 注册成功 64 */ 65 String INFO_REGISTER_OK = "注册成功"; 66 /** 67 * 请输入登陆账号和密码 68 */ 69 String INFO_LOGIN_EMPTY_DATA = "请输入登陆账号和密码"; 70 /** 71 * 登陆账号或密码错误 72 */ 73 String INFO_LOGIN_ERROR_DATA = "登陆账号或密码错误"; 74 /** 75 * 暂不支持文件群发 76 */ 77 String INFO_FILE_TO_ALL_ERROR = "暂不支持文件群发"; 78 /** 79 * 文件发送成功 80 */ 81 String INFO_FILE_SEND_SUCCESSFULLY = "文件发送成功"; 82 /** 83 * 文件接收成功 84 */ 85 String INFO_FILE_RECEIVE_SUCCESSFULLY = "文件接收成功"; 86 }
关于socket聊天程序的实现,详见:
时间: 2024-11-05 06:00:24