Preface
In the previous article, Spring boot + LayIM + t-io file upload and monitoring user status, two small details have been introduced: the user's offline status and the state changes in the number of people. Today's main content is the implementation of user add friends.
Introduction
Add friends. Everyone knows that they have used QQ. It’s nothing more than starting a friend application. The other party receives a message notification and then processes it. However, this article only talks about the first half, and the processing of message notifications will be left to the next article. Because the content is a bit too much, I'm afraid I can't digest it for a while. Before introducing the main process, let me introduce the preparation work to you first.
Preparation
First of all, in order to make the data closer to actual combat, I used more "real" user data. Combined with the fly template, the data binding of user information in the user center head is improved. The data binding part determines whether you are already a friend to decide whether the "Add as a friend" button appears. The example is as follows: When a user sees his homepage by himself, it is like this:
When you see the user's homepage that is not a friend, it looks like this:
The binding data part, let me briefly introduce it to you, which is to use the thymleaf template to bind. When accessing the page in the background, just assign the Model value.
/** * Attribute assignment* */ private void setModel(User user,Model model){ long currentUserId = getUserId(); long visitUserId = user.getId(); //Is it your own boolean isSelf = currentUserId == visitUserId; //Whether the two users are already friends boolean isFriend = groupService.isFriend(currentUserId,visitUserId); Map<String,Object> userMap = new HashMap<>(8); userMap.put("avatar",user.getAvatar()); userMap.put("name",user.getUserName()); userMap.put("addtime", TimeUtil.formatDate(user.getCreateAt())+" Join"); if(user.getSign()==null ||user.getSign().length()==0) { userMap.put("sign", ""); }else { userMap.put("sign", "(" + user.getSign() + ")"); } userMap.put("uid",user.getId()); userMap.put("self",isSelf || isFriend); model.addAttribute("user",userMap); }Then, on the page, extract the data from the model.
<div style="background-image: url();"> <input type="hidden" th:value="${user.uid}" id="visitUid"/> <img src="" th:src="${user.avatar}" th:alt="${user.name}"/> <h1> <p th:text="${user.name}"></p> <i></i> </h1> <p> <!--<i></i><span style="color: #FF7200;">67206Flying Kiss</span>--> <i></i><span th:text="${user.addtime}"></span> <!--<i></i><span>From Hangzhou</span>--> <i th:if="${user.self==false}"></i><a lay-event="addFriend" href="#" rel="external nofollow" th:if="${user.self==false}">Add as a friend</a> </p> <p th:text="${user.sign}"></p> </div>OK, the above is the simple preparation. If you want to know the detailed code, you can search for it at the end of the article.
Initiate a friend application
Let’s first follow Layim’s business analysis. First of all, we need to know who (toId) we want to add as friends. Then add a remark. It's OK to hand these things over to the backend. In order to avoid table queries, I have made redundant username and user avatar for storing system messages. The table mainly contains fields: user ID, user avatar, user name, applied user ID, application time, application type, notes, read and other attributes.
Therefore, it is very easy to initiate a friend application. It is an added function. The front-end passes the respondent's user ID and application notes. The back-end organizes the data to be inserted into the database. The code is as follows:
/** * Submit a friend application* */ public JsonResult saveFriendApply(long toId,String remark){ remark = HtmlUtils.htmlEscape(remark); ContextUser user = ShiroUtil.getCurrentUser(); long userId = Long.parseLong(user.getUserid()); int record = applyRepository.countByToidAndUidAndTypeAndResult(toId,userId,ApplyType.friend,0); if(record > 0){ return JsonResult.fail("After applied"); } Apply apply = new Apply(); apply.setType(ApplyType.friend); apply.setToid(toId); apply.setRemark(remark); apply.setUid(userId); apply.setAvatar(user.getAvatar()); apply.setName(user.getUsername()); apply.setRead(false); apply.setResult(0); return saveApply(apply); }OK, the application is over, what are we going to do next? That’s right, notify the other party, hey, I’ve sent you an application and process it quickly. I've encountered a problem here. Since the springboot program occupies port 8080, and t-io occupies port 8888, that is, if I want to actively call 8888's service push in the business of port 8080, I don't know how to get the corresponding channelContext. However, after asking the author, my problem was solved in one sentence.
Get ServerGroupContext and the problem is solved.
The LayimWebsocketStarter bean was registered when the previous program was started. So, if you can get it on the 8080 business side, there will be no problem.
Get the LayimWebsocketStarter, you can get the ServerGroupContext, and then you can actively push it on the server.
Of course, this thing may not have been developed, and I don’t understand the above problem very well. It doesn’t matter. Actually, I want to explain that if you actively push messages to the client from the server side, just use ServerGroupContext.
Active push on the server
The following code is in com.fyp.layim.im.common.util.PushUtil
OK, follow the steps above.
The first step is to get the LayimWebsocketStarter.
/** * Get starter*/private static LayimWebsocketStarter getStarter(){ return (LayimWebsocketStarter)SpringUtil.getBean("layimWebsocketStarter"); }Step 2: Get ServerGroupContext
private static ServerGroupContext getServerGroupContext(){ return getStarter().getServerGroupContext(); }The third step is to obtain the ChannelContext.
/** * Get channelContext * */ private static ChannelContext getChannelContext(String toId) { ServerGroupContext context = getServerGroupContext(); //Find the user ChannelContext channelContext = context.users.find(context, toId); return channelContext; }The fourth step is to launch, and the code here is almost the same as the part of the code in the chat. The core part is to get the ChannelContext and then send it a message. If you are not online, don't worry.
/** * The server actively pushes messages* */ public static void pushApplyMessage(String toId) { logger.info("Execute to send method: pushApplyMessage"); LayimToClientNoticeMsgBody body = new LayimToClientNoticeMsgBody(); ChannelContext channelContext = getChannelContext(toId); //First determine whether it is online, then query the database to reduce the number of queries if (channelContext != null && !channelContext.isClosed()) { int count = getApplyService().getUnreadMsgCount(Long.parseLong(toId)); body.setCount(count); push(channelContext, body); } } /** * Server actively pushes messages* */ private static void push(ChannelContext channelContext,Object msg) { try { WsResponse response = BodyConvert.getInstance().convertToTextResponse(msg); Aio.send(channelContext, response); }catch (IOException ex){ } }Now that the push is done, then when will it be pushed? Since the push of messages in this system does not need to be so instant, I took a look and found that there is a similar event mechanism in springboot, so ApplyEvent was born.
public class ApplyEvent extends ApplicationEvent { public ApplyEvent(Object source) { super(source); } private long toid; public long getToId(){ return toid; } public ApplyEvent(Object source, long toId) { super(source); this.toid = toId; }}Create a Listener to listen for events.
public class ApplyListener implements ApplicationListener<ApplyEvent> { private Logger logger = LoggerFactory.getLogger(ApplyListener.class); @Override public void onApplicationEvent(ApplyEvent applyEvent) { new Thread(){ public void run(){ Long toId = applyEvent.getToId(); // Here we will call the push above PushUtil.pushApplyMessage(toId.toString()); } }.start(); }}However, I have a question and found that the execution in the listener is synchronous. Later, adding @Async and @EnableAsync was useless, so I used new Thread().start() to achieve asynchronousness to ensure that it does not affect the main application process. (This is a question, I haven't figured it out)
Finally, don't forget to add listener when Application starts.
public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(LayimApplication.class); /** * Only when the listener is added here will the listener trigger* ApplyListener is an event that listens to friends' applications* */ springApplication.addListeners(new ApplyListener()); springApplication.run(args); }Functional stitching
It will be successful soon. We are stringing up the events and publishing the events after the friend application is successful.
/** * Friend application* */ @PostMapping(value = "/apply-friend") public JsonResult apply(@RequestParam("toid") Long toId,@RequestParam("remark") String remark){ JsonResult result = applyService.saveFriendApply(toId, remark); //Application is successful, the application event is posted, notify toId to process the message. If it is not online, it will not be processed if(result.isSuccess()){ applicationContext.publishEvent(new ApplyEvent("apply",toId)); } return result; }Functional demonstration
I have talked so much, let me show you the effect of the finished product. (User Scene: An Xiaoniao adds the emperor as a friend, the emperor receives the message and checks it)
The emperor received the message and the small number 4 in the lower left corner popped up. (Call the layim.msgbox(msgCount) method)
The emperor clicked on the message box:
The emperor received applications from his four beloved concubines and was unable to sleep or eat. What would he do? If you want to know what happens next, please listen to the next breakdown~~~
Summarize
This article mainly introduces the implementation of a friend-adding process.
The code address in the article: https://github.com/fanpan26/SpringBootLayIM
http://xiazai.VeVB.COM/201712/yuanma/SpringBootLayIM-master.rar
The above is the SpringBoot+LayIM+t-io introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!