java web 在线聊天_javaweb与websocket实现在线聊天功能总结

技术从一开始ajax轮询后来改成websocket 碰到的一些问题的处理:

websocket的pom依赖

org.springframework

spring-websocket

4.0.5.RELEASE

首先是配置处理器

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import org.springframework.web.socket.config.annotation.EnableWebSocket;

import org.springframework.web.socket.config.annotation.WebSocketConfigurer;

import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

/**

* WebScoket配置处理器

* @author Goofy

* @Date 2015年6月11日 下午1:15:09

*/

@Component

@EnableWebSocket

public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {

@Resource

MyWebSocketHandler handler;

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(handler, "/ws").addInterceptors(new HandShake());

registry.addHandler(handler, "/ws/sockjs").addInterceptors(new HandShake()).withSockJS();

}

}

2.请求所经过的握手拦截器 主要用来将ServerHttpRequest里的session的用户信息存放在attributes里 到处理的handle中 会自动存入websocketsession的attribute里

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.http.server.ServletServerHttpRequest;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.HandshakeInterceptor;

/**

* Socket建立连接(握手)和断开

*

* @author Goofy

* @Date 2015年6月11日 下午2:23:09

*/

public class HandShake implements HandshakeInterceptor {

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception {

System.out.println("Websocket:用户[ID:" + ((ServletServerHttpRequest) request).getServletRequest().getSession(false).getAttribute("uid") + "]已经建立连接");

if (request instanceof ServletServerHttpRequest) {

ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;

HttpSession session = servletRequest.getServletRequest().getSession(false);

// 标记用户

Long uid = (Long) session.getAttribute("uid");

if(uid!=null){

attributes.put("uid", uid);

}else{

return false;

}

}

return true;

}

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {

}

}

Socket处理器 处理连接通信 或错误 关闭等

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Map.Entry;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.WebSocketMessage;

import org.springframework.web.socket.WebSocketSession;

import org.xdemo.example.websocket.entity.Message;

import com.google.gson.Gson;

import com.google.gson.GsonBuilder;

/**

* Socket处理器

*

* @author Goofy

* @Date 2015年6月11日 下午1:19:50

*/

@Component

public class MyWebSocketHandler implements WebSocketHandler {

public static final Map userSocketSessionMap;

static {

userSocketSessionMap = new HashMap();

}

/**

* 建立连接后

*/

public void afterConnectionEstablished(WebSocketSession session)

throws Exception {

Long uid = (Long) session.getAttributes().get("uid");

if (userSocketSessionMap.get(uid) == null) {

userSocketSessionMap.put(uid, session);

}

}

/**

* 消息处理,在客户端通过Websocket API发送的消息会经过这里,然后进行相应的处理

*/

public void handleMessage(WebSocketSession session, WebSocketMessage> message) throws Exception {

if(message.getPayloadLength()==0)return;

Message msg=new Gson().fromJson(message.getPayload().toString(),Message.class);

msg.setDate(new Date());

sendMessageToUser(msg.getTo(), new TextMessage(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg)));

}

/**

* 消息传输错误处理

*/

public void handleTransportError(WebSocketSession session,

Throwable exception) throws Exception {

if (session.isOpen()) {

session.close();

}

Iterator> it = userSocketSessionMap

.entrySet().iterator();

// 移除Socket会话

while (it.hasNext()) {

Entry entry = it.next();

if (entry.getValue().getId().equals(session.getId())) {

userSocketSessionMap.remove(entry.getKey());

System.out.println("Socket会话已经移除:用户ID" + entry.getKey());

break;

}

}

}

/**

* 关闭连接后

*/

public void afterConnectionClosed(WebSocketSession session,

CloseStatus closeStatus) throws Exception {

System.out.println("Websocket:" + session.getId() + "已经关闭");

Iterator> it = userSocketSessionMap

.entrySet().iterator();

// 移除Socket会话

while (it.hasNext()) {

Entry entry = it.next();

if (entry.getValue().getId().equals(session.getId())) {

userSocketSessionMap.remove(entry.getKey());

System.out.println("Socket会话已经移除:用户ID" + entry.getKey());

break;

}

}

}

public boolean supportsPartialMessages() {

return false;

}

