Reconstruction of JAVA chat room -- a simple framework of CS mode

Posted by samvelyano on Fri, 26 Jun 2020 04:17:25 +0200

preface

Since the beginning of data mining, I haven't written blog about technology for a long time. Recently, school JAVA The course design requires to realize a chat room. I think I wrote one last year, but I didn't realize some of the required functions, but looking at the original code, it seems that it's a little bit difficult to add functions, so I thought about reconstruction. I saw the CS architecture code written by others before, and I felt that the expansibility was good, so I tried to write it. After writing this chat room At the same time, I also wrote a teaching whiteboard. The whiteboard code based on this chat room took only three or four hours to complete! So it's important to have a good architecture. Let's start with my reconstructed chat room( Code uploaded to github)

Function introduction

1. Write chat server and client with Java GUI, and support multiple clients to connect to one server. Each client can input account, including registration function.

2. Group chat can be realized (chat record is displayed in all client interfaces).

3. Complete the display of friends list on each client, including the avatar and user name.

4. It can realize private chat, and users can select a certain other user to send information separately. At the same time, it can realize file transmission and send window vibration.

5. The server can send system messages in groups, private messages to users, and force some users to go offline.

6. When the client is online or offline, it is required to be able to refresh in real time on other clients.

7. The server can view online users and registered users

(those underlined are beyond the requirements of the course)

Overall thinking

After counting, I wrote 27 classes in total, which seems to be quite a lot, but it's very simple to look at them carefully. I'll explain some of them below

Tools

In several socket communication projects I wrote before, the client and the server transmit strings. This time, I encapsulate the content to be transmitted into two classes: Response and Request: the client sends a request to the server, and the server responds to the client. The operation to be performed is determined by the request type contained in the two classes. ObjectStream is used for transmission. If you look closely, you will find that the contents of these two classes are very similar

Request

 1 public class Request implements Serializable {
 2     private static final long serialVersionUID = -1237018286305074249L;
 3     /** Data type requested for transfer */
 4     private ResponseType type;
 5     /** Request action */
 6     private String action;
 7     /** Data in request domain, name value */
 8     private Map<String, Object> attributesMap;
 9 
10     public Request(){
11         this.attributesMap = new HashMap<String, Object>();
12     }
13 
14     public ResponseType getType() {
15         return type;
16     }
17 
18     public void setType(ResponseType type) {
19         this.type = type;
20     }
21 
22     public String getAction() {
23         return action;
24     }
25 
26     public void setAction(String action) {
27         this.action = action;
28     }
29 
30     public Map<String, Object> getAttributesMap() {
31         return attributesMap;
32     }
33 
34     public Object getAttribute(String name){
35         return this.attributesMap.get(name);
36     }
37 
38     public void setAttribute(String name, Object value){
39         this.attributesMap.put(name, value);
40     }
41 
42     public void removeAttribute(String name){
43         this.attributesMap.remove(name);
44     }
45 
46     public void clearAttribute(){
47         this.attributesMap.clear();
48     }
49 }
Request

Response

 1 public class Response implements Serializable {
 2     private static final long serialVersionUID = 1689541820872288991L;
 3     /** Response status */
 4     private ResponseStatus status;
 5     /** Type of response data */
 6     private ResponseType type;
 7 
 8     private Map<String, Object> dataMap;
 9 
10     /** Response output stream */
11     private OutputStream outputStream;
12 
13     public Response(){
14         this.status = ResponseStatus.OK;
15         this.dataMap = new HashMap<String, Object>();
16     }
17 
18 
19     public ResponseStatus getStatus() {
20         return status;
21     }
22 
23     public void setStatus(ResponseStatus status) {
24         this.status = status;
25     }
26 
27     public ResponseType getType() {
28         return type;
29     }
30 
31     public void setType(ResponseType type) {
32         this.type = type;
33     }
34 
35     public Map<String, Object> getDataMap() {
36         return dataMap;
37     }
38 
39     public void setDataMap(Map<String, Object> dataMap) {
40         this.dataMap = dataMap;
41     }
42 
43     public OutputStream getOutputStream() {
44         return outputStream;
45     }
46 
47     public void setOutputStream(OutputStream outputStream) {
48         this.outputStream = outputStream;
49     }
50 
51     public void setData(String name, Object value){
52         this.dataMap.put(name, value);
53     }
54 
55     public Object getData(String name){
56         return this.dataMap.get(name);
57     }
58 
59     public void removeData(String name){
60         this.dataMap.remove(name);
61     }
62 
63     public void clearData(){
64         this.dataMap.clear();
65     }
66 }
Response

In the above two classes, the content of transmission will include files and messages. For files and messages, we need to know who is the sender and the receiver, the sending time, and so on, so we also encapsulate them into two classes

