Under the SSM framework, websocket obtains real-time database change information and then displays it to the foreground (idea)

I read a lot of websocket blogs on the Internet, but basically failed according to the above operations. The reason is that either the information given is incomplete, or the project environment is different. In order to solve this problem, I went all the way and explored all the way and finally realized what I wanted. The desired effect. Let me talk about my project environment first. My project uses the SSM framework , and then uses annotations to inject Bean. The development tool is idea , the tomcat version is 7.0.84 , and the Jdk version is 1.8.0_152 . It is said on the Internet that tomcat needs to be 8 or more, but the tomcat7.0.84 I used also achieves the desired function. As for the minimum version of tomcat, I did not research this. Next, let's explain the program.


The first step: the program of the HTML page, you can paste it directly, and then modify the corresponding fields. Note that the browser version is too low is not supported websocket of

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>测试websocket</title>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style type="text/css">
        * {
            margin: 0px;
            padding: 0px;
        }
    </style>
    <script type="text/javascript">
        var websocket = null;
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket' in window) {
            //建立连接,这里的/websocket ,是Servlet中注解中的那个值,一定对应哈
            websocket = new WebSocket("ws://localhost:8086/项目名称/websocket");//这里的项目名称,有的人进行了设置,有的人没有进行设置,还是根据自己的项目情况来
          
        }
        else {
            alert('当前浏览器不支持websocket');
        }
        //连接发生错误的回调方法
        websocket.onerror = function () {
            document.write("WebSocket连接发生错误<br>")
        };
        //连接成功建立的回调方法
        websocket.onopen = function () {
            document.write("WebSocket连接成功<br>");
        }
        //接收到消息的回调方法
        websocket.onmessage = function (event) {
            //我在编写逻辑时,如果后端数据库发生变化,就给前端传送的数据设置为1,
            if(event.data=="1"){
                //这里就可以在前端进行相应的功能展示,我这里就只用打印一句话进行表示了
                document.write("数据更新啦<br>");
                
            }
        }
        //连接关闭的回调方法
        websocket.onclose = function () {
            document.write("WebSocket连接关闭<br>");
        }
        //监听窗口关闭事件,当窗口关闭时,主动去关闭WebSocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function () {
            closeWebSocket();
        }
        //关闭WebSocket连接
        function closeWebSocket() {
            websocket.close();
        }
    </script>
</head>
<body>
</body>
</html>

Step 2: Configure pom.xml

<!--		下面的是websocket的依赖-开始处 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-websocket</artifactId>
		</dependency>
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-api</artifactId>
			<version>7.0</version>
			 <scope>provided</scope>
		</dependency>
<!--		上面的是websocket的依赖-结尾处-->

Step 3: Dao layer

/**
     * 下面的方法是测试websocket下数据库中商品总数的变化
     * @return
     */
    Integer WebsocketSumFood();

Step 4: mapper

<!--    websocket查询商品总数-->
    <select id="WebsocketSumFood" resultType="Integer" >
        select count(*) from t_product
    </select>

Step 5: servic layer

/**
     * 测试食品修改下websocket的使用
     * @return
     */
    int WebsocketSumFood();

Step 6: Servic implementation layer

/**
     * websocket下测试食品总数修改的变化
     * @return
     */
    @Override
    public int WebsocketSumFood() {
        return foodDao.WebsocketSumFood();
    }

Step 7: Write the WebSocketConfig class

import org.apache.catalina.session.StandardSessionFacade;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;

/**
 * @Author: Wxz
 * @Date: 2020/9/1 11:49
 */
@Configuration
public class WebSocketConfig extends Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        /*如果没有监听器,那么这里获取到的HttpSession是null*/
        StandardSessionFacade ssf = (StandardSessionFacade) request.getHttpSession();
        if (ssf != null) {
            HttpSession httpSession = (HttpSession) request.getHttpSession();
            //关键操作
            sec.getUserProperties().put("sessionId", httpSession.getId());
        }
    }


    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

The eighth step: write monitoring class


import org.springframework.stereotype.Component;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @Author: Wxz
 * @Date: 2020/9/1 14:59
 */
@Component
public class RequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        //将所有request请求都携带上httpSession
        HttpSession httpSession = ((HttpServletRequest) sre.getServletRequest()).getSession();
    }

    public RequestListener() {
    }

    @Override
    public void requestDestroyed(ServletRequestEvent arg0) {
    }
}

Step 9: Write the thread class MyThread

package com.example.orderserver.foodwebsocket;

import com.example.orderserver.service.foodManage.FoodService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @Author: Wxz
 * @Date: 2020/9/1 10:29
 */
@Component
public class MyThread implements Runnable{
    //普通类获取service对象,否则会报空指针
    @Autowired
    private FoodService foodService;
    public static MyThread testUtils;
    //下面的注解一定要有哈
    @PostConstruct
    public void init() {
        testUtils = this;
    }
    //原始数量
    private int sum;
    //数据库变化后的数量
    private int new_sum;
    //设置循环状态
    private boolean stopMe = true;
    public void stopMe() {
        stopMe = false;
    }


    @Override
    public void run() {
        sum=testUtils.foodService.WebsocketSumFood();
        WebSocketServlet wbs=new WebSocketServlet();
        while(stopMe){
            new_sum=testUtils.foodService.WebsocketSumFood();
            if(sum!=new_sum){
                sum=new_sum;
                wbs.onMessage(sum);
            }
            try {
                //每10秒检查一下数据库
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

The tenth step: write WebSocketServlet

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @Author: Wxz
 * @Date: 2020/9/1 10:30
 */

@ServerEndpoint("/websocket")
@Component
public class WebSocketServlet {
    MyThread thread1=new MyThread();
    //开启线程
    Thread thread=new Thread(thread1);
    //用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServlet> webSocketSet = new CopyOnWriteArraySet<WebSocketServlet>();
    private  javax.websocket.Session session=null;

    /**
     * @ClassName: onOpen
     * @Description: 开启连接的操作
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) throws IOException{
        //获取WebsocketConfig.java中配置的“sessionId”信息值
        String httpSessionId = (String) config.getUserProperties().get("sessionId");
        this.session=session;
        webSocketSet.add(this);
        //开启一个线程对数据库中的数据进行轮询
        thread.start();

    }

    /**
     * @ClassName: onClose
     * @Description: 连接关闭的操作
     */
    @OnClose
    public void onClose(){
        thread1.stopMe();
        webSocketSet.remove(this);
    }

    /**
     * 告知前端数据库发生变化,调用sendMessage()方法
     * @param count
     */
    @OnMessage
    public void onMessage(int count) {
        System.out.println("发生变化"+count);
        try {
            sendMessage();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 出错操作
     * @param error
     */
    @OnError
    public void onError(Throwable error){
        error.printStackTrace();
    }

    /**
     * 此方法是被调用的方法,所以没注解,这里才是真正处理逻辑的地方,可以给前台传输你想要传输的内容,我只是用1进行代替了。
     * @throws IOException
     * 发送自定义信号,“1”表示告诉前台,数据库发生改变了,需要刷新
     */
    public void sendMessage() throws IOException{
        //群发消息
        for(WebSocketServlet item: webSocketSet){
            item.session.getBasicRemote().sendText("1");
        }
    }
}

Step 11: Start the project, then modify the database:

Step 12: Check the browser:

So far, the effect I want has been achieved, and I am happy to communicate with everyone!

 

 

Guess you like

Origin blog.csdn.net/xgysimida/article/details/108345694