H5的新规范,强调实时性,websocket传输的都是字符串。传统中的web请求-响应模式中实时传输的实现,comet可以一定程度上模拟双向通信,但是效率较低,并且需要服务器较好的支持,还有flash中的socket和xmlsocket可以真正的实现双向通信,通过flex ajax bridge,可以在js中使用这两个功能。而H5定义的websocket协议是将代替上面两个技术,它是建立在http协议的基础之上,可以更好的节省服务器资源和带宽并且达到实时通信,JavaEE7也实现了该协议。主要实现的是4个操作,在B-S的架构下面,客户端可以进行取放、服务器拿取的操作以及客户端进行拿取,服务器进行取放。
【说明】这里的利用Tomcat自带的一个Demo,自己实现。这里新建WEB项目的时候直接引入Tomcat的目录即可,不再需要其他的jar包,这里我们用到的是两个jar,一个是tomcat7-websocket.jar和websocket-api.jar,前者实现了后者的接口。
DEMO 1
(Eclipse–>WebSocketTest)
首先是一个配置类:
package com.hhu.config;
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
//这里实现的是ServerApplicationConfig,有两个方法,一种是注解启动,一种接口启动
//这是一个启动类
public class DemoConfig implements ServerApplicationConfig {
//注解方式 启动,这里它是自动执行的,自动扫描带有@ServerEndPoint(即终端)注解的类来自动注册
//这里我们通常都是用注解的方式来完成
@Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
System.out.println("config.........." + scan.size());
//返回scan,如果返回,服务器不会帮助注册任何Socket,提供了一定的过滤作用
return scan;
}
//接口方式 启动,由于使用了注解的方式,那这个接口的方式我们不予关注
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
// TODO Auto-generated method stub
return null;
}
}
然后写Socket,这里包含了服务端对客户端所有的响应
package com.hhu.socket;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
/**
* 就是Socket
* @author Weiguo Liu
*
*/
@ServerEndpoint("/echo")
public class EchoSocket {
//用来查看单例还是多例的
public EchoSocket() {
System.out.println("EchoSocket.EchoSocket()");
}
/*这个注解表示只要有人链接这个Socket,这个方法就会执行
*带进来一个Session,一个管道(会话)代表一次Session
*/
@OnOpen
public void open(Session session) {
//一个Session代表一个通信会话(不同的客户端链接他们的建立的session的id不一样)
System.out.println("已进入open方法,session的id:" + session.getId());
}
/*
* 浏览器关闭的时候,自动调用@OnClose的方法,表示session会话结束
*/
@OnClose
public void close(Session session){
System.out.println("当前session关闭:session.id" + session.getId());
}
/*
* 服务端接受客户端发送的信息之后所要执行的方法
*/
@OnMessage
public void message(Session session,String msg) throws IOException {
System.out.println("客户端说" + msg);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
Date date = new Date();
String now = sdf.format(date);
//这里服务端也可以给客户端发送消息,当然如果是其他类别的消息需要用不同的sendxxx()方法
session.getBasicRemote().sendText(now + ":我是服务器,我已经接受你的消息,客户端说“" + msg + "”");
}
}
前端的页面也很简单:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<input id="msg"/>
<button onclick="subOpen()">链接</button>
<button onclick="subSend()">发送</button>
<div id="servermsg"></div>
<script type="text/javascript">
var ws; //一个ws对象就是一个通信管道
//target表示的是请求地址,你要链接谁
var target = "ws://localhost:8080/WebSocketTest/echo";
function subOpen(){
if('WebSocket'in window) {
ws = new WebSocket(target);
} else if('MozWebSocket'in window) {
ws = new MozWebSocket(target);
} else {
alert("当前浏览器不支持WebSocket!");
return;
}
//客户端从服务端接收信息也是基于事件的,异步,所以在open的时候就要注册一个message
ws.onmessage = function(MsgEvent) {//这里返回的是一个事件对象!!
console.info(MsgEvent.data);//真实的服务端发送的消息在事件对象的data变量中
//往div中注入内容用document.getElementById("divid").innerHTML
//追加内容的时候就用+=,不追加就直接用=就好
document.getElementById("servermsg").innerHTML += MsgEvent.data;
}
}
//发送消息
function subSend() {
//获取输入框的内容
var msg = document.getElementById("msg").value;
//发送消息(客户端给服务端发送消息)
ws.send(msg);
//清空输入框中的内容
document.getElementById("msg").value = "";
}
</script>
</body>
</html>
Demo2:聊天室–群聊+私聊
(Eclipse–>WebChat)
第二个Demo是实现了一个聊天室的常规功能:群聊和私聊,其实就是服务端向客户端发送消息所选择的Session不同而已其他的还是一样的。
还是一样,配置不能少:
package com.hhu.config;
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
//这里实现的是ServerApplicationConfig,有两个方法,一种是注解启动,一种接口启动
//这是一个启动类
public class DemoConfig implements ServerApplicationConfig {
//注解方式 启动,这里它是自动执行的,自动扫描带有@ServerEndPoint(即终端)注解的类来自动注册
//这里我们通常都是用注解的方式来完成,有几个类(加了注解的)scan的size()就是多少
@Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scan) {
System.out.println("config.........." + scan.size());
//返回scan,如果返回,服务器不会帮助注册任何Socket,提供了一定的过滤作用
return scan;
}
//接口方式 启动,由于使用了注解的方式,那这个接口的方式我们不予关注
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> arg0) {
// TODO Auto-generated method stub
return null;
}
}
然后是webSocket
package com.hhu.socket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import com.google.gson.Gson;
import com.hhu.util.ContentVo;
import com.hhu.util.Message;
/**
* 建立聊天室的webSocket程序
* @author Weiguo Liu
*
*/
//标记前台请求的地址
@ServerEndpoint("/chatSocket")
public class ChatSocket {
private String username;
//这里声明为static类型的变量是为了将sessions整个变量变为公共的变量才能共同使用
private static List<Session> sessions = new ArrayList<Session>();
private static List<String> names = new ArrayList<String>();
private static Map<String,Session> map = new HashMap<String,Session>();
//在聊天室链接后(即成功创建聊天室的Socket)所要干的事儿
@OnOpen
public void open(Session session) {
//这里的session和Servlet中的session不是同一个session,
//要获取用户的名字,就要先从Servlet中获取,然后再在请求的时候将参数传过来即可
//getQueryString()可以将问号后面全部拿出来,在SpringMVC中又是不一样的
String user = session.getQueryString();
//将username=xx中的xx取出来
username = user.split("=")[1];
//将当前的session放到List中
this.sessions.add(session);
//将用户添加进List
this.names.add(username);
this.map.put(this.username, session);
Message msg = new Message();
msg.setWelcom("欢迎" + this.username + "进入聊天室!");
msg.setUsernames(names);
//进行广播,将这条消息广播到每一个session中
broadcast(this.sessions, msg.toJson());
}
//进行广播,将消息发送给每个session中,需要遍历每一个session
public void broadcast(List<Session> ss,String msg) {
Iterator<Session> iterator=ss.iterator();
while(iterator.hasNext()){
//获取每个通信通道
Session session = (Session)iterator.next();
try {
//向每个用户广播一条消息
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//session关闭时候的触发的方法
@OnClose
public void close(Session session) {
//在浏览器关闭时需要,将该session从List中移除,否则再进行广播的时候,该还会遍历这
//个已经移除的session,将会报错
this.sessions.remove(session);
this.names.remove(this.username);
Message message = new Message();
message.setWelcom(this.username + "已退出聊天室!");
message.setUsernames(this.names);
broadcast(this.sessions, message.toJson());
}
private static Gson gson = new Gson();
//接受到来自客户端发送的消息
@OnMessage
public void message(Session session, String json) {
//将json字符串转成ContentVo对象
ContentVo vo = gson.fromJson(json, ContentVo.class);
if(vo.getType()==1) {//广播
Message message = new Message();
message.setContent(this.username,vo.getMsg());
//这里不再是广播,而是选择性进行发送
broadcast(sessions, message.toJson());
} else {//单聊
String to = vo.getTo();
Session to_session = this.map.get(to);
Message message = new Message();
message.setContent(this.username, "<font color=red>私聊:</font>"+vo.getMsg());
try {
//发送消息
to_session.getBasicRemote().sendText(message.toJson());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
登录跳转的Servlet:
package com.hhu.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class LoginServlet
*/
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//从提交的表单中获取“username”的值
String username = request.getParameter("username");
System.out.println("进入Servelet");
//将这个名字放到session中
request.getSession().setAttribute("username", username);
System.out.println("表单提交成功username=" + username);
//跳转到另一页面
response.sendRedirect("chart.jsp");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
两个用于发送消息的工具类
package com.hhu.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.google.gson.Gson;
/**
* 消息包装类
* @author Weiguo Liu
*
*/
public class Message {
private String welcom;
private List<String> usernames;
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public void setContent(String name,String msg) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
this.content = sdf.format(new Date()) + "<br/>" + name + ":" + msg + "<br/>";
}
public String getWelcom() {
return welcom;
}
public void setWelcom(String welcom) {
this.welcom = welcom;
}
public List<String> getUsernames() {
return usernames;
}
public void setUsernames(List<String> usernames) {
this.usernames = usernames;
}
public Message() {
super();
}
private static Gson gson = new Gson();
public String toJson() {
return gson.toJson(this);
}
@Override
public String toString() {
return "Message [welcom=" + welcom + ", usernames=" + usernames + "]";
}
}
package com.hhu.util;
public class ContentVo {
private String to;
private String msg;
private Integer type;
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
}
最后是登录界面只是简单的进行模拟,这里仅给出聊天室的界面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>聊天室</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/resources/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
//var username = "${sessionScope.username}";
/*当然也可以用上面的写法,这里需要注意的是一定要加引号,通过el表达式获取的是
*一个变量,只有加了引号才是字符串
*/
var username = '${username}';
//进入页面就直接打开socket通道
var ws;
var target = "ws://localhost:8080/WebChat/chatSocket?username="+username;
window.onload = function() {
//判定浏览器是否支持websocket协议
if('WebSocket' in window) {
ws = new WebSocket(target);
} else if('MoWebSocket' in window) {
ws = new MozWebSocket(target);
} else {
alert("当前浏览器不支持WebSocket");
return;
}
//接受来自服务器的消息,返回一个事件对象,具体的返回内容在data属性中
ws.onmessage = function(event) {
//由于传过来的变成了json内容的字符串,所以这里所处理,eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码
eval("var msg=" + event.data + ";");
if(undefined!=msg.welcom){
//在div中追加消息
$("#content").append(msg.welcom+"</br>");
}
if(undefined!=msg.usernames){
//刷新的时候清空用户列表,否则刷新会造成用户的重复添加
$("#userList").html("");
//这是遍历的用户列表
$(msg.usernames).each(function(){
$("#userList").append("<input type=checkbox value='" + this +"'/>" + this + "</br>");
});
}
//接受到服务端的消息后
if(undefined!=content) {
//在聊天追加用户发送的内容
$("#content").append(msg.content);
}
}
}
//向后发送消息
function subSend() {
//获取输入框中的值,这里的获取和清空都是jquery中的写法
var val = $("#msg").val();
console.info("msg===" + val);
//清空输入框中的值
$("#msg").val("");
//获取复选框选中了几个,这里注意有的时候写成size(),有时写成length,根据jquery的版本不同做适当调整
console.info($('#userList :checked').length);
var obj = null;
if($('#userList :checked').length==0) {
obj = {
msg:val,
type:1//1表示广播 2表示单聊
}
} else {
//获取发送对象,即复选框中的选中值
var to = $('#userList :checked').val();
//获取复选框中的选中值
console.info(to);
obj = {
to:to,
msg:val,
type:2//1表示广播 2表示单聊
}
}
var str = JSON.stringify(obj);//将obj转换成JSON字符串
ws.send(str);
$("#msg").val("");
}
</script>
</head>
<body>
<!--聊天的主体窗口 -->
<div id="container" style="border: 1px solid black;width: 400px;height: 400px;float: left;">
<div id="content" style="height: 350px;">
</div>
<div style="border-top: 1px solid black;width: 400px;height: 55px;">
<input id="msg" style="border: 1px solid white;width: 348px;height:55px;"/>
<button onclick="subSend()">发送</button>
</div>
</div>
<!-- 聊天用户列表 -->
<div id="userList" style="border: 1px solid black;width: 100px;height: 390px;float: left;">
</div>
</body>
</html>
最后再来一个在线聊天的加强版来说明SpringMVC中websocket的使用,这个案例很管用!!!
(Eclipse–>SpringWebSocket)
websocket的配置文件
/**
* WebScoket配置处理器
*/
@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();
}
}
HandShake处理类
/**
* 每次建立连接都会进行握手
* @author Weiguo Liu
*
*/
public class HandShake implements HandshakeInterceptor {
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> 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) {
}
}
拦截器
@Component
public class MyWebSocketHandler implements WebSocketHandler {
public static final Map<Long, WebSocketSession> userSocketSessionMap;
static {
userSocketSessionMap = new HashMap<Long, WebSocketSession>();
}
/**
* 建立连接后
*/
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<Entry<Long, WebSocketSession>> it = userSocketSessionMap
.entrySet().iterator();
// 移除Socket会话
while (it.hasNext()) {
Entry<Long, WebSocketSession> 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<Entry<Long, WebSocketSession>> it = userSocketSessionMap
.entrySet().iterator();
// 移除Socket会话
while (it.hasNext()) {
Entry<Long, WebSocketSession> 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<Entry<Long, WebSocketSession>> it = userSocketSessionMap
.entrySet().iterator();
// 多线程群发
while (it.hasNext()) {
final Entry<Long, WebSocketSession> 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);
}
}
}
Spring中的配置:
<mvc:annotation-driven />
<mvc:resources location="/resources/" mapping="/resources/**" />
<context:component-scan base-package="com.hhu" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1" />
</bean>
web.xml中常规配置即可,记得加上Spring的DispatcherServlet
前端界面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getServerName() + ":"
+ request.getServerPort() + path + "/";
String basePath2 = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script type="text/javascript" src="<%=basePath2%>resources/jquery.js"></script>
<style>
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%;
}
</style>
<script>
var path = '<%=basePath%>';
var uid=${uid eq null?-1:uid};
if(uid==-1){
location.href="<%=basePath2%>";
}
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("<div class='fmsg'><label class='name'>"+data.fromName+" "+data.date+"</label><div class='"+textCss+"'>"+data.text+"</div></div>");
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("<div class='tmsg'><label class='name'>我 "+new Date().Format("yyyy-MM-dd hh:mm:ss")+"</label><div class='tmsg_text'>"+data.text+"</div></div>");
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();
}
</script>
</head>
<body>
欢迎:${sessionScope.name }
<div id="content"></div>
<input type="text" placeholder="请输入要发送的信息" id="msg" class="msg" onkeydown="send(event)">
<input type="button" value="发送" class="send" onclick="sendMsg()" >
<input type="button" value="清空" class="clear" onclick="clearAll()">
</body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath= request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script type="text/javascript" src="<%=basePath%>resources/jquery.js"></script>
<script type="text/javascript">
var path='<%=basePath%>';
function broadcast(){
$.ajax({
url:path+'msg/broadcast',
type:"post",
data:{text:$("#msg").val()},
dataType:"json",
success:function(data){
alert("发送成功");
}
});
}
</script>
</head>
<body>
发送广播
<textarea style="width:100%;height:300px;" id="msg" ></textarea>
<input type="button" value="发送" onclick="broadcast()">
</body>
</html>