Spring_webSocket学习

 

在线测试:

在线websocket测试-在线工具-postjson (coolaf.com)

开启注解:

<!--Socket集成框架-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--使用SessingApi-->
<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
</dependency>

开启扫描:@EnableScheduling

@SpringBootApplication
@EnableScheduling
public class SpringWsApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringWsApplication.class, args);
	}
}

一:接口版:

1.注册配置类,把:MyWsHandler注册为Socket服务

同时开启跨域访问

和编码格式

import com.example.spring_web_socket.Socket.MyWsHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.standard.TomcatRequestUpgradeStrategy;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	
	@Autowired
	private MyWsHandler myWsHandler;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry
                //表示:MyWsHandler为websocket实现类,myWs为访问路径,例如:ws://localhost:10003/myWs
				.addHandler(myWsHandler, "myWs")
				//允许跨域
				.setAllowedOrigins("*")
				//  设置请求编码为Utf-8
				.setHandshakeHandler(new DefaultHandshakeHandler(new TomcatRequestUpgradeStrategy()))
		        ;
	}
}

 2.编写MyWsHandler 类 ,继承AbstractWebSocketHandler类

package com.example.spring_web_socket.Socket;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.time.LocalDateTime;

/**
 * ws消息处理类
 */
@Component
public class MyWsHandler extends AbstractWebSocketHandler {
	
	
	/**
	 * 连接成功
	 * @param session
	 * @throws Exception
	 */
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		System.out.println("建立ws连接");
		WsSessionManager.add(session.getId(),session);
	}
	
	/**
	 * 获取客户端消息
	 * @param session
	 * @param message
	 * @throws Exception
	 */
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		System.out.println("发送文本消息");
		// 获得客户端传来的消息
		String payload = message.getPayload();
		System.out.println("server 接收到消息 " + payload);
		session.sendMessage(new TextMessage("server 发送给的消息 " + payload + ",发送时间:" + LocalDateTime.now().toString()));
	}
	
	@Override
	protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
		System.out.println("发送二进制消息");
	}
	
	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		System.out.println("异常处理");
		WsSessionManager.removeAndClose(session.getId());
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		System.out.println("关闭ws连接");
		WsSessionManager.removeAndClose(session.getId());
	}
}

到此剩下的,就是自定义功能了:比如我的:

控制Sessing
 package com.example.spring_web_socket.Socket;

import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;


public class WsSessionManager {
	/**
	 * 保存连接 session 的地方
	 */
	public  static ConcurrentHashMap<String, WebSocketSession> SESSION_POOL = new ConcurrentHashMap<>();
	
	/**
	 * 添加 session
	 *
	 * @param key
	 */
	public static void add(String key, WebSocketSession session) {
		// 添加 session
		SESSION_POOL.put(key, session);
	}
	
	/**
	 * 删除 session,会返回删除的 session
	 *
	 * @param key
	 * @return
	 */
	public static WebSocketSession remove(String key) {
		// 删除 session
		return SESSION_POOL.remove(key);
	}
	
