1.WebSocket
平时开发的时候,对于一些平常的需求是不会使用基于WebSocket开发的需求。但是在一些特定场景,比如:主动推送,模拟聊天等等,因为WebSocket建立等实际上是一个长链接。
2.基于Java实现WebSocket的开发
代码方面很简单。
1.config配置
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
2.Server 的实现
基于注解的实现,
核心注解:
ServerEndpoint:标示一个websocket,两个参数设置:
value指定请求地址。
configurator:配置请求拦截类。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* socket推送消息(服务端)
*/
@ServerEndpoint(value = "/socket/websocket/{idno}", configurator = SocketServerConfigurator.class)
//@ServerEndpoint(value = "/socket/websocket/{idno}")
@Component
public class WebSocketServer {
private final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
private static int onlineCount = 0;
private static CopyOnWriteArrayList<WebSocketServer> webSockets = new CopyOnWriteArrayList<>();
private static ConcurrentMap<String, WebSocketServer> socketConcurrentHashMap = new ConcurrentHashMap<>();
private Session session;
private String idno;
//连接建立成功调用的方法
@OnOpen
public void onOpen(@PathParam("idno")String idno, Session session){
this.session = session;
this.idno = idno;
socketConcurrentHashMap.put(idno,this);
webSockets.add(this); //加入set中
addOnlineCount();
logger.info("有新连接加入!当前在线人数为" + getOnlineCount());
}
@OnClose
public void onClose(){
if (!idno.equals("")) {
socketConcurrentHashMap.remove(idno); //从set中删除
}
webSockets.remove(this);
subOnlineCount();
logger.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
@OnMessage
public void onMessage(String message, Session session){
logger.info("client message:"+message);
if(StringUtils.isEmpty(idno)){ //群发消息
sendAll(message);
}else{ //单独推送
if(message.equalsIgnoreCase("ping")){
heartCheck(message);
}else{
sendToUser(message);
}
}
}
private void sendAll(String message){
for (String userId:socketConcurrentHashMap.keySet()) {
try {
socketConcurrentHashMap.get(userId).sendMessage(message);
} catch (IOException e) {
logger.error("WebSocketServer|sendAll[error]:e={}",e.getMessage());
}
}
}
private void heartCheck(String message){
if(socketConcurrentHashMap.get(idno)!=null){
try {
socketConcurrentHashMap.get(idno).sendMessage(message);
} catch (IOException e) {
logger.error("WebSocketServer|heartCheck[error]:e={}",e.getMessage());
}
}
}
private void sendToUser(String message){
if(socketConcurrentHashMap.get(idno)!=null){
for (String userId:socketConcurrentHashMap.keySet()) {
if(userId.equals(this.idno)){
continue;
}
try {
socketConcurrentHashMap.get(userId).sendMessage(message);
} catch (IOException e) {
logger.error("WebSocketServer|sendToUser[error]:e={}",e.getMessage());
}
}
}
}
@OnError
public void onError(Session session, Throwable e){
// throwable.printStackTrace();
logger.error("WebSocketServer|onError[error]:e={}",e.getMessage());
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
}
3.client的实现
import com.alipay.api.java_websocket.client.WebSocketClient;
import com.alipay.api.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;
/**
* socket推送消息(客户端)
*/
public class SocketClient extends WebSocketClient {
private final static Logger logger = LoggerFactory.getLogger(SocketClient.class);
public SocketClient(URI serverUri) {
super(serverUri);
}
/**
* demo
* @param args
* @throws URISyntaxException
* @throws InterruptedException
*/
public static void main(String[] args) throws URISyntaxException, InterruptedException {
String url = "ws://127.0.0.1:8080/socket/websocket/1233435";
SocketClient client = new SocketClient(new URI(url));
client.connect();
Thread.sleep(5000);
System.out.println(client.isOpen());
client.send("哈哈哈哈");
client.close();
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
logger.info("SocketClient:------打开socket--------");
}
@Override
public void onMessage(String s) {
logger.info("SocketClient:-----接受服务端消息-----"+s);
}
@Override
public void onClose(int i, String s, boolean b) {
logger.info("SocketClient:----关闭socket链接");
}
@Override
public void onError(Exception e) {
logger.error("SocketClient|onError[error]:e={}",e.getMessage());
}
}
4.websocket鉴权配置类
package com.ythk.crm.socket;
import com.ythk.crm.config.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* websocketserver 鉴权
*/
@Slf4j
@Component
public class SocketServerConfigurator extends ServerEndpointConfig.Configurator {
private final Logger logger = LoggerFactory.getLogger(SocketServerConfigurator.class);
/**
* token鉴权认证
*
* @param originHeaderValue
* @return
*/
@Override
public boolean checkOrigin(String originHeaderValue) {
// 业务判断代码,可以判断一些请求参数时候合法
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
String whiteUser = Constant.SETTING_MAP.get("websocket_white_user");
try {
HttpServletRequest request = servletRequestAttributes.getRequest();
String url = request.getServletPath();
if (StringUtils.isBlank(url)) {
return false;
}
String phone = url.substring(url.lastIndexOf("/") + 1);
logger.info("SocketServerConfigurator|checkOrigin:phone=" + phone);
if (phones.contains(phone)) {
return super.checkOrigin(originHeaderValue);
} else {
return false;
}
} catch (Exception e) {
logger.error("SocketServerConfigurator|checkOrigin[ERROR]:e={}", e);
return false;
}
}
/**
* Modify the WebSocket handshake response
* 修改websocket 返回值
*
* @param sec
* @param request
* @param response
*/
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
}
}
以上就很简单的实现类一个websocket服务的创建和client请求demo,以供参考。