websocket显示实时消息

news2024/11/24 22:49:44

websocket实现实时消息展示

前面介绍过websocket聊天功能的实现,不清楚的可以先看下
websocket实现在线聊天
https://blog.csdn.net/qq_51076413/article/details/124644500

之前发过websocket的相关使用和一对一聊天的·demo·代码,这里是针对上几篇文章的补充,不明白的可以看下我以前的websocket技术文章

这里介绍下如何实时显示好友推送过来的消息
在这里插入图片描述
右下角实时推送和接收通知
在这里插入图片描述

好友列表中实时显示最新消息
在这里插入图片描述

下面直接上代码

代码并未完善,比如显示未读条数、好友下线刷新好友列表等,这些功能在websocket实现在线聊天中都有实现,有需要的可以自己整合下

不废话上代码

后台代码展示

package cn.molu.ws.socket;
import cn.hutool.core.util.ObjUtil;
import cn.molu.ws.pojo.Message;
import cn.molu.ws.pojo.User;
import cn.molu.ws.vo.Result;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ApiNote: 网络连接控制器
 * @Author: 陌路
 * @Date: 2023/1/16 13:23
 * @Tool: Created by IntelliJ IDEA.
 */
@Slf4j
@Component
@ServerEndpoint("/socket/{userId}")
public class WebSocketService {
    // 存储已连接用户数据
    private static final Map<String, Session> onLineUser = new ConcurrentHashMap<>();
    private static final String PONG = "PONG";
    private static final String PING = "PING";

    /**
     * 连接建立时 会调用该方法
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) {
        log.info("系统消息推送。。。{}	", userId);
        setonLineUser(userId, session);
    }

    /**
     * @apiNote: 接收到客户端发送的数据时 会调用此方法
     * @param: [message, session]
     * @return: void
     */
    @OnMessage
    public void onMessage(String msg, Session session) {
        log.info("来自客户端的消息:{}", msg);
        if (StringUtils.isNotBlank(msg)) {
            Message message = JSON.parseObject(msg, Message.class);
            if (ObjUtil.isNotEmpty(message) && StringUtils.isNotBlank(message.getHeartbeat())) {
                if (PING.equals(message.getHeartbeat()) && 1 == message.getType() && ObjUtil.isNotEmpty(session) && session.isOpen()) {
                    // 发送和接收心跳包,30s一次
                    message.setHeartbeat(PONG);
                    try {
						session.getBasicRemote().sendText(JSON.toJSONString(message));
					} catch (IOException e) {
						log.error("同步消息发送出错",e.getMessage());
						e.printStackTrace();
					}
                    return;
                }
            }
        }
    }