	/**
	 * 删除并同步关闭连接
	 *
	 * @param key
	 */
	public static void removeAndClose(String key) {
		WebSocketSession session = remove(key);
		if (session != null) {
			try {
				// 关闭连接
				session.close();
			} catch (IOException e) {
				// todo: 关闭出现异常处理
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 获得 session
	 *
	 * @param key
	 * @return
	 */
	public static WebSocketSession get(String key) {
		// 获得 session
		return SESSION_POOL.get(key);
	}
}
生成自动消息
 package com.example.spring_web_socket.Socket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;

/**
 * 消息生成job
 */
@Component
public class MessageJob {
	@Autowired
	WsService wsService;
	
	/**
	 * 每5s发送
	 */
	@Scheduled(cron = "0/5 * * * * *")
	public void run(){
		try {
			wsService.broadcastMsg("自动生成消息 "  + LocalDateTime.now().toString());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
发送消息
 package com.example.spring_web_socket.Socket;

import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;

/**
 * ws操作相关服务
 */
@Service
public class WsService {
	
	/**
	 * 发送消息
	 * @param session
	 * @param text
	 * @return
	 * @throws IOException
	 */
	public void sendMsg(WebSocketSession session, String text) throws IOException {
		session.sendMessage(new TextMessage(text));
	}
	
	/**
	 * 广播消息
	 * @param text
	 * @return
	 * @throws IOException
	 */
	public void broadcastMsg(String text) throws IOException {
		for (WebSocketSession session: WsSessionManager.SESSION_POOL.values()) {
			session.sendMessage(new TextMessage(text));
		}
	}
	
}
界面
 <!DOCTYPE HTML>
<html>
<head>

    <meta charset="UTF-8">
    <title>My WebSocket</title>
</head>

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


</body>

<script type="text/javascript">

    let ws = null;
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        ws = new WebSocket("ws://localhost:10003/myWs");
    }
    else {
        alert('当前浏览器 Not support websocket')
    }

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

    //连接成功建立的回调方法
    ws.onopen = function(event) {
        console.log("ws调用连接成功回调方法")
        //ws.send("")
    }
    //接收到消息的回调方法
    ws.onmessage = function(message) {
        console.log("接收消息:" + message.data);
        if (typeof(message.data) == 'string') {
            setMessageInnerHTML(message.data);
        }
    }
    //ws连接断开的回调方法
    ws.onclose = function(e) {
        console.log("ws连接断开")
        //console.log(e)
        setMessageInnerHTML("ws close");
    }

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

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


    //发送消息
    function send(msg) {
        if(!msg){
            msg = document.getElementById('text').value;
            document.getElementById('message').innerHTML += "发送的消息:" + msg + '<br/>';
            ws.send(msg);
        }
    }
</script>
</html>

二.注解版

导包一定要导包:jakarta 下的,有个javax下的包和我们的包完全匹配,如果用错的话启动不了!!!

  • @ServerEndpoint:将目前的类定义成一个websocket服务器端,注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
  • @OnOpen:当WebSocket建立连接成功后会触发这个注解修饰的方法。
  • @OnClose:当WebSocket建立的连接断开后会触发这个注解修饰的方法。
  • @OnMessage:当客户端发送消息到服务端时,会触发这个注解修改的方法。
  • @OnError:当WebSocket建立连接时出现异常会触发这个注解修饰的方法。

作者:威廉王子
链接:https://juejin.cn/post/7157150311323271176
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考:

Spring Boot 集成 WebSocket(原生注解与Spring封装) - 掘金 (juejin.cn)

Spring Boot 集成 WebSocket(原生注解与Spring封装)_springboot集成websocket-CSDN博客

1.返回一个Socket容器:注解表示这是个WebSocket类:

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

@Configuration
public class WebSocketConfiguration {
	/**
	 * 	注入ServerEndpointExporter,
	 * 	这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
	 */
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}
}

 

2.创建Socket类


import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;


/**
 *  websocket服务实现类
 *  ws://localhost:10003/sok
 *  <br><a href="http://coolaf.com/zh/tool/chattest">在线websocket测试-在线工具</a>
 */


@ServerEndpoint(value = "/sok")  //注册为Socket类,并分配地址
@Component
public class MySocket {
	//连接成功
	@OnOpen
	public void onopen(Session session ){
		System.out.println(session +" 连接成功了 " +"");
	}
	//收到消息
	@OnMessage
	public void OnMessage(Session session, String message){
		System.out.println(session +" 发来了消息: " +message);
		//原文发回去:
		session.getAsyncRemote().sendText("--------服务器重复你的话:"+message);
	}
	//连接关闭
	@OnClose
	public void OnClose(Session session){
		System.out.println(session +" 关闭了连接 " +"");
	}
	@OnError
	public void OnError(Session session,Throwable exception){
		System.out.println(session +" 发生了错误: " +exception);
	}
}

前端调用:

//连接已建立:
socket.onopen = function(event) {
// 执行连接已建立后的操作
};

// 接收到消息:
socket.onmessage = function(event) {
    var message event.data;
// 处理接收到的消息
};

// 发生错误:
socket.onerror = function(event) {
// 处理连接错误
};

// 连接已关闭:
socket.onclose = function(event) {
// 处理连接已关闭
};

 

实战案例:

基于我之前写的蓝奏云解析,实现后端运行进程,前端实时播报:

思路:

1.连接监听窗口

2.后端处理事件时,log打印方法重写,  所有的log都通过Socket发送

3.前端接收框,  甚至可以发送消息,  实现指令式服务

 

开始:

第一步前端:

开启前端支持:

<!--开启前端thymeleaf支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

前端代码:

<!DOCTYPE html>
<html lang = "en">
<head>
    <meta charset = "UTF-8">
    <title>Title</title>
    <!-- 引入axios -->
    <script src = "https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <style>
        .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            height: 100vh;
            background-color: #f4f4f4;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            max-width: 800px;
            margin: 0 auto;
            border-radius: 20px;
            background-image: linear-gradient(45deg, #ff9a9e, #fad0ff);
        }

        .card-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px;
            border-bottom: 1px solid #ffbfbf;
        }

        .card-body {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-top: 20px;
        }

        #urlInput, #mmInput, #startButton, #progressArea, #clearButton {
            margin-bottom: 20px;
        }

        #progressArea {
            margin-top: 20px;
        }

