springboot整合websocket(一)简单聊天室
springboot整合websocket(二)上传文件(引导篇)
springboot整合websocket(三)上传文件(终篇)
1、回顾一下接上一章,这次我们把文件上传的坑给填了。
不过之前的内容我就没有保留,因为上传文件和发消息在一起,需要一些其他操作,我会在末尾说明一下,也不难。
上次提到有一个方法:
void onMessage(Session session, byte[] message);
这个是用来上传文件用的,先解释一下 byte[] 这个参数。
好吧~ 大家猜的没错,这个就是我们文件的二进制流。
所以说,我们要干两件事:
第一,我们js要获得文件,并转成二进制流发过来
第二,在上传之前,我们需要知道文件的名字,因为这个二进制流是一个数组,没法知道文件的名字!(实测,js不能修改这个二进制流哦)
说一下重点
1、在onMessage(string)中用session.getUserProperties()将文件名存起来,并删除已有的文件(因为要追加到文件末尾)
2、在onMessage(byte[])中保存文件,至于我那里为什么要追加,在后面会说(透露一点,文件要切分上传,所以要追加)
3、在onClose中将关闭原因打印一下(埋个雷,一会要用)
@Log4j2
@Controller
@ServerEndpoint("/websocket")
public class baseWebsocketController
{
//使用 ConcurrentHashMap, 保证线程安全, static全局共享 session
//这里之所以static,是因为这个类不是单例的!!
//他虽然有@Controller注解,但是不适用Ioc容器中拿对象,每一次请求过来都是一个新的对象
//存放 session
private final static Map sessions = new ConcurrentHashMap<>();
//onopen 在连接创建(用户进入聊天室)时触发
@OnOpen
public void openSession(Session session, EndpointConfig config)
{
//将session存起来, 用于服务器向浏览器发送消息
sessions.put(session.getId(), session);
sendAll("[" + session.getId() + "]进入房间");
}
//响应字符串
@OnMessage
public void onMessage(Session session, String message)
{
// session.getUserProperties() 是一个 Map, 用于存放数据
session.getUserProperties().put("filename", message);
//这里处理一下, 如果有该文件, 就先删除
File file = new File(getProjectRootPath(), message);
if (file.exists()) {
file.delete();
}
}
//响应字节流
@OnMessage
public void onMessage(Session session, byte[] message) throws Exception
{
// 1、先拿到文件名
final String filename = (String) session.getUserProperties().get("filename");
// 2、追加到该文件
File file = new File(getProjectRootPath(), filename);
//输出一下文件路径
System.out.println(file.getCanonicalPath());
try (OutputStream os = new FileOutputStream(file, true)) {
os.write(message, 0, message.length);
}
catch (IOException e) {
e.printStackTrace();
}
sendAll("[" + session.getId() + "]上传了一个文件[" + filename + "]");
}
//onclose 在连接断开(用户离开聊天室)时触发
@OnClose
public void closeSession(Session session, CloseReason closeReason)
{
//记得移除相对应的session
sessions.remove(session.getId());
//打印一下原因
System.out.println(closeReason.getReasonPhrase());
sendAll("[" + session.getId() + "]离开了房间");
}
@OnError
public void sessionError(Session session, Throwable throwable)
{
//通常有异常会关闭session
try {
session.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private void sendAll(String message)
{
for (Session s : sessions.values()) {
//获得session发送消息的对象
//Basic是同步, 会阻塞
//Async是异步, 这个会有多线程并发导致异常, 发送消息太快也会有并发异常, 需要有 消息队列 来辅助使用
final RemoteEndpoint.Basic remote = s.getBasicRemote();
try {
//发送消息
remote.sendText(message);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
private String getProjectRootPath()
{
try {
String path = ResourceUtils.getURL(ResourceUtils.CLASSPATH_URL_PREFIX).getPath();
path = URLDecoder.decode(path, "UTF-8");
final File file = new File(path, "static");
return file.getCanonicalPath();
}
catch (Exception e) {
e.printStackTrace();
return "";
}
}
}
3、页面
3.1 第一版傻白甜的页面
说一下重点
1、通过FileReader将文件读取成二进制流
let reader = new FileReader();
reader.readAsArrayBuffer(files[0]);
2、发送的时候一样用的是webSocket.send()
再看看效果
大家开心的上传文件,然后就会有这么一个问题websocket-demo
没有这个的童鞋,就选个大一点的文件
看一下后台的报错
(检查一下onClose是不是和我上面的一样,要打印一下关闭原因哦~)
No async message support and buffer too small. Buffer size: [8,192], Message size: [2,254,618]
这个意思是说-------->
文件:我有2,254,618B,我的很大,你忍一下
Websocket:不行,我只有8192B,太大了,忍不了,放不开
所以啊,我们要将文件切开,挨个上传,一次传一点,这篇有点长,我们下篇再说
End
springboot整合websocket(一)简单聊天室
springboot整合websocket(二)上传文件(引导篇)
springboot整合websocket(三)上传文件(终篇)