FileInfo

 1 public class FileInfo implements Serializable {
 2     private static final long serialVersionUID = -5394575332459969403L;
 3     /** Message Receiver  */
 4     private User toUser;
 5     /** message sender  */
 6     private User fromUser;
 7     /** Source filename */
 8     private String srcName;
 9     /** Send time */
10     private Date sendTime;
11     /** Destination IP */
12     private String destIp;
13     /** Destination port */
14     private int destPort;
15     /** Destination filename */
16     private String destName;
17     public User getToUser() {
18         return toUser;
19     }
20     public void setToUser(User toUser) {
21         this.toUser = toUser;
22     }
23     public User getFromUser() {
24         return fromUser;
25     }
26     public void setFromUser(User fromUser) {
27         this.fromUser = fromUser;
28     }
29     public String getSrcName() {
30         return srcName;
31     }
32     public void setSrcName(String srcName) {
33         this.srcName = srcName;
34     }
35     public Date getSendTime() {
36         return sendTime;
37     }
38     public void setSendTime(Date sendTime) {
39         this.sendTime = sendTime;
40     }
41     public String getDestIp() {
42         return destIp;
43     }
44     public void setDestIp(String destIp) {
45         this.destIp = destIp;
46     }
47     public int getDestPort() {
48         return destPort;
49     }
50     public void setDestPort(int destPort) {
51         this.destPort = destPort;
52     }
53     public String getDestName() {
54         return destName;
55     }
56     public void setDestName(String destName) {
57         this.destName = destName;
58     }
59 }
FileInfo

Message

 1 public class Message implements Serializable {
 2     private static final long serialVersionUID = 1820192075144114657L;
 3     /** Message Receiver  */
 4     private User toUser;
 5     /** message sender  */
 6     private User fromUser;
 7     /** Message content */
 8     private String message;
 9     /** Send time */
10     private Date sendTime;
11 
12 
13     public User getToUser() {
14         return toUser;
15     }
16     public void setToUser(User toUser) {
17         this.toUser = toUser;
18     }
19     public User getFromUser() {
20         return fromUser;
21     }
22     public void setFromUser(User fromUser) {
23         this.fromUser = fromUser;
24     }
25     public String getMessage() {
26         return message;
27     }
28     public void setMessage(String message) {
29         this.message = message;
30     }
31 
32     public Date getSendTime() {
33         return sendTime;
34     }
35     public void setSendTime(Date sendTime) {
36         this.sendTime = sendTime;
37     }
38 }
Message

User

The User class is used to store User information, because it will be used for transmission, and the serialization transmission is required

  1 public class User implements Serializable {
  2     private static final long serialVersionUID = 5942011574971970871L;
  3     private long id;
  4     private String password;
  5     private String nickname;
  6     private int head;
  7     private char sex;
  8 
  9     public User(String password, String nickname, char sex, int head){
 10         this.password = password;
 11         this.sex = sex;
 12         this.head = head;
 13         if(nickname.equals("")||nickname==null)
 14         {
 15             this.nickname = "Unnamed";
 16         }else{
 17             this.nickname = nickname;
 18         }
 19     }
 20 
 21     public User(long id, String password){
 22         this.id = id;
 23         this.password = password;
 24     }
 25 
 26     public long getId(){
 27         return  id;
 28     }
 29 
 30     public void setId(long id){
 31         this.id = id;
 32     }
 33 
 34     public void setPassword(String password){
 35         this.password = password;
 36     }
 37 
 38     public String getPassword(){
 39         return password;
 40     }
 41 
 42     public void setSex(char sex){
 43         this.sex=sex;
 44     }
 45 
 46     public char getSex(){
 47         return this.sex;
 48     }
 49 
 50     public void setNickname(String nickname){
 51         this.nickname = nickname;
 52     }
 53 
 54     public String getNickname(){
 55         return this.nickname;
 56     }
 57 
 58     public void setHead(int head){
 59         this.head = head;
 60     }
 61 
 62     public int getHead(){
 63         return this.head;
 64     }
 65 
 66     public ImageIcon getHeadIcon(){
 67         ImageIcon image = new ImageIcon("images/"+head+".png");
 68         return image;
 69     }
 70 
 71     @Override
 72     public int hashCode() {
 73         final int prime = 31;
 74         int result = 1;
 75         result = prime * result + head;
 76         result = prime * result + (int)(id ^ (id >> 32));
 77         result = prime * result + ((nickname == null) ? 0 : nickname.hashCode());
 78         result = prime * result + ((password == null) ? 0 : password.hashCode());
 79         result = prime * result + sex;
 80         return result;
 81     }
 82 
 83     @Override
 84     public boolean equals(Object obj) {
 85         if(this == obj)
 86             return true;
 87         if(obj == null)
 88             return false;
 89         if(getClass() != obj.getClass())
 90             return false;
 91         User other = (User) obj;
 92         if(head != other.head || id != other.id || sex != other.sex)
 93             return false;
 94         if(nickname == null){
 95             if(other.nickname != null)
 96                 return false;
 97         }else if(!nickname.equals(other.nickname))
 98             return false;
 99         if(password == null){
100             if(other.password != null)
101                 return false;
102         }else if(!password.equals(other.password))
103             return  false;
104         return true;
105     }
106 
107     @Override
108     public String toString() {
109         return this.getClass().getName()
110                 + "[id=" + this.id
111                 + ",pwd=" + this.password
112                 + ",nickname=" + this.nickname
113                 + ",head=" + this.head
114                 + ",sex=" + this.sex
115                 + "]";
116     }
117 }
User