        button {
            background-color: #4CAF50;
            border: none;
            color: white;
            padding: 10px 20px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 4px 2px;
            cursor: pointer;
            border-radius: 5px;
        }

        button:hover {
            background-color: #45a049;
        }

        #zt {
            background-color: #999999;
            width: 500px;
            height: 400px;
            overflow-y: scroll;
        }

        #zt::-webkit-scrollbar {
            /*隐藏滚动条*/
            display: none;
        }

    </style>
</head>
<body class = "container">
<div class = "card-header">
    <h1>蓝奏云在线直连解析</h1>
</div>
<div class = "card-body">
    <label for = "url">地址:</label><input type = "text" id = "url" placeholder = "请输入蓝奏云地址"><br>
    <label for = "mm">密码:</label><input type = "text" id = "mm" placeholder = "如果没有请留空"><br>
    <button id = "startButton" onclick = "ks()">开始解析</button>
    <div id = "progressArea">
        解析进度:<br>
        <div id = "zt"><a>准备就绪。。。。。</a></div>
    </div>
    <label for = "fs"></label><input type = "text" id = "fs" placeholder = "测试用"><br>
    <button id = "clearButton" onclick = "qk()">清空</button>
</div>
</div>
<script>
    document.getElementById("mm").value="6666";
    document.getElementById("url").value="https://zhe--xin--ke--ji.lanzouw.com/i6jTUje2x0d";
    var names = "zhexin";
    var urlym ="localhost:10014";
    var socket=new WebSocket("ws://"+urlym+"/sok/"+names);
    //初始化:
    fs("正在初始化....")
    socket.onopen = function() {fs("<a style=\"color: green;\">状态连接成功。。。</a>",1000); socket.send("客户端收到");};
    socket.onmessage = function(event) { fs( "<a style=\"color:yellow;\">"+event.data+"</a>", 500);};
    socket.onerror = function() { fs("<a style=\"color: red;\">状态,连接失败..请重试...</a>");};
    // 执行相应的操作
    document.getElementById("fs").addEventListener("keyup", function (event) {
        if (event.key === "Enter") {
            var nr = document.getElementById("fs");
            socket.send(nr.value)
            nr.value = ""
        }
    });

    async function ks() {
        //获取控件文本属性
        var mm = document.getElementById("mm").value;
        var url = document.getElementById("url").value;
         //开始解密:
        await jm(url, mm)

    }
    async function jm(url , mm) {
        var config = {
            method: 'post',
              url: "http://"+urlym+"/"+names+"/lzy",
               data: {
                'url': url,
                'mm': mm,
            }
        };

       await axios(config)
            .then(function (response) { //访问成功
                fs(response.data, 1)
            })
            .catch(function (error) {  //发生错误
                fs("出错" + error, 1)
            });
    }

    // 发送到状态框
    function fs(wb, ys) {
        var thi = document.getElementById("zt");

        //记录原始文本
        //延时输出,更有可看性
        setTimeout(() => {
            var wbs = thi.innerHTML + "</br>" + wb
            thi.innerHTML = wbs
            //文本自动滚动到底部
            thi.scrollTop = document.getElementById("zt").scrollHeight;

        }, ys)
    }

    function qk() {
        document.getElementById("zt").innerHTML = ""
    }
