java+websocket实现网页聊天室

核心技术websocket

前提

1、tocmat7.02版本以上

2、浏览器支持websocket通讯

3、这个是html5的功能


客户端和服务器建立连接

jsp/html页面

1、浏览器和后台服务器要通信,首先是url

通俗易懂的格式如下    "ws://localhost:8080/项目名/请求名"   

如果要携带参数的话, "ws://localhost:8080/项目名/请求名/"+参数 

 var target = "ws://"+window.location.host+"/LawerSys/websocket"+"/"+username;

2、与后台服务器建立连接
  var socket = new WebSocket(target);

Java后台部分

1、新建一个普通的类,在这个类上面加上@ServerEndpoint("/请求名");

这个"/请求名"与html中 "ws://localhost:8080/项目名/请求名"    请求名一致;

html页面与后台之所以可以建立的连接,就是根据@ServerEndpoint来识别websocket通讯类,根据("/请求名")和前台的请求相匹配的对应的类;

java+websocket实现网页聊天室_第1张图片

2、new 一个方法,来和前台建立连接,

java+websocket实现网页聊天室_第2张图片

 websocket通讯,浏览器和服务器只会建立一次连接,因此,我们需要在建立连接握手的时候,把这个会话存储到集合里面

 1、一般是用map集合,因为key是不能重复的

2、如果是List集合的话,无法区分是自己发的信息还是别人发的信息

3、集合存在意义,就是实现循环遍历转发给连接服务器的客户端浏览器页面

 但是我不能说open()这个方法是建立连接的它就连接的,需要标识@Onopen

java+websocket实现网页聊天室_第3张图片
 

注意:value可以是java类的类型

注意要有static关键字,如果没有这个关键字,添加集合的长度一直都是1;

原因是两个浏览器访问后台服务器,然后虽然执行了添加操作,但是执行结束,这个集合就销毁了,动态分配内存,所以需要static关键字;

 value也可以是Session,我试过这两个,都没有问题

 

 1、由于jsp请求是基于http请求,无状态的,就是独立的线程,两个jsp是没有任何关系的;sesion的作用就是标识,给这个jsp页面做唯一标识;

2、把session会话存储到map集合里面(两个人聊天),如果是多人聊就是CopyOnWriteArraySet集合;目的是转发信息

在open方法里面,添加会话,username是唯一标识符,这个符号是区分浏览器的,一个浏览器一个标识符

java+websocket实现网页聊天室_第4张图片

现在浏览器和服务器可以建立连接了,当然你现在测试肯定有问题,启动都会报错,因为其他的方法没有 

 在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) {
    		// 添加错误操作
    	}
    
    }
    

    你可能感兴趣的:(socket通讯专栏)