关于WebSocket的使用,之前有介绍在SpringMVC中的使用方法,最近项目需要在SpringBoot中使用WebSocket,使用方法大同小异,在配置项方面有些许差别,特此记录。
环境:
SpringBoot 2.0.3.RELEASE
JDK 1.8
首先在pom.xml文件中引入相关依赖:
org.springframework.boot
spring-boot-starter-websocket
其次需要手动注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。这是与SpringMVC中的用法不同的一点。
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WS的具体代码和springmvc就没什么差别了,这里放了一段常规的聊天室代码作为例子:
@Component
@ServerEndpoint(value ="/webChat/{userId}")
public class WebSocketChat {
private Logger logger = LoggerFactory.getLogger(WebSocketChat.class);
//此处是解决无法注入的关键
private static ApplicationContext applicationContext;
//要注入的service或者dao
private TestService testService;
public static void setApplicationContext(ApplicationContext applicationContext) {
WebSocketChat.applicationContext = applicationContext;
}
/**
* 在线人数
*/
public static int onlineNumber = 0;
/**
* 以用户的姓名为key,WebSocketChat类为value保存起来
*/
private static Map clients = new ConcurrentHashMap();
/**
* 会话
*/
private Session session;
/**
* 用户名称
*/
private String userId;
/**
* 建立连接
*
* @param session
*/
@OnOpen
public void onOpen(@PathParam("userId") String userId, Session session)
{
onlineNumber++;
logger.info("现在来连接的客户id:"+session.getId()+"用户名:"+userId);
this.userId = userId;
this.session = session;
//设置能接收的消息体字节大小()
session.setMaxTextMessageBufferSize(104857600);//100M
logger.info("有新连接加入! 当前在线人数" + onlineNumber);
clients.put(userId, this);
}
@OnError
public void onError(Session session, Throwable error) {
logger.info("连接发生错误");
error.printStackTrace();
}
/**
* 连接关闭
*/
@OnClose
public void onClose(){
onlineNumber--;
clients.remove(userId);
logger.info("有连接关闭! 当前在线人数" + onlineNumber);
}
/**
* 收到客户端的消息
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session) throws IOException {
logger.info("message length=="+message.length());
JSONObject jsonObject = JSON.parseObject(message);
try {
// logger.info("来自客户端消息:" + message+"客户端的id是:"+session.getId());
//消息类型
String messageType = jsonObject.getString("messageType");
String messageText = jsonObject.getString("messageText");
String fromusername = jsonObject.getString("sendId");
String tousername = jsonObject.getString("receiveId");
//messageType 1(文字)/2(图片)/3(语音)/4(视频)/5(文件)
testService = applicationContext.getBean(TestService.class);
long MS = System.currentTimeMillis();//获取当前时间(精确到毫秒)
String timeMS = String.valueOf(MS);
if(messageType.equals("1")){
testService.saveMsg(fromusername,tousername,messageType,messageText,timeMS);
}else{
testService.saveFile(fromusername,tousername,messageType,messageText,timeMS);
}
Map map4 = new HashMap<>();
int voiceDuration =0;
if(messageType.equals("3") || messageType.equals("4")){
voiceDuration=jsonObject.getInteger("voiceDuration");
map4.put("voiceDuration",voiceDuration);
}
map4.put("status",0);
map4.put("messageText",messageText);
map4.put("messageType",messageType);
logger.info("map4Info==="+map4);
if(tousername.equals("All")){//发送给所有人
map4.put("tousername","所有人");
sendMessageAll(JSON.toJSONString(map4),fromusername);
}else{//指定发送给某人
// map4.put("tousername",tousername);
sendMessageTo(JSON.toJSONString(map4),tousername);
}
}
catch (Exception e){
String tousername = jsonObject.getString("receiveId");
Map map4 = new HashMap<>();
map4.put("status",1);
map4.put("textMessage","发送失败!");
sendMessageTo(JSON.toJSONString(map4),tousername);
e.printStackTrace();
logger.info("WebSocketChat发生了错误了");
}
}
public void sendMessageTo(String message, String ToUserName) throws IOException {
for (WebSocketChat item : clients.values()) {
if (item.userId.equals(ToUserName) ) {
if(item.session.isOpen()){
item.session.getBasicRemote().sendText(message);
break;
}
}
}
}
public void sendMessageAll(String message,String meName) throws IOException {
for (WebSocketChat item : clients.values()) {
if(!item.userId.equals(meName)){
if(item.session.isOpen()){
item.session.getBasicRemote().sendText(message);
}
}
}
}
public static synchronized int getOnlineCount() {
return onlineNumber;
}
}
开头的 TestService 是自定义的一个用于操作数据库的类,由于websocket中是不能通过 @Autowired标签注入资源的,所以必须通过ApplicationContext获取bean。首先需要在启动类的main方法中将websocket类加入容器上下文。
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(ChatApplication.class);
ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
//解决WebSocket不能注入的问题
WebSocketChat.setApplicationContext(configurableApplicationContext);
}
然后就像上述代码所示在WebSocketChat类中开头加入如下代码即可获取到要注入的TestService 。
//此处是解决无法注入的关键
private static ApplicationContext applicationContext;
//要注入的service或者dao
private TestService testService;
public static void setApplicationContext(ApplicationContext applicationContext) {
WebSocketChat.applicationContext = applicationContext;
}
testService = applicationContext.getBean(TestService.class);