</script>
</body>
</html>

java端代码

两个配置类同上

爬虫主类
 package com.example.spingwebsocket2.servlet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.spingwebsocket2.Controller.Socket.Sessions;
import com.example.spingwebsocket2.utils.jq;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


public class GetDownloadURL {
	private String url;
	private String mm;
	private String duan;
	private String id;
	
	public GetDownloadURL(String urls, String mm, String id) {
		try {
			//截取url和域名
			this.url = jq.jqzf(urls, "", ".com") + ".com";
			this.duan = jq.jqzf(urls, url, null);
			this.mm = mm;
			this.id = id;
			Sessions.v1(this.id, "服务器初始化完毕!");
		} catch (Exception e) {
			Sessions.v1(this.id, "解析失败:" + e);
		}
	}
	
	public GetDownloadURL(String urls, String mm) {
		try {
			//截取url和域名
			this.url = jq.jqzf(urls, "", ".com") + ".com";
			this.duan = jq.jqzf(urls, url, null);
			this.mm = mm;
			Sessions.v1(this.id, "服务器初始化完毕!");
		} catch (Exception e) {
			Sessions.v1(this.id, "解析失败:" + e);
		}
	}
//	public static void main(String[] args) {
//		System.out.println(new GetDownloadURL("https://zhe--xin--ke--ji.lanzouw.com/i6jTUje2x0d", "6666").GO());
//	}
	
	//1.读取界面url
	private String getTowSign() throws IOException {
		// <iframe class="n_downlink" name="1700356049" src="/fn?BmAFb1wwBGQJZ1cxVzFUZQFpVGlSOFB0CnlTaFQ5BjAIOFUyXDIGZ1U1VDIKalJqBHgHdFAyUWILKlorUWhWNQZ1BTtcZgQ_bCTRXZFd6VGgBMVQ0UkpQCA_c_c" frameborder="0" scrolling="no"></iframe></div>
		//取到html原文
		String src = "";
		Document gethtml = Jsoup.connect(url + this.duan).get();
		Sessions.v1(this.id, "取到html原文:" + gethtml);
		//取到关键元素
		Elements nDownlink = gethtml.getElementsByClass("ifr2");
		if (nDownlink.size() == 0) {  //非vip
			nDownlink = gethtml.getElementsByClass("n_downlink");
		}
		for (Element element : nDownlink) {
			String attrsrc = element.attr("src");
			src = attrsrc; //不管有没有都返回有个值,默认空字符串
			if (!attrsrc.isEmpty()) {
				Sessions.v1(this.id, "取到结果:" + src);
				//不为null退出
				break;
			}
		}
		
		return src;
	}
	
