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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
链接: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;
}
效果演示:


浙公网安备 33010602011771号