    /**
     * 连接关闭时 调用此方法
     * @throws IOException 
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId, Session session) {
        log.debug("关闭连接-->{}", userId);
        remove(userId);
        User user = User.getUserById(userId);
        user.setDate(new Date());
        Message message = new Message();
        message.setContent("好友" + user.getUsername() + "下线了");
        message.setType(-1); // 系统消息
        message.setUserId(userId);
        message.setUsername(user.getUsername());
        sendMessage2Everyone(message);
    }

    /**
     * 出现错误时调用改方法
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("连接出错了......{}", error);
    }


    /**
     * @apiNote: 添加新连接用
     * @param: [userId, session]
     * @return: void
     * @throws IOException 
     */
    private void setonLineUser(String userId, Session session) {
        if (StringUtils.isNotBlank(userId)) {
            onLineUser.put(userId, session);
            log.info("有新的用户加入:{},人数:{}", userId, onLineUser.size());
            User user = User.getUserById(userId);
            user.setDate(new Date());
            Message message = new Message();
            message.setContent("好友" + user.getUsername() + "上线了");
            message.setType(1); // 系统消息
            message.setUserId(userId);
            message.setUsername(user.getUsername());
            User.setUser(user);
            // 给所有在线用户推送上线通知
            sendMessage2Everyone(message);
        }
        try {
        	Set<User> list = getList();
			session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(list)));
		} catch (IOException e) {
			log.error("同步消息发送出错",e.getMessage());
			e.printStackTrace();
		}	
    }

    /**
     * @apiNote: 获取指定已建立连接的用户
     * @param: [userId]
     * @return: Session
     */
    public static Session getWebSocketSession(String userId) {
        return (!StringUtils.isBlank(userId) && onLineUser.containsKey(userId)) ? onLineUser.get(userId) : null;
    }

    /**
     * @apiNote: 获取所有连接用户
     * @param: []
     * @return: Map<String,Session>
     */
    public static Map<String,Session> getAllOnlineUsers(){
        return onLineUser;
    }

    /**
     * @apiNote: 一对一发送消息
     * @param: [message:toId、content]
     * @return: void
     */
    public static void sendMessageO2O(Message message) {
        Session session = null;
        if (ObjUtil.isNotEmpty(message) && StringUtils.isNotBlank(message.getToId())
                && StringUtils.isNotBlank(message.getContent())
                && StringUtils.isNotBlank(message.getUserId())) {
            final String toId = message.getToId();
            if (onLineUser.containsKey(toId)) {
                session = onLineUser.get(toId);
            }
            if (ObjUtil.isNotEmpty(session) && session.isOpen()) {
    		// 异步消息发送
            // session.getAsyncRemote().sendText(JSON.toJSONString(message));
	    		try {
	    			 // 同步消息发送
					session.getBasicRemote().sendText(JSON.toJSONString(message));
				} catch (IOException e) {
					log.error("同步消息发送出错",e.getMessage());
					e.printStackTrace();
				}
            }
        }
    }

    /**
     * @apiNote: 给所有人发送消息
     * @param: [message]
     * @return: void
     */
    public static void sendMessage2Everyone(Message message) {
        if (ObjUtil.isNotEmpty(message) && onLineUser.size() > 0) {
            onLineUser.entrySet().forEach(item -> {
                final Session session = item.getValue();
                if (ObjUtil.isNotEmpty(session) && session.isOpen()) {
                    message.setType(1); // 系统消息
                    message.setDate(new Date());
                    // 同步发送
					// session.getBasicRemote().sendText(JSON.toJSONString(message));
					try {
						// 异步消息发送
						session.getBasicRemote().sendText(JSON.toJSONString(message));
					} catch (IOException e) {
						log.error("同步消息发送出错",e.getMessage());
						e.printStackTrace();
					}
                }
            });
        }
    }

    /**
     * @apiNote: 从缓存中删除已连接的用户
     * @param: [userId]
     * @return: Session
     */
    public static void remove(String userId) {
        if (StringUtils.isNotBlank(userId) && onLineUser.containsKey(userId)) {
            onLineUser.remove(userId);
        }
        log.debug("移除连接用户:{},当前人数:{}", userId, onLineUser.size());
    }
    
    /**
     * @apiNote: 获取所有在线用户信息
     * @return: Set<User>
     */
    public static Set<User> getList() {
        final Map<String, Session> allOnlineUsers = WebSocketService.getAllOnlineUsers();
        Set<User> users = new HashSet<>();
        for (Map.Entry<String, Session> entry : allOnlineUsers.entrySet()) {
            final User user = User.getUserById(entry.getKey());
            users.add(user);
        }
        return users;
    }
}

说明:异步发送在并发下会出现异常错误,此时在发送消息的地方加上锁可以解决

// 异步消息发送
synchronized (session) {
    session.getAsyncRemote().sendText(JSON.toJSONString(message));
}

消息处理控制器,这里可以自定义消息的过滤,拦截替换或终止发送消息

/**
 * @ApiNote: 消息处理控制器
 * @Author: 陌路
 * @Date: 2023/1/16 15:25
 * @Tool: Created by IntelliJ IDEA.
 */
@RestController
@RequestMapping("/message/*")
public class MessageController {

    @GetMapping("sendMessage")
    public Result sendMessage(Message message) {
        message.setDate(new Date());
        WebSocketService.sendMessageO2O(message);
        return Result.ok("发送成功!");
    }

