JavaEE中websocket使用示例

目前要在后端中实现websocket基本就是依靠javaee-api或者spring4.0以后的spring版本,本片文章记录下使用javaee-api后端的websocket的过程。

项目依赖

本项目使用maven构建,相关的几个依赖如下:(其他依赖不再列出)

<!-- 添加servlet3.0核心包 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
</dependency>
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.2-b01</version>
</dependency>
<!-- WebSocket配置开始-->
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
</dependency>
<!-- WebSocket配置结束-->复制代码

服务端具体实现

创建HttpSession的配置器类HttpSessionConfigurator
public class HttpSessionConfigurator extends ServerEndpointConfig.Configurator{
    //用来保存session的信息,后面的websocket就可以获取到了
    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
       HttpSession session = (HttpSession) request.getHttpSession();
       config.getUserProperties().put(HttpSession.class.getName(), session);
    }
}
复制代码
创建ChatServer,最主要的websocket实现类,通过注解实现连接、关闭、接收消息等等方法。
//@ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
//configurator使用上一步的HttpSessionConfigurator类,这样就可以通过EndpointConfig的实例获取session
@ServerEndpoint(value="/chatServer/{userid}", configurator = HttpSessionConfigurator.class)
public class ChatServer {

    private static Logger logger = Logger.getLogger(ChatServer.class);
    private static int onlineCount = 0; // 记录连接数目
    // Map<用户id,用户信息>
    private static Map<String, OnlineUser> onlineUserMap = new ConcurrentHashMap<String, OnlineUser>(); // 在线用户

    /**
     * 连接成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("userid") String userid , Session session, EndpointConfig config){

        logger.info("[ChatServer] connection : userid = " + userid + " , sessionId = " + session.getId());

        // 增加用户数量
        addOnlineCount();

        // 获取当前用户的session
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        User user  = (User) httpSession.getAttribute("user"); // 获得当前用户信息

        // 将当前用户存到在线用户列表中
        OnlineUser onlineUser = new OnlineUser(user.getUserid(),user.getNickname(),session);
        onlineUserMap.put(user.getUserid(),onlineUser);

        // 通知所有在线用户,当前用户上线
        String content = "[" + CommonDate.getTime24() + " : " + user.getNickname() + "加入聊天室,当前在线人数为 " + getOnlineCount() + "位" + "]";
        JSONObject msg = new JSONObject();
        msg.put("content",content);
        String message = Message.getMessage(msg.toString(),Message.NOTICE,onlineUserMap.values());
        Message.broadcast(message,onlineUserMap.values());

    }

    /**
     * 连接关闭方法
     */
    @OnClose
    public void onClose(@PathParam("userid") String userid,Session session,CloseReason closeReason){

        logger.info("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +
                " , closeCode = " + closeReason.getCloseCode().getCode() + " , closeReason = " +closeReason.getReasonPhrase());

        // 减少当前用户
        subOnlienCount();

        // 移除的用户信息
        OnlineUser removeUser = onlineUserMap.remove(userid);
        onlineUserMap.remove(userid);

        // 通知所有在线用户,当前用户下线
        String content = "["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 离开聊天室,当前在线人数为 " + getOnlineCount() + "位" + "]";
        JSONObject msg = new JSONObject();
        msg.put("content",content);
        if(onlineUserMap.size() > 0){
            String message = Message.getMessage(msg.toString(), Message.NOTICE, onlineUserMap.values());
            Message.broadcast(message,onlineUserMap.values());
        }else{
            logger.info("content : ["+ CommonDate.getTime24() + " : " + removeUser.getNickname() + " 离开聊天室,当前在线人数为 " + getOnlineCount() + "位" + "]");
        }

    }

    /**
     * 接收客户端的message,判断是否有接收人而选择进行广播还是指定发送
     * @param data 客户端发来的消息
     */
    @OnMessage
    public void onMessage(@PathParam("userid") String userid,String data){
        logger.info("[ChatServer] onMessage : userid = " + userid + " , data = " + data);

        JSONObject messageJson = JSONObject.fromObject(data);
        JSONObject message = messageJson.optJSONObject("message");
        String to = message.optString("to");
        String from = message.optString("from");
        // 将用户id转换为名称
        to = this.userIdCastNickName(to);

        OnlineUser fromUser = onlineUserMap.get(from);
        String sendMessage = Message.getContent(fromUser,to,message.optString("content"),message.optString("time"));
        String returnData = Message.getMessage(sendMessage, messageJson.optString("type"),null);

        if(to == null || to.equals("")){ // 进行广播
            Message.broadcast(returnData.toString(),onlineUserMap.values());
        }else{
            Message.singleSend(returnData.toString(), onlineUserMap.get(from));   // 发送给自己
            String[] useridList = message.optString("to").split(",");
            for(String id : useridList){
                if(!id.equals(from)){
                    Message.singleSend(returnData.toString(), onlineUserMap.get(id)); // 分别发送给指定的用户
                }
            }
        }
    }

    /**
     * 发生错误
     * @param throwable
     */
    @OnError
    public void onError(@PathParam("userid") String userid,Session session,Throwable throwable){
        logger.info("[ChatServer] close : userid = " + userid + " , sessionId = " + session.getId() +" , throwable = " + throwable.getMessage() );
    }


    public static int getOnlineCount() {
        return onlineCount;
    }

    public synchronized void addOnlineCount(){
        onlineCount++;
    }

    public synchronized void subOnlienCount(){
        onlineCount--;
    }

    /**
     * 将用户id转换为名称
     * @param userIds
     * @return
     */
    private String userIdCastNickName(String userIds){
        String niceNames = "";
        if(userIds != null && !userIds.equals("")){
            String[] useridList = userIds.split(",");
            String toName = "";
            for (String id : useridList){
                toName = toName + onlineUserMap.get(id).getNickname() + ",";
            }
            niceNames = toName.substring(0,toName.length() - 1);
        }
        return niceNames;
    }
}复制代码