The remaining classes will not be introduced one by one. You can go to my github Source code found on.

Server side

The classes used in the server-side code are shown above. Two classes in entity and ServerInfoFrame are only used for the interface, so they will not be introduced.

UserService

It is used for user account management. Several accounts are created in advance and then saved in the file. Each time the server executes, the account information in the file will be read in, and the newly created user account will also be saved in the file.

  1 public class UserService {
  2     private static int idCount = 3; //id
  3 
  4     /** New users */
  5     public void addUser(User user){
  6         user.setId(++idCount);
  7         List<User> users = loadAllUser();
  8         users.add(user);
  9         saveAllUser(users);
 10     }
 11 
 12     /** User login */
 13     public User login(long id, String password){
 14         User result = null;
 15         List<User> users = loadAllUser();
 16         for (User user : users) {
 17             if(id == user.getId() && password.equals(user.getPassword())){
 18                 result = user;
 19                 break;
 20             }
 21         }
 22         return result;
 23     }
 24 
 25     /** Load users by ID */
 26     public User loadUser(long id){
 27         User result = null;
 28         List<User> users = loadAllUser();
 29         for (User user : users) {
 30             if(id == user.getId()){
 31                 result = user;
 32                 break;
 33             }
 34         }
 35         return result;
 36     }
 37 
 38 
 39     /** Load all users */
 40     @SuppressWarnings("unchecked")
 41     public List<User> loadAllUser() {
 42         List<User> list = null;
 43         ObjectInputStream ois = null;
 44         try {
 45             ois = new ObjectInputStream(
 46                     new FileInputStream(
 47                             DataBuffer.configProp.getProperty("dbpath")));
 48 
 49             list = (List<User>)ois.readObject();
 50         } catch (Exception e) {
 51             e.printStackTrace();
 52         }finally{
 53             IOUtil.close(ois);
 54         }
 55         return list;
 56     }
 57 
 58     private void saveAllUser(List<User> users) {
 59         ObjectOutputStream oos = null;
 60         try {
 61             oos = new ObjectOutputStream(
 62                     new FileOutputStream(
 63                             DataBuffer.configProp.getProperty("dbpath")));
 64             //Write back user information
 65             oos.writeObject(users);
 66             oos.flush();
 67         } catch (Exception e) {
 68             e.printStackTrace();
 69         }finally{
 70             IOUtil.close(oos);
 71         }
 72     }
 73 
 74 
 75 
 76     /** Initialize several test users */
 77     public void initUser(){
 78         User user = new User("admin", "Admin", 'm', 0);
 79         user.setId(1);
 80 
 81         User user2 = new User("123", "yong", 'm', 1);
 82         user2.setId(2);
 83 
 84         User user3 = new User("123", "anni", 'f', 2);
 85         user3.setId(3);
 86 
 87         List<User> users = new CopyOnWriteArrayList<User>();
 88         users.add(user);
 89         users.add(user2);
 90         users.add(user3);
 91 
 92         this.saveAllUser(users);
 93     }
 94 
 95     public static void main(String[] args){
 96         new UserService().initUser();
 97         List<User> users = new UserService().loadAllUser();
 98         for (User user : users) {
 99             System.out.println(user);
100         }
101     }
102 }
UserService

DataBuffer

