参考文章  :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>

配置成功后界面如下

最新文章

  1. Linux快速入门04-扩展知识
  2. SQL——系统函数
  3. zb的生日
  4. iOS5中UIViewController的新方法
  5. 【Todo】【读书笔记】大数据Spark企业级实战版 &amp; Scala学习
  6. ubuntu 换源
  7. [原]命令模式在MVC框架中的应用
  8. dict字典学习笔记
  9. redis源码分析之事务Transaction(上)
  10. 选取id不为sth的div元素
  11. iOS中 UITableViewCell cell划线那些事 韩俊强的博客
  12. pyqt pyside QLineEdit 重写键盘事件
  13. 开发H5页面遇到的问题以及解决
  14. poj1195二维树状数组模板
  15. 01List.ashx(班级列表动态页面)
  16. Vue + Element UI 实现权限管理系统 前端篇(六):更换皮肤主题
  17. Python3.6+nginx+uwsgi部署Django程序到阿里云Ubuntu16.04系统
  18. 搞不清FastCgi与php-fpm之间是个什么样的关系
  19. [转]11个在线编码大赛,与全球程序员PK
  20. JVM源码分析之javaagent原理完全解读

热门文章

  1. Unity 游戏框架搭建 (十三) 无需继承的单例的模板
  2. 一个logstash引发的连环案,关于logstash提示:Reached open files limit: 4095, set by the &#39;max_open_files&#39; option or default, files yet to open: 375248
  3. idea常用技巧
  4. 序列(Sequence)创建、使用、修改和删除
  5. js对URL的相关操作集锦
  6. #leetcode刷题之路4-寻找两个有序数组的中位数
  7. linux后台程序开发常用工具
  8. bean工具类
  9. Hue联合(hdfs yarn hive) 后续......................
  10. 【Thrift一】Thrift安装部署