    @GetMapping("getList")
    public Result getList() {
        final Set<User> users = WebSocketService.getList();
        return Result.ok(users);
    }
}

这里是用的map集合存储的用户数据来模拟数据库用户,可根据自己的业务替换真实的数据库数据

/**
 * @ApiNote: 用户实体类
 * @Author: 陌路
 * @Date: 2023/1/16 13:31
 * @Tool: Created by IntelliJ IDEA.
 */
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User extends BaseEntity{

    private static final long serialVersionUID = -31513108721728277L;
    /**
     * 用户id
     */
    private String userId;
    /**
     * 用户名
     */
    private String username;
    /**
     * 用户手机号
     */
    private String phone;
    /**
     * 用户密码
     */
    private String password;
    /**
     * 账号
     */
    private String account;

    /**
     * 构造用户数据 模拟数据库用户
     */
    public static Map<String, User> userMap = new HashMap<String, User>();

    static {
        userMap.put("123456789", new User("001", "jack", "150******67", "123456","123456789"));
        userMap.put("987654321", new User("002", "mary", "135******88", "123456","987654321"));
    }

    public static User getUserById(String userId){
        for (User user : userMap.values()) {
            if (user.getUserId().equals(userId)) {
                return user;
            }
        }
        return new User();
    }

    public static void setUser(User user) {
        if (ObjUtil.isNotEmpty(user)) {
            userMap.put(user.getAccount(), user);
        }
    }
}

前台完整代码展示

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>消息推送</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.js"></script>
    <style type="text/css">
        .main {
            width: 70%;
            margin: auto;
            padding: 10px;
            text-align: center;
        }

        .login-main {
            display: block;
            width: 60%;
            margin: auto;
            padding: 20px;
            box-shadow: 1px 0px 5px 2px #d0d0d0;
            border-radius: 10px;
        }

        .login-main div {
            font-size: 1.3em;
            font-family: cursive;
        }

        .login-main div p input {
            border-radius: 5px;
            height: 25px;
            border: 1px solid #999;
            outline-color: #50a7f6;
        }

        .login-btn {
            font-size: 1.2em;
            background-color: #06cd06;
            color: #ffffff;
            border: 1px solid #06cd06;
            padding: 5px 15px;
            border-radius: 8px;
        }

        .list-main {
            display: none;
            width: 100%;
        }

        .main-win {
            width: 100%;
            box-shadow: 1px 0px 5px 2px #d0d0d0;
            border-radius: 10px;
            display: flex;
        }

        .main-list, .main-chat {
            border: 1px solid #999;
            height: 500px;
        }

        .main-list {
            width: 30%;
        }

        .main-chat {
            width: 70%;
        }

        .chat {
            width: 100%;
            text-align: left;
            background-color: #fafafa;
            border: 1px solid #e8e8e8;
            cursor: pointer;
        }

        .message {
            font-size: 14px;
            overflow: hidden;
            white-space: nowrap;
        }

        .chat p {
            margin: 3px;
        }

        .chat:hover {
            background-color: antiquewhite;
        }

        .notice {
            position: fixed;
            bottom: 6px;
            right: 6px;
            box-shadow: 1px 0px 5px 2px #d0d0d0;
            width: 300px;
            display: none;
            background-color: #fff;
        }

        .notice-title {
            width: 100%;
            height: 30px;
            display: flex;
            justify-content: space-between;
            border-bottom: 1px solid #999;
        }

        .notice-title div {
            padding: 5px 10px;
            cursor: pointer;
        }

        .close {
            background-color: red;
            color: #fff;
        }

        .notice-msg {
            height: 100px;
            text-align: center;
            font-size: 1.1em;
            padding: 20px 5px;
            margin: 10px;
            max-height: 150px;
        }

        .chat-msg {
            width: 100%;
            height: 410px;
        }

        .edit-msg {
            width: 100%;
        }

        .edit-msg textarea {
            width: 99%;
            height: 50px;
            outline: none;
            resize: none;
        }

        .send-btn {
            width: 100%;
            height: 30px;
        }

        .send-msg {
            font-size: 1.1em;
        }
        .msg-left {
            padding: 5px;
            background-color: #50a7f6;
        }

        .msg-right{
            padding: 5px;
            background-color: skyblue;
        }
        .p-msg-right{
            height: 30px;
            text-align: right;
            padding: 5px;
        }

        .p-msg-left{
            height: 30px;
            text-align: left;
            padding: 5px;
        }


    </style>