It is used by the server to read data from the file and cache it

 1 public class DataBuffer {
 2     // Server socket
 3     public static ServerSocket serverSocket;
 4     //For online users IO Map
 5     public static Map<Long, OnlineClientIOCache> onlineUserIOCacheMap;
 6     //Online users Map
 7     public static Map<Long, User> onlineUsersMap;
 8     //Server configuration parameter property set
 9     public static Properties configProp;
10     // Of registered user tables Model
11     public static RegistedUserTableModel registedUserTableModel;
12     // Of the current online user table Model
13     public static OnlineUserTableModel onlineUserTableModel;
14     // Screen size of the system where the current server is located
15     public static Dimension screenSize;
16 
17     static{
18         // initialization
19         onlineUserIOCacheMap = new ConcurrentSkipListMap<Long,OnlineClientIOCache>();
20         onlineUsersMap = new ConcurrentSkipListMap<Long, User>();
21         configProp = new Properties();
22         registedUserTableModel = new RegistedUserTableModel();
23         onlineUserTableModel = new OnlineUserTableModel();
24         screenSize = Toolkit.getDefaultToolkit().getScreenSize();
25 
26         // Load server profile
27         try {
28             configProp.load(Thread.currentThread()
29                     .getContextClassLoader()
30                     .getResourceAsStream("serverconfig.properties"));
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34     }
35 
36 }
DataBuffer

RequestProcessor

At this time, the most important class on the server side is used to process the messages sent by the client side and reply to them. The implementation principle of each operation is nothing more than that the server processes internal data or sends messages to the specified client side. See the code comments in detail

  1 public class RequestProcessor implements Runnable {
  2     private Socket currentClientSocket;  //Client currently requesting server Socket
  3 
  4     public RequestProcessor(Socket currentClientSocket){
  5         this.currentClientSocket = currentClientSocket;
  6     }
  7 
  8     public void run() {
  9         boolean flag = true; //Continuous monitoring or not
 10         try{
 11             OnlineClientIOCache currentClientIOCache = new OnlineClientIOCache(
 12                     new ObjectInputStream(currentClientSocket.getInputStream()),
 13                     new ObjectOutputStream(currentClientSocket.getOutputStream()));
 14             while(flag){ //Constantly reading the request object sent by the client
 15                 //Read the request object submitted by the client from the request input stream
 16                 Request request = (Request)currentClientIOCache.getOis().readObject();
 17                 System.out.println("Server Read client's request:" + request.getAction());
 18 
 19                 String actionName = request.getAction();   //Get action in request
 20                 if(actionName.equals("userRegiste")){      //User registration
 21                     registe(currentClientIOCache, request);
 22                 }else if(actionName.equals("userLogin")){  //User login
 23                     login(currentClientIOCache, request);
 24                 }else if("exit".equals(actionName)){       //Request to disconnect
 25                     flag = logout(currentClientIOCache, request);
 26                 }else if("chat".equals(actionName)){       //chat
 27                     chat(request);
 28                 }else if("shake".equals(actionName)){      //Vibration
 29                     shake(request);
 30                 }else if("toSendFile".equals(actionName)){ //Ready to send file
 31                     toSendFile(request);
 32                 }else if("agreeReceiveFile".equals(actionName)){ //Agree to receive documents
 33                     agreeReceiveFile(request);
 34                 }else if("refuseReceiveFile".equals(actionName)){ //Reject file
 35                     refuseReceiveFile(request);
 36                 }
 37             }
 38         }catch(Exception e){
 39             e.printStackTrace();
 40         }
 41     }
 42 
 43     /** Reject file */
 44     private void refuseReceiveFile(Request request) throws IOException {
 45         FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");
 46         Response response = new Response();  //Create a response object
 47         response.setType(ResponseType.REFUSERECEIVEFILE);
 48         response.setData("sendFile", sendFile);
 49         response.setStatus(ResponseStatus.OK);
 50         //Output response to the requester's output stream
 51         OnlineClientIOCache ocic = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());
 52         this.sendResponse(ocic, response);
 53     }
 54 
 55     /** Agree to receive documents */
 56     private void agreeReceiveFile(Request request) throws IOException {
 57         FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");
 58         //To the requesting party(Sender)Output stream output response of
 59         Response response = new Response();  //Create a response object
 60         response.setType(ResponseType.AGREERECEIVEFILE);
 61         response.setData("sendFile", sendFile);
 62         response.setStatus(ResponseStatus.OK);
 63         OnlineClientIOCache sendIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());
 64         this.sendResponse(sendIO, response);
 65 
 66         //Send the response of receiving file to the receiver
 67         Response response2 = new Response();  //Create a response object
 68         response2.setType(ResponseType.RECEIVEFILE);
 69         response2.setData("sendFile", sendFile);
 70         response2.setStatus(ResponseStatus.OK);
 71         OnlineClientIOCache receiveIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());
 72         this.sendResponse(receiveIO, response2);
 73     }
 74 
 75     /** Client exit */
 76     public boolean logout(OnlineClientIOCache oio, Request request) throws IOException{
 77         System.out.println(currentClientSocket.getInetAddress().getHostAddress()
 78                 + ":" + currentClientSocket.getPort() + "be gone");
 79 
 80         User user = (User)request.getAttribute("user");
 81         //Put the current online client's IO from Map Delete from
 82         DataBuffer.onlineUserIOCacheMap.remove(user.getId());
 83         //Cache from online users Map Delete current user from
 84         DataBuffer.onlineUsersMap.remove(user.getId());
 85 
 86         Response response = new Response();  //Create a response object
 87         response.setType(ResponseType.LOGOUT);
 88         response.setData("logoutUser", user);
 89         oio.getOos().writeObject(response);  //Write the response object to the client
 90         oio.getOos().flush();
 91         currentClientSocket.close();  //Close this client Socket
 92 
 93         DataBuffer.onlineUserTableModel.remove(user.getId()); //List current offline users from online users Model Delete from
 94         iteratorResponse(response);//Notify all other online clients
 95 
 96         return false;  //Disconnect monitor
 97     }
 98     /** register */
 99     public void registe(OnlineClientIOCache oio, Request request) throws IOException {
100         User user = (User)request.getAttribute("user");
101         UserService userService = new UserService();
102         userService.addUser(user);
103 
104         Response response = new Response();  //Create a response object
105         response.setStatus(ResponseStatus.OK);
106         response.setData("user", user);
107 
108         oio.getOos().writeObject(response);  //Write the response object to the client
109         oio.getOos().flush();
110 
111         //Add new registered users to RegistedUserTableModel in
112         DataBuffer.registedUserTableModel.add(new String[]{
113                 String.valueOf(user.getId()),
114                 user.getPassword(),
115                 user.getNickname(),
116                 String.valueOf(user.getSex())
117         });
118     }
119 
120     /** Sign in */
121     public void login(OnlineClientIOCache currentClientIO, Request request) throws IOException {
122         String idStr = (String)request.getAttribute("id");
123         String password = (String) request.getAttribute("password");
124         UserService userService = new UserService();
125         User user = userService.login(Long.parseLong(idStr), password);
126 
127         Response response = new Response();  //Create a response object
128         if(null != user){
129             if(DataBuffer.onlineUsersMap.containsKey(user.getId())){ //The user is already logged in
130                 response.setStatus(ResponseStatus.OK);
131                 response.setData("msg", "The user is already online elsewhere!");
132                 currentClientIO.getOos().writeObject(response);  //Write the response object to the client
133                 currentClientIO.getOos().flush();
134             }else { //Log in correctly
135                 DataBuffer.onlineUsersMap.put(user.getId(), user); //Add to online users
136 
137                 //Set up online users
138                 response.setData("onlineUsers",
139                         new CopyOnWriteArrayList<User>(DataBuffer.onlineUsersMap.values()));
140 
141                 response.setStatus(ResponseStatus.OK);
142                 response.setData("user", user);
143                 currentClientIO.getOos().writeObject(response);  //Write the response object to the client
144                 currentClientIO.getOos().flush();
145 
146                 //Notify other users that someone is online
147                 Response response2 = new Response();
148                 response2.setType(ResponseType.LOGIN);
149                 response2.setData("loginUser", user);
150                 iteratorResponse(response2);
151 
152                 //Put the current online users IO Add to cache Map in
153                 DataBuffer.onlineUserIOCacheMap.put(user.getId(),currentClientIO);
154 
155                 //Add current online users to OnlineUserTableModel in
156                 DataBuffer.onlineUserTableModel.add(
157                         new String[]{String.valueOf(user.getId()),
158                                 user.getNickname(),
159                                 String.valueOf(user.getSex())});
160             }
161         }else{ //Login failed
162             response.setStatus(ResponseStatus.OK);
163             response.setData("msg", "Incorrect account or password!");
164             currentClientIO.getOos().writeObject(response);
165             currentClientIO.getOos().flush();
166         }
167     }
168 
169     /** chat */
170     public void chat(Request request) throws IOException {
171         Message msg = (Message)request.getAttribute("msg");
172         Response response = new Response();
173         response.setStatus(ResponseStatus.OK);
174         response.setType(ResponseType.CHAT);
175         response.setData("txtMsg", msg);
176 
177         if(msg.getToUser() != null){ //Private chat:Only respond to private chat objects
178             OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
179             sendResponse(io, response);
180         }else{  //Group chat:Returns a response to all clients except those sending messages
181             for(Long id : DataBuffer.onlineUserIOCacheMap.keySet()){
182                 if(msg.getFromUser().getId() == id ){    continue; }
183                 sendResponse(DataBuffer.onlineUserIOCacheMap.get(id), response);
184             }
185         }
186     }
187 
188     /*radio broadcast*/
189     public static void board(String str) throws IOException {
190         User user = new User(1,"admin");
191         Message msg = new Message();
192         msg.setFromUser(user);
193         msg.setSendTime(new Date());
194 
195         DateFormat df = new SimpleDateFormat("HH:mm:ss");
196         StringBuffer sb = new StringBuffer();
197         sb.append(" ").append(df.format(msg.getSendTime())).append(" ");
198         sb.append("System notification\n  "+str+"\n");
199         msg.setMessage(sb.toString());
200 
201         Response response = new Response();
202         response.setStatus(ResponseStatus.OK);
203         response.setType(ResponseType.BOARD);
204         response.setData("txtMsg", msg);
205 
206         for (Long id : DataBuffer.onlineUserIOCacheMap.keySet()) {
207             sendResponse_sys(DataBuffer.onlineUserIOCacheMap.get(id), response);
208         }
209     }
210 
211     /*Kick user*/
212     public static void remove(User user_) throws IOException{
213         User user = new User(1,"admin");
214         Message msg = new Message();
215         msg.setFromUser(user);
216         msg.setSendTime(new Date());
217         msg.setToUser(user_);
218 
219         StringBuffer sb = new StringBuffer();
220         DateFormat df = new SimpleDateFormat("HH:mm:ss");
221         sb.append(" ").append(df.format(msg.getSendTime())).append(" ");
222         sb.append("System informs you\n  "+"You are forced to go offline"+"\n");
223         msg.setMessage(sb.toString());
224 
225         Response response = new Response();
226         response.setStatus(ResponseStatus.OK);
227         response.setType(ResponseType.REMOVE);
228         response.setData("txtMsg", msg);
229 
230         OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
231         sendResponse_sys(io, response);
232     }
233 
234     /*private letter*/
235     public static void chat_sys(String str,User user_) throws IOException{
236         User user = new User(1,"admin");
237         Message msg = new Message();
238         msg.setFromUser(user);
239         msg.setSendTime(new Date());
240         msg.setToUser(user_);
241 
242         DateFormat df = new SimpleDateFormat("HH:mm:ss");
243         StringBuffer sb = new StringBuffer();
244         sb.append(" ").append(df.format(msg.getSendTime())).append(" ");
245         sb.append("System informs you\n  "+str+"\n");
246         msg.setMessage(sb.toString());
247 
248         Response response = new Response();
249         response.setStatus(ResponseStatus.OK);
250         response.setType(ResponseType.CHAT);
251         response.setData("txtMsg", msg);
252 
253         OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
254         sendResponse_sys(io, response);
255     }
256 
257     /** Send vibration */
258     public void shake(Request request)throws IOException {
259         Message msg = (Message) request.getAttribute("msg");
260 
261         DateFormat df = new SimpleDateFormat("HH:mm:ss");
262         StringBuffer sb = new StringBuffer();
263         sb.append(" ").append(msg.getFromUser().getNickname())
264                 .append("(").append(msg.getFromUser().getId()).append(") ")
265                 .append(df.format(msg.getSendTime())).append("\n  Sent you a window jitter\n");
266         msg.setMessage(sb.toString());
267 
268         Response response = new Response();
269         response.setStatus(ResponseStatus.OK);
270         response.setType(ResponseType.SHAKE);
271         response.setData("ShakeMsg", msg);
272 
273         OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
274         sendResponse(io, response);
275     }
276 
277     /** Ready to send file */
278     public void toSendFile(Request request)throws IOException{
279         Response response = new Response();
280         response.setStatus(ResponseStatus.OK);
281         response.setType(ResponseType.TOSENDFILE);
282         FileInfo sendFile = (FileInfo)request.getAttribute("file");
283         response.setData("sendFile", sendFile);
284         //Forward a request from the sender to the receiver
285         OnlineClientIOCache ioCache = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());
286         sendResponse(ioCache, response);
287     }
288 
289     /** Send a response to all online customers */
290     private void iteratorResponse(Response response) throws IOException {
291         for(OnlineClientIOCache onlineUserIO : DataBuffer.onlineUserIOCacheMap.values()){
292             ObjectOutputStream oos = onlineUserIO.getOos();
293             oos.writeObject(response);
294             oos.flush();
295         }
296     }
297 
298     /** Outputs the specified response to the output stream of the specified client IO */
299     private void sendResponse(OnlineClientIOCache onlineUserIO, Response response)throws IOException {
300         ObjectOutputStream oos = onlineUserIO.getOos();
301         oos.writeObject(response);
302         oos.flush();
303     }
304 
305     /** Outputs the specified response to the output stream of the specified client IO */
306     private static void sendResponse_sys(OnlineClientIOCache onlineUserIO, Response response)throws IOException {
307         ObjectOutputStream oos = onlineUserIO.getOos();
308         oos.writeObject(response);
309         oos.flush();
310     }
311 }
RequestProcessor

