文章目录

  • 前言: 只是做笔记.-不够明白,故.不做解释
  • 参考博客
  • 源码下载地址:
  • 目录结构
  • config
  • MyEndpointConfigure
  • WebSocketConfiguration
  • push
  • ProductExpireTask
  • socket
  • ProductWebSocket
  • util
  • SpringUtil
  • TimeConversionUtil
  • config
  • application.properties
  • application-dev.properties
  • templates
  • index.html
  • 启动类:HuawenCloudStockApplication
  • http://localhost:8080/


前言: 只是做笔记.-不够明白,故.不做解释

参考博客

参考

源码下载地址:

链接:https://pan.baidu.com/s/1wNqE-Auba8sZuf129QazEg 
提取码:cs6s
目录结构

spring boot 集成tcp spring boot集成websocket_java

config

MyEndpointConfigure
package com.hwqh.huawencloudstock.config;

import com.hwqh.huawencloudstock.util.SpringUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.websocket.server.ServerEndpointConfig;


public class MyEndpointConfigure extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
    private static  ApplicationContext applicationContext = SpringUtil.getApplicationContext();

    /**
     * 3
     * @param clazz
     * @param <T>
     * @return
     */
    @Override
    public <T> T getEndpointInstance(Class<T> clazz)  {
        return  applicationContext.getBean(clazz);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        MyEndpointConfigure.applicationContext = applicationContext;
    }

}
WebSocketConfiguration
package com.hwqh.huawencloudstock.config;

import com.hwqh.huawencloudstock.socket.ProductWebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 首先访问的
 */
@Configuration
public class WebSocketConfiguration  {
    private Logger log = LoggerFactory.getLogger(ProductWebSocket.class);
    /**
     * ServerEndpointExporter  这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

push

ProductExpireTask
package com.hwqh.huawencloudstock.push;

import com.hwqh.huawencloudstock.socket.ProductWebSocket;
import com.hwqh.huawencloudstock.util.TimeConversionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;

@Component
public class ProductExpireTask {
    private Logger log = LoggerFactory.getLogger(ProductWebSocket.class);
    @Scheduled(fixedRate=2000)
    public void productExpire() throws IOException {
        String[] strs={/*"Test随机消息 :30.1123",*/
/*                "Test随机消息 :32.1021",
                "Test随机消息 :33.1774",
                "Test随机消息 :33.2372",
                "Test随机消息 :31.0281",
                "Test随机消息 :30.0222",
                "Test随机消息 :32.1322",
                "Test随机消息 :33.3221",
                "Test随机消息 :31.2311",*/
                "Test随机消息 :32.3112"};
        ProductWebSocket.sendInfo(TimeConversionUtil.getTimeStrNow()+"    Test 消息---->"+ RandomStr(strs));

    }

    //随机返回字符串数组中的字符串
    public static String RandomStr(String[] strs){
        int random_index = (int) (Math.random()*strs.length);
        return strs[random_index];
    }


}

socket

ProductWebSocket
package com.hwqh.huawencloudstock.socket;

import com.hwqh.huawencloudstock.config.MyEndpointConfigure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import springfox.documentation.schema.Entry;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@ServerEndpoint(value = "/productWebSocket/{userId}", configurator = MyEndpointConfigure.class)
public class ProductWebSocket {

    private Logger log = LoggerFactory.getLogger(ProductWebSocket.class);
    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static final AtomicInteger OnlineCount = new AtomicInteger(0);
    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的ProductWebSocket对象。
     */
    private static CopyOnWriteArrayList<ProductWebSocket> webSocketSet = new CopyOnWriteArrayList<ProductWebSocket>();
    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) {
        log.info("新客户端连入,用户id:" + userId);
        this.session = session;
        webSocketSet.add(this); // 加入set中
        addOnlineCount(); // 在线数加1
        if (userId != null) {
            List<String> totalPushMsgs = new ArrayList<String>();
            totalPushMsgs.add(userId + "连接成功-" + "-当前在线人数为:" + getOnlineCount());
            if (totalPushMsgs != null && !totalPushMsgs.isEmpty()) {
                totalPushMsgs.forEach(e -> sendMessage(e));
            }
        }

    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        log.info("一个客户端关闭连接");
        webSocketSet.remove(this); // 从set中删除
        subOnlineCount(); // 在线数减1
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户发送过来的消息为:" + message);
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket出现错误");
        error.printStackTrace();
    }

    public void sendMessage(String message) {
        this.session.getAsyncRemote().sendText(message);
        log.info("推送消息成功,消息为:" + message);
    }

    /**
     * 群发自定义消息
     */
   /* public static void sendInfo(String message) {
        for (ProductWebSocket productWebSocket : webSocketSet) {
            productWebSocket.sendMessage(message);

        }
    }
*/

    /**
     * 向所有连接客户端推送消息
     */
    public static void sendInfo(String message) {
        if (webSocketSet.size() != 0) {
            for (ProductWebSocket p : webSocketSet) {
                if (p != null) {
                    p.sendMessage(message);

                }
            }
        }
    }


    public static synchronized int getOnlineCount() {
        return OnlineCount.get();
    }

    public static synchronized void addOnlineCount() {
        OnlineCount.incrementAndGet(); // 在线数加1
    }

    public static synchronized void subOnlineCount() {
        OnlineCount.decrementAndGet(); // 在线数加1
    }

}

