当前位置:网站首页>Push related summary

Push related summary

2022-06-09 07:17:00 The first person in the examination

First of all, let's introduce the scenario above :

When our front end requests the rear terminal service , When our back terminal service handles related logic , It is likely that the complexity of the business will lead to http Request connection timed out , And for the current era , We all require high-performance systems , After the user submits a request , Separate assumptions 20s Just responded , Obviously, it is also unreasonable .

The traditional way to solve the above problems

The front end sends the request , Our sub service can respond immediately and return , But the return is the request success, not the processing success , After the back-end business logic is processed , And then it is returned to the front end for processing , This obviously meets the requirements of high-performance systems . But there is also a problem http Request after our first response , The back end has no ability to notify the front end , And because the completion time of back-end business logic processing is uncertain , The traditional way is to call the service by front-end polling , This will greatly increase the pressure on the server , Obviously, although the above methods can solve , But we don't use .

The promotion method solves the above problems

  As shown in the figure above , We set up a push service ( use websocket agreement , Some companies are called message centers just by name ), When the sub service is unable to push the corresponding message to the front end , Push messages can be pushed to the message center , The message center maintains a long connection with the front end , In this way, messages can be pushed to the front end .( According to different front-end users, we can id And corresponding sessionId To establish a mapping relationship )

Websocket It's a full duplex protocol ( The server can push the front end , The front end can also be pushed to the server ), It is only used by the front-end push back-end http agreement , That is, half of it is used websocket agreement .

PS:Websocket Introduction to the agreement :HTML5 WebSocket | Novice tutorial

Use Java Language in springboot Realize... In the project :

The first must be import dependencies :

<!-- websocket rely on  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

Establish backend :

① structure WebSocket

package com.qianfeng.gp09.server;

import com.alibaba.fastjson.JSONObject;
import com.qianfeng.gp09.dao.MessageDao;
import com.qianfeng.gp09.model.Message;
import com.qianfeng.gp09.model.MessageExample;
import com.qianfeng.gp09.util.SpringContextUtil;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket The server 
 * 
 */
@ServerEndpoint("/webSocket/{uid}")
@Component
public class WebSocketServer {

    /**
     *  Each user establishes a session with the server 
     *  We consider saving the session 
     *  One uid Corresponding to one session
     *  It should be a multi-threaded concurrency map
     */
    private static ConcurrentHashMap<String,Session> sessionPool=new ConcurrentHashMap<>();

    @Resource
    private MessageDao messageDao;


    /**
     *  When the connection is established , Method of operation .
     * @param session  Conversation object 
     * @param uid  user id
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="uid") String uid){
        sessionPool.put(uid,session);
        // Inquire about uid The news of   state=0  And  overTime Is greater than the current time .
        MessageExample example=new MessageExample();
        MessageExample.Criteria criteria = example.createCriteria();
        criteria.andUidEqualTo(uid);
        criteria.andStateEqualTo(0);
        criteria.andOverTimeGreaterThanOrEqualTo(new Date());
        if(messageDao==null){
            // Get this object manually .
            messageDao=SpringContextUtil.getBean(MessageDao.class);
        }
        List<Message> messages = messageDao.selectByExample(example);
        sendMessage(session, JSONObject.toJSONString(messages));
    }

    /**
     *  When the other party sends me data , This method runs .
     * @param message  The message content 
     */
    @OnMessage
    public void onMessage(String message){
        // no need .
    }

    /**
     *  When the connection is closed , This method runs 
     * @param uid  user id
     */
    @OnClose
    public void onClose(@PathParam(value="uid")String uid){
        sessionPool.remove(uid);
    }


    /**
     *  When a connection error occurs , This method runs 
     * @param session  Conversation object 
     * @param throwable  error 
     */
    @OnError
    public void onError(Session session,Throwable throwable){
        throwable.printStackTrace();
    }


    /**
     *  according to session Send a message 
     * @param session  Session with user 
     * @param message  Content sent to users 
     */
    private boolean sendMessage(Session session,String message){
        if(session!=null){
            synchronized (session){
                try{
                    // According to a session, Send message content to the other party .
                    session.getBasicRemote().sendText(message);
                    return true;
                }catch (Exception e){
                    e.printStackTrace();
                    return false;
                }
            }
        }
        return false;
    }


