流程:
(群发图片)
1.前台获取并连接websocket服务器,上传图片,将流、图片流通过websocket发送至服务器。
2.后台搭建websocket服务器,以及消息处理服务,将接收到的图片流转发给所有在线客户端。
3.客户端收到服务器转发的图片流,动态添加img标签,将图片在页面上展示。
效果:
1.未发图片时图片列表为空
2.发送图片,在线的客户端都会收到图片消息。
实现过程:
1.前台代码:
(1)html代码
<!--发送图片按钮-->
<form name="form1">
<input type="file" name="picpath" id="choose-img" style="display:none;" onChange="setImagePreview()">
<input name="path" style="display:none;" readonly>
<input type="button" value="发送照片" onclick="document.form1.picpath.click()">
</form>
<!--收到的图片列表-->
<div id="show"><h3>图片列表:</h3></div>
(2)js代码(收到服务端的图片流后动态添加img标签,将图片显示在页面上)
//获取并建立websocket连接
get("/getWebSocketUrlImg")
.then((data) => {
if (!websocketImg) {
websocketImg = new WebSocket(data.url);
log("websocket连接成功Image服务器")
}
websocketImg.onopen = () => {
log("open")
};
websocketImg.onclose = () => {
log("Connection closed.");
};
websocketImg.onerror = () => {
log("websocket error");
};
//收到消息后动态添加img标签,显示在页面上
websocketImg.onmessage = function(event){
var reader = new FileReader();
reader.onload=function(eve){
if(eve.target.readyState==FileReader.DONE)
{
var img = document.createElement("img");
img.src=this.result;
img.height=300;
img.width=500;
document.getElementById("show").appendChild(img);
}
};
reader.readAsDataURL(event.data);
};
});
//上传按钮触发的方法
function setImagePreview() {
var file = document.getElementById('choose-img').files[0];
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function(e) {
var rawData = e.target.result;
// websocketImg.send(rawData);
websocketImg.send(rawData);
};
// websocketImg.send("asdasdadsadasdasda");
}
//get请求封装
//get 请求
const get = (url,params) => {
if (params) {
let paramsArray = [];
//拼接参数
Object.keys(params).forEach(key =>
paramsArray.push(key + '=' + encodeURI(params[key].toString())));
if (paramsArray.length > 0) {
if (url.search(/\?/) === -1) {
url += '?' + paramsArray.join('&');
} else {
url += '&' + paramsArray.join('&');
}
}
}
return new Promise((resolve, reject) => {
fetch(url)
.then(res => res.json())
.then(data => resolve(data))
.catch(err => reject(err));
});
};
2.后端代码
(1)get请求地址,返回链接
@GetMapping("/getWebSocketUrlImg")
public Map<String, String> getIpAddressImg(HttpServletRequest request) {
Map<String, String> result = new HashMap<>(1);
if(IP_CODE.equals(request.getRemoteAddr())){
//本地访问
result.put("url", "wss:"+request.getRemoteAddr()+":"+port+ "/sendImage");
}else{
//服务IP访问
result.put("url", "wss:" + "192.168.1.178" +":"+port+ "/sendImage");
}
return result;
}
(2)websocket图片服务器
@ServerEndpoint(value = "/sendImage", configurator = ConfiguratorForClientIp.class)
@Component
@Slf4j
public class ImgMessage{
/**
* 在线总人数
*/
private static volatile AtomicInteger onlineCount = new AtomicInteger(0);
private static RoomService roomService;
private static MessageService messageService;
@Autowired
public void setRoomService(RoomService roomService) {
ImgMessage.roomService = roomService;
}
@Autowired
public void setMessageService(MessageService messageService) {
ImgMessage.messageService = messageService;
}
/**
* 某个客户端的ip
*/
private String ip;
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
@OnMessage(maxMessageSize = 5000000)
public void getMessage(Session session , byte[] stringMessage) throws IOException {
messageService.sendImgMessageForEveryInRoom(stringMessage);
}
@OnOpen
public void start(Session session){
this.session = session;
ip = (String) session.getUserProperties().get("clientIp");
//将本次连接放到大厅里面
roomService.enterLobbyImg(this);
log.info("用户: {}, 连接到服务器,当前在线人数为:{}", ip, onlineCount.incrementAndGet());
}
}
(3)房间处理服务(只有大厅,可以按照自己的逻辑扩展业务,添加多个房间)
@Service
public class RoomService {
private Map<String, Set<ImgMessage>> roomsImg = new ConcurrentHashMap<>();
/**
* 加入到大厅
*/
public void enterLobbyImg(ImgMessage connection) {
Set<ImgMessage> lobby = roomsImg.get("lobby");
if (lobby == null) {
roomsImg.put("lobby", new HashSet<>());
lobby = roomsImg.get("lobby");
lobby.add(connection);
} else {
lobby.add(connection);
}
}
/**
* 离开大厅
*/
public void leaveLobby(Connection connection) {
Set<Connection> lobby = rooms.get("lobby");
lobby.remove(connection);
}
}
(4)消息处理服务(只有图片处理方法,可以根据自己需求处理其他消息,例如文本,文件等)
/**
* 消息处理服务
*/
@Slf4j
@Service
public class MessageService {
@Autowired
private RoomService roomService;
/**
* 给房间内的所有人发送图片(包括自己)
*/
public void sendImgMessageForEveryInRoom(byte[] message) throws IOException {
Set<ImgMessage> room = roomService.queryRoomByIdImg("lobby");
room.stream().forEach(t->{
try {
t.getSession().getBasicRemote().sendBinary(ByteBuffer.wrap(message));
} catch (IOException e) {
}
});
}
}