这是我的项目,下载后用idea打开
https://github.com/yonggandeliuguang/websocket-test
选择pom.xml右键添加为maven工程
点击file->project Structure,添加jdk
唯一要改的地方就是socket.js下面的tomcat端口号,改为自己的。
运行
1.依赖:
<properties>
<spring.version>5.1.5.RELEASE</spring.version>
</properties>
<dependencies>
<!--SpringMVC依赖包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--ServletAPI依赖包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!--webSocket依赖-->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
<!--JSON依赖包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
</dependencies>
2.web.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<!-- 项目名,改为自己的 -->
<display-name>websocket-demo</display-name>
<!-- 编码过滤器 -->
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--//End 编码过滤器 -->
<!-- SpringMVC -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定SpringMVC核心配置文件的位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<!--启动加载优先级-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.shtml</url-pattern>
</servlet-mapping>
<!-- //End SpringMVC -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
3.springmvc.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!-- 包扫描,写自己的包 -->
<context:component-scan base-package="com.demo"/>
<!--注解驱动-->
<mvc:annotation-driven/>
</beans>
4.websocket后端配置:
package com.demo.websocket.controller;
import org.springframework.stereotype.Controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
//该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。
@ServerEndpoint(value = "/websocket/{id}")
@Controller
public class WebSocketController {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
public WebSocketController() {
}
// 若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
private static Map<String,Session> sessionMap = new HashMap<String,Session>();
/**
* 连接建立成功调用的方法
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(Session session, @PathParam("id") String id){
sessionMap.put(id,session); //加入map中
addOnlineCount(); //在线数加1
System.out.println("有新连接加入!id为"+id+",当前在线人数为" + getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("id")String id){
sessionMap.remove(id); //从map中删除
subOnlineCount(); //在线数减1
System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
* @param session 可选的参数
* @param id 用户id标识
*/
@OnMessage
public void onMessage(String message, Session session,@PathParam("id")String id) {
System.out.println("来自客户端"+id+"的消息:" + message);
}
/**
* 发生错误时调用
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
System.out.println("发生错误");
error.printStackTrace();
}
/**
* 向客户端发送消息
* @param message 要发送的消息
* @param id 用户id标识
* @throws IOException
*/
public void sendMessage(String id,String message) throws IOException{
Session session = sessionMap.get(id); //获得当前用户的session
session.getBasicRemote().sendText(message);
//this.session.getAsyncRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketController.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketController.onlineCount--;
}
}
5.controller配置,用于调用服务端向客户端发送消息
package com.demo.websocket.controller;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private WebSocketController webSocketController;
/**
* 调用服务端向客户端发送消息
* @param id 用户id标识
* @return
*/
@RequestMapping("/message")
public String sendMessage(String id) throws IOException {
String message = id+"调用服务端向客户端发送消息成功!";
webSocketController.sendMessage(id,message);
return "success";
}
/**
* 调用服务端向客户端发送json数据
* @param id 用户id标识
* @return
*/
@RequestMapping("/json")
public String sendJson(String id) throws IOException {
Map<String,String> map = new HashMap<String,String>();
map.put("name","张三");
map.put("age","22");
String json = JSON.toJSONString(map);
webSocketController.sendMessage(id,json);
return "success";
}
}
6.前端配置,使用vue完成,所以必须先把vue.js和axios.js导入项目,如图
然后创建一个js,比如我起的名字是socket.js,然后配置如下:
let ws = {}
let app = new Vue({
el:'#app',
data:{
id:'', //用户id
message:'', //向服务器发送的消息
},
methods:{
//创建webSocket连接
createSession(){
//生成随机id,模拟用户唯一id
this.id=Math.floor(Math.random()*100000+1000)
if ("WebSocket" in window) {
// alert("您的浏览器支持 WebSocket!");
// 打开一个 web socket
ws = new WebSocket("ws://localhost:28087/websocket/"+this.id);
ws.onopen = function () {
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send("发送数据");
alert("数据发送中...");
};
ws.onmessage = function (evt) {
//获取服务端发来的消息
alert(evt.data)
};
ws.onclose = function () {
// 关闭 websocket
alert("连接已关闭...");
};
}
else {
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
},
//调用服务端向客户端发送消息
recallMessage(){
axios.post('/demo/message.shtml?id='+this.id).then(function (response) {
console.log(response.data)
})
},
//调用服务端向客户端发送json对象
recallJson(){
axios.post('/demo/json.shtml?id='+this.id).then(function (response) {
console.log(response.data)
})
},
//向客户端发送消息
sendMessage(){
ws.send(app.message)
}
},
created(){
//初始化建立socket连接
this.createSession();
}
})
7.html配置如下,为H5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/js/vuejs-2.5.16.js"></script>
<script src="/js/axios-0.18.0.js"></script>
</head>
<body>
<div id="app">
<button @click="recallMessage()">调用服务端向客户端发消息</button><br>
<button @click="recallJson()">调用服务端向客户端发JSON对象</button>
<hr/>
请输入要发送的消息:<input type="text" v-model="message"><br>
<button @click="sendMessage()">向服务端发送消息</button>
</div>
<script src="/js/socket.js"></script>
</body>
</html>
总结,那个发送json其实就是把对象转换为字符串发送,前端接到的只是json格式的字符串,可以通过一下方法转换为json对象
//可以在ws.onmessage中转换
let json = JSON.parse(evt.data)