最近,需要公司需要写一个app下单之后,后台要接收到提醒的功能,需要服务器向浏览器推送下单提醒通知。查了好多资料,中间也是遇到了一些坑,所以在这里记录一下。第一次写博客,有不对的地方,希望大牛指正。
一、要做的准备工作:
1.将项目放在tomcat里面
2.下载一个wepsockt-api的jar包
3.新建一个websocketController
4.新建一个indexConter和一个test页面(这里因为涉及到 公司的私密,所以暂时搞了个test页面)
二、wepsockt-api.jar包下载
下载地址:https://download.csdn.net/download/zixing2000/10317413
三.websocketContrller代码
package com.mult.work.websocket;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
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;
import com.jfinal.kit.Kv;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
@ServerEndpoint("/websocket.ws/{ids}")
public class WebSocketController {
public static final WebSocketController me = new WebSocketController();
//用来存放每个客户端对应的MyWebSocket对象。
private static final Map<String, WebSocketController> WEB_SOCKET_MAP = new ConcurrentHashMap<String, WebSocketController>();
private static final Map<String, Kv> WEB_KV = new ConcurrentHashMap<String, Kv>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//UUID 生成的IDS
private String ids;
//name 昵称
private String name;
/**
* 连接建立成功调用的方法
* @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
@OnOpen
public void onOpen(@PathParam("ids")String ids,Session session){
this.ids = ids;
this.session = session;
WEB_SOCKET_MAP.put(ids, this);
this.name = getKvByIds(ids).getStr("name");
System.out.println("session=" + session.getId());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(){
WEB_SOCKET_MAP.remove(this.session);
System.out.println("有一连接关闭!当前在线人数为" + WEB_SOCKET_MAP.size());
System.out.println("session=" + session.getId());
sendMessage(this.name);
}
/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息
* @param session 可选的参数
*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("来自客户端的消息:" + message);
System.out.println("session=" + session.getId());
sendMessage(message);
}
/**
* 发生错误时调用
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
error.printStackTrace();
}
/**
* 指定 发送消息
*/
public void sendMessage(String ids, String message){
WebSocketController me = WEB_SOCKET_MAP.get(ids);
if (me != null) {
me.sendMessage(message);
}
// else{
// this.sendMessage("【系统消息】" + getNameByIds(ids) + " 不在线");
// }
}
/**
* 向客户端 发送消息
*/
protected void sendMessage(String message){
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
//this.session.getAsyncRemote().sendText(message);
}
public static Kv getKvByIds(String ids){
Kv kv = WEB_KV.get(ids);
if (kv == null) {
WEB_KV.put(ids, new Kv());
return getKvByIds(ids);
}
return kv;
}
public static String getNameByIds(String ids){
return getKvByIds(ids).getStr("name");
}
public static String setNameByIds(String ids, String name){
if (StrKit.isBlank(name)) {
name = "匿名用户";
}
Kv kv = getKvByIds(ids);
if ( ! name.equals(kv.get("name"))) {
kv.set("name", name);
// 同步成员变量
WebSocketController me = WEB_SOCKET_MAP.get(ids);
if (me != null) {
me.name = name;
}
}
return name;
}
}
@ServerEndpoint("/websocket.ws/{ids}")因为这里没有在config里面配置,所以要在路由这里加上一个.ws的后缀,不然的话会报404的错
四、indexController文件代码段
package com.mult.work.websocket;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.mult.common.annotation.Controller;
import com.mult.common.controller.WorkController;
/**
* 总控制器
* @author dufuzhong
*
*/
@Controller(controllerKey = "/websocket/index")
public class IndexController extends WorkController {
/***
* 设置昵称
*/
public void getwebsocket(){
String host = getPara("host");
String name = getPara("name");
String ids = getPara("ids");
if (StrKit.isBlank(ids)) {
ids = StrKit.getRandomUUID();
setCookie("websocket_ids", ids, (3 * 365 * 24 * 60 * 60), true);
}
name = WebSocketController.setNameByIds(ids, name);
setCookie("websocket_name", encode(name), (3 * 365 * 24 * 60 * 60), true);
renderJson(Ret.ok("url", "ws://" + host + "/websocket.ws/" + ids));
}
private String encode(String name){
if (StrKit.notBlank(name)) {
try {
return URLEncoder.encode(name, "utf-8");
} catch (UnsupportedEncodingException e) {}
}
return null;
}
private String decode(String name){
if (StrKit.notBlank(name)) {
try {
return URLDecoder.decode(name, "utf-8");
} catch (UnsupportedEncodingException e) {}
}
return null;
}
}
五、test页面代码段
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- for HTML5 -->
<title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
Welcome
<br />
<input id="text" type="text" />
<button onclick="send()">发送消息</button>
<hr />
<button onclick="closeWebSocket()">关闭WebSocket连接</button>
<hr />
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null; //判断当前浏览器是否支持WebSocket
var name = $("#name").val();
var host = window.location.host;//+window.location.pathname;
$.getJSON("/websocket/index/getwebsocket", { "name": name, "host": host,"ids":88 }, function(ret){
if(ret.state == "ok") {
newWebSocket(ret.url);
}else{
alert('抱歉,失败')
}
});
function newWebSocket(url){
if ('WebSocket' in window) {
websocket = new WebSocket(url);
} else {
alert('请使用火狐或谷歌浏览器')
return;
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("离线");
}
//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("上线");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("下线");
}
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
六、总结
1.公司服务器用的是tomcat和nginx反代理,所以在配置的时候要注意下配置nginx的配置。
参考这个连接:https://www.cnblogs.com/lxwphp/p/8206269.html
2.websocket-api.jar包在服务器环境中可以不要,但是在开发环境中需要,不然的话会报错的。