zoukankan      html  css  js  c++  java
  • springmvc实现long-pulling技术

    背景介绍:

    项目中有一个通讯模块,本来是用websocket全双工技术实现的,但IE10下面不支持websocket,而国内的360、2345浏

    览器封装的所有是IE10下面的内核,考虑到站点在国内的客户,不得不在不支持websocket时候也要提供通讯支持,于

    是决定在不支持websocket的浏览器上用long-pulling技术替代。


    可行性分析:

    Servlet 3.0已经開始支持async,Spring MVC 3.2也開始对异步提供支持,于是结合DeferredResult来实现聊天技术。


    详细实现:

    1 文件配置:

    如果你已经有了spring+springmvc框架,我们仅仅需对配置文件做微小修改,要在web.xml中的全部的filter及servlet中须要声明使用async:

    <async-supported>true</async-supported>
    web.xml完整配置例如以下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://java.sun.com/xml/ns/javaee"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    	version="3.0">
    	<!-- 配置spring-mybatis.xml -->
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>classpath:spring-mybatis.xml</param-value>
    	</context-param>
    	<filter>
    		<filter-name>encodingFilter</filter-name>
    		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    		<async-supported>true</async-supported>
    		<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>
    	<!-- 配置spring-mvc -->
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    	<listener>
    		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</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-mvc.xml</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    		<async-supported>true</async-supported>
    	</servlet>
    	<servlet-mapping>
    		<servlet-name>SpringMVC</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>	
    	<welcome-file-list>
    		<welcome-file>index.jsp</welcome-file>
    	</welcome-file-list>
    	
    </web-app>
    文件配置搞定。

    2 建立控制器Controller

    /**
     * @作者 yyp
     * @文件名称 ChatController.java
     * @作用 处理聊天消息
     * @Blog http://blog.csdn.net/gisredevelopment
     */
    @Controller
    public class ChatController {
    	//存放全部的用户请求
    	private final Map<String, DeferredResult<Message>> chatRequests = new ConcurrentHashMap<String, DeferredResult<Message>>();
    	//时间格式化
    	private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    	/**
    	 * @作者 yyp
    	 * @作用 登录
    	 * @param name username
    	 * @param session 会话
    	 * @return 聊天室页面
    	 */
    	@RequestMapping(value = "/login", method = RequestMethod.POST)
    	public String login(@RequestParam String name, HttpSession session){
    		session.setAttribute("user", name);
    		Message msg = new Message();
    		msg.setUser("系统");
    		msg.setDate(sdf.format(new Date()));
    		msg.setContent(name + "已增加");
    		//通知全部用户有人进入聊天室
    		processMessage(msg);
    		return "room";
    	}
    	/**
    	 * 
    	 * @作者 yyp
    	 * @作用 读取最新消息
    	 * @param session 会话
    	 * @return DeferredResult<Message>
    	 */
    	@RequestMapping(value = "/getMessages", method = RequestMethod.GET)
    	@ResponseBody
    	public DeferredResult<Message> getMessages(HttpSession session){
    		//取出当前登录用户
    		final String user = (String)session.getAttribute("user");
    		//创建DeferredResult<Message>
    		DeferredResult<Message> dr = new DeferredResult<Message>();
    		//若用户不存在则直接返回,否则将其放入用户请求列表中然后返回
    		if(null == user){
    			return dr;
    		}else{
    			//当DeferredResult对client响应后将其从列表中移除
    			dr.onCompletion(new Runnable() {
    				@Override
    				public void run() {
    					// TODO 自己主动生成的方法存根
    					chatRequests.remove(user);
    				}
    			});
    			chatRequests.put(user, dr);
    			return dr;
    		}
    	}
    	/**
    	 * @作者 yyp
    	 * @作用 接收client消息
    	 * @param session 会话
    	 * @param content 消息内容
    	 * @return Map<String, String>
    	 */
    	@RequestMapping(value = "/setMessage", method = RequestMethod.POST)
    	@ResponseBody
    	public Map<String, String> setMessage(HttpSession session, @RequestParam String content){
    		Message msg = new Message();
    		msg.setContent(content);
    		msg.setDate(sdf.format(new Date()));
    		msg.setUser((String)session.getAttribute("user"));
    		//公布消息给全部用户
    		processMessage(msg);
    		Map<String, String> map = new HashMap<String, String>(1);
    		map.put("success", "true");
    		return map;
    	}
    	/**
    	 * @作者 yyp
    	 * @作用 退出聊天室
    	 * @param session 会话
    	 * @return Map<String, String>
    	 */
    	@RequestMapping(value = "/logout", method = RequestMethod.GET)
    	@ResponseBody
    	public Map<String, String> logout(HttpSession session){
    		Message msg = new Message();
    		String user = (String)session.getAttribute("user");
    		msg.setContent("已离开");
    		msg.setDate(sdf.format(new Date()));
    		msg.setUser(user);
    		chatRequests.remove(user);
    		//通知全部用户有人离开聊天室
    		processMessage(msg);
    		Map<String, String> map = new HashMap<String, String>(1);
    		map.put("success", "true");
    		return map;
    	}
    	/**
    	 * @作者 yyp
    	 * @作用 将消息信息公布给全部在线用户
    	 * @param msg 消息
    	 */
    	private void processMessage(Message msg){
    		Set<String> keys = chatRequests.keySet();
    		for(String key : keys){
    			chatRequests.get(key).setResult(msg);
    		}
    	}
    }

    3 建立消息实体

    /**
     * @作者 yyp
     * @文件名称 Message.java
     * @作用 封装用户的聊天内容
     * @Blog http://blog.csdn.net/gisredevelopment
     */
    public class Message {
    	private String user;
    	private String date;
    	private String content;
    }

    4 页面代码-登录

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>登录</title>
    </head>
    <body>
    <form action="login" method="post">
    name: <input type="text" name="name"/>
    <input value="登录" type="submit"/>
    </form>
    </body>
    </html>

    5 页面代码-聊天

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <% String user =(String)session.getAttribute("user"); %>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>聊天室</title>
    <script type="text/javascript" src="/imgr?src=http%3A%2F%2Fwww.ineeke.com%2Farchives%2F1486%2Fjquery-1.10.1.min.js"></script>
    <script type="text/javascript">
    	$(function(){
    		(function getMessages(){
    			$.ajax({
    				dataType: "json",
    				url: 'getMessages',
    				cache: false,
    				success: function(data){
    					var v = $('#text').val();
    					v += '
    ' + data.date + ' ' + data.user + ':' + data.content;
    					$('#text').val(v);
    				}
    			}).always(function(){
    				getMessages();
    			});
    		})();
    		$('#form').submit(function(event){
    			event.preventDefault();
    			var values = $(this).serialize();
    			$.post('setMessage', values, function(data){
    				$('#form>[name=content]').val('');
    			}, 'json');
    		});
    		$('#logout').click(function(){
    			$.ajax({
    				dataType: "json",
    				url: 'logout',
    				cache: false,
    				success: function(data){
    					window.location.href = 'index.jsp';
    				}
    			});
    		});
    	});
    </script>
    </head>
    <body>
    欢迎:<%=user %><br/>
    <textarea id="text" rows="20" style=" 500;"></textarea>
    <form id="form" action="sendMessage" method="post">
    <input type="text" name="content" />
    <input value="发送" type="submit"/>
    <input id="logout" value="离开" type="button"/>
    </form>
    </body>
    </html>




  • 相关阅读:
    【linux】Centos下登陆mysql报错#1045
    tomcat在centos7里面启动很慢的解决办法
    tomcat日志文件 转载https://www.cnblogs.com/operationhome/p/9680040.html
    tomcat的文件目录结构
    centos 7服务器下tomcat 问题 1.配置问题
    x11转发遇到的问题
    x11转发,可以在shell里面看到图形界面
    linux里面tomcat配置遇到的问题
    vim中文乱码 vim字符集设置
    c#.net常见字符串处理方法
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4384341.html
Copyright © 2011-2022 走看看