上次我们说了spring集成websocket,实现用websocket通讯
集成配置连接:http://www.jiajiajia.club/weblog/blog/artical/128
下面来模拟一次实现上传文件的进度条
原理:在上传文件之前,请求以下服务器,获取一个socketId(作用:用来标识本次连接,服务器端也是通过这个id找到对应的连接,然后给这个连接发送消息(进度)),此时socketId已经被保存在服务器的session中(作用:服务器发送消息的时候从session中获取socketId),客户端浏览器获取这个socketId以后,开始连接,连接时把获取的socketId当作参数带入,服务器会判断这个连接是否合法,或者是是否已经有这个id的连接,保证服务器发送消息的准确性。等websocket连接成功以后,就可以进行上传文件等操作,服务器端可以通过保存在session中的socketId向客户端浏览器发送数据。
1.首先对websocket处理器进行改进
package com.dzqc.dz.common.controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
/**
* websocket处理器
* @author LENOVO
*/
public class WebSocketHandler extends TextWebSocketHandler {
public static Map<String,WebSocketSession> map=new HashMap<String,WebSocketSession>();
private String id;
//连接建立后处理
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String id=(String) session.getAttributes().get("socketId");
this.id=id;
System.out.println(id+":建立链接");
if(!map.containsKey(id)) {
map.put(id, session);
}else {
session.close();
}
super.afterConnectionEstablished(session);
}
//抛出异常时处理
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if(session.isOpen()){
session.close();
if(map.containsKey(this.id)) {
map.remove(this.id);
}
}
}
//连接关闭后处理
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
try {
if(map.containsKey(this.id)) {
map.remove(this.id);
}
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//接收文本消息,并发送出去
@Override
protected void handleTextMessage(WebSocketSession session,TextMessage message) throws Exception {
return ;
}
public static boolean sendMessage(String id,String message) {
if(map.containsKey(id)) {
WebSocketSession session=map.get(id);
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}else {
return false;
}
}
/**
* 关闭指定连接
* @param socketId
* @return
*/
public static boolean closeSocket(String socketId) {
if(map.containsKey(socketId)) {
WebSocketSession w=map.get(socketId);
if(w.isOpen()) {
try {
w.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}else {
return false;
}
}else {
return false;
}
}
}
2.模拟获取socketId,以及发送数据的controller
package com.dzqc.dz.common.controller;
import java.util.UUID;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.dzqc.dz.common.util.MyAjaxResult;
@Controller
@RequestMapping("/test")
public class TestControllers {
/**
* 跳转页面
* @param session
* @param id
* @return
*/
@RequestMapping("/test")
public String test(HttpSession session,String id) {
return "index2";
}
/**
* 获取标识socketId
* @param session
* @return
*/
@RequestMapping("/socketId")
@ResponseBody
public MyAjaxResult yanz(HttpSession session) {
String uid=UUID.randomUUID().toString();
session.setAttribute("socketId",uid);
return MyAjaxResult.success(uid);
}
/**
* 模拟发送信息
* @param session
* @return
*/
@RequestMapping("/send")
@ResponseBody
public String test(HttpSession session) {
String socketId=(String) session.getAttribute("socketId");
try {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<100;i++){
boolean b=WebSocketHandler.sendMessage(socketId,i+"%");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
WebSocketHandler.closeSocket(socketId);
}
}).start();
} catch (Exception e) {
e.printStackTrace();
return "send error";
}
return "send success";
}
}
3.模拟进度条页面
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<div>
测试 websocket<br>
<button id="up">开始上传</button><br>
进度<span id="jindu">0%</span>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
var uid;
$("#up").click(function(){
//请求socketId
$.ajax({
url:'${path}/test/socketId',
dataType:'json',
type:'get',
success:function(res){
uid=res.msg;
//请求成功以后 与服务器建立 ws协议 连接
var ws;
if ('WebSocket' in window) {
ws = new WebSocket("ws://"+window.location.host+"${pageContext.request.contextPath}/socket.do?type="+uid);
} else {
ws = new SockJS("http://"+window.location.host+"${pageContext.request.contextPath}/socket/info?type="+uid);
}
ws.onopen = function (evnt) {
console.log("websocket连接成功");
send();
};
ws.onmessage = function (evnt) {
console.log("进度:"+evnt.data);
$("#jindu").html(evnt.data);
};
ws.onerror = function (evnt) {
send();
console.log("连接失败");
$("#jindu").html("100%");
};
ws.onclose = function (evnt) {
console.log("关闭连接");
$("#jindu").html("100%");
}
}
})
//发送数据
function send(){
$.ajax({
url:'${path}/test/send',
dataType:'json',
type:'get',
success:function(res){
console.log(res);
}
})
}
})
})
</script>
</body>
</html>
4.测试
开始之前

连接成功:上传中

上传完成:关闭连接

测试结束