参考文章  :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. oracle https://localhost:1158/em 无法打开

    解决办法一: 首先查看本机Oracle安装路径中 portlist.ini 文件里面的端口号是多少,例如我的就是5500. 那么在浏览器中输入的地址就是:https://localhost:5500/ ...

  2. 序列(Sequence)创建、使用、修改和删除

    序列(Sequence)是用来生成连续的整数数据的对象.序列常常用来作为主键中增长列,序列中的可以升序生成,也可以降序生成. 语法结构:创建序列 CREATE SEQUENCE sequence_na ...

  3. jquery获取父级元素、子级元素、兄弟元素

    1:$(this).parent(expr) 找父亲节点,可以传入expr进行过滤,比如$("span").parent()或者$("span").parent ...

  4. git克隆出错 github clone Permission denied (publickey) fatal Could not read from remote repo

    原文网址:http://blog.csdn.net/feeling450/article/details/53067563 github clone "Permission denied ( ...

  5. 移植Linux Kernel SM750 驱动到VxWorks 7

    一.SM750简介 SM750 是SiliconMotion 推出的一款适合嵌入式设备的显卡(Embedded GPU),采用PCIe接口与CPU连接,内部集成16MB DDR SDRAM显存,产品具 ...

  6. python字符串编码

    python默认编码 python 2.x默认的字符编码是ASCII,默认的文件编码也是ASCII. python 3.x默认的字符编码是unicode,默认的文件编码是utf-8. 中文乱码问题 无 ...

  7. print(__file__)返回<encoding error>的问题

    今天写了一下代码,本来是想得到当前文件的上面三层的目录的,结果返回的却是错误 import os import sys print(__file__) # 得到上上层目录的路径之后,加入到默认的环境变 ...

  8. POJ3687 反向拓扑排序

    Labeling Balls Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16032   Accepted: 4713 D ...

  9. mybatis 打印SQL

    如果使用的是application.properties文件,加入如下配置: #打印SQL logging.level.com.jn.ssr.supererscuereporting.dao=debu ...

  10. Git更改远程仓库地址

    最近在开发一个公司内部的公共组件库.老大整理了git仓库里的一些项目,其中就包括这个项目. 项目git地址变了,于是我本地的代码提交成功后push失败. 查看远程地址 git remote -v 更改 ...