JAVA前后端实现WebSocket消息推送(针对性推送)

1、需要添加依赖包,在pom.xml文件中添加

javax javaee-api 7.0 provided

2、客户端代码
在这里我为了做成httpsession登录后是同一个,所以我做成两个页面,一个登录跳转页面,一个用于链接WebSocket接收消息

a.登录页面

<head>
	<meta charset="UTF-8">
	<title>WebSocket</title>
	<script src="js/jquery-1.8.3.min.js"></script>
	<script type="text/javascript">
		function dl() {
			$.ajax({
				xhrFields: {  
                    withCredentials: true  
                }, 
				type:"get",
				url:"http://localhost:8080/cloudmgr/api/login?user=ppp",
			});
		}
	</script>
</head>

<body>
	<input type="button" value="登录" onclick="dl()" />
	<a href="login.html">tiaozhuan</a>
</body>

b.接收消息推送页面

<head>
	<meta charset="UTF-8">
	<title>WebSocket</title>
	<script src="js/jquery-1.8.3.min.js"></script>
	<script type="text/javascript">
		var ws = null;
		//判断当前浏览器是否支持WebSocket
		if('WebSocket' in window) {
			ws = new WebSocket("ws://localhost:8080/cloudmgr/chat");
		} else {
			alert('当前浏览器 Not support websocket')
		}
		/*
		 *监听三种状态的变化js会回调
		 */
		ws.onopen = function(message) {
			// 连接回调
		};
		ws.onclose = function(message) {
			// 断开连接回调
		};
		ws.onmessage = function(message) {
			// 消息监听
			showMessage(message.data);
		};
		//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
		window.onbeforeunload = function() {
			ws.close();
		};
		//关闭连接
		function closeWebSocket() {
			ws.close();
		}
		//发送消息
		function send() {

			var input = document.getElementById("msg");
			var text = input.value;

			// 消息体JSON 对象 对应JAVA 的 Msg对象
			var data = {
				// 定点发送给其他用户的userId
				toUid: "3d535429-5fcb-4490-bcf7-96fd84bb17b6",
				data: text
			}

			ws.send(JSON.stringify(data));
			input.value = "";
		}

		function showMessage(message) {
			/*var text = document.createTextNode(JSON.parse(message).data);
			var br = document.createElement("br")
			var div = document.getElementById("showChatMessage");
			div.appendChild(text);
			div.appendChild(br);*/
			var text = document.createTextNode(message);
			document.getElementById("showText").appendChild(text);
			
		}
	</script>
</head>

<body>
	<div>
		<style="width: 600px; height: 240px; overflow-y: auto; border: 1px solid #333;" id="show">
			<div id="showChatMessage"></div>
			<div id="showText"/>
			<input type="text" size="80" id="msg" name="msg" placeholder="输入聊天内容" />
			<input type="button" value="发送" id="sendBn" name="sendBn" onclick="send()">
	</div>
</body>

3、关于后端代码这边事由4个文件

一个通用msg文件、一个用于获取当前会话的httpsession、一个用监听有没有httpsession(没有则创建)、一个用于WebSocket链接和发送消息

a.通用msg文件

package com.boli.srcoin.websocket;

import java.util.Date;

