参考文章  :java使用websocket,并且获取HttpSession,源码分析    http://www.cnblogs.com/zhuxiaojie/p/6238826.html

1.在项目中引入依赖

websocket遵循了javaee规范,所以需要引入javaee的包

      <dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>

2.编写一个处理websocket请求的类

 import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import com.itheima.bos.domain.User;
import com.itheima.bos.utils.HTMLFilter; // 进行配置 websocket 通过下面的地址链接服务器
@ServerEndpoint(value = "/ws/chat" ,configurator = HttpSessionConfigurator.class)
public class ChatAnnotation { private static final Log log = LogFactory.getLog(ChatAnnotation.class); private static final String GUEST_PREFIX = "用户";
private static final AtomicInteger connectionIds = new AtomicInteger(0); //统计及在线人数
private static final Set<ChatAnnotation> connections = new CopyOnWriteArraySet<ChatAnnotation>(); private final String nickname;
private Session session;
private HttpSession httpSession;//httpsession 手动添加进来的值
private User user = null; public Session getSession() {
return session;
} public void setSession(Session session) {
this.session = session;
} public HttpSession getHttpSession() {
return httpSession;
} public void setHttpSession(HttpSession httpSession) {
this.httpSession = httpSession;
} public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} public ChatAnnotation() {
nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
} /*当websocket的客户端连接到服务器时候,这个方法就会执行,并且传递一个session会话对象来
我们拿到这话session,就是可以给客户端发送消息*/
@OnOpen
public void start(Session session,EndpointConfig config) {
HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
user = (User)httpSession.getAttribute("user"); //如果已经登录,在别的action中已经将一个user对象存入session中,此处直接取出
if(user != null){
//TODO 判断登录的用户是否已经存在于连接中
this.session = session;
this.httpSession = httpSession;
connections.add(this);
String message = String.format(" 用户 %s %s , 当前在线人数 %s", user.getUsername(), "加入聊天.",connectionIds);
broadcast(message); }else{
//用户未登陆
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} public static Set<ChatAnnotation> getConnections() {
return connections;
} /*客户端被关闭时候,就会自动会调用这个方法*/
@OnClose
public void end() {
connections.remove(this);
String message = String.format("- %s %s %s", user.getUsername(), "已经下线,当前用户数量是 ",connectionIds.decrementAndGet());
broadcast(message);
} /*客户端给服务器发送消息,这个方法会自动调用,并且可以拿到发送过来的数据*/
@OnMessage
public void incoming(String message) {
// Never trust the client
String filteredMessage = String.format("%s: %s",
user.getUsername(), HTMLFilter.filter(message.toString()));
broadcast(filteredMessage);
} /*发生了异常自动执行*/
@OnError
public void onError(Throwable t) throws Throwable {
log.error("Chat Error: " + t.toString(), t);
} /*广播:遍历客户端集,发送消息,注意发送要用的session,用session.getBasicRemote().sendText(msg)发送消息*/
private static void broadcast(String msg) {
for (ChatAnnotation client : connections) {//遍历所有
try {//如果这个client已经在线
synchronized (client) {
client.session.getBasicRemote().sendText(msg);//发送消息
}
} catch (IOException e) {//如果这个client不在线
log.debug("Chat Error: 向用户"+client.getUser().getUsername()+"发送消息失败", e);
connections.remove(client);
try {
client.session.close();
} catch (IOException e1) {
// Ignore
}
String message = String.format("-- %s %s", client.user.getUsername(), "已经下线.");
broadcast(message);
}
}
} @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ChatAnnotation other = (ChatAnnotation) obj;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
} }

3.编写获取httpsesion的类,和配置这些类

由于HTTP协议与websocket协议的不同,导致没法直接从websocket中获取协议,我们必须手动添加,具体细节可参考   获取httpsession 源码分析

 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; /**
* 从websocket中获取用户session
* 由于HTTP协议与websocket协议的不同,导致没法直接从websocket中获取协议,
* 下面的类中写了获取HttpSession的代码,但是如果真的放出去执行,那么会报空指值异常,因为这个HttpSession并没有设置进去。
需要我们自己来来设置HttpSession。这时候我们需要写一个监听器 下面有监听器的代码。
*
*/
public class HttpSessionConfigurator extends Configurator { @Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { HttpSession httpSession = (HttpSession) request.getHttpSession();
// ServerEndpointConfig 继承->EndpointConfig 中一个方法
// Map<String,Object> getUserProperties(); 对这个map进行赋值
sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
}
}

