catalogue
-
1, Foreword
-
2, Demonstration
-
3, System design
-
4, UI development
-
1. Overall structure definition and sidebar
-
2. Dialog box
-
3. Friends bar
-
4. Event definition
-
5, Communication design
-
1. System architecture
-
2. Communication protocol
-
3. Add friends
-
4. Message response
-
5. Disconnection and reconnection
-
6. Trunking communication
-
6, Source download 🎉
-
7, Summary
1, Foreword
I learned this knowledge and didn't forget it at all?!
Do you think there are a lot of materials? It's cool to collect them. Hi when watching videos and reading articles. As long as you go through that effort, it's over. You don't remember what's said here. Time is wasted and things have not been learned. Why?
In fact, learning is also divided into the best policy, the middle policy and the worst policy:
- Bad policy: just look at it with your eyes. You can sit, nest or lie down. You're not tired anyway. You can reply to the wechat group blowing water at the same time
- Medium policy: take notes, sort out and summarize the data you have read, and accumulate data for a long time
- Best policy: practice, get started, apply, debug, summarize and sort out data, summarize experience and output documents
To sum up, I feel like I've learned a lot soon. The middle one needs to do something. I'm lazy and don't want to move. The best one is time-consuming and labor-consuming. I need to be able to do everything myself. In this way, when you study, you unconsciously choose the worst policy, so you haven't learned anything.
Learning can learn knowledge by hand. What we pay attention to is practice. In the articles written by Xiao Fuge, we basically focus on the verification results of practice code and tell the content of the article. 😁 Since I was a child, I like to do it. Taking an instant messaging project as an example, it has been implemented 5 or 6 times based on different technical schemes. Just to practice the technology, the screenshot is as follows:
- Some just finished learning Socket and Swing and want to try whether these technologies can write a QQ.
- There are also projects that need to be completed because of internship training, but with some foundation, all functions can be written in a week.
- Although these projects still look ugly at present, the interface and code logic may not be so perfect. However, in each implementation of the learning stage, it can bring a lot of technical growth to itself.
Well, this im practice opportunity is for you. I hope you can use it! Next, I will introduce you to the system architecture, communication protocol, single chat, group chat, expression sending, UI event driven and other contents of IM, and provide a full set of source code for you to learn.
2, Demonstration
Before starting to learn, I'd like to demonstrate the operation effect of this IM system modeled on the PC wechat interface.
Chat page
Add friends
3, System design
In this set of IM, the server is built using DDD domain driven design mode. It is very convenient to operate the communication system for user and communication management by giving the function of Netty to spring boot for start-up and stop control, and setting up a console on the server. In the construction of the client, the UI is separated to ensure the separation of business code and UI display, so as to achieve very easy extension control.
In addition, the function realization includes; Perfectly imitate the core functions of wechat desktop client, login, search and add friends, user communication, group communication, expression sending and so on. If there are functions that need to be used in practice, they can be extended according to this system framework.
- UI development: build a UI desktop project with JavaFx and Maven, and gradually explain various UI display and operation events such as login box, chat box, dialog box, friend bar, etc. In this chapter, Java programmers learn to develop desktop applications.
- Architecture design: in this chapter, we will use the four layer model structure of DDD Domain Driven Design in combination with Netty to build a reasonable layered framework. At the same time, there is the design of corresponding library and table functions. I believe that after learning these contents, you can also assume a better framework.
- Function realization: in this part, we mainly realize various functions in communication step by step, including; Login, add friends, conversation notification, message sending, disconnection reconnection and other functions. Finally complete the development of the whole project, but also let you learn skills from practice.
4, UI development
1. Overall structure definition and sidebar
Chat form, compared with the login form, the content of chat form will be more and more complex. Therefore, we will implement these forms, events and interface functions step by step in chapters. In this article, we will mainly explain the construction of chat box and the development of sidebar UI.
- The first is the definition of our whole chat main form, which is a blank panel and removes the default border buttons (minimize, exit, etc.)
- Then there is the left sidebar, which we call the Bar, and the implementation of the functional area.
- Finally, add a form event. When the button is clicked, change the filling information in the content panel.
2. Dialog box
The content area after the dialog box is selected is displayed, that is, information transmission and display between users. On the whole, this is a linkage process. Click the user dialog box on the left and the corresponding content will be filled on the right. Then, the dialogue list ListView filled on the right needs to be associated with each dialogue user. When clicking the chat user, it is filled through repeated switching.
- Click each dialog box on the left, and the filling content of the chat box on the right will change accordingly. At the same time, the corresponding dialog name will also change.
- The left side of the dialog box shows the information sent by friends, and the right side shows the information sent by individuals. At the same time, the message content will increase in height and width with the increase of content.
- At the bottom is the text input box. In the later implementation, our text input box is designed in a public way. Of course, you can also design it for individual use.
3. Friends bar
Everyone often uses wechat on the PC. you can know that there are several paragraphs in the friends column, including; New friends, official account, group and bottom buddies.
- The content of the top search box remains the same as the previous one. The method we currently use is fxml design. For example, this part is a general function, which can be extracted into the code and designed as a component element class.
- After our analysis, based on JavaFx component development, this part is a nested ListView, that is, the bottom panel is a ListView, and friends and groups are each a ListView. After this processing, we will easily fill in data.
- In addition, this structure is mainly conducive to the operation of our program. If you add friends, we need to refresh the friend information into the friend column. In order to be more convenient and efficient when filling the data, we have designed a nested ListView. If you don't particularly understand it, you can get the answer from the subsequent code.
4. Event definition
In desktop UI development, in order to isolate the UI from business logic, we need to provide an interface for displaying the effect of the operation interface and an interface operation event abstract class after packaging the UI. Then it can be understood according to the following figure;
Serial number | Interface name | describe |
---|---|---|
1 | void doShow() | open windows |
2 | void setUserInfo(String userId, String userNickName, String userHead) | Set login user ID, nickname and Avatar |
3 | void addTalkBox(int talkIdx, Integer talkType, String talkId, String talkName, String talkHead, String talkSketch, Date talkDate, Boolean selected) | Populate dialog list |
4 | void addTalkMsgUserLeft(String talkId, String msg, Date msgData, Boolean idxFirst, Boolean selected, Boolean isRemind) | Fill in dialog messages - Friends (messages from others) |
- The above interfaces are all the behavior interfaces provided by our UI for the outside. A link description of these interfaces is; Open window, search for friends, add friends, open dialog box, send message.
5, Communication design
1. System architecture
Earlier, we talked about a more suitable architecture, which is the best architecture that meets your current needs. So how to design such an architecture is basically to find the goal of meeting the point. The reason why we design this way is that there are the following points in this system;
- Our system should have a web page on the server to manage communication users and control and monitor the server.
- The object class of the database should not be polluted by the outside and should be isolated. for instance; Your database class is exposed to external display classes, so now you need to add a field, which is not an attribute of your database. Then the database class has been polluted by this time.
- At present, we all implement Netty communication in Java language, so both the server and the client need to use the protocol definition and analysis in the communication process. Then we need to pull away from this layer to provide Jar package.
- Interfaces, business processing, underlying services and communication interaction shall be clearly distinguished and implemented to avoid confusion and difficult maintenance.
Combined with our goals of the above four points, what model structure does your mind embody? And whether there is a plan for the selection of the corresponding technology stack? Next, we will introduce two architecture design models, one is MVC, which you are very familiar with, and the other is DDD domain driven design, which you may have heard of.
2. Communication protocol
From the drawings, when transmitting objects, we need to add a frame ID in the transmission package to judge which object the current business object is, which can make our business clearer and avoid using a large number of if statements.
Protocol framework
agreement └── src ├── main │ ├── java │ │ └── org.itstack.naive.chat │ │ ├── codec │ │ │ ├── ObjDecoder.java │ │ │ └── ObjEncoder.java │ │ ├── protocol │ │ │ ├── demo │ │ │ ├── Command.java │ │ │ └── Packet.java │ │ └── util │ │ └── SerializationUtil.java │ ├── resources │ │ └── application.yml │ └── webapp │ └── chat │ └── res │ └── index.html └── test └── java └── org.itstack.demo.test └── ApiTest.java
Protocol package
public abstract class Packet { private final static Map<Byte, Class<? extends Packet>> packetType = new ConcurrentHashMap<>(); static { packetType.put(Command.LoginRequest, LoginRequest.class); packetType.put(Command.LoginResponse, LoginResponse.class); packetType.put(Command.MsgRequest, MsgRequest.class); packetType.put(Command.MsgResponse, MsgResponse.class); packetType.put(Command.TalkNoticeRequest, TalkNoticeRequest.class); packetType.put(Command.TalkNoticeResponse, TalkNoticeResponse.class); packetType.put(Command.SearchFriendRequest, SearchFriendRequest.class); packetType.put(Command.SearchFriendResponse, SearchFriendResponse.class); packetType.put(Command.AddFriendRequest, AddFriendRequest.class); packetType.put(Command.AddFriendResponse, AddFriendResponse.class); packetType.put(Command.DelTalkRequest, DelTalkRequest.class); packetType.put(Command.MsgGroupRequest, MsgGroupRequest.class); packetType.put(Command.MsgGroupResponse, MsgGroupResponse.class); packetType.put(Command.ReconnectRequest, ReconnectRequest.class); } public static Class<? extends Packet> get(Byte command) { return packetType.get(command); } /** * Get protocol instruction * * @return Return instruction value */ public abstract Byte getCommand(); }
3. Add friends
- As can be seen from the above process, there are two parts here; (1) Search for friends, (2) add friends. After you finish your friends on the same day, your friends will appear in our friends column.
- In addition, we unilaterally agree to add friends, that is, when you add a friend, the other party also has your friend information.
- If you need to add friends and agree in your business, you can add a status message to request adding friends when initiating friend addition. After the other party agrees, the two users can become friends and communicate.
Add friends, case code
public class AddFriendHandler extends MyBizHandler<AddFriendRequest> { public AddFriendHandler(UserService userService) { super(userService); } @Override public void channelRead(Channel channel, AddFriendRequest msg) { // 1. Add friends to the database [a - > b - > A] List<UserFriend> userFriendList = new ArrayList<>(); userFriendList.add(new UserFriend(msg.getUserId(), msg.getFriendId())); userFriendList.add(new UserFriend(msg.getFriendId(), msg.getUserId())); userService.addUserFriend(userFriendList); // 2. Push friends to add A UserInfo userInfo = userService.queryUserInfo(msg.getFriendId()); channel.writeAndFlush(new AddFriendResponse(userInfo.getUserId(), userInfo.getUserNickName(), userInfo.getUserHead())); // 3. Push friend add completed B Channel friendChannel = SocketChannelUtil.getChannel(msg.getFriendId()); if (null == friendChannel) return; UserInfo friendInfo = userService.queryUserInfo(msg.getUserId()); friendChannel.writeAndFlush(new AddFriendResponse(friendInfo.getUserId(), friendInfo.getUserNickName(), friendInfo.getUserHead())); } }
4. Message response
- It can be seen from the overall process that when a user initiates friend and group communication, an event behavior will be triggered, and then the client sends a conversation request with friends to the server.
- After the server receives the conversation request, if it is a friend conversation, it needs to save the communication information with the friend in the dialog box. At the same time, inform my friends that I want to communicate with you. You add me to your dialog list.
- In case of group communication, such notification is not necessary, because it is impossible to notify all group users who are not online (they have not logged in yet), so this part only needs to create a dialog box to the list after the user receives the information online. You can understand it carefully and think about other implementation methods at the same time.
Message response, case code
public class MsgHandler extends MyBizHandler<MsgRequest> { public MsgHandler(UserService userService) { super(userService); } @Override public void channelRead(Channel channel, MsgRequest msg) { logger.info("Message information processing:{}", JSON.toJSONString(msg)); // Asynchronous write library userService.asyncAppendChatRecord(new ChatRecordInfo(msg.getUserId(), msg.getFriendId(), msg.getMsgText(), msg.getMsgType(), msg.getMsgDate())); // Add dialog [add if the other party doesn't have your dialog] userService.addTalkBoxInfo(msg.getFriendId(), msg.getUserId(), Constants.TalkType.Friend.getCode()); // Get friend communication pipeline Channel friendChannel = SocketChannelUtil.getChannel(msg.getFriendId()); if (null == friendChannel) { logger.info("user id: {}Not logged in!", msg.getFriendId()); return; } // send message friendChannel.writeAndFlush(new MsgResponse(msg.getUserId(), msg.getMsgText(), msg.getMsgType(), msg.getMsgDate())); } }
5. Disconnection and reconnection
- From the above process, we can see that when the network connection is disconnected, it will send a re link request to the server. Then, the process of initiating links is different from the initial links of the system. For disconnection reconnection, you need to send the user's ID information to the server, so that the server can update the binding relationship between the user and the communication Channel.
- At the same time, it is also necessary to update the reconnection information in the group and add the user's reconnection to the group mapping. At this time, the communication function between users and friends and groups can be restored.
Message response, case code
// Regular patrol inspection of Channel status; Every 5 seconds after 3 seconds scheduledExecutorService.scheduleAtFixedRate(() -> {while (!nettyClient.isActive()) {System.out.println("Communication pipeline patrol inspection: communication pipeline status" + nettyClient.isActive()); try {System.out.println("Communication pipeline patrol inspection: disconnection and reconnection [Begin]"); Channel freshChannel = executorService.submit(nettyClient).get(); if (null == CacheUtil.userId) continue; freshChannel.writeAndFlush(new ReconnectRequest(CacheUtil.userId)); } catch (InterruptedException | ExecutionException e) {System.out.println("Communication pipeline patrol inspection: disconnection and reconnection [Error]");} } }, 3, 5, TimeUnit.SECONDS);
6. Trunking communication
- For cross service cases, redis publish and subscribe are used to deliver messages. If you are a large service, you can use zookeeper
- When user A sends A message to user B, it needs to pass B's channelid for the server to find out whether the channelid belongs to its own service
- A single machine can also start multiple Netty services, and the program will automatically find available ports
6, Source download
The author of this project is Xiao Fuge using JavaFx and netty4 x. SpringBoot, Mysql and other technology stacks and the desktop like wechat built by the DDD domain driven design method realize the core communication functions.
This set of IM} codes is divided into three groups of modules; UI, client and server. The reason for this split is to isolate the UI display from the business logic, use events and interfaces to drive, and make the code level cleaner and cleaner, easy to expand and maintain.
Serial number | engineering | introduce |
---|---|---|
1 | itstack-naive-chat-ui | The UI side developed with JavaFx is provided in our UI side; Login box and chat box, and there are a large number of behavior interaction interfaces, interfaces and events in the chat box. Finally, my UI side uses Maven packaging to provide Jar packages to the outside, so as to separate the UI interface from the business behavior process. |
2 | itstack-naive-chat-client | The client is our communication core project, mainly using netty4 X as our socket framework to complete communication interaction. In this project, we are responsible for introducing the Jar package of the UI, completing the events defined by the UI (login verification, searching and adding friends, conversation notification, sending information, etc.), and using the communication protocol defined in the server project to complete the interactive operation of information. |
3 | itstack-navie-chat-server | The server also uses Netty4 X is used as the communication framework of socket. At the same time, Layui is used as the management background page at the server. Our server adopts the way of DDD Domain Driven Design and Netty collection, so as to achieve that our framework structure is clean and easy to expand. |
4 | itstack.sql | System engineering database table structure and initialization data information, a total of 6 core tables; User table, group table, user group association table, friend table, conversation table and chat record table. Users can expand and improve themselves in actual business development. At present, the library table structure is only based on core functions. |
- Source code acquisition: like + pay attention to the background private letter source code
7, Summary
- This IM system involves a lot of technology stack content, netty4 x. The use of SpringBoot, Mybatis, Mysql, JavaFx, layui and other technology stacks, as well as the whole system framework structure are built in the way of DDD four-tier architecture + Socket module. All UI s are designed in the previous back-end separation event driven way. In this process, as long as you can continue to learn, you will gain a lot of content. Enough bragging! 🌶
- The learning process of any new technology stack will include such a route; Run HelloWorld, skillfully use API, project practice and finally deep source code mining. When hearing such a requirement, Java programmers will certainly think of some columns of technical knowledge points to fill each module in our project, such as; JavaFx and Swing are used for the interface, Socket for communication, or know the Netty framework, MVC model for server control and SpringBoot. However, how to set up our system reasonably is the most important part in the process of learning, practice and growth.
- END -
Pay attention, learn, grow and make progress together with bloggers, and be the most expensive Coder in a code field!