	//2.读取二级url
	private Map<String, String> getAjaxmSign(String sign) throws IOException {
		String headerurl = this.url + sign; //请求头的验证url
		//取到html原文
		String src = "";
		String gethtml = Jsoup.connect(headerurl).get().outerHtml();
		Sessions.v1(this.id, "取二级url完成.........");
//		System.out.println("---------:"+url+sign );
		//取请求数据
		Map<String, String> ajaxmSign = new HashMap<>();
		//固定值
		ajaxmSign.put("header", headerurl);
		ajaxmSign.put("action", "downprocess");
		ajaxmSign.put("ves", "1");
		if (!mm.isEmpty()) { //有密码
			Sessions.v1(this.id, "输入密码:" + mm);
			ajaxmSign.put("sign", jq.jqzf(gethtml, "var skdklds = '", "';"));
			ajaxmSign.put("signs", "");
			ajaxmSign.put("websign", "");   //设置为空防止取值时报错
			ajaxmSign.put("websignkey", "");
		} else {
			ajaxmSign.put("signs", jq.jqzf(gethtml, "var ajaxdata = '", "';"));
			ajaxmSign.put("sign", jq.jqzf(gethtml, "'sign':'", "','websign'"));
			ajaxmSign.put("websign", jq.jqzf(gethtml, "var ciucjdsdc = '", "';"));
			ajaxmSign.put("websignkey", jq.jqzf(gethtml, "var aihidcms = '", "';"));
		}
//		System.out.println("---------:"+ajaxmSign );
		Sessions.v1(this.id, "取到请求结果:" + ajaxmSign);
		return ajaxmSign;
	}
	
