写在前面:
上一篇记录了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 }
View Code
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 }
View Code
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 }
View Code
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 }
View Code
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 }
View Code
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 }
View Code
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 }
View Code
对于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 }