/**

* 给所有在线用户发送消息

*

* @param message

* @throws IOException

*/

public void broadcast(final TextMessage message) throws IOException {

Iterator> it = userSocketSessionMap

.entrySet().iterator();

// 多线程群发

while (it.hasNext()) {

final Entry entry = it.next();

if (entry.getValue().isOpen()) {

// entry.getValue().sendMessage(message);

new Thread(new Runnable() {

public void run() {

try {

if (entry.getValue().isOpen()) {

entry.getValue().sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

}

}).start();

}

}

}

/**

* 给某个用户发送消息

*

* @param userName

* @param message

* @throws IOException

*/

public void sendMessageToUser(Long uid, TextMessage message)

throws IOException {

WebSocketSession session = userSocketSessionMap.get(uid);

if (session != null && session.isOpen()) {

session.sendMessage(message);

}

}

}

页面

String path = request.getContextPath();

String basePath = request.getServerName() + ":"

+ request.getServerPort() + path + "/";

String basePath2 = request.getScheme() + "://"

+ request.getServerName() + ":" + request.getServerPort()

+ path + "/";

%>

/p>

"http://www.w3.org/TR/html4/strict.dtd">

textarea {

height: 300px;

width: 100%;

resize: none;

outline: none;

}

input[type=button] {

float: right;

margin: 5px;

width: 50px;

height: 35px;

border: none;

color: white;

font-weight: bold;

outline: none;

}

.clear {

background: red;

}

.send {

background: green;

}

.clear:active {

background: yellow;

}

.send:active {

background: yellow;

}

.msg {

width: 100%;

height: 25px;

outline: none;

}

#content {

border: 1px solid gray;

width: 100%;

height: 400px;

overflow-y: scroll;

}

.from {

background-color: green;

width: 80%;

border-radius: 10px;

height: 30px;

line-height: 30px;

margin: 5px;

float: left;

color: white;

padding: 5px;

font-size: 22px;

}

.to {

background-color: gray;

width: 80%;

border-radius: 10px;

height: 30px;

line-height: 30px;

margin: 5px;

float: right;

color: white;

padding: 5px;

font-size: 22px;

}

.name {

color: gray;

font-size: 12px;

}

.tmsg_text {

color: white;

background-color: rgb(47, 47, 47);

font-size: 18px;

border-radius: 5px;

padding: 2px;

}

.fmsg_text {

color: white;

background-color: rgb(66, 138, 140);

font-size: 18px;

border-radius: 5px;

padding: 2px;

}

.sfmsg_text {

color: white;

background-color: rgb(148, 16, 16);

font-size: 18px;

border-radius: 5px;

padding: 2px;

}

.tmsg {

clear: both;

float: right;

width: 80%;

text-align: right;

}

.fmsg {

clear: both;

float: left;

width: 80%;

}

var path = '';

var uid=${uid eq null?-1:uid};

if(uid==-1){

location.href="";

}

var from=uid;

var fromName='${name}';

var to=uid==1?2:1;

var websocket;

if ('WebSocket' in window) {

websocket = new WebSocket("ws://" + path + "/ws?uid="+uid);

} else if ('MozWebSocket' in window) {

websocket = new MozWebSocket("ws://" + path + "/ws"+uid);

} else {

websocket = new SockJS("http://" + path + "/ws/sockjs"+uid);

}

websocket.onopen = function(event) {

console.log("WebSocket:已连接");

console.log(event);

};

websocket.onmessage = function(event) {

var data=JSON.parse(event.data);

console.log("WebSocket:收到一条消息",data);

var textCss=data.from==-1?"sfmsg_text":"fmsg_text";

$("#content").append("

"+data.fromName+" "+data.date+"
"+data.text+"
");

scrollToBottom();

};

websocket.onerror = function(event) {

console.log("WebSocket:发生错误 ");

console.log(event);

};

websocket.onclose = function(event) {

console.log("WebSocket:已关闭");

console.log(event);

}

function sendMsg(){

var v=$("#msg").val();

if(v==""){

return;

}else{

var data={};

data["from"]=from;

data["fromName"]=fromName;

data["to"]=to;

data["text"]=v;

websocket.send(JSON.stringify(data));

$("#content").append("

我 "+new Date().Format("yyyy-MM-dd hh:mm:ss")+"
"+data.text+"
");

scrollToBottom();

$("#msg").val("");

}

}

function scrollToBottom(){

var div = document.getElementById('content');

div.scrollTop = div.scrollHeight;

}

Date.prototype.Format = function (fmt) { //author: meizz

var o = {

"M+": this.getMonth() + 1, //月份

"d+": this.getDate(), //日

"h+": this.getHours(), //小时

"m+": this.getMinutes(), //分

"s+": this.getSeconds(), //秒

"q+": Math.floor((this.getMonth() + 3) / 3), //季度

"S": this.getMilliseconds() //毫秒

};

if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));

for (var k in o)

if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));