	//3.读取ajam.php
	private String getDownloadSign(Map<String, String> field) {
		//url固定的
		HttpResponse<String> response = Unirest.post(this.url + "/ajaxm.php")
				.header("Accept", "application/json, text/javascript, */*")
				.header("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
				.header("Connection", "keep-alive")
				.header("Origin", "https://wwx.lanzoui.com")
				.header("Referer", field.get("header"))  //这个很重要
				.header("Sec-Fetch-Dest", "empty")
				.header("Sec-Fetch-Mode", "cors")
				.header("Sec-Fetch-Site", "same-origin")
				.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36")
				.header("X-Requested-With", "XMLHttpRequest")
				.header("sec-ch-ua", "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"119\", \"Google Chrome\";v=\"119\"")
				.header("sec-ch-ua-mobile", "?0")
				.header("sec-ch-ua-platform", "\"Windows\"")
				.header("Host", "wwx.lanzoui.com")
				.multiPartContent()
				.field("action", field.get("action"))
				.field("signs", field.get("signs"))
				.field("sign", field.get("sign"))
				.field("websign", field.get("websign"))
				.field("websignkey", field.get("websignkey"))
				.field("ves", field.get("websignkey"))
				.field("p", this.mm)
				.asString();
//		System.out.println(field);
		Sessions.v1(this.id, "请求数据:" + field);
		return response.getBody();
	}
	
	private Map<String, String> getdownload(String url, String downloadurl) {
		//解析第一个地址
		Map<String, String> map = new HashMap();
		String response1 = Unirest.get(url + downloadurl).asString().getBody();
		String downloadurls = jq.jqzf(response1, "'file':'", "','el':el,'sign':'");
		String sign = jq.jqzf(response1, "'el':el,'sign':'", "' },");
		map.put("downloadurls", downloadurls);
		map.put("sign", sign);
		map.put("url", url);
		Sessions.v1(this.id, "第二个url:" + map);
		return map;
	}
	
	//解析第二个地址
	//4.获取重定向的值:
	private String getLocation(Map<String, String> map) throws InterruptedException {

//		//url固定的
		HttpResponse<String> response = Unirest.post(map.get("url") + "ajax.php")
				.header("Accept", "application/json, text/javascript, */*; q=0.01")
				.header("Referer", "")
				.header("X-Requested-With", "XMLHttpRequest")
				.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0")
				.header("Content-Type", "application/x-www-form-urlencoded")
				.header("Host", "developer-oss.lanzouc.com")
				.header("Connection", "keep-alive")
				.field("file", map.get("downloadurls"))
				.field("el", "2")
				.field("sign", map.get("sign"))
				.asString();
		//递归,防止失败娶不到重定向
		if (response.getBody().contains("SignErro")) {
			Sessions.v1(this.id, "开始重定向循环.................:");
			Thread.sleep(800); //控制到1500毫秒
			return this.getLocation(map);
		} else {
			Sessions.v1(this.id, "成功.................:");
			return response.getBody();
		}
	}
	
	//入口
	//4.合成url,去除重定向,返回结果
	public String GO() {
		try {
			String geturl = "";
			//有密码的只需要访问两次,减少服务器资源消耗
			if (!mm.equals("")) {
				Sessions.v1(this.id, "当前有状态密码:" + this.mm);
				Sessions.v1(this.id, "开始:获取二级url");
				Map<String, String> getajax = this.getAjaxmSign(this.duan);
				Sessions.v1(this.id, "获取完成:结果如下:");
				getajax.forEach((key, value) -> {
					Sessions.v1(this.id, getajax.get(key));
				});
				Sessions.v1(this.id, "开始获取下载密钥:");
				geturl = this.getDownloadSign(getajax);
				Sessions.v1(this.id, "读取完毕,结果:" + geturl);
			} else {
				//三次访问
				Sessions.v1(this.id, "当前状态没有密码:需要先取第一个页面");
				Sessions.v1(this.id, "开始:获取二级url访问sign");
				String gettow = this.getTowSign();
				Sessions.v1(this.id, "获取成功,结果:" + gettow);
				Sessions.v1(this.id, "开始:获取二级url");
				Map<String, String> getajax = this.getAjaxmSign(gettow);
				Sessions.v1(this.id, "获取完成:结果如下:");
				getajax.forEach((key, value) -> {
					Sessions.v1(this.id, getajax.get(key));
				});
				Sessions.v1(this.id, "开始获取下载密钥:");
				geturl = this.getDownloadSign(getajax);
				Sessions.v1(this.id, "读取完毕,结果:" + geturl);
			}
			
			//json取出重定向地址
			Sessions.v1(this.id, "开始,json取出重定向地址........");
			JSONObject data = JSON.parseObject(geturl);
			String url = data.get("dom") + "/file/";
			String downloadurl = (String) data.get("url");
			Sessions.v1(this.id, "重定地址为:" + downloadurl);
			//读取重定向界面
			Sessions.v1(this.id, "开始,读取重定向界面。。。。。。。。。。");
			Map<String, String> downloadui = this.getdownload(url, downloadurl);
			Sessions.v1(this.id, "重定向界面读取完成:");
			downloadui.forEach((key, value) -> {
				Sessions.v1(this.id, downloadui.get(key));
			});
			//读取最终地址
			Sessions.v1(this.id, "开始,读取最终地址。。。。。。。。。。");
			String locationURL = this.getLocation(downloadui);
			Sessions.v1(this.id, "读取完成:" + locationURL);
			Sessions.v1(this.id, "开始解析。。。。。。。。。");
			JSONObject data2 = JSON.parseObject(locationURL);
			Sessions.v1(this.id, "解析完毕。。。。。。。。。");
			String downloadurl2 = (String) data2.get("url");
			
			return downloadurl2;
		} catch (Exception e) {
			Sessions.v1(this.id, "解析失败:" + e);
			return "解密失败!!!";
		}
	}
}

 

工具类
 package com.example.spingwebsocket2.utils;

import org.springframework.lang.Nullable;

//字符串截取
public class jq {
    public static String jqzf(String yuanwen, String ks, @Nullable String js) throws StringIndexOutOfBoundsException{
        int kswz = yuanwen.indexOf(ks);
        String jqks = yuanwen.substring(kswz).replaceAll(ks, "");

        
        if (js == null) {
            String jqjs = jqks.substring(0);
            return jqjs;
        }
        int jswz = jqks.indexOf(js);
        String jqjs = jqks.substring(0, jswz).replaceAll(js, "");

        return jqjs;
    }
}
Socket类
 package com.example.spingwebsocket2.Controller.Socket;

import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;



/**
 * websocket服务实现类
 * ws://localhost:10002/sok/ss
 * <br><a href="http://coolaf.com/zh/tool/chattest">在线websocket测试-在线工具</a>
 */


@ServerEndpoint(value = "/sok/{wb}")  //注册为Socket类,并分配地址
@Component
public class MySocket {

	
	//连接成功
	@OnOpen
	public void onopen(Session session, @PathParam("wb") String wb) {
		//初始化信息
		
		Sessions.session = session;
		Sessions.name = wb;
		Sessions.sessionMap.put(Sessions.name, session);
		Sessions.mySockets.add(this);
		System.out.println(session.getId() + " 连接成功了 " + wb);
	}
	
