springmvc是怎样接受websocket请求的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springmvc是怎样接受websocket请求的相关的知识,希望对你有一定的参考价值。

浏览器客户端和服务器建立起websocket的链接,最初也是http请求握手,通过httpServletRequest发送http请求到服务器,其中头部就包含需要请求websocket链接的一系列信息,大概过程如下
1.客户端请求一个链接,头部中包含如下信息
GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Upgrade: WebSocket
Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5
Origin: http://example.com
[8-byte security key]
2.服务器根据头部中的Sec-WebSocket-Key2,Sec-WebSocket-Key1,Upgrade,[8-byte security key] 知道客户端需要一个websocket协议链接,于是返回一个消息,包含如下头部
HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: http://example.com
WebSocket-Location: ws://example.com/demo
[16-byte hash response]
3.客户端收到消息之后,建立起websocket链接,这时就可以进行实时通信了
我们可以定义一个处理器来实现WebSocketHandler处理请求
public class MyWebSocketHandler implements WebSocketHandler
/**
* webscoket建立好链接之后的处理函数
* @param session 当前websocket的会话id,打开一个websocket通过都会生成唯一的一个会话,可以通过该id进行发送消息到浏览器客户端
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception
// TODO Auto-generated method stub

/**
* 客户端发送服务器的消息时,的处理函数,在这里收到消息之后可以分发消息
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception
// TODO Auto-generated method stub

/**
* 消息传输过程中出现的异常处理函数
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception
// TODO Auto-generated method stub

/**
* websocket链接关闭的回调
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception
// TODO Auto-generated method stub

/**
* 是否支持处理拆分消息,返回true返回拆分消息
*/
@Override
public boolean supportsPartialMessages()
// TODO Auto-generated method stub
return false;


websocket的链接建立是基于http握手协议,我们可以添加一个拦截器处理握手之前和握手之后过程
public class MyHandShakeInterceptor implements HandshakeInterceptor
/**
* 握手之前,若返回false,则不建立链接
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception
// TODO Auto-generated method stub
return true;

/**
* 握手之后
*/
@Override
public void afterHandshake(ServerHttpRequest requestscjgcj.comServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception)
// TODO Auto-generated method stub


接下来,需要我们把处理器和拦截器注册到spring websocket中
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry)
registry.addHandler(new MyWebSocketHandler(), "/portfolio")//添加一个处理器还有定义处理器的处理路径
.addInterceptors(new MyHandShakeInterceptor())
.withSockJS();


在这里我们用到.withSockJS(),SockJS是spring用来处理浏览器对websocket的兼容性,目前浏览器支持websocket还不是很好,特别是IE11以下.SockJS能关键浏览器能否支持websocket来提供三种方式用于websocket请求,三种方式分别是 WebSocket, HTTP Streaming以及 HTTP Long Polling
SockJS提供了浏览器客户端的js库,在浏览器我们请求websocket就这么用
var socket = new SockJS('/whats/portfolio');//项目名称 + 处理器拦截路径名就会打开的目的websocket链接口
/**
* 建立成功的回调函数
*/
socket.onopen = function()
console.log('open');
;
/**
* 服务器有消息返回的回调函数
*/
socket.onmessage = function(e)
console.log('message', e.data);
;
/**
* websocket链接关闭的回调函数
*/
socket.onclose = function()
console.log('close');
;
然后客户端发送一个消息
document.getElementById("ws").onclick = function()
socket.send("fff");