</head>
<body>
<div class="main">
    <!--  登录框  -->
    <div class="login-main">
        <div>请登录</div>
        <div>
            <p>
                <span>账号:</span><input type="text" id="account" maxlength="16" placeholder="请输入账号"/>
            </p>
            <p>
                <span>密码:</span><input type="password" id="password" maxlength="16" placeholder="请输入密码"/>
            </p>
            <p>
                <button class="login-btn">登录</button>
            </p>
        </div>
    </div>

    <!--  聊天界面  -->
    <div class="list-main">
        <div class="main-win">
            <div class="main-list"></div>
            <div class="main-chat">
                <div class="chat-msg">

                </div>
                <div class="edit-msg">
                    <textarea id="edit-msg-val"></textarea>
                </div>
                <div class="send-btn">
                    <button class="send-msg">发送</button>
                </div>
            </div>
        </div>
    </div>
</div>
<!--  右下角消息通知  -->
<div class="notice">
    <div class="notice-title">
        <div class="notice-title-msg">消息通知</div>
        <div class="close">X</div>
    </div>
    <div class="notice-msg">
        <span class="notice-msg">好友李明上线了</span><br/>
        <span class="notice-date">2023-01-16 22:04</span>
    </div>
</div>
</body>
<script type="text/javascript">
    let user = {}; // 当前登录用户
    let userList = []; // 好友列表
    let selectedUser = {}; // 当前聊天好友
    let socket = {};//websocket连接
    let interval = null; // 定时器
    let msgChatArr = []; // 聊天记录
    $(function () {
        user = JSON.parse(localStorage.getItem("user")) || {};
        selectedUser = JSON.parse(localStorage.getItem("selectedUser")) || {};
        userList = JSON.parse(localStorage.getItem("userList")) || [];
        msgChatArr = JSON.parse(localStorage.getItem("msgChatArr")) || [];
        if (!user.userId) {
            $(".list-main").hide();
            $(".login-main").show();
        } else {
            $(".list-main").show();
            $(".login-main").hide();
            initWebsocket(user.userId)
            getUserList();
        }
        if (selectedUser && selectedUser.userId) {
            selectedUserChat(selectedUser.userId, selectedUser.username);
        }
    })

    // 初始化连接
    function initWebsocket(userId) {
        if (userId && socket.readyState != 1) {
            // 创建连接
            socket = new WebSocket(`ws://127.0.0.1:8088/socket/${userId}`);
            // 建立连接
            socket.onopen = function (res) {
                //建立连接,开始发送心跳包
                sendPing(userId);
            };
            // 接收到消息
            socket.onmessage = function (res) {
                let data = res.data || '';
                if (typeof res.data == 'string') {
                    data = JSON.parse(res.data);
                }
                console.log('onmessage.data', data);
                if (data.type == 1) {
                    showNotice(data);
                    updateShowView(data);
                } else {
                    updateShowView(data);
                    pushMsg(data);
                }
                if (data.code == 200) {
                    getUserList(data.data);
                }
            };
            // 连接失败
            socket.onerror = function (res) {
                alert(res.msg || '连接失败!');
            };
            // 关闭连接
            socket.onclose = function (res) {

            };
        } else {

        }
    }

    // 登录按钮
    $(".login-btn").click(function () {
        let password = $("#password").val() || '';
        let account = $("#account").val() || '';
        if (!account.trim() || !password.trim()) {
            return alert("请输入账号和密码!");
        }
        $.getJSON("/user/login", {account: account, password: password}, function (res) {
            if (typeof res == 'string') {
                res = JSON.parse(res);
            }
            if (res.code == 200) {
                user = res.data || {};
                console.log('user', user);
                if (user.userId) {
                    localStorage.setItem("user", JSON.stringify(user));
                    initWebsocket(user.userId)
                    $(".list-main").show();
                    $(".login-main").hide();
                }
            } else {
                alert(res.msg || '未知错误');
            }
        });
    });

    // 获取好友列表
    function getUserList(data) {
        if (!data) return;
        if (typeof data == 'string') {
            data = JSON.parse(data);
        }
        userList = data;
        if (userList.length > 0) {
            localStorage.setItem("userList", JSON.stringify(userList));
            showListView(userList);
        }
    }

    // 显示好友列表
    function showListView(list) {
        if (!list || list.length == 0) {
            list = userList;
        }
        $.each(list, function (index, item) {
            if(item.userId != user.userId){
                let date = item.date || '';
                date = date + "".substring(0, 16);
                let html = `<div class="${item.userId} chat" οnclick="selectedUserChat('${item.userId}','${item.username}')">
            				<p>${item.username || ''}</p>
            				<p id="${item.userId}" class="message">${item.message || date || ''}</p>
            			</div>`;
                if (item.username) {
                    $(".main-list").append(html);
                }
            }
        });
    }

    // 选择好友
    function selectedUserChat(id, name) {
        $("." + id).css("background", "antiquewhite").siblings().css("background", "#fafafa");
        selectedUser = {userId: id, username: name};
        localStorage.setItem("selectedUser", JSON.stringify(selectedUser));
    }

    // 更新好友列表中的显示消息
    function updateShowView(data) {
        if (data.content && data.type != 1) {
            $("#" + data.userId).text(data.content);
        }
    }

    function pushMsg(data){
        let cls = "msg-left";
        if (user.userId == data.userId){
            cls = "msg-right";
        }
        if (data.content){
            let html = `<p class="p-${cls}"><span class="${cls}">${data.content}</span></p>`;
            $(".chat-msg").append(html);
        }
    }

    // 30s发送一次心跳包
    function sendPing(userId) {
        userId = userId || user.userId || '';
        if (!userId) return;
        interval = setInterval(() => {
            if (socket.readyState == 1) {
                socket.send(JSON.stringify({heartbeat: "PING", type: 1}));
            }
        }, 30 * 1000);
    }

    // 显示消息提醒框
    function showNotice(data) {
        let title = data.title || '消息通知';
        let msg = data.content || '';
        let userId = data.userId || '';
        let date = data.date || '';
        if (!msg || user.userId == userId) {
            return;
        }
        $(".notice-title-msg").text(title);
        $(".notice-msg").text(msg);
        $(".notice-date").text(date);
        $(".notice").show("slow");
        setTimeout(() => {
            $(".notice").hide("slow");
        }, 5000);
    }

    // 关闭右下角提醒框
    $(".close").click(function () {
        $(".notice").hide("slow");
        $(".notice-title-msg").text('');
        $(".notice-msg").text('');
        $(".notice-date").text('');
    });

    // 发送消息给后台
    $(".send-msg").click(function () {
        let val = $("#edit-msg-val").val();
        if (!val) {
            return alert("内容不要为空!");
        }
        if (!selectedUser || !selectedUser.userId) {
            return alert("请选择好友!");
        }
        let param = {
            userId: user.userId,
            username: user.username,
            toId: selectedUser.userId,
            toName: selectedUser.username,
            content: val,
            type: 0
        };
        $.getJSON("/message/sendMessage", param, function (res) {
            if (typeof res == 'string') {
                res = JSON.parse(res);
            }
            if (res.code == 200) {
                $("#edit-msg-val").val('');
                pushMsg(param);
            } else {
                alert(res.msg || '未知错误!');
            }
        });
    });
