SpringBoot之整合WebSocket服务并兼容IE8浏览器的方式
文章目录
- SpringBoot之整合WebSocket服务并兼容IE8浏览器的方式
- 1. web-socket-js
- 1.下载web-socket-js
- 2. 配置
- 2. FlashSocket安全服务策略文件843端口配置
- 1. 配置方式1_xxx.xml配置方式
- 1. 编写flash843端口监听类
- 2. SpringBoot应用启时启动843监听程序配置
- 3. 配置flash通信协议的策略文件
- 2. 配置方式2_Java编码方式
- 1.编写监听843端口的服务类
- 2. 实现**ServletContextListener**监听接口并在实现方法中启动843端口监听类
- 3. 编写页面进行调试
- 4. 启动应用进行测试
- SpringBoot整合WebSocket过程请查看 SpringBoot之WebSocket服务搭建;
- 以下WebSocket兼容IE8浏览器的方式就是在 SpringBoot之WebSocket服务搭建基础上完成的。
1. web-socket-js
为了兼容IE8浏览器,WebSocket采用Adobe Flash来实现,而Flash由于安全策略问题,会向TCP:843端口发送请求文件,服务器应该返回安全策略文件给客户端;
这里是使用开源项目web-socket-js对IE8中使用webSocket进行兼容适配与实现;
web-socket-js官网地址:https://github.com/gimite/web-socket-js
1.下载web-socket-js
从官网中下载并提取
swfobject.js
、web_socket.js
、WebSocketMain.swf
等三个文件
2. 配置
将上面三个文件放在SpringBoot静态资源目录下
- 在·src\main\resources\static
目录下新建
myjs文件夹,并将
swfobject.js与
web_socket.js`放在myjs中- 将
WebSocketMain.swf
放在跟目录src\main\resources\
下
2. FlashSocket安全服务策略文件843端口配置
1. 配置方式1_xxx.xml配置方式
此配置方式只需要两步:
- 编写一个flash安全服务策略文件监听843端口的监听器线程类;
- 在spring boot应用启动后,随即启动监听843端口的监听器线程;
- 配置flash通信协议的策略文件
1. 编写flash843端口监听类
兼容IE8方式1:将crossdomain.xml改名后放在跟目录下的方式
package org.yuan.mysoket;import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/*** 兼容IE8方式1:将crossdomain.xml改名后放在跟目录下的方式* 为了兼容IE8浏览器,WebSocket采用Adobe Flash来实现,而Flash由于安全策略问题,会向TCP:843端口发送请求文件,服务器应该返回安全策略文件给客户端。*/
public class WebSocketPolicyListener implements Runnable {private ServerSocket server;public WebSocketPolicyListener() {try {server = new ServerSocket(843);System.out.println("Adobe Flash安全策略监听启动");} catch (IOException e) {System.err.println();e.printStackTrace();}}@Overridepublic void run() {while (true) {System.out.println("线程run");try {Socket s = server.accept();//获取安全策略请求文件BufferedInputStream bin = new BufferedInputStream(s.getInputStream());//打开文件流////网络操作调用avaiable()方法时,可能数据并没有到达,这时需要等待数据变为可用int avaiable = 0;//当有可用数据时,退出循环while (avaiable == 0) {avaiable = bin.available();}byte[] buf = new byte[avaiable];int count = bin.read(buf);String request = new String(buf, 0, count);System.out.println("安全策略文件请求:\n" + request);//如果是安全策略文件请求,将安全策略文件发给客户端if (request.indexOf("<policy-file-request/>") != -1) {//获取文件路径,我放在src目录下String path = WebSocketPolicyListener.class.getResource("/").getPath() + "websocket-policy.xml";FileInputStream fin = new FileInputStream(path);buf = new byte[1024];StringBuilder sb = new StringBuilder();while ((count = fin.read(buf)) > 0) {s.getOutputStream().write(buf, 0, count);sb.append(new String(buf, 0, count));}System.out.println("安全策略文件响应:\n" + sb.toString());fin.close();//关闭文件流}s.close();//关闭Socket流} catch (IOException e) {e.printStackTrace();}}}
}
2. SpringBoot应用启时启动843监听程序配置
实现CommandLineRunner接口,并在run方法中启动WebSocketPolicyListener
package org.yuan.config;import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.yuan.mysoket.WebSocketPolicyListener;@Component
public class InitConfig implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {WebSocketPolicyListener webSocketPolicyListener = new WebSocketPolicyListener();new Thread(webSocketPolicyListener).start();}
}
3. 配置flash通信协议的策略文件
默认的策略文件名为
crossdomain.xml
;
这里我自己定义为
ebsocket-policy.xml
,并将此文件放在项目跟目录下;如
src\main\resources\websocket-policy.xml
websocket-policy.xml
内容如下
<?xml version="1.0" encoding="UTF-8" ?>
<cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-http-request-headers-from domain="*" headers="*"/><allow-access-from domain="*" to-ports="2001"/>
</cross-domain-policy>
2. 配置方式2_Java编码方式
1.编写监听843端口的服务类
SocketService.java
类如下J
package org.yuan.config;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 兼容IE8方式2:将crossdomain.xml中的内容直接写入Java代码中* 这个socket主要还是为了flash的socket*/
public class SocketService {private ServerSocket serverSocket = null;private static Object locker = new Object();// 线程池private static ExecutorService executorService = null;public synchronized void initSocketServer() {try {if (executorService == null) {executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 20);} else {return;}//启动843端口serverSocket = new ServerSocket(843);Runnable runnable = new Server();Thread thread = new Thread(runnable);thread.start();} catch (Exception e) {e.printStackTrace();}}public void closeServer() {locker = null;if (serverSocket != null && !serverSocket.isClosed()) {try {serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}class Server implements Runnable {@Overridepublic void run() {try {while (locker != null) {if (serverSocket == null || serverSocket.isClosed()) {continue;}//接收客户端的连接Socket incoming = serverSocket.accept();Runnable runnable = new ThreadClient(incoming);executorService.execute(runnable);}} catch (Exception e) {//此处有一种异常,当关掉Tomcat时,会去关闭ServerSocket对象,//从而抛出异常java.net.SocketException: socket closed,//原因是ServerSocket对象正在等待客户端连接或正在连接中e.printStackTrace();}}}class ThreadClient implements Runnable {private Socket incoming;private ThreadClient(Socket socket) {incoming = socket;}public void run() {InputStreamReader isr = null;BufferedReader br = null;OutputStreamWriter osw = null;BufferedWriter bw = null;try {isr = new InputStreamReader(incoming.getInputStream(), "UTF-8");br = new BufferedReader(isr);osw = new OutputStreamWriter(incoming.getOutputStream(), "UTF-8");bw = new BufferedWriter(osw);//读取客户端发送的数据StringBuilder sb = new StringBuilder();int c;while ((c = br.read()) != -1) {if (c != '\0') {sb.append((char) c);} else {break;}}String info = sb.toString();System.out.println(String.format("客户端发送的数据:%s", info));//接收到客户端请求之后,将策略文件发送出去if (info.contains("<policy-file-request/>")) {bw.write("<cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0");bw.flush();System.out.println(String.format("将安全策略文件发送至:%s", incoming.getInetAddress()));} else {bw.write("请求无法识别\0");bw.flush();System.out.println(String.format("请求无法识别:%s", incoming.getInetAddress()));}} catch (IOException e) {e.printStackTrace();} finally {try {if (br != null) {br.close();}} catch (IOException e) {e.printStackTrace();}try {if (isr != null) {isr.close();}} catch (IOException e) {e.printStackTrace();}try {if (bw != null) {bw.close();}} catch (IOException e) {e.printStackTrace();}try {if (osw != null) {osw.close();}} catch (IOException e) {e.printStackTrace();}try {if (incoming != null) {incoming.close();}} catch (IOException e) {e.printStackTrace();}}}}
}
2. 实现ServletContextListener监听接口并在实现方法中启动843端口监听类
- 实现
ServletContextListener
监听接口并在实现方法中启动843端口监听类;- 编写MyServletContextListener类让其实现ServletContextListener接口,并实现其中的两个方法
MyServletContextListener.java
具体内容如下
package org.yuan.config;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;/*** <p>* Description: <br>* <p>* Author:jinshengyuan <br>* Datetime: 2020-06-16 15:25* </p>**/
@WebListener
public class MyServletContextListener implements ServletContextListener {private SocketService service;@Overridepublic void contextInitialized(ServletContextEvent sce) {service = new SocketService();service.initSocketServer();}@Overridepublic void contextDestroyed(ServletContextEvent sce) {service.closeServer();}
}
3. 编写页面进行调试
index.html
内容如下
<!--Lincense: Public Domain
--><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Sample of web_socket.js</title><!-- Include these three JS files: --><script type="text/javascript" src="/myjs/swfobject.js"></script><script type="text/javascript" src="/myjs/web_socket.js"></script><script type="text/javascript">// Set URL of your WebSocketMain.swf here:WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";// Set this to dump debug message from Flash to console.log:WEB_SOCKET_DEBUG = true;// Everything below is the same as using standard WebSocket.var ws;function init() {// Connect to Web Socket.// Change host/port here to your own Web Socket server.ws = new WebSocket("ws://localhost:2001/myChat");// Set event handlers.ws.onopen = function() {output("onopen");};ws.onmessage = function(e) {// e.data contains received string.output("onmessage: " + e.data);};ws.onclose = function() {output("onclose");};ws.onerror = function() {output("onerror");};}function onSubmit() {var input = document.getElementById("input");// You can send message to the Web Socket using ws.send.ws.send(input.value);output("send: " + input.value);input.value = "";input.focus();}function onCloseClick() {ws.close();}function output(str) {var log = document.getElementById("log");var escaped = str.replace(/&/, "&").replace(/</, "<").replace(/>/, ">").replace(/"/, """); // "log.innerHTML = escaped + "<br>" + log.innerHTML;}</script>
</head><body onload="init();"><form onsubmit="onSubmit(); return false;"><input type="text" id="input"><input type="submit" value="Send"><button onclick="onCloseClick(); return false;">close</button></form><div id="log"></div>
</body></html>
4. 启动应用进行测试
启动SpringBoot应用后,浏览器中输入地址进行测试:http://localhost:2001