util

SpringUtil
package com.hwqh.huawencloudstock.util;

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

/**
 * 说明:Spring获取Bean工具类
 */
@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}
TimeConversionUtil
package com.hwqh.huawencloudstock.util;

import org.springframework.util.Assert;

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;


public class TimeConversionUtil {


    //传入long时间戳 ,转换成格式化的String类型时间

    public  String TimeOfLongToStr(long time) {
        Assert.notNull(time, "time is null");
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));

    }

    //传入String类型格式化时间,转换成Long类型的时间戳

    public  long TimeOfStrToLong(String strTime){
        Assert.notNull(strTime, "time is null");
        DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime parse = LocalDateTime.parse(strTime, ftf);
        return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

    }


    //通过LocalDateTime获取当前格式化时间

    public  static String getTimeStrNow(){
        //DateTimeFormatter替换了SimpleDateFormat, 因为线程安全问题。
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    //通过LocalDateTime获取当前格式化时间

    public  static  String getTimeStrNow1(){
        //DateTimeFormatter替换了SimpleDateFormat, 因为线程安全问题。
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }


    //获取当前时间戳方法一

    public long getTimeLongOfClock(){

        return Clock.systemDefaultZone().millis();
    }

    //获取当前时间戳方法二

    public long getTimeLongOfCalendar(){
        Calendar calendar = Calendar.getInstance();

        return calendar.getTimeInMillis();
    }

    //获取当前时间戳方法三

    public long getTimeLongOfSystem(){

        return System.currentTimeMillis();
    }

    //获取当前时间戳方法四

    public long getTimeLongOfDate(){

        Date date = new Date();

        return date.getTime();
    }

    //获取当前时间戳五
    public long getTimeLongOfInstant(){

        Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
        //   System.out.println("秒数:"+now.getEpochSecond());
        //   System.out.println("毫秒数:"+now.toEpochMilli());
        return now.toEpochMilli();
    }



工具类调试
//    public static void main(String[] args) {
        TimeConversionUtil timeConversionUtil=new TimeConversionUtil();
        System.out.println(timeConversionUtil.getTimeLongOfCalendar());
        System.out.println(timeConversionUtil.getTimeLongOfDate());
        System.out.println(timeConversionUtil.getTimeLongOfInstant());
        System.out.println(timeConversionUtil.TimeOfLongToStr(timeConversionUtil.getTimeLongOfDate()));
        System.out.println(TimeConversionUtil.getTimeStrNow());
//          String a=null;
//          Assert.notNull(a,"a是空的");
//
//    }

}

config

application.properties
server.port=8080

# 是否使用缓存,开发阶段最填false,方便使用ctrl+shift+F9 进行重新编译,无需重启服务
spring.thymeleaf.cache=false
# 检查该模板是否存在
spring.thymeleaf.check-template-location=true
# 启动 MVC 对Thymeleaf 视图的解析
spring.thymeleaf.enabled=true
# 模板的字符集
spring.thymeleaf.encoding=UTF-8
# 从解析中排除的视图名称的逗号分隔列表,没有的话就空咯
spring.thymeleaf.excluded-view-names=
# 使用的是什么类型模板
spring.thymeleaf.mode=HTML5
# 在构建URL时可以预览查看名称的前缀。就是路径在哪
spring.thymeleaf.prefix=classpath:/templates/
spring.resources.static-locations=classpath:/templates/
spring.mvc.view.prefix=/ 
spring.mvc.view.suffix=.html
spring.mvc.servlet.load-on-startup=100
#测试
spring.profiles.active=dev
#线上测试
#spring.profiles.active=test
application-dev.properties
#-----------------------------mysql-----------------------------------
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456

templates

index.html
<!DOCTYPE HTML>
<html>
<head>
    <title>Test My WebSocket</title>
</head>


<body>
Test<br/>
<input id="text" type="text"/>
<button  onclick="send()">Send</button>
<button  onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>


<script type="text/javascript">
    var websocket = null;


    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/productWebSocket/001");
    } else {
        console.log("您的浏览器不支持WebSocket");
        alert('Not support websocket')
    }


    //连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("error");
    };


    //连接成功建立的回调方法
    websocket.onopen = function (event) {
        setMessageInnerHTML("open");
    }


    //接收到消息的回调方法
    websocket.onmessage = function (event) {
        setMessageInnerHTML(event.data);
    }


    //连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("close");
    }


    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        websocket.close();
    }


    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }


    //关闭连接
    function closeWebSocket() {
        websocket.close();
    }


    //发送消息
    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
</script>
</html>

启动类:HuawenCloudStockApplication

package com.hwqh.huawencloudstock;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling //该注解是开启定时任务的支持
public class HuawenCloudStockApplication extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(HuawenCloudStockApplication.class);
    }


    public static void main(String[] args) {
        SpringApplication.run(HuawenCloudStockApplication.class, args);
    }

}
http://localhost:8080/

spring boot 集成tcp spring boot集成websocket_整合WebSocket_02