</script>
</html>

这里就是前台和后台核心代码的地方了,有需要的可以自己整理到项目使用

不懂的可以在作者主页搜索"websocket"相关文章,里面有详细说明和代码地址
.
.
.
.

完整代码目前尚未整理,待完整代码整理完成后会放到git

.
.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nacos服务注册与发现源码剖析

文章目录前提介绍Nacos源码下载Nacos客户端源码Spring Cloud Starter Nacos 源码Nacos服务端源码前提介绍 服务注册与发现作用主要是为了更好的管理众多的服务&#xff0c;不论Nacos还是Zookeeper、Eureka&#xff0c;作为注册中心都是为了解决以下两个问题&#xff1a; 屏蔽…

【论文写作】英文写作工具推荐及使用教程:DeepL(翻译) + EasyEssay(扩写) + QuillBot(改写润色)

文章目录一、DeepL二、EasyEssay2.1 润写2.2 扩写2.3 生成文章2.4 英文查重三、QuillBot一、DeepL DeepL官网 DeepL的主要作用是翻译&#xff0c;一开始我也是在B站上看到有人推荐用这款翻译工具的&#xff0c;抱着试一试的心态去用了一下&#xff0c;感觉翻译效果真的很不错&a…

【贪心】AcWing 803. 区间选点

