一对一网页聊天 jsp+js+ajax+servlet+tomcat+mysql

来源:互联网 发布:c语言99乘法表的输出 编辑:程序博客网 时间:2024/05/28 11:30

初学javaweb,很想做一个网页版的一对一聊天系统,但是在网上查了一下发现并没有相应的资源,网页聊天室倒是有很多,一个原因是B/S与C/S相比不适合做实时通讯,另外可能是一对一聊天做起来比较难(我一开始认为的)。做的时候确实遇到了难题,两人交互不知道怎样进行,不知道怎样设计数据库等,后来参照聊天室,得到了一些想法,就尝试去做,调试很久之后终于可以运行了!下面具体介绍一对一聊天交互的实现。
聊天页面:jsp+js+ajax
jsp代码主要用于消息显示框和输入框,以及获取参数,设置参数
js+ajax 是比较重要的,用于向servlet发送请求,保证聊天的正常进行,除了自己发送消息的请求,还包括每隔1秒请求一次servlet获取更新的消息
servlet:
TalkServlet:用于处理自己发送消息的请求
TalkFromServlet:用于处理更新页面消息的请求,每秒钟会接收一次

截图1
截图2
chat.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <title>chat</title>      <%!       //设置为全局变量,以便js中传递参数        String fname; //fname为正在聊天的朋友的名字,需要传递给servlet      %>      <%        //防止中文乱码        fname = new String(request.getParameter("fname").getBytes("iso-8859-1"), "utf-8");      %>    <script type="text/javascript">     function createXMLHttpRequest(){            try{                return new XMLHttpRequest();            }catch(e){                try{                    return ActiveXObject("Msxml2.XMLHTTP");                }catch(e){                    try{                        return ActiveXObject("Microsoft.XMLHTTP");                     }catch(e){                        throw(e);                    }                }            }        }        //自己发送消息        function chat(){            var xmlHttp=createXMLHttpRequest();            xmlHttp.open("POST","<c:url value='/TalkServlet'/>",true);            xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");            var message=document.getElementById("text").value;            var input=document.getElementById("text");            input.value="";            xmlHttp.send("fname=<%=fname%>&message="+message);            xmlHttp.onreadystatechange=function(){            if(xmlHttp.readyState==4&&xmlHttp.status==200){                    var text=xmlHttp.responseText;                    var tr=document.getElementById("textarea");                    tr.innerHTML=text;                    /* tr.scrollTop=tr.scrollHeight; */                    }            }        }        //接收对方发送消息        function chat_from(){            var xmlHttp=createXMLHttpRequest();            xmlHttp.open("POST","<c:url value='/TalkFromServlet'/>",true);            xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");            xmlHttp.send("fname=<%=fname%>");            xmlHttp.onreadystatechange=function(){            if(xmlHttp.readyState==4&&xmlHttp.status==200){                    var text=xmlHttp.responseText;                    var tr=document.getElementById("textarea");                    tr.innerHTML=text;                    tr.scrollTop=tr.scrollHeight;//每次更新消息都使下拉框处在最底端,方便阅读消息                    }            }        }        //每隔一秒向服务器发送一次请求,查看是否有新消息        setInterval(chat_from,1000);    </script>  </head>  <body><div><%=this.fname %></div>    <div id="textarea" style="height:100;width:500;overflow:auto;border-style:solid;border-width:1pt; border-color:blue;">    </div>    <input type="text" id="text" autofocus="true" onkeydown="if(event.keyCode==13){send.click();}"/>    <input type="button" id="send" value="发送" onclick="chat();"/>  </body></html>

上面是聊天页面的设计,以及使用ajax实现聊天消息的发送与更新

TalkServlet