Message类,组装信息,发送或广播到具体客户端。

public class Message {

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

    /**
     * 消息类型
     */
    public static String NOTICE = "notice";     //通知
    public static String MESSAGE = "message";   //消息

    /**
     * 组装信息返回给前台
     * @param message  交互信息
     * @param type     信息类型
     * @param userList 在线列表
     * @return
     *
     * "massage" : {
     *              "from" : "xxx",
     *              "to" : "xxx",
     *              "content" : "xxx",
     *              "time" : "xxxx.xx.xx"
     *          },
     * "type" : {notice|message},
     * "list" : {[xx],[xx],[xx]}
     */
    public static String getMessage(String message,String type,Collection<OnlineUser> userList){
        JSONObject msg = new JSONObject();
        msg.put("message",message);
        msg.put("type", type);

        if(CollectionUtils.isNotEmpty(userList)){
            List<String> propertys = new ArrayList<String>();
            propertys.add("session");
            JSONArray userListArray = JSONArray.fromObject(userList,JsonConfigUtils.getJsonConfig(propertys));
            msg.put("list", userListArray);
        }
        return msg.toString();
    }

    /**
     * 消息内容
     * @param fromUser
     * @param to
     * @param content
     * @param time
     * @return
     *          {
     *              "from" : "xxx",
     *              "to" : "xxx",
     *              "content" : "xxx",
     *              "time" : "xxxx.xx.xx"
     *          }
     */
    public static String getContent(OnlineUser fromUser,String to,String content,String time){
        JSONObject contentJson = new JSONObject();

        // 转化为json串时去掉session,用户session不能被序列化
        List<String> propertys = new ArrayList<String>();
        propertys.add("session");
        contentJson.put("from",JSONObject.fromObject(fromUser,JsonConfigUtils.getJsonConfig(propertys)));

        contentJson.put("to",to);
        contentJson.put("content",content);
        contentJson.put("time",time);
        return contentJson.toString();
    }

    /**
     * 广播消息
     * @param message 消息
     * @param onlineUsers 在线用户
     */
    public static void broadcast(String message,Collection<OnlineUser> onlineUsers){
        StringBuilder userStr = new StringBuilder();
        for(OnlineUser user : onlineUsers){
            userStr.append(user.getNickname()).append(",");
        }
        userStr.deleteCharAt(userStr.length()-1);
        logger.info("[broadcast] message = " + message + ", onlineUsers = " + userStr.toString());
        for(OnlineUser user : onlineUsers){
                try {
                    for (int i = 0; i < 20; i++) {
                        user.getSession().getBasicRemote().sendText(message);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                    logger.info("消息发送失败!" + e.getMessage());
                }
        }
    }

    /**
     * 对特定用户发送消息
     * @param message
     * @param onlineUser
     */
    public static void singleSend(String message, OnlineUser onlineUser){
        logger.info("[singleSend] message = " + message + ", toUser = " + onlineUser.getNickname());
        try {
            onlineUser.getSession().getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
            logger.info("消息发送失败!" + e.getMessage());
        }
    }
}复制代码


客户端实现

var wsServer = null;
var ws = null;
wsServer = "ws://" + location.host+"${pageContext.request.contextPath}" + "/chatServer/${userid}";
ws = new WebSocket(wsServer); //创建WebSocket对象
ws.onopen = function (evt) {
    layer.msg("已经建立连接", { offset: 0});
};
ws.onmessage = function (evt) {
    analysisMessage(evt.data);  //解析后台传回的消息,并予以展示
};
ws.onerror = function (evt) {
    layer.msg("产生异常", { offset: 0});
};
ws.onclose = function (evt) {
    layer.msg("已经关闭连接," + evt.reason, { offset: 0});
};复制代码


转载于:https://juejin.im/post/5bb07b6ce51d450e654893aa

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值