前提
1、tocmat7.02版本以上
2、浏览器支持websocket通讯
3、这个是html5的功能
1、浏览器和后台服务器要通信,首先是url
通俗易懂的格式如下 "ws://localhost:8080/项目名/请求名"
如果要携带参数的话, "ws://localhost:8080/项目名/请求名/"+参数
var target = "ws://"+window.location.host+"/LawerSys/websocket"+"/"+username;
2、与后台服务器建立连接
var socket = new WebSocket(target);
1、新建一个普通的类,在这个类上面加上@ServerEndpoint("/请求名");
这个"/请求名"与html中 "ws://localhost:8080/项目名/请求名" 请求名一致;
html页面与后台之所以可以建立的连接,就是根据@ServerEndpoint来识别websocket通讯类,根据("/请求名")和前台的请求相匹配的对应的类;
2、new 一个方法,来和前台建立连接,
websocket通讯,浏览器和服务器只会建立一次连接,因此,我们需要在建立连接握手的时候,把这个会话存储到集合里面
1、一般是用map集合,因为key是不能重复的
2、如果是List集合的话,无法区分是自己发的信息还是别人发的信息
3、集合存在意义,就是实现循环遍历转发给连接服务器的客户端浏览器页面
但是我不能说open()这个方法是建立连接的它就连接的,需要标识@Onopen
注意:value可以是java类的类型
注意要有static关键字,如果没有这个关键字,添加集合的长度一直都是1;
原因是两个浏览器访问后台服务器,然后虽然执行了添加操作,但是执行结束,这个集合就销毁了,动态分配内存,所以需要static关键字;
value也可以是Session,我试过这两个,都没有问题
1、由于jsp请求是基于http请求,无状态的,就是独立的线程,两个jsp是没有任何关系的;sesion的作用就是标识,给这个jsp页面做唯一标识;
2、把session会话存储到map集合里面(两个人聊天),如果是多人聊就是CopyOnWriteArraySet集合;目的是转发信息
在open方法里面,添加会话,username是唯一标识符,这个符号是区分浏览器的,一个浏览器一个标识符
现在浏览器和服务器可以建立连接了,当然你现在测试肯定有问题,启动都会报错,因为其他的方法没有
在java后台添加关闭和错误的方法
@OnClose
public void close(){
System.out.println("关闭");
}
@OnError
public void error(Throwable t) {
// 添加处理错误的操作
System.out.println("发生错误");
t.printStackTrace();
}
1、有一个文本框一个按钮,点击按钮实现发送消息
咨询页面
2、js代码(点击按钮触发事件,最主要的是socket.send()方法,这个是websocket的发送消息的方法)
//1.只有点击按钮以后,才可以发送消息
document.getElementById("sendmes").onclick = function(){
var mess=$("#mess").val();
if(mess!=null&&mess!=""){
socket.send("消息内容:"+mess);
}else{
alert("发送的消息或用户名不能为空");
}
}
//1.只有点击按钮以后,才可以发送消息
3、接收来自客户端的信息,然后把消息显示在框里面
接收客户端 socket.onmessage=function(evt){}就是接受服务器发送的信息
socket.onmessage=function(evt){
var s=evt.data;
//把数据显示在文本框里面
var cs=$("#content").val();
$("#content").val(cs+s);
}
1、一个无返回值的方法 注解@OnMessaage 代表服务器一旦接收消息,就触发这个方法
2、循环遍历连接服务器的客户端们,判断这个会话是来是这个请求自己发的,还是其他请求发的,目的在于在浏览器上面显示在左边还是右边;
3、this.session.getAsyncRemote().sendText()是异步发送消息,非阻塞的
以下这个代码只是服务器转发给客户端,没有区分是本身还是他人
@OnMessage
public void getMessage(String str, Session session) {
for (String s : map.keySet()) {
System.out.println("this:"+this+"客户端的信息:" + str);
// 服务器把信息分为是自己的还是其他人发的,再加上时间,然后群发到连接的用户session会话里面
String time = sim.format(new Date());
String info = str + "时间:" + time;
// 会话异步发送消息
map.get(s).session.getAsyncRemote().sendText(info);
}
}
1、用了富文本编辑器https://blog.csdn.net/qq_37591637/article/details/89378284
2、websocket网页技术
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
即时群聊
律师平台
java代码
package cn.com.socket;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
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 net.sf.json.JSONObject;
@ServerEndpoint("/websocket/{userId}")
public class ServerSocket {
// 日期格式化
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
private static Map webSocketSet = new ConcurrentHashMap();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String userId;
@OnOpen
public void open(@PathParam("userId")String userIds,Session session) {
// 添加初始化操作
System.out.println("---初始化----userId:"+userIds);
this.session = session;
//获取当前登录用户的id
this.userId = userIds;
webSocketSet.put(userIds,this); //加入set中
System.out.println("有新连接加入!当前在线人数为" +webSocketSet.size());
}
@OnMessage
public void getMessage(String message, Session session1) {
// 把客户端的消息解析为JSON对象
JSONObject jsonObject = JSONObject.fromObject(message);
// 在消息中添加发送日期
jsonObject.put("date", DATE_FORMAT.format(new Date()));
// -----------------------把消息发送给所有连接的会话--------------------------------
System.out.println("来自客户端的消息"+this.userId+":" + message);
Set str=webSocketSet.keySet();
for(String item: str){
try {
//当前用户右侧显示,非本用户左侧显示
if(this.userId.equals( webSocketSet.get(item).userId)){jsonObject.put("isSelf", true);}
else{jsonObject.put("isSelf", false);}
// 发送JSON格式的消息
webSocketSet.get(item).sendMessage(jsonObject.toString());
} catch (IOException e) {
e.printStackTrace();
continue;
}
}
}
@OnClose
public void close() {
// 添加关闭会话时的操作
webSocketSet.remove(this); //从set中删除
}
@OnError
public void error(Throwable t) {
// 添加处理错误的操作
System.out.println("发生错误");
t.printStackTrace();
}
public synchronized void sendMessage(String message) throws IOException{
this.session.getAsyncRemote().sendText(message);//非阻塞式的
}
}
html代码不需要改的
package cn.com.socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
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.ServerEndpoint;
@ServerEndpoint("/serverSocket")
public class MySocket {
// 时间
private SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 一个线程集合存储session线程会话
private Map map = new ConcurrentHashMap();
private Session session;
@OnOpen
public void open(Session session) {
// 把当前的session存储起来,以便后来的时候服务器转发数据
this.session = session;
System.out.println(+map.size());
map.put(this,"");
}
@OnClose
public void close() {
System.out.println("关闭连接");
}
@OnMessage
public void getMessage(String str, Session session) {
for (MySocket s : map.keySet()) {
System.out.println("this:"+this+"客户端的信息:" + str);
// 服务器把信息分为是自己的还是其他人发的,再加上时间,然后群发到连接的用户session会话里面
String time = sim.format(new Date());
String info = str + "时间:" + time;
// 会话异步发送消息
s.session.getAsyncRemote().sendText(info);
}
}
@OnError
public void error(Throwable t) {
// 添加错误操作
}
}