package cn.chat.web.servlet;import java.io.IOException;import java.util.ArrayList;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import cn.chat.domain.Chat;import cn.chat.domain.User;/** * Servlet implementation class TalkServlet */@WebServlet("/TalkServlet")/** * 对应用户发消息的处理 *  * */public class TalkServlet extends HttpServlet {    private static final long serialVersionUID = 1L;    /**     * @see HttpServlet#HttpServlet()     */    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        // TODO Auto-generated method stub        request.setCharacterEncoding("utf-8");        response.setContentType("text/html;charset=utf-8");        //获取用户(登陆时已保存在session中)        User user = ((User) request.getSession().getAttribute("sessionUser"));        String uname = user.getUsername();        /**         * servlet是线程不安全的,但是局部变量并不会共享,所以把获取的参数保存在局部变量中可以保证参数的线程安全         *          * 局部变量需要先声明后赋值,而不是直接在声明时就赋值         *          * 这点很重要         *          * */        //错误示范,如果这样的话,将会出现线程异常        /*String fname = request.getParameter("fname");        String message = request.getParameter("message");*/        String fname = "";        String message = "";        String msg = "";        String msg2 = "";        //获得参数值        fname = request.getParameter("fname");        message = request.getParameter("message");        Chat chat = new Chat(); //新建一个对话        chat.setUname(uname);        chat.setFname(fname);        Chat chat2 = new Chat();        chat2.setFname(uname);        chat2.setUname(fname);        //从application域中获取已存在的对话列        ArrayList<Chat> ac = (ArrayList<Chat>) request.getServletContext()                .getAttribute("chatList");        //如果为空,则新建一个        if (ac == null) {            ac = new ArrayList<Chat>();        } else {            /**             * 在已存在对话列中查找当前对话,uname为用户名,fname为对方名字             * 如果存在则取出message,并将该对话从列表中移除(更新message后再放回去)             * */            for (Chat c : ac) {                if (c.getFname().equals(fname) && c.getUname().equals(uname)) {                    msg += c.getMessage();                    ac.remove(c);                    break;//不能省略,以为list已经改变,继续迭代遍历的话会报异常                }            }            /**             * 在已存在对话列中查找当前对话,uname为对方名字,fname为用户名             * 如果存在则取出message,并将该对话从列表中移除(更新message后再放回去)             *              * 因为两人对话是没有主次之分的,对话消息的保存不能只有一方,否则在聊天页面可能只显示对方的消息,而没有自己已经发送的消息             * 另外,保存两份,在信息显示时也可以分开,像qq那样,消息分为两侧,在后期优化UI时比较方便             * */            for (Chat c : ac) {                if (c.getFname().equals(uname) && c.getUname().equals(fname)) {                    msg2 += c.getMessage();                    ac.remove(c);                    break;                }            }        }        //如果没输入消息不小心点了发送,保证不会出错        if (!message.trim().isEmpty()) {            //自己保存的消息            msg = msg + "<div style='float:right;'>" + message + ":" + uname                    + "</div><br>";            //对方保存的消息            msg2 = msg2 + uname + ":" + message + "<br>";        }        //将更新后的对话保加入list        chat.setMessage(msg);        ac.add(chat);        chat2.setMessage(msg2);        ac.add(chat2);        //将对话列保存到application域中,这样才能完成不同浏览器之间的交互        request.getServletContext().setAttribute("chatList", ac);        //返回结果给页面        response.getWriter().print(msg);    }}

TalkFromServlet

package cn.chat.web.servlet;import java.io.IOException;import java.util.ArrayList;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import cn.chat.domain.Chat;import cn.chat.domain.User;/** * Servlet implementation class TalkFromServlet */@WebServlet("/TalkFromServlet")/** * 对应接收消息 *  * */public class TalkFromServlet extends HttpServlet {    private static final long serialVersionUID = 1L;    protected void doPost(HttpServletRequest request,            HttpServletResponse response) throws ServletException, IOException {        // TODO Auto-generated method stub        request.setCharacterEncoding("utf-8");        response.setContentType("text/html;charset=utf-8");        // 获取用户,若未保存说明没有登录,无法进行对话        User user = (User) request.getSession().getAttribute("sessionUser");        if (user == null) {            response.getWriter().print("");        } else {            String uname = user.getUsername();            String fname = "";            String msg = "";            fname = request.getParameter("fname");            ArrayList<Chat> ac = (ArrayList<Chat>) request.getServletContext().getAttribute("chatList");            /**             * 在对话列存在的情况下,获取保存的message,用于显示在页面上,因为保存了两份,在对方发送消息后,自己保存的message也会更新,             * 所以每隔一秒访问一次该servlet可以更新页面对话             *              * 如果不存在对话列则返回空串,保证程序的健壮性             * */            if (ac != null) {                for (Chat c : ac) {                    if (c.getFname().equals(fname)                            && c.getUname().equals(uname)) {                        msg = c.getMessage();                        break;                    }                }                response.getWriter().print(msg);            } else {                response.getWriter().print("");            }        }    }}

上面就是一对一聊天系统实现的核心代码,因为经验较少,所以在文件及变量命名上有缺点,代码风格也不是很好,希望看到的能指教一二。
另外每隔1s的轮询占用很多带宽,想用websocket实现,但是对websocket不熟悉,所以,希望有感兴趣的大神能够给些思路,谢谢了!
完整源码已上传至资源,源码下载链接

2 0