监听器

 import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest; public class RequestListener implements ServletRequestListener { public void requestInitialized(ServletRequestEvent sre) {
//将所有request请求都携带上httpSession
((HttpServletRequest) sre.getServletRequest()).getSession();
}
public RequestListener() {
} public void requestDestroyed(ServletRequestEvent arg0) {
}
}

有了监听器我们需要在web.xml中配置它

 <listener>
<listener-class>com.xwer.bos.web.websocket.RequestListener</listener-class>
</listener>

4. 前台页面

 <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>即时通讯</title>
<style type="text/css">
input#chat {
width: 410px
} #console-container {
width: 400px;
} #console {
border: 1px solid #CCCCCC;
border-right-color: #999999;
border-bottom-color: #999999;
height: 170px;
overflow-y: scroll;
padding: 5px;
width: 100%;
} #console p {
padding: 0;
margin: 0;
}
</style>
<script type="text/javascript">
var Chat = {}; Chat.socket = null; Chat.connect = (function(host) {
if ('WebSocket' in window) {
Chat.socket = new WebSocket(host);
} else if ('MozWebSocket' in window) {
Chat.socket = new MozWebSocket(host);
} else {
Console.log('Error: WebSocket is not supported by this browser.');
return;
} Chat.socket.onopen = function () {
Console.log('Info: 登录成功');
document.getElementById('chat').onkeydown = function(event) {
if (event.keyCode == 13) {
Chat.sendMessage();
}
};
}; Chat.socket.onclose = function () {
document.getElementById('chat').onkeydown = null;
Console.log('Info: 已经下线.');
}; Chat.socket.onmessage = function (message) {
Console.log(message.data);
};
}); Chat.initialize = function() {
var urls=window.location.href;
url = urls.substring(0,urls.lastIndexOf("/")).replace("http:",""); if (window.location.protocol == 'http:') {
Chat.connect('ws://' + url + '/ws/chat');
} else {
Chat.connect('wss://' + url + '/ws/chat');
}
}; Chat.sendMessage = (function() {
var message = document.getElementById('chat').value;
if (message != '') {
Chat.socket.send(message);
document.getElementById('chat').value = '';
}
}); var Console = {}; Console.log = (function(message) {
var console = document.getElementById('console');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.innerHTML = message;
console.appendChild(p);
while (console.childNodes.length > 25) {
console.removeChild(console.firstChild);
}
console.scrollTop = console.scrollHeight;
}); //关闭WebSocket连接
function closeWebSocket() {
Chat.socket.close();
} //发送消息
function sendMessage(){
Chat.sendMessage();
}
Chat.initialize(); </script>
</head>
<body>
<noscript><h2 style="color: #ff0000">浏览器不支持websocket</h2></noscript>
<div>
<p>
<input type="text" placeholder="按下 enter键开始聊天 " id="chat">
<button onclick="sendMessage()">发送消息</button>
</p>
<div id="console-container">
<div id="console"></div>
</div> <hr/>
<button onclick="closeWebSocket()">关闭连接</button>
<hr/>
</div>
</body>
</html>

5. 由于使用了Struts框架,在Struts配置文件中配置,不过滤WS请求

     <!--不拦截ws请求 -->
<constant name="struts.action.excludePattern" value="/ws/chat"></constant>

配置成功后界面如下