905. 区间选点 文章目录题目描述输入格式&#xff1a;输出格式&#xff1a;数据范围输入样例输出样例方法&#xff1a;贪心解题思路代码复杂度分析&#xff1a;题目描述 给定 N 个闭区间 [ai,bi][a_i,b_i][ai​,bi​]&#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每…

利用时间序列预测电量,冷量和压缩空气量

利用时间序列预测电量&#xff0c;冷量和压缩空气量背景分析与思路代码结果一&#xff0c;电量预测二&#xff0c;冷量预测三&#xff0c;压缩空气预测调优一&#xff0c;电量预测(m6)二&#xff0c;冷量预测三&#xff0c;压缩空气预测背景 根据提供的数据&#xff0c;详见附…

企业开发项目【1】— — 流程、开发环境搭建模板

企业开发项目【1】— — 流程、开发环境搭建模板 以黑马的学成在线为例 1 项目背景 2 项目介绍 3 开发环境搭建 3.1 开发工具配置&#xff08;后端&#xff09; 3.1.1 Idea配置 环境编码 编译级别配置 project structure - 设置JDK版本和编译级别3. 自动导包设置 IDEA可以…

远距离车载高速网络通讯方案

一 车载网络的发展 随着电子、半导体和通讯等行业的快速发展&#xff0c;汽车智能化的诉求也愈发强烈。越来越多的传感器和处理器的应用推动了汽车的智能化和电气化&#xff0c;与此同时&#xff0c;也使得ECU&#xff08;电子控制单元&#xff09;的数量快速增加。随着自动驾…

基于“python+”潮汐、风驱动循环、风暴潮等海洋水动力模拟

ADCIRC是新一代海洋水动力计算模型&#xff0c;它采用了非结构三角形网格广义波动连续方程的设计&#xff0c;在提高计算精确度的同时还减小了计算时间。被广泛应用于&#xff1a;模拟潮汐和风驱动的循环、预测风暴潮和洪水和近岸海上作业等。 除此之外&#xff0c;ADCIRC也是我…

目前市场上比较好的oa办公系统企业管理软件有哪些?

行政小李拿着《疫情期间春节返乡填报单》在工位之间来回穿梭…… 财务小王把年终奖金和福利方法拿给老板签字…… 行政小李的和人事小赵回回都因为入职新人培训的事情扯皮…… 后勤小郑每次办公物资的整理都要做半天…… OA系统本就是为企业内部的员工沟通、工作效率提高、协作…

WebDAV之葫芦儿·派盘+BookxNote

BookxNote 支持WebDAV方式连接葫芦儿派盘。 BookxNote是全新设计的电子书阅读学习笔记软件,以不同的思维方式重塑我们的学习过程。一边阅读一边划重点,提供多种划重点笔记工具,包括直线、矩形、圆形、高亮文本,图片摘录。高亮的文本自动编辑为重点的批注内容,还可以对重点…

查看网站历史记录的2种办法,怎样查看网站历史记录?

