今天是六一儿童节,祝愿小朋友们节日快乐!大朋友们事事顺心!

Websocet服务端实现

WebSocketConfig.Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(newWebSocketHandshakeInterceptor());
 
        registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(newWebSocketHandshakeInterceptor())
                .withSockJS();
    }
 
    @Bean
    public WebSocketHandler systemWebSocketHandler(){
        return new SystemWebSocketHandler();
    }
 
}

不要忘记在springmvc的配置文件中配置对此类的自动扫描

1
<context:component-scan base-package="com.ldl.origami.websocket" />

@Configuration

@EnableWebMvc
@EnableWebSocket
这三个大致意思是使这个类支持以@Bean的方式加载bean,并且支持springmvc和websocket,不是很准确大致这样,试了一下@EnableWebMvc不加也没什么影响,@Configuration本来就支持springmvc的自动扫描

1
registry.addHandler(systemWebSocketHandler(),"/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())

用来注册websocket server实现类,第二个参数是访问websocket的地址

1
2
3
registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new WebSocketHandshakeInterceptor())
                .withSockJS();
    }

这个是使用Sockjs的注册方法

首先SystemWebSocketHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class SystemWebSocketHandler implements WebSocketHandler {
 
    private static final Logger logger;
 
    private static final ArrayList<WebSocketSession> users;
 
    static {
        users = new ArrayList<>();
        logger = LoggerFactory.getLogger(SystemWebSocketHandler.class);
    }
 
    @Autowired
    private WebSocketService webSocketService;
 
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        logger.debug("connect to the websocket success......");
        users.add(session);
        String userName = (String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME);
        if(userName!= null){
            //查询未读消息
            int count = webSocketService.getUnReadNews((String) session.getAttributes().get(Constants.WEBSOCKET_USERNAME));
 
            session.sendMessage(new TextMessage(count + ""));
        }
    }
 
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
 
        //sendMessageToUsers();
    }
 
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        if(session.isOpen()){
            session.close();
        }
        logger.debug("websocket connection closed......");
        users.remove(session);
    }
 
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        logger.debug("websocket connection closed......");
        users.remove(session);
    }
 
    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
 
    /**
     * 给所有在线用户发送消息
     *
     * @param message
     */
    public void sendMessageToUsers(TextMessage message) {
        for (WebSocketSession user : users) {
            try {
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 
    /**
     * 给某个用户发送消息
     *
     * @param userName
     * @param message
     */
    public void sendMessageToUser(String userName, TextMessage message) {
        for (WebSocketSession user : users) {
            if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) {
                try {
                    if (user.isOpen()) {
                        user.sendMessage(message);
                    }
                catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }
}

相关内容大家一看就能明白,就不多解释了

然后WebSocketHandshakeInterceptor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {
 
    private static Logger logger = LoggerFactory.getLogger(HandshakeInterceptor.class);
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object
                > attributes) throws Exception {
        if (request instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
            HttpSession session = servletRequest.getServletRequest().getSession(false);
            if (session != null) {
                //使用userName区分WebSocketHandler,以便定向发送消息
                String userName = (String) session.getAttribute(Constants.SESSION_USERNAME);
                attributes.put(Constants.WEBSOCKET_USERNAME,userName);
            }
        }
        return true;
    }
 
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
 
    }
}

这个的主要作用是取得当前请求中的用户名,并且保存到当前的WebSocketHandler中,以便确定WebSocketHandler所对应的用户,具体可参考HttpSessionHandshakeInterceptor

用户登录建立websocket连接

index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script type="text/javascript" src="http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"></script>
        <script>
            var websocket;
            if ('WebSocket' in window) {
                websocket = new WebSocket("ws://localhost:8080/Origami/webSocketServer");
            else if ('MozWebSocket' in window) {
                websocket = new MozWebSocket("ws://localhost:8080/Origami/webSocketServer");
            else {
                websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");
            }
            websocket.onopen = function (evnt) {
            };
            websocket.onmessage = function (evnt) {
                $("#msgcount").html("(<font color='red'>"+evnt.data+"</font>)")
            };
            websocket.onerror = function (evnt) {
            };
            websocket.onclose = function (evnt) {
            }
 
        </script>

使用sockjs时要注意

1、这两个的写法

1
<script type="text/javascript" src="http://localhost:8080/Origami/websocket/sockjs-0.3.min.js"></script>
1
websocket = new SockJS("http://localhost:8080/Origami/sockjs/webSocketServer");

2、web.xml中

1
2
3
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd">
1
version
1
web-app_3_1.xsd

这两个的版本都要是3.0+

然后在这个servlet中加入

1
<async-supported>true</async-supported>
1
2
3
4
5
6
7
8
9
10
<servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>

然后所有的filter中也加入

1
<async-supported>true</async-supported>

3、添加相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.3.3</version>
        </dependency>

好了,现在websocket可以正常建立起来了

返回用户未读的消息

当连接建立后,会进入SystemWebSocketHandler的afterConnectionEstablished方法,代码看上边,取出WebSocketHandshakeInterceptor中保存的用户名

查询信息后使用session.sendMessage(new TextMessage(count + ""));返回给用户,从哪来回哪去

服务端推送消息给用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Controller
public class AdminController {
 
    static Logger logger = LoggerFactory.getLogger(AdminController.class);
 
    @Autowired(required = false)
    private AdminService adminService;
 
    @Bean
    public SystemWebSocketHandler systemWebSocketHandler() {
        return new SystemWebSocketHandler();
    }
 
 
    @RequestMapping("/auditing")
    @ResponseBody
    public String auditing(HttpServletRequest request){
        //无关代码都省略了
        int unReadNewsCount = adminService.getUnReadNews(username);
        systemWebSocketHandler().sendMessageToUser(username, new TextMessage(unReadNewsCount + ""));
        return result;
    }
}

在这里可以使用sendMessageToUser给某个用户推送信息,也可以使用sendMessageToUsers给所有用户推送信息

160601、Websocet服务端实现的更多相关文章

  1. Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)

    本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...

  2. 关于如何提高Web服务端并发效率的异步编程技术

    最近我研究技术的一个重点是java的多线程开发,在我早期学习java的时候,很多书上把java的多线程开发标榜为简单易用,这个简单易用是以C语言作为参照的,不过我也没有使用过C语言开发过多线程,我只知 ...

  3. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之一服务端启动过程

    zookeeper简介 zookeeper是为分布式应用提供分布式协作服务的开源软件.它提供了一组简单的原子操作,分布式应用可以基于这些原子操作来实现更高层次的同步服务,配置维护,组管理和命名.zoo ...

  7. 创建APPID&&部署服务端教程

    创建APPID&&部署服务端 一.创建APPID 1.打开https://console.developers.google.com ,左击顶部Project,然后左击创建项目 2.输 ...

  8. 简析服务端通过GT导入SHP至PG的方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 项目中需要在浏览器端直接上传SHP后服务端进行数据的自动入PG ...

  9. TYPESDK手游聚合SDK服务端设计思路与架构之二:服务端设计

    在前一篇文中,我们对一个聚合SDK服务端所需要实现的功能作了简单的分析.通过两个主要场景的功能流程图,我们可以看到,作为多款游戏要适配多个渠道的统一请求转发中心,TYPESDK服务端主要需要实现的功能 ...

随机推荐

  1. 简洁经常使用权限系统的设计与实现(一):构造权限菜单树的N(N&gt;=4)种方法

    权限系统.Web开发常见标准子系统之中的一个.结合自己的一些思考和实践,从本篇開始权限系统的设计与实现之路. 近期,重构了项目的权限菜单构造过程,向前端返回json格式的权限树. 这一篇.仅仅是大致介 ...

  2. pow(x,y)函数的实现算法(递归函数)

    函数pow(x,y)实现运算x^y,即x的y次方,这里x和y都为整数. 算法的基本思想是,减少乘法次数,重复利用结算结果,例如: x^4,如果逐个相乘的话,需要四次乘法.如果我们这样分解(x^2)*( ...

  3. Python强制抛出自定义异常

    raise Exception("My Exception") 当程序运行到这行时,会抛出异常,打印出Exception: My Exception

  4. dataGridViewX操作

    private void dataGridView1_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e) { ...

  5. Java线程停止interrupt()方法

    程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程. 中 ...

  6. Java 之进制转换

    //十进制转十六进制 import java.util.Scanner; public class Main{ public static void main(String[] args){ Scan ...

  7. WWDC 2014 Session笔记 - iOS界面开发的大一统

    本文是我的 WWDC 2014 笔记 中的一篇,涉及的 Session 有 What's New in Cocoa Touch Building Adaptive Apps with UIKit Wh ...

  8. mof提权原理及其过程

    mof提权的原理: mof是windows系统的一个文件(在c:/windows/system32/wbem/mof/nullevt.mof)叫做"托管对象格式"其作用是每隔五秒就 ...

  9. myeclipse 上安装 Maven3<转>

    环境准备: JDK 1.6 Maven 3.0.4 myeclipse 8.6.1 安装 Maven 之前要求先确定你的 JDK 已经安装配置完成.Maven是 Apache 下的一个项目,目前最新版 ...

  10. 新手入门贴:史上最全Web端即时通讯技术原理详解

    关于IM(InstantMessaging)即时通信类软件(如微信,QQ),大多数都是桌面应用程序或者native应用较为流行,而网上关于原生IM或桌面IM软件类的通信原理介绍也较多,此处不再赘述.而 ...