SSH 项目中 使用websocket 实现网页聊天功能的更多相关文章

  1. Java和WebSocket开发网页聊天室

    小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ Java和WebSocket开发网页聊天室 一.项 ...

  2. SpringBoot基于websocket的网页聊天

    一.入门简介正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序. 有人有疑问这个技术有什么作用,为什么要有它?其实我们虽然有http协议,但是它有一个缺 ...

  3. MVC实现类似QQ的网页聊天功能-ajax(下)

    此篇文章主要是对MVC实现类似QQ的网页聊天功能(上)的部分代码的解释. 首先说一下显示框的滚动条置底的问题: 结构很简单一个大的div(高度一定.overflow:auto)包含着两个小的div第一 ...

  4. 【C#】MVC项目中搭建WebSocket服务器

    前言 因为项目需要,前端页面中需要不断向后台请求获取一个及一个以上的状态值.最初的方案是为每个状态值请求都建立一个定时器循环定时发起Ajax请求,结果显而 易见.在HTTP1.1协议中,同一客户端浏览 ...

  5. 在SSH项目中实现分页效果

    在实现分页的时候,我使用的是数据库下面的User表,实现的效果是通过分页查询 能够将表中的数据分页显示,点击相关的按钮实现:首页.上一页.下一页.末页的显示 1新建一个dynamic web proj ...

  6. hessian在ssh项目中的配置

    一. 在服务端发布一个web项目 1.创建一个动态的web项目,并导入hessian的jar包 2. 在服务端的crm项目中创建接口 package cn.rodge.crm.service;impo ...

  7. SSH 项目中 用Hibernate底层 简单的封装DAO层

    废话不多少了,主要是使用hibernate的查询方法,自己封装了DAO层,供service来方便使用. 首先:必须要继承的 public class CommonDao extends Hiberna ...

  8. 使用websocket实现在线聊天功能

    很早以前为了快速达到效果,使用轮询实现了在线聊天功能,后来无意接触了socket,关于socket我的理解是进程间通信,首先要有服务器跟客户端,服务的启动监听某ip端口定位该进程,客户端开启socke ...

  9. vue-i18n vue-cli项目中实现国际化 多语言切换功能 一

    vue-cli项目中引入vue-i18n 安装: npm install vue-i18n可参考vue-i18n官网文档 main.js中引入: import Vue from 'vue' impor ...

随机推荐

  1. [NOI2015]程序自动分析(并查集)

    题目描述 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3...代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变 ...

  2. leetcode笔记(六)740. Delete and Earn

    题目描述 Given an array nums of integers, you can perform operations on the array. In each operation, yo ...

  3. JDBC配置文件db.properties(Mysql) 及dbutils的编写

    #数据库驱动driver=com.mysql.jdbc.Driver#数据库连接url=jdb:mysql://localhost:3306/newdb3?useUnicode=true&ch ...

  4. Ajax异步交互

    一.简介 Ajax(Asynchronous JavaScript and XML).一般都写为Ajax. Ajax是与服务器交换数组并更新部分网页的艺术.最初的使用时2005中Google Sugg ...

  5. ubuntu系統如何啟動root用戶登陸?

    之前分享過關於這個問題的文章,現在自己在分享一個關於這個問題的文章給大家.為了學習Linux,一氣之下把win10的換成了ubuntu的系統.安裝就不給大家介紹了(網上很多教程). 在我們安裝好之後, ...

  6. Windows下安装Mysql5.5.27(社区版)

    所有平台的 MySQL 下载地址为: MySQL 下载. 挑选你需要的 MySQL Community Server 版本及对应的平台. 运行mysql-5.5.27-win32.msi 进入欢迎界面 ...

  7. 出现java.lang.NoSuchMethodError错误的原因

    作为Java开发者我们都遇到过java.lang.NoSuchMethodError错误,究其根源,是JVM的"双亲委托模型"引发的问题.如果在类路径下放置了多个不同版本的类包,如 ...

  8. php使用file_get_contents 或者curl 发送get/post 请求 的方法总结

    file_get_contents模拟GET/POST请求 模拟GET请求: <?php $data = array( 'name'=>'zhezhao', 'age'=>'23' ...

  9. spark-day1

    #!/usr/bin/python # -*- coding: utf_8 -*- from pyspark import SparkConf, SparkContext import os, tim ...

  10. 08 datetime与logging模块(进阶)

    datetime与logging模块 阶段一:日期与时间 1.datetime 模块中 主要类: 类名 功能说明 date 日期对象,常用的属性有year, month, day time 时间对象h ...