Client side

Personal feeling when doing this kind of project, the difficulty is in the client. I have considered the interface switching for a long time before, because it involves the login interface, the registration interface and the chat interface, so how to connect the socket of the client with these interfaces is a problem worthy of consideration. At the same time, I also thought about the display method of friends list for a long time, and finally thought of TIM. Here are some of the classes

ClientThread

Client thread, a thread represents a user, processes messages sent by the server, and uses the variable currentFrame to represent the current window.

  1 public class ClientThread extends Thread {
  2     private JFrame currentFrame;  //Current form
  3 
  4     public ClientThread(JFrame frame){
  5         currentFrame = frame;
  6     }
  7 
  8     public void run() {
  9         try {
 10             while (DataBuffer.clientSeocket.isConnected()) {
 11                 Response response = (Response) DataBuffer.ois.readObject();
 12                 ResponseType type = response.getType();
 13 
 14                 System.out.println("Get response content:" + type);
 15                 if (type == ResponseType.LOGIN) {
 16                     User newUser = (User)response.getData("loginUser");
 17                     DataBuffer.onlineUserListModel.addElement(newUser);
 18 
 19                     ChatFrame.onlineCountLbl.setText(
 20                             "List of online users("+ DataBuffer.onlineUserListModel.getSize() +")");
 21                     ClientUtil.appendTxt2MsgListArea("[System message] user"+newUser.getNickname() + "Online!\n");
 22                 }else if(type == ResponseType.LOGOUT){
 23                     User newUser = (User)response.getData("logoutUser");
 24                     DataBuffer.onlineUserListModel.removeElement(newUser);
 25 
 26                     ChatFrame.onlineCountLbl.setText(
 27                             "List of online users("+ DataBuffer.onlineUserListModel.getSize() +")");
 28                     ClientUtil.appendTxt2MsgListArea("[System message] user"+newUser.getNickname() + "Offline!\n");
 29 
 30                 }else if(type == ResponseType.CHAT){ //chat
 31                     Message msg = (Message)response.getData("txtMsg");
 32                     ClientUtil.appendTxt2MsgListArea(msg.getMessage());
 33                 }else if(type == ResponseType.SHAKE){ //Vibration
 34                     Message msg = (Message)response.getData("ShakeMsg");
 35                     ClientUtil.appendTxt2MsgListArea(msg.getMessage());
 36                     new JFrameShaker(this.currentFrame).startShake();
 37                 }else if(type == ResponseType.TOSENDFILE){ //Ready to send file
 38                     toSendFile(response);
 39                 }else if(type == ResponseType.AGREERECEIVEFILE){ //The other party agrees to receive the documents
 40                     sendFile(response);
 41                 }else if(type == ResponseType.REFUSERECEIVEFILE){ //The other party refuses to receive the document
 42                     ClientUtil.appendTxt2MsgListArea("[File message] the other party refused to receive, file sending failed!\n");
 43                 }else if(type == ResponseType.RECEIVEFILE){ //Start receiving files
 44                     receiveFile(response);
 45                 }else if(type == ResponseType.BOARD){
 46                     Message msg = (Message)response.getData("txtMsg");
 47                     ClientUtil.appendTxt2MsgListArea(msg.getMessage());
 48                 }else if(type == ResponseType.REMOVE){
 49                     ChatFrame.remove();
 50                 }
 51             }
 52         } catch (IOException e) {
 53             //e.printStackTrace();
 54         } catch (ClassNotFoundException e) {
 55             e.printStackTrace();
 56         }
 57     }
 58 
 59     /** send files */
 60     private void sendFile(Response response) {
 61         final FileInfo sendFile = (FileInfo)response.getData("sendFile");
 62 
 63         BufferedInputStream bis = null;
 64         BufferedOutputStream bos = null;
 65         Socket socket = null;
 66         try {
 67             socket = new Socket(sendFile.getDestIp(),sendFile.getDestPort());//socket connection 
 68             bis = new BufferedInputStream(new FileInputStream(sendFile.getSrcName()));//File read in
 69             bos = new BufferedOutputStream(socket.getOutputStream());//Document writing out
 70 
 71             byte[] buffer = new byte[1024];
 72             int n = -1;
 73             while ((n = bis.read(buffer)) != -1){
 74                 bos.write(buffer, 0, n);
 75             }
 76             bos.flush();
 77             synchronized (this) {
 78                 ClientUtil.appendTxt2MsgListArea("[File message] file sending completed!\n");
 79             }
 80         } catch (IOException e) {
 81             e.printStackTrace();
 82         }finally{
 83             IOUtil.close(bis,bos);
 84             SocketUtil.close(socket);
 85         }
 86     }
 87 
 88     /** receive files */
 89     private void receiveFile(Response response) {
 90         final FileInfo sendFile = (FileInfo)response.getData("sendFile");
 91 
 92         BufferedInputStream bis = null;
 93         BufferedOutputStream bos = null;
 94         ServerSocket serverSocket = null;
 95         Socket socket = null;
 96         try {
 97             serverSocket = new ServerSocket(sendFile.getDestPort());
 98             socket = serverSocket.accept(); //receive
 99             bis = new BufferedInputStream(socket.getInputStream());//Buffer reading
100             bos = new BufferedOutputStream(new FileOutputStream(sendFile.getDestName()));//Buffer write out
101 
102             byte[] buffer = new byte[1024];
103             int n = -1;
104             while ((n = bis.read(buffer)) != -1){
105                 bos.write(buffer, 0, n);
106             }
107             bos.flush();
108             synchronized (this) {
109                 ClientUtil.appendTxt2MsgListArea("[File message] file receiving completed!Store in["
110                         + sendFile.getDestName()+"]\n");
111             }
112 
113         } catch (IOException e) {
114             e.printStackTrace();
115         }finally{
116             IOUtil.close(bis,bos);
117             SocketUtil.close(socket);
118             SocketUtil.close(serverSocket);
119         }
120     }
121 
122     /** Ready to send file     */
123     private void toSendFile(Response response) {
124         FileInfo sendFile = (FileInfo)response.getData("sendFile");
125 
126         String fromName = sendFile.getFromUser().getNickname()
127                 + "(" + sendFile.getFromUser().getId() + ")";
128         String fileName = sendFile.getSrcName()
129                 .substring(sendFile.getSrcName().lastIndexOf(File.separator)+1);
130 
131         int select = JOptionPane.showConfirmDialog(this.currentFrame,
132                 fromName + " Send files to you [" + fileName+ "]!\n Do you agree to accept?",
133                 "receive files", JOptionPane.YES_NO_OPTION);
134         try {
135             Request request = new Request();
136             request.setAttribute("sendFile", sendFile);
137 
138             if (select == JOptionPane.YES_OPTION) {
139                 JFileChooser jfc = new JFileChooser();
140                 jfc.setSelectedFile(new File(fileName));
141                 int result = jfc.showSaveDialog(this.currentFrame);
142 
143                 if (result == JFileChooser.APPROVE_OPTION){
144                     //Set destination file name
145                     sendFile.setDestName(jfc.getSelectedFile().getCanonicalPath());
146                     //Set the IP And receive file port
147                     sendFile.setDestIp(DataBuffer.ip);
148                     sendFile.setDestPort(DataBuffer.RECEIVE_FILE_PORT);
149 
150                     request.setAction("agreeReceiveFile");
151 //                    receiveFile(response);
152                     ClientUtil.appendTxt2MsgListArea("[File message] you have agreed to receive from "
153                             + fromName +" Files for, receiving files ...\n");
154                 } else {
155                     request.setAction("refuseReceiveFile");
156                     ClientUtil.appendTxt2MsgListArea("[File message] you have declined to receive from "
157                             + fromName +" Documents of!\n");
158                 }
159             } else {
160                 request.setAction("refuseReceiveFile");
161                 ClientUtil.appendTxt2MsgListArea("[File message] you have declined to receive from "
162                         + fromName +" Documents of!\n");
163             }
164 
165             ClientUtil.sendTextRequest2(request);
166         } catch (IOException e) {
167             e.printStackTrace();
168         }
169     }
170 }
ClientThread