有个想购买二手域名的朋友问小黑&#xff1a;如何查看网站历史记录&#xff1f;于是今天就分享查看网站历史记录的 2种办法&#xff1a;网站历史记录和快照。 如果你在下单之前想查一查域名以前做过些什么&#xff0c;有没有违禁记录&#xff0c;被惩罚过&#xff0c;被K过等等…

LeetCode082_82. 删除排序链表中的重复元素 II

LeetCode082_82. 删除排序链表中的重复元素 II 一、描述 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;…

CODESYS开发教程8-定时、触发和计数

今天继续我们的小白教程&#xff0c;老鸟就不要在这浪费时间了&#x1f60a;。 前面一期我们介绍了CODESYS的字符串及其操作。这一期主要介绍CODESYS的定时器及触发的相关功能块特性及用法&#xff0c;注意本文介绍的定时器、触发器和计数器均包含在CODESYS的Standard库中。 一…

c-note:字符串常量初始化存放位置

两行代码&#xff0c;分别以数组形式和指针形式&#xff0c;先说结论。 对于字面量"he"的存放位置&#xff1a; 1、数组形式&#xff0c;字面量直接存放进栈给temp处开辟的空间 2、指针形式&#xff0c;字面量"he"是一个常量&#xff0c;在编译之初便存在于…

如何在mac上使用idea做大数据开发

1 软件包下载jdk1.8 (jdk1.8.0_231)idea(包括2018,2019) (ideaIC-2019.3.3/ideaIC-2018.3.5)汉化包:汉化包.rarmaven3.6.3 (apache-maven-3.6)2 jdk的安装第一:把包直接放到自定义目录下第二:配置环境变量a) 打开终端 输入 sudo vi /etc/profile 或者 sudo vi .bash_profile解释…

联合证券|滴滴出行即日起恢复!A股嗨了!券商扛起领涨大旗

A股今天全线走高&#xff0c;沪指涨超1%克复3200点&#xff0c;深成指、创业板指盘中涨超2%&#xff1b;港股午后回落走低&#xff0c;恒生科技指数一度跌超2%。 详细来看&#xff0c;A股方面&#xff0c;两市股指盘中强势拉升&#xff0c;沪指涨超1%站稳3200点&#xff0c;深成…

『速查手册』MIME 多用途互联网邮件扩展

『速查手册』MIME 多用途互联网邮件扩展 文章目录『速查手册』MIME 多用途互联网邮件扩展一、多用途互联网邮件扩展 / 互联网媒体类型二、MIME 命名规则&#x1f60e;三、MIME 类型列表&#x1f349;1)、Type 类型形式2)、Application 应用文件3)、Text 文本4)、Video 视频文件…

elasticsearch(三)-- 理解ES的索引操作

一、前言 上一章我们主要学习了es的几个客户端&#xff0c;那么我们后面也主要通过kibana客户端、HighLevelClient高级客户端这两个来学习es. 这一章的学习我们主要是学习一些Elasticsearch的基础操作&#xff0c;主要是深入一些概念&#xff0c;比如索引的具体操作&#xff0…

三、WEB框架介绍以及设计模式

web框架介绍 什么是web框架 应该叫web应用框架(web application framework)&#xff0c;它是一种开发框架。 通俗点来讲&#xff0c;就是用来开发web应用的程序。 为什么要使用框架来开发 互联网行业流行一句话叫“不要重复造轮子”&#xff0c;特别是对于新手和应用层开发…

day22-JDK新特性

接口中的新特性 接口我们之前已经学过了&#xff0c;那么接口中内部主要就是封装了方法&#xff0c;包含抽象方法&#xff08;JDK 7及以前&#xff09;&#xff0c;默认方法和静态方法&#xff08;JDK 8&#xff09;&#xff0c;私有方法 &#xff08;JDK 9&#xff09;。 接口…

使用Navicat导入和导出sql语句

创建mysql数据库 创建数据库之前&#xff0c;肯定要先连接上数据库&#xff0c;如果不知道怎么使用navicat连接mysql数据库&#xff0c;可以参考之前的文章哦 https://blog.csdn.net/weixin_43860634/article/details/128716733 接下来进入正题 1、首先要双击test &#xff0…