最近在一次偶然的机会下接触到了EasyUI,里面有一个layout的demo和QQ聊天窗口超像,于是萌发了写一个在线聊天室的想法。
实现步骤也非常简单,首先是先创建两个存储数据的表,![图片描述][1]![图片描述][2],分别是保存用户姓名密码的user表,还有保存用户聊天记录的chat表.
建好表了,第一步就是创建对应的类。然后通过MyEclipse搭建一个最简单的SSH框架,![图片描述][3],UserAction主要实现用户的注册和登陆,ChatAction用于聊天数据的传输。
@Controller//用于标注控制层组件
@Namespace("/user")//url前缀
@Scope("prototype")//Action默认是单例,但实际开发中,一般是多例,因为一般一个Action可能会对应多个不同的请求
//@ParentPackage("struts-default")//继承特定的package,默认是“struts-default”,因此可以省略不写
@Results({
@Result(name="loginSuccess",type="redirect",location="/Test/chat.jsp"),
@Result(name="msg",location="/msg.jsp"),
@Result(name="tologin",location="/index.jsp")
})
public class UserAction extends ActionSupport implements ModelDriven<User>{
@Autowired//自动注入
private UserService service ;
private User user=new User();
//struts默认拦截“.action以及不加任何后缀”
@Action(value="login")//访问:/user/regist.action 或 /user/regist
public String login(){
//获取request
HttpServletRequest request = ServletActionContext.getRequest();
//调用service层的方法,向数据库查询
List<User> u =service.loginUser(user);
System.out.println(u+u.toString());
if(u.isEmpty()){
System.out.println("登陆失败");
request.setAttribute("msg", "登陆失败");
return "msg";
}
request.getSession().setAttribute("user", u.get(0));
return "loginSuccess";
//将提示信息存入request域中,用以前台显示
}
@Action(value="regist")
public String regist(){
List<User> u = service.findUserByName(user.getUsername());
HttpServletRequest request = ServletActionContext.getRequest();
if(u.isEmpty()){
service.addUser(user);
request.setAttribute("msg", "注册成功");
return "msg";
}
request.setAttribute("msg", "用户名已被注册");
return "msg";
}
@Override
public User getModel() {
// TODO Auto-generated method stub
return user;
}
}
这里没有对用户名为空等等各种情况的判断,只简单的实现注册和登陆。
@Controller
@Namespace("/chat")
@Scope("prototype")
@Results({
@Result(name="msg",location="/msg.jsp"),
@Result(name="success",location="/Test/chat.jsp",type="redirect")
})
public class ChatAction extends ActionSupport implements ModelDriven<Chat>{
@Autowired
private ChatService chatService;
@Autowired//自动注入
private UserService userService ;
private Chat chat= new Chat();
private int chatnum;
@Action(value="chatAdd")
public void chatAdd(){
chat.setChattime(new Date());
chatService.addChat(chat);
}
//第一次更新
@Action(value="chatUpate")
public String chatUpdate(){
List<Chat> chats=chatService.getChat();
String json = JSONArray.fromObject(chats).toString();
//将json发送给浏览器
try {
ServletActionContext.getResponse().setContentType("application/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("出错了");
e.printStackTrace();
}
return null;//告诉struts2不需要进行结果处理
}
//ajax轮询更新
@Action(value="chatFlash")
public String chatFlash(){
// TODO Auto-generated method stub
try {
while(true){
List<Chat> chatf=chatService.getChatById(chatnum);
if(chatf.isEmpty()){
//睡觉1秒
Thread.sleep(1000);
}else{
String json = JSONArray.fromObject(chatf).toString();
ServletActionContext.getResponse().setContentType("application/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
return null;
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("出错了");
e.printStackTrace();
}
return null;//告诉struts2不需要进行结果处理
}
public int getChatnum() {
return chatnum;
}
public void setChatnum(int chatnum) {
this.chatnum = chatnum;
}
@Override
public Chat getModel() {
// TODO Auto-generated method stub
return chat;
}
}
chatAction主要分三块,插入聊天记录,用户第一次进入聊天室时把记录追加到“聊天记录”的div中,然后通过ajax的方式更新聊天信息到主面板。聊天页面没有才有表单提交的方式,全部通过ajax实现。因为感觉每提交一次,又要从服务器查询一次,追加一次,感觉很费劲。
然后其实最关键的,是冠以聊天记录刷新如何实现,最初的思路是,ajax每隔1S发送一次请求,把查询到的新信息追加到主面板上,虽然这种方式很简单实现,但是感觉很不合理。我的解决方案是,只发送一次ajax请求,服务器接收到请求后死循环,每隔1S查询一次数据库,一旦发现有新的聊天记录(这里是通过判断最新的聊天记录id和网页现存的记录id进行比较),跳出死循环,把新记录返回,把新记录data追加到面板后,又一次发送ajax请求,其实就相当于无限递归。网页源代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!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>Border Layout on Panel - jQuery EasyUI Demo</title>
<link rel="stylesheet" type="text/css" href="../themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="../themes/icon.css">
<link rel="stylesheet" type="text/css" href="demo.css">
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="../jquery-1.7.2.min.js"></script>
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="../jquery.easyui.min.js"></script>
<style>
p{
margin:0 auto;
color:red;
font-size:10px;
}
</style>
<script type="text/javascript">
$(function(){
//发送ajax请求
chatUpdate();
var id=setTimeout(flash,1000);
});
function addChat(){
var chatnum=$("#chatnum").val();
var chattext=$("#chattext").val();
$("#chattext").val("");
var username="${sessionScope.user.username}";
$.post("${pageContext.request.contextPath}/chat/chatAdd",{"chattext":chattext,"username":username},function(){});
}
function flash(){
var chatnum=$("#chatnum").val();
var username="${sessionScope.user.username}";
$.post("${pageContext.request.contextPath}/chat/chatFlash?chatnum="+chatnum,function(data){
$(data).each(function(){
if(username==this.username){
$("#main").append("<p align='right' style='color:green;'>"+this.chattimes+"</p>");
$("#main").append("<p align='right' style='color:green;''> "+this.chattext+"</p>");
}else{
$("#main").append("<p>"+this.username+" "+this.chattimes+"</p>");
$("#main").append("<p> "+this.chattext+"</p>");
}
chatnum=this.id;
});
$("#chatnum").val(chatnum);
flash();
},"json");
}
function chatUpdate(){
var username="${sessionScope.user.username}";
var num=0;
$.post("${pageContext.request.contextPath}/chat/chatUpate",function(data){
$(data).each(function(){
if(username==this.username){
$("#east").append("<p align='right' style='color:green;'>"+this.chattimes+"</p>");
$("#east").append("<p align='right' style='color:green;''> "+this.chattext+"</p>");
}else{
$("#east").append("<p>"+this.username+" "+this.chattimes+"</p>");
$("#east").append("<p> "+this.chattext+"</p>");
}
num=this.id;
});
$("#chatnum").val(num);
},"json");
}
</script>
</head>
<body>
<h2>欢迎<s:property value="#session.user.username"/>加入聊天室</h2>
<div class="demo-info" style="margin-bottom:10px">
<div class="demo-tip icon-tip"></div>
<div>This is a chat-room.</div>
</div>
<div class="easyui-layout" style="width:700px;height:400px;">
<div region="north" style="overflow:hidden;height:60px;padding:10px">
<h2>JAVA 聊天室</h2>
</div>
<div region="south" split="true" style="height:120px;background:#fafafa;overflow:hidden;">
<form action="${pageContext.request.contextPath}/chat/chat" method="post" style="width:100%;height:100%;">
<textarea name ="chattext" id="chattext" style="width:99%;height:99%;overflow:hidden;">
重点是 flash()的无限调用,看懂就明白了。
于是乎,java在线聊天1.0版本就上线了,有没有同学有兴趣进行2.0版本的升级呢,增加在线私聊的功能,左侧的面板正好可以用作显示在线人数,问题是如何实现弹窗。可恶刚才写的没了,又写一遍。