/**

  • @author : admin

  • @DESC :

    WebSocket消息模型


    */
    public class Msg {

    // 推送人ID
    private String fromUid;

    // 定点推送人ID
    private String toUid;

    // 定点推送单位ID
    private String toOrgId;

    // 消息体
    private String data;

    // 推送时间
    private Date createDate = new Date();

    // 消息状态
    private Integer flag;

    public Msg() {

    }

    public Msg(String fromUid, String toUid, String toOrgId, String data, Date createDate, Integer flag) {
    this.fromUid = fromUid;
    this.toUid = toUid;
    this.toOrgId = toOrgId;
    this.data = data;
    this.createDate = createDate;
    this.flag = flag;
    }

    public String getFromUid() {
    return fromUid;
    }

    public void setFromUid(String fromUid) {
    this.fromUid = fromUid;
    }

    public String getToUid() {
    return toUid;
    }

    public void setToUid(String toUid) {
    this.toUid = toUid;
    }

    public String getToOrgId() {
    return toOrgId;
    }

    public void setToOrgId(String toOrgId) {
    this.toOrgId = toOrgId;
    }

    public String getData() {
    return data;
    }

    public void setData(String data) {
    this.data = data;
    }

    public Date getCreateDate() {
    return createDate;
    }

    public void setCreateDate(Date createDate) {
    this.createDate = createDate;
    }

    public Integer getFlag() {
    return flag;
    }

    public void setFlag(Integer flag) {
    this.flag = flag;
    }

    @Override
    public String toString() {
    return “Msg{” +
    “fromUid=’” + fromUid + ‘’’ +
    “, toUid=’” + toUid + ‘’’ +
    “, toOrgId=’” + toOrgId + ‘’’ +
    “, data=’” + data + ‘’’ +
    “, createDate=” + createDate +
    “, flag=” + flag +
    ‘}’;
    }
    }

b.用于在WebSocket或去httpsession

package com.boli.srcoin.websocket;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;

/**

  • @author : admin

  • @DESC :

    讲http request的session 存入websocket的session内


    */
    public class HttpSessionConfigurator extends Configurator {

    @Override
    public void modifyHandshake(ServerEndpointConfig sec,
    HandshakeRequest request, HandshakeResponse response) {

     // 获取当前Http连接的session
     HttpSession httpSession = (HttpSession) request.getHttpSession();
     // 将http session信息注入websocket session
     sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
    

    }
    }
    c.用于监听有没有httpsession,没有则创建

package com.boli.srcoin.websocket;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;

@WebListener
public class RequestListener implements ServletRequestListener {

public void requestInitialized(ServletRequestEvent sre)  { 
    //将所有request请求都携带上httpSession
    ((HttpServletRequest) sre.getServletRequest()).getSession();
    
}
public RequestListener() {
    // TODO Auto-generated constructor stub
}

public void requestDestroyed(ServletRequestEvent arg0)  { 
     // TODO Auto-generated method stub
}

}