return fmt;

}

function send(event){

var code;

if(window.event){

code = window.event.keyCode; // IE

}else{

code = e.which; // Firefox

}

if(code==13){

sendMsg();

}

}

function clearAll(){

$("#content").empty();

}

欢迎:${sessionScope.name }

碰到的一些问题 以及处理的想法

1.之前在拦截器的请求里面得不到session   使用从页面传进来的get方式得到参数uid(后来也没改什么 调试的时候发现可以得到session)

2.客服防止多处登陆的处理:

每次登陆获取loginusermap 如果没有该用户 新增有就更新 然后替换map到session中

登陆拦截器校验登陆的用户的sessionid和map里的是否一致 不一致说明被挤 重新跳转

loginUserMap.put(user.getFid(), sessionId);

request.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);

3.

按钮嵌在右侧的工具栏 点击固定只弹出一个聊天网页

var op;

op = window.open("${webRoot}customerChat.json","newWin1");

op.focus();

4.

兼容ios(看了请求头里的sec-websocket-extensions不一致  就想的馊主意改头  结果可用)

if(request.getHeaders().get("sec-websocket-extensions").contains("x-webkit-deflate-frame")){

List list = new ArrayList();

list.add("permessage-deflate");

request.getHeaders().remove("sec-websocket-extensions");

request.getHeaders().put("sec-websocket-extensions",list);

}

兼容nginx

upstream tjxm.com{

server 127.0.0.1:8080;

}

server {

listen 80;

server_name localhost;

location / {

proxy_pass http://tjxm.com/;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

proxy_read_timeout 1000s;

}

}

前端WebSocket 连接关闭(代码:1006) 还需配置proxy_read_timeout 1000s;

哈哈 第一次写博客  有点菜鸡 websokcet部分也是从网上找的demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现在线客服功能,可以使用JavaWeb技术结合WebSocket实现WebSocket是一种在Web浏览器和服务器之间进行双向数据传输的技术,可以实现实时通信和服务器主动推送信息给客户端的功能\[3\]。 首先,你可以使用Tomcat中自带的WebSocket小例子作为基础,该例子是一个群聊功能\[1\]。你可以根据需求对其进行改写,实现一对一的私聊功能。可以通过在服务器端维护一个用户列表,每个用户都有一个唯一的标识符,当用户发送私聊消息时,服务器根据标识符找到对应的用户,并将消息发送给该用户。 另外,你还需要连接数据库来保存用户信息和聊天记录。可以使用DButils类中的getConnection方法来获取数据库连接\[2\]。在数据库中创建相应的表来存储用户信息和聊天记录。 在客户端,你可以使用HTML、CSS和JavaScript来实现用户界面。可以使用WebSocket API来与服务器进行通信,发送和接收消息。 总结起来,要实现在线客服功能,你需要: 1. 使用JavaWeb技术结合WebSocket实现实时通信和服务器推送功能。 2. 改写Tomcat中自带的WebSocket小例子,实现一对一的私聊功能。 3. 连接数据库,使用DButils类中的getConnection方法获取数据库连接。 4. 在服务器端维护用户列表,根据用户标识符将私聊消息发送给对应的用户。 5. 在客户端使用HTML、CSS和JavaScript实现用户界面,使用WebSocket API与服务器进行通信。 希望以上信息对你有帮助! #### 引用[.reference_title] - *1* [JavaWeb--使用Websocket实现在线聊天功能](https://blog.csdn.net/AE86JayChou/article/details/72872275)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [javaweb——在线聊天室(附源码)](https://blog.csdn.net/qq_62560115/article/details/130828931)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值