    /**
     *  Appoint id Send messages to users 
     *  Implementation of business logic 
     * @param uid  user id
     * @param message  The content of the message sent to the user 
     * @return  Whether the sending is successful 
     */
    public boolean sendInfo(String uid,String message){
        Session session=sessionPool.get(uid);
        if(session==null){
            return false;
        }
        return sendMessage(session,message);
    }




}

② structure websockect The configuration is as follows :

package com.qianfeng.gp09.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 *  Configuration manager 
 * 
 */
@Configuration
public class WebSocketConfig {
    /**
     *  To configure a serverendpoint
     *  Used to manage the connection server uri
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

③ stay controller In the injection :

package com.qianfeng.gp09.controller;

import com.alibaba.fastjson.JSONObject;
import com.qianfeng.gp09.dto.MessageDTO;
import com.qianfeng.gp09.model.Message;
import com.qianfeng.gp09.model.User;
import com.qianfeng.gp09.result.R;
import com.qianfeng.gp09.server.WebSocketServer;
import com.qianfeng.gp09.service.PushService;
import com.qianfeng.gp09.service.UserService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 *  User interface 
 * 
 */
@RestController
@RequestMapping("qf/user")
public class UserController {


    @Resource
    private WebSocketServer webSocketServer;

    @Resource
    private PushService pushService;

  

    @PostMapping("pushWeb")
    public R pushWeb(@RequestBody MessageDTO messageDTO){
        String uid=messageDTO.getUid();
        String message=messageDTO.getMessage();
        Integer overTime=messageDTO.getOverTime();
        boolean flag = webSocketServer.sendInfo(uid, message);
        Message msg=new Message();
        msg.setUid(uid);
        msg.setContent(message);
        msg.setSendTime(new Date());
        msg.setOverTime(new Date(System.currentTimeMillis()+overTime*1000*60));
        if(flag){
            msg.setState(1);
            pushService.saveMessage(msg);
            return R.ok(" Send successfully ");
        }else{
            msg.setState(0);
            pushService.saveMessage(msg);
            return R.ok(" User offline , Push task has been set .");
        }
    }


}

Build the front end :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <input type="text" id="uid" placeholder=" Please enter id"/>
    <br>
    <button onclick="onConnectionClick();"> Connect to server </button>
    <br>
    <div id="messages"></div>

<script>
    let socket;
    function onConnectionClick(){
        if(typeof(WebSocket) == "undefined") {
            // This browser does not support WebSocket
            alert(" Please use the latest Google Chrome browser ");
            return ;
        }

        if(socket!=null){
            socket.close();
            socket=null;
        }
        // Get the id
        let uid=document.getElementById("uid").value;

        // Connect to the server url
        let url="ws://localhost:8080/webSocket/"+uid;


        // Instantiation webSocket
        socket=new WebSocket(url);

        socket.onopen=function(){
            console.info(" A connection has been established with the server ");
        };
        socket.onmessage=function(msg){
            let receiveMessage=msg.data;
            document.getElementById("messages").innerHTML+="<span>"+receiveMessage+"</span><br>"

        };
        socket.onclose=function(){
            console.info(" Disconnected from the server ");
        };
        socket.onerror=function(){
            console.info(" An error occurred while connecting to the server ");
        };


    }


</script>
</body>
</html>

PS: In verifying the above logic , encounter dao The problem of null pointer of items during layer injection , This is because Spring At the time of Injection , According to the situation and notes , It is injected in a different order , So I wrote a tool class directly , You can use injection directly , There is no need to focus on the order . Tools are as follows :

package com.qianfeng.gp09.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * spring Tool classes for context 
 * 
 *
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    /**
     *  It is spring Context object , You can use it to get spring Any object in the container 
     */
    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtil.applicationContext=applicationContext;
    }



    public static <T> T getBean(Class<T> clazz){
        return applicationContext.getBean(clazz);
    }
}

There is also an extension of the above , The details are shown in the picture , Do not go into :


 

Mobile terminal APP push

  First, describe the above scenario :

        When one of our mobile phones App You want to push messages to your mobile phone , We use a third-party Aurora server or Youmeng server , Explain why , Pictured above , If you do not use a three-party integrated server , Servers for different mobile phones , our App All have to be connected separately , And special customer service is needed to ensure the smoothness of this line , Therefore, the three-party integration platform is recommended , They help us connect with all mobile phone manufacturers .

原网站

版权声明
本文为[The first person in the examination]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206090706226034.html