d.接收WebSocket链接和发送消息
package com.boli.srcoin.websocket;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**

  • @author : admin

  • @DESC :

    注解{@link ServerEndpoint}声明websocket 服务端


    */
    @ServerEndpoint(value = “/chat”, configurator = HttpSessionConfigurator.class)
    public class WSServer {

    static private Logger logger = Logger.getLogger(WSServer.class);

    // 在线人数 线程安全
    private static int onlineCount = 0;

    // 连接集合 userId => server 键值对 线程安全
    static public final ConcurrentMap<String, WSServer> map = new ConcurrentHashMap<>();

    // 与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

    // 当前会话的httpsession
    private HttpSession httpSession;

    /**

    • @param session websocket连接sesson

    • @param config {@link com.github.websocket.configuration.HttpSessionConfigurator}

    • @DESC

      注解{@link OnOpen} 声明客户端连接进入的方法


      */
      @OnOpen
      public void onOpen(Session session, EndpointConfig config) {

      // 得到httpSession
      this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

      // 获取session对象 SObject(这个就是java web登入后的保存的session对象,此处为用户信息,包含了userId)
      String user = (String) this.httpSession.getAttribute(“user”);

      this.session = session;
      System.out.println(user+"-------"+this.session.getId());

      //针对一个用户只能有一个链接
      if(map.get(user)!=null){
      // 移除连接
      map.remove(user);
      // 连接数-1
      subOnlineCount();
      }

      // 将连接session对象存入map
      map.put(user, this);

      // 连接数+1
      addOnlineCount();

      logger.info(“有新的连接,当前连接数为:” + getOnlineCount());
      }

    /**

    • {@link OnClose} 关闭连接

    */
    @OnClose
    public void onClose() {

     /**
      * 获取当前连接信息 {@code CommonConstant.USER_LOGIN_SESSION} 为Http session 名
      */
    
     String user = (String) this.httpSession.getAttribute("user");
    
     // 移除连接
     map.remove(user);
    
     // 连接数-1
     subOnlineCount();
    
     logger.info("有一连接断开,当前连接数为:" + getOnlineCount());
    

    }

    /**

    • {@link OnMessage} 消息监听处理方法

    • @param message 消息对象{@link com.github.websocket.msg.Msg}的JSON对象

    • @throws IOException 异常
      */
      @OnMessage
      public void onMessage(String message) throws IOException {

      // 将消息转Msg对象
      Msg msg = JSON.parseObject(message, Msg.class);

      //TODO 可以对msg做些处理…

      // 根据Msg消息对象获取定点发送人的userId
      WSServer _client = map.get(msg.getToUid());

      // 定点发送
      if (StringUtils.isNotEmpty(msg.getToUid())) {
      if (null != _client) {
      // 是否连接判断
      if (_client.session.isOpen())
      // 消息发送
      _client.session.getBasicRemote().sendText(JSON.toJSONString(msg));
      }
      }

      // 群发
      if (StringUtils.isEmpty(msg.getToUid())) {
      // 群发已连接用户
      for (WSServer client : map.values()) {
      client.session.getBasicRemote().sendText(JSON.toJSONString(msg));
      }
      }

    }

    /**

    • {@link OnError} websocket系统异常处理

    • @param t 异常
      */
      @OnError
      public void onError(Throwable t) {
      logger.error(t);
      t.printStackTrace();
      }

    /**

    • 系统主动推送 这是个静态方法在web启动后可在程序的其他合适的地方和时间调用,这就实现了系统的主动推送

    • @param msg 消息对象{@link com.github.websocket.msg.Msg}的JSON对象
      */
      static
      public void pushBySys(Msg msg) {

      //TODO 也可以实现定点推送
      //msg传输的时候会带上需要发送消息给谁msg.getToUid()
      //通过map去获取那个用户所在的session
      WSServer ws=map.get(msg.getToUid());
      try {
      if(ws!=null){
      ws.session.getBasicRemote().sendText(“123456”);
      }
      } catch (IOException e1) {
      e1.printStackTrace();
      }

      // 群发
      /for (WSServer client : map.values()) {
      try {
      client.session.getBasicRemote().sendText(JSON.toJSONString(msg));
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      /
      }

    // 获取连接数
    private static synchronized int getOnlineCount() {
    return WSServer.onlineCount;
    }

    // 增加连接数
    private static synchronized void addOnlineCount() {
    WSServer.onlineCount++;
    }

    // 减少连接数
    private static synchronized void subOnlineCount() {
    WSServer.onlineCount–;
    }

}

4、在后端的调用,也就是登录和调用发送消息

package com.boli.srcoin.member.service.impl;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.boli.framework.system.result.StandardResult;
import com.boli.framework.utils.WebUtil;
import com.boli.srcoin.member.form.MemberLoginForm;
import com.boli.srcoin.member.service.LoginMemberService;
import com.boli.srcoin.websocket.Msg;
import com.boli.srcoin.websocket.WSServer;

@Service
public class LoginMemberServiceImpl implements LoginMemberService{

@Override
@Transactional(readOnly = false)
public StandardResult toLogin(MemberLoginForm loginForm) {
	WebUtil.getSession().setAttribute("user", loginForm.getUser());
	Map<String,Object> map=new HashMap<>();
	map.put("sessionId", WebUtil.getSession().getId());
	map.put("user", loginForm.getUser());
	System.out.println("调用登录方法:"+WebUtil.getSession().getId()+loginForm.getUser());
	return StandardResult.ok(map);
}

@Override
@Transactional(readOnly = false)
public StandardResult tishi() {
	Msg msg=new Msg();
	msg.setToUid("ppp");
	WSServer.pushBySys(msg);
	return StandardResult.ok();
}

}

5、调用结果如图

附带源码链接:http://download.csdn.net/download/qq_31151929/10207702

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值