服务器MyWebSocketHandler中,通过handlemessage接收消息并进行分发
/**
* 客户端发送服务器的消息时,的处理函数,在这里收到消息之后可以分发消息
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception
//获取消息
String body = (String) message.getPayload();
//一系列的处理之后...
//发送消息
session.sendMessage(message);

session可以用来标注客户端id,相对于我们的httpsession,这样,如果我们想做一个精准推送和全部推送,我们可以这么做
首先在自定义的处理其中,建一个队列来存储连进来的websocketsession
public class MyWebSocketHandler implements WebSocketHandler
private List<WebSocketSession> users = new ArrayList<WebSocketSession>(); //存放WebSocketSession的队列
/**
* webscoket建立好链接之后的处理函数
* @param session 当前websocket的会话id,打开一个websocket通过都会生成唯一的一个会话,可以通过该id进行发送消息到浏览器客户端
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception
session.getAttributes().put("userid", "xxxx");//如果有用户登录,可以把用户的id绑定到session里面,便于后面做精准推送
users.add(session); //每个链接来的客户端都把WebSocketSession保存进来

//...

然后呢,我们在接收到消息的时候,就可以直接的根据需要精准推送到用户或者全部推送了
/**
* 客户端发送服务器的消息时,的处理函数,在这里收到消息之后可以分发消息
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception
// TODO Auto-generated method stub
for (WebSocketSession webSocketSession : users)
//Long id = (Long) session.getAttributes().get("userid");//可以通过获取userid进行匹配,从而进行精准推送
message = new TextMessage("ggg");
webSocketSession.sendMessage(message); //全部推送


spring websocket大概的请求过程就是这样子,这是基础的请求过程,细心的同学可能发现,如果我有很多种不同的业务请求,是不是要写很多个处理器??能不能只实现一个处理器,然后由这个处理器来进行分发处理,做到类似springmvc的DispatcherServlet那样子??下次研究看看
参考技术A 用node.js安装WebSocket库: npm install ws然后建立serve 参考技术B http://blog.csdn.net/yingxiake/article/details/51194125

SpringMVC

  1. 首先什么是MVC

MVC包含Model(模型层)、View(视图层)、Controller(控制层)三层,用户发送请求到Controller,Controller层接受请求、转发请求,委托Model层进行数据处理,Model层(模型层)处理请求,将结果返回给Controller层,Controller层将试图渲染交给View层完成, View返回jstl到Controller,Controller响应结果给用户。

 技术图片

 

2. SpringMVC是什么?

SpringMVC是一个web层的MVC框架,是Spring的一部分。

3. SpringMVC的执行过程

用户根据地址访问到web.xml中配置好的前端控制器(DispatcherServlet),前端控制器根据请求找到对应的处理器映射器(HandlerMapping),处理器映射器返回chain给前端控制器;再由前端控制器请求执行Controller,这一步首先通过由处理器映射器获取的chain找到处理器适配器(ControllerHandlerAdapter),由处理器适配器执行Controller并且返回ModelAndView到前端控制器;前端控制器将ModelAndView交给视图解析器(ViewResolver)解析视图,视图解析器将View传给前端控制器再交予View层进行渲染视图,最终响应用户。

4. 处理器映射器

4.1 BeanNameUrlHandlerMapping

功能:寻找Controller

         根据url请求去匹配bean的name属性url,从而获取Controller

 

4.2 SimpleUrlHandlerMaping

功能:寻找Controller

         根据浏览器url匹配简单url的key,key又Controller的id找到Controller

 

4.3 ControllerClassNameHandlerMapping

功能:寻找Controller

          根据类名(MyController)类名.do来访问,类名首字母小写

 

5. 处理器适配器

5.1   SimpleControllerHandlerAdapter

功能:执行controller

         调用controller里面方法,返回modelAndView。

5.2 HttpRequestHandlerAdapter

功能:执行controller

 

 

6.配置web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

  <display-name>springMVC_01_self</display-name>

    <servlet>

    <servlet-name>springmvc</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 如果将配置文件的名字写成:springmvc-servlet.xml,核心控制器可以自动找到并执行

        1.名字必须是springmvc-servlet.xml   2.配置文件必须放在WEB-INF下面

     -->

    <init-param>

        <!-- 7.核心控制器会根据contextConfigLocation自动查找配置文件并执行 -->

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:springmvc.xml</param-value>

    </init-param>

  </servlet>

  <servlet-mapping>

  <servlet-name>springmvc</servlet-name>

  <!-- 在控制寻找具体的controller的时候,可以把它类似看成过滤器,但是不会自动触发

    这里不能写/*等控制范围太广的路径  ,核心控制器在进行捕获路径的时候,存在一些静态的文件,如果写成/*,同样会被捕获,

    但是这些文件在springmvc1.xml并没有去设置相应的对象.所以会报404

    最好使用:*.do   *.ok    *.haha

     -->

  <url-pattern>*.do</url-pattern>

  </servlet-mapping>

 

  <welcome-file-list>

    <welcome-file>index.html</welcome-file>

    <welcome-file>index.htm</welcome-file>

    <welcome-file>index.jsp</welcome-file>

    <welcome-file>default.html</welcome-file>

    <welcome-file>default.htm</welcome-file>

    <welcome-file>default.jsp</welcome-file>

  </welcome-file-list>

</web-app>

7. 配置springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

                           http://www.springframework.org/schema/beans/spring-beans.xsd

                           http://www.springframework.org/schema/context

                           http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 1.导入相关的约束文件 -->

<!-- 2.再web.xml配置前端控制器 -->

<!-- 3.寻找Controller-BeanNameUrlHandlerMapping(处理器的映射器)-->

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

 <!-- 5.通过bean的方式创建Controller的对象  name:就是访问路径 -->

<bean name="/test.do"  class="com.qianfeng.web.TestController"></bean>

<!-- 6.执行Controller,让他工作

通过 SimpleControllerHandlerAdapter实现(处理器适配器) -->

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

 

 <!-- 8.配置返回视图的信息

这里对返回视图的配置要与Controller页面的逻辑视图配合

 -->

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <!-- 设置前缀后缀 -->

    <property name="prefix" value="/"></property>

    <property name="suffix" value=".jsp"></property>

</bean>

</beans>

8.  通过注解方式配置web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

  <!-- 设置编码 -->

  <filter>

    <filter-name>encodingFilter</filter-name>

    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

    <init-param>

        <param-name>encoding</param-name>

        <param-value>UTF-8</param-value>

    </init-param>

  </filter>

  <filter-mapping>

    <filter-name>encodingFilter</filter-name>

    <url-pattern>/*</url-pattern>

  </filter-mapping>

  <display-name>J2EE_Email_SSM</display-name>

  <!-- spring的applicationContext.xml文件路径的配置放在这里、全局的配置文件name必须是contextConfigLocation -->

  <context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>classpath:spring/applicationContext.xml</param-value>

  </context-param>

  <!-- 执行applicationContext.xml,监听器只要发现配置了这个文件,就会自动执行这个文件 -->

  <listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

  </listener>

  <!-- 配置sessionlistener获取当前在线人数 -->

  <listener>

    <listener-class>com.swpu.listener.MyListener</listener-class>

  </listener>

  <!-- 前端控制器 -->

  <servlet>

    <servlet-name>springmvc</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:spring/springmvc.xml</param-value>

    </init-param>

  </servlet>

  <servlet-mapping>

    <servlet-name>springmvc</servlet-name>

    <url-pattern>*.do</url-pattern>

    <url-pattern>*.test</url-pattern>

  </servlet-mapping>

  <welcome-file-list>

    <welcome-file>index.html</welcome-file>

    <welcome-file>index.htm</welcome-file>

    <welcome-file>index.jsp</welcome-file>

    <welcome-file>default.html</welcome-file>

    <welcome-file>default.htm</welcome-file>

    <welcome-file>default.jsp</welcome-file>

  </welcome-file-list>

</web-app>

9. 通过注解方式配置springmvc.xml

  <!-- 扫描注释-->

<context:component-scan base-package="com.swpu"></context:component-scan>

<!-- 自动生成映射器和适配器对象 -->

<mvc:annotation-driven></mvc:annotation-driven>

<!-- 配置视图解析器 -->

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="prefix" value="/"></property>

    <property name="suffix" value=".jsp"></property>

</bean>

  1. 实例

10.1       结构

 技术图片

 

10.2       service层的注解

 技术图片

 

10.3       Controller层的注解

 技术图片

 

以上是关于springmvc是怎样接受websocket请求的的主要内容,如果未能解决你的问题,请参考以下文章

如何配置 WebSocket 服务器以接受安全连接请求

SpringMVC之请求部分

java八股系列——SpringMVC从接受请求到完成响应的过程

请教怎样发送socket请求包,并获得返回数据

如何异步接受 WebSocket?

springMVC接受json类型数据