ClientUtil

For clients to send messages to servers

 1 public class ClientUtil {
 2 
 3     /** Send request object and receive response actively */
 4     public static Response sendTextRequest(Request request) throws IOException {
 5         Response response = null;
 6         try {
 7             // Send request
 8             DataBuffer.oos.writeObject(request);
 9             DataBuffer.oos.flush();
10             System.out.println("Client sent request object:" + request.getAction());
11 
12             if(!"exit".equals(request.getAction())){
13                 // Get response
14                 response = (Response) DataBuffer.ois.readObject();
15                 System.out.println("Client got response object:" + response.getStatus());
16             }else{
17                 System.out.println("Client disconnected");
18             }
19         } catch (IOException e) {
20             throw e;
21         } catch (ClassNotFoundException e) {
22             e.printStackTrace();
23         }
24         return response;
25     }
26 
27     /** Send request object, do not actively receive response */
28     public static void sendTextRequest2(Request request) throws IOException {
29         try {
30             DataBuffer.oos.writeObject(request); // Send request
31             DataBuffer.oos.flush();
32             System.out.println("Client sent request object:" + request.getAction());
33         } catch (IOException e) {
34             throw e;
35         }
36     }
37 
38     /** Add the specified text to the message list text field */
39     public static void appendTxt2MsgListArea(String txt) {
40         ChatFrame.msgListArea.append(txt);
41         //Position the cursor to the last line of the text field
42         ChatFrame.msgListArea.setCaretPosition(ChatFrame.msgListArea.getDocument().getLength());
43     }
44 }
ClientUtil

summary

I will introduce these in general details. Most of the rest is interface related code. I will put the whole project into github Yes, I feel that the current framework can adapt to all tasks related to CS architecture arranged by the school. I've learned that it's only a few hours for others to finish in a few days, and it looks more comfortable than others. The next article will introduce the use of this framework to achieve another project - teaching whiteboard.

Topics: socket github Java REST