5.SpringTask,WebSocket

Spring Task,WebSocket

Spring Task

介绍:

Spring Task是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑;
定位:定时任务框架
作用:定时自动执行某段Java代码;

应用场景:

信用卡每月还款提醒;
银行贷款每月还款提醒;
火车票售票系统处理未支付订单;
入职纪念日为用户发送通知;

cron表达式:

介绍:

cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间
构成规则:分为6或7个域,由空格分隔开,每个域代表一个含义;
每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选);

各字段含义:
字段 允许值 允许的特殊字符
秒(Seconds) 0~59的整数 , – * / 四个字符
分(Minutes) 0~59的整数 , – * / 四个字符
小时(Hours) 0~23的整数 , – * / 四个字符
日期(DayofMonth) 1~31的整数(但是你需要考虑你月的天数) , – * ? / L W C 八个字符
月份(Month) 1~12的整数或者 JAN-DEC , – * / 四个字符
星期(DayofWeek) 1~7的整数或者 SUN-SAT(1=SUM) , – * ? / L C # 八个字符
年(可选,留空)(Year) 1970~2099 , – * / 四个字符
特殊字符含义

* :表示匹配该域的任意值。假如在Minutes域使用,即表示每分钟都会触发事件。
?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法:1313 15 20*?,其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。

:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次

/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着第5分钟触发一次,之后每隔20分钟触发一次;
,:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
L:表示最后,只能出现在DayofWeek和DayofMonth域。在DayofMonth域使用L,表示最后一天;如果在DayofWeek域使用5L,意味着在最后的一个星期五触发。
W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份。
LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第四个星期二,第四周的星期二。

例子:
分钟 小时
0 0 9 12 10 2022

2022年10月12日上午9点整 对应的表达式为:0 0 9 12 10 ? 2022

在线工具:

在线Cron表达式生成器 (qqe2.com)

使用步骤:

导入maven坐标 spring-context(已存在),没有属于自己的jar包,集成在spring-context中;
启动类添加注解 @EnableScheduling 开启任务调度;
自定义定时任务类:

类中添加方法,方法添加 @Scheduled 注解设置定时执行;
注解参数为 cron表达式;

自定义定时任务类:

@Component
@Slf4j
public class MyTask {
	// 定时任务 每隔5秒触发一次
	@Scheduled(cron = "0/5 * * * * ?")
	public void executeTask(){
		log.info("定时任务开始执行");
	}
}

WebSocket

介绍:

简介:

WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输;

HTTP协议和WebSocket协议对比:

HTTP是短连接
WebSocket是长连接
HTTP通信是单向的,基于请求响应模式;
WebSocket支持双向通信;
HTTP和WebSocket底层都是TCP连接;

应用场景:

视频弹幕;
网页聊天;
体育实况更新;
股票基金报价实时更新;

后端实施:

简介:

导入WebSocket的maven坐标;
创建一个配置类,注册WebSocket的服务端组件;
创建WebSocket服务端组件自定义类,用于和客户端通信;

导入依赖:

在pom.xml中导入WebSocket的maven坐标:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</<artifactId>>
</dependency>
配置类开启对WebSocket的支持:
/**
 *注册WebSocket的服务端组件
 */
@Configuration
public class WebSocketConfig {
	
	@Bean
	public ServerEndpointExporter serverEndpointExporter(){
		return new ServerEndpointExporter();
	}
}
WebSocket服务端, 用于与客户端通信:

添加注解会自动回调:
session: 在WebSocket上下文中,session对象代表了一个打开的WebSocket会话。这个对象提供了与远程端点通信的方法和属性。
getBasicRemote(): 这是Session对象的一个方法,它返回一个RemoteEndpoint.Basic对象。RemoteEndpoint.Basic是一个接口,它提供了发送文本消息、二进制消息以及关闭连接等方法。
sendText(message): 这是RemoteEndpoint.Basic接口的一个方法,它用于向远程端点发送一个文本消息。参数message是一个字符串,代表了要发送的消息内容。

package com.sky.websocket;

import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@Component
// 定义WebSocket服务器端点的访问路径
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

前端实施:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Demo</title>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">发送消息</button>
    <button onclick="closeWebSocket()">关闭连接</button>
    <div id="message">
    </div>
</body>
<script type="text/javascript">
    var websocket = null;
    // 生成随机id,防止重复
    var clientId = Math.random().toString(36).substr(2);

    // 判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        // 连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
    }
    else{
        alert('Not support websocket')
    }

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

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

    // 接收到消息的回调方法
    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 send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
	
	// 关闭连接
    function closeWebSocket() {
        websocket.close();
    }
</script>
</html>

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...