	//收到消息
	@OnMessage
	public void OnMessage(Session session, String message) {
		//System.out.println(session.getId() + " 发来了消息: " + message);
		//原文发回去:
//		session.getAsyncRemote().sendText("--------服务器重复你的话:" + message);

		
		
	}
	
	//连接关闭
	@OnClose
	public void OnClose(Session session) {
		System.out.println(session.getId() + " 关闭了连接 " + "");
	}
	
	@OnError
	public void OnError(Session session, Throwable exception) {
		System.out.println(session.getId() + " 发生了错误: " + exception);
	}
}
session接收类
 package com.example.spingwebsocket2.Controller.Socket;

import jakarta.websocket.Session;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class Sessions {
	public static List<MySocket> mySockets = new ArrayList<>();
	public static Map<String, Session> sessionMap = new HashMap<>();
	public static Session session;
	public static String name;
	
	
	// 此为群发消息
	public static <T> void vq(T messages) {
		String message = messages.toString();
		System.out.println("【websocket消息】广播消息:" + message);
		for (MySocket mySocket : mySockets) {
			if (session.isOpen()) {
				session.getAsyncRemote().sendText(message);
			}
		}
	}
	
	public static <T> void v1(String name, T messages) {
		
		try {
			try {
				_v1(name, messages);
			} catch (IllegalStateException e) {
				Thread.sleep(500);
				v1(name, messages);
			}
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		
	}
	
	//发给一个人
	public static <T> void _v1(String name, T messages) {
		String message = messages.toString();
		//发送给的人
		Session session = sessionMap.get(name);
		if (session != null && session.isOpen()) {
			System.out.println("【websocket消息】 发给一个人消息:" + message);
			session.getAsyncRemote().sendText(message);
		} else {
			System.out.println("找不到:" + name);
			v1(messages);
		}
	}
	
	// 发给多个人
	public static <T> void vx(String[] names, T messages) {
		String message = messages.toString();
		for (String name : names) {
			Session session = sessionMap.get(name);
			if (session != null && session.isOpen()) {
				try {
					System.out.println("【websocket消息】 发给多个人消息:" + message);
					session.getAsyncRemote().sendText(message);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static <T> void v1(T message) {
		String wb = message.toString();
		System.out.println(wb);
	}
}
直连post接口
 package com.example.spingwebsocket2.Controller.lzy;

import com.example.spingwebsocket2.Controller.Socket.Sessions;
import com.example.spingwebsocket2.servlet.GetDownloadURL;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

//返回字符串
@RestController
@Controller
public class API {
	
	@PostMapping("/{id}/lzy")
	public String lay(@PathVariable("id") String id, @RequestBody QQti qQti) {
		System.out.println(id + qQti.getMm() + qQti.getUrl());
		String go = new GetDownloadURL( qQti.getUrl(), qQti.getMm() , id).GO();
		//String go = new GetDownloadURL("https://zhe--xin--ke--ji.lanzouw.com/i6jTUje2x0d", "6666" , id).GO();
		System.out.println(Sessions.name);
		Sessions.v1(id, "解密完成!!!");
		return "<a style=\"color: green;\" href=\"" + go + "\">" + go + "</a>";
	}
}
class QQti{
	public String getMm() {
		return mm;
	}
	
	public void setMm(String mm) {
		this.mm = mm;
	}
	
	public String getUrl() {
		return url;
	}
	
	public void setUrl(String url) {
		this.url = url;
	}
	
	String mm;
	String url;
}

 

效果演示:

 

posted @ 2023-11-24 15:36  哲_心  阅读(56)  评论(0)    收藏  举报