首页 > 技术文章 > 基于servlet和ajax的聊天室

shenzhi 2017-06-16 16:57 原文

  (手贱点了更新发布时间,发布时间变成6-9。。。)

  2017-5-20,在这个奇特的日子,我不再满足于在本地测试javaweb,于是在上腾讯云买了第一个云服务器,由于是学生认证,所以一个月只要10块钱,还是要抢的,每天早上9点开抢(腾讯云的学生优惠活动好像取消了,所以我又选择了阿里云)打开后,发现其实是一个云主机,就是远程主机,只不过他可以给你一个公网ID,就是在浏览器输入公网ID的话,全国所有人都可以访问你的项目

  关于怎么把自己的javaweb项目放到云主机,有一个教程http://www.cnblogs.com/diyunfei/p/6826557.html,前提是得先在云主机下载配置jkd,tomcat

  安装eclipse后先安装servers,在help中的安装软件,输入http://download.eclipse.org/releases/kepler,选择Web,XML, java EE and OSGi Enterprise Development 

  配置jdk

    新建 JAVA_HOME 变量 。

    变量值填写jdk的安装目录

 

    寻找 Path 变量

    在变量值最后输入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

    (注意原来Path的变量值末尾有没有;号,如果没有,先输入;号再输入上面的代码)

 

    新建 CLASSPATH 变量

     .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一点)

 

    检验是否配置成功 运行cmd 输入 java -version (java 和 -version 之间有空格)

    若如图所示 显示版本信息 则说明安装和配置成功。

 

  配置tomcat

    新建CATALINA_HOME,变量值是tomcat的安装路径

    找到PATH,在最后增加tomcat的bin文件的绝对路径(我的就是F:\eclipse\apache-tomcat-7.0.77\bin)

    配置后可以在浏览器输入localhost:8080,试试看可以可以访问tomcat的主页,如果可以即为配置成功

  

  云主机全部准备好了之后,可以把在本机的eclipse中的maven项目导出成一个war包,复制这个war包到云主机,放到tomcat的webapp的目录下,打开tomcat/bin里的start.bat,然后就可以在别的电脑通过“公网ID:端口号/项目名/”的方式访问该项目

 

 

 ----------------------------------------------------------------------------------------------------------------------------------

 

 

 下面开始说我这个项目,是跟我室友合作的,前端页面是他做的,这个是一个多人即时聊天室,在此之前没有接触过怎么实现即时聊天,走了很多弯路,不过幸好可以说是摸出点门道。

一、实现效果如下:

1、先进入登录界面,输入呢称和选择头像后进入

2、进入后的界面是这样的:

3、然后就可以输入聊天内容了

 

二、主要逻辑代码

因为我现在只会后端,就不把前端的代码贴出来了,主要逻辑是建立在servlet和ajax通信之上

1、我使用maven来构建这个项目,不过我这里并没有用maven来导入包,因为就几个包,我就手动导入项目结构如下

 

2、Control类用来接收用户名,头像id,聊天内容,然后生成一个系统当前时间,把这4个当成参数传给Model,这里先说一下为什么要生成一个系统当前时间,这就说到我遇到的另一个问题了,本来我们是商量说让前台把用户名,头像id,聊天内容,用户当前时间也传过来,但是发现效果并不好,因为如果涉及到多人同时聊天,各个客户端的当前时间不一定会一样,会造成一些请求得不到正确的响应,然后就想了个办法,客户端在发送聊天记录这条请求时,只发送用户名,头像id,聊天内容,然后由服务器生成时间作为响应返回,然后把4个属性传给Model

 1 public class Control extends HttpServlet {
 2 
 3     @Override
 4     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 5 
 6         doGet(req, resp);
 7     }
 8 
 9     @Override
10     protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
11             throws ServletException, IOException {
12 
13         // 接受聊天记录不发送东西:1
14         req.setCharacterEncoding("utf-8");
15 
16         String username = req.getParameter("username");// 用户名
17         String content = req.getParameter("content");// 内容
18         String pic = req.getParameter("picture");
19         SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");// 设置日期格式
20             
21         String time = df.format(new Date());
22     
23         String callbackName = req.getParameter("jsoncallback");// 时间
24         // -------------------------------------------------------------------------
25 
26         try {
27             new Model();
28             Model.write(username, content, time, pic);
29         } catch (ClassNotFoundException e) {
30             e.printStackTrace();
31         }
32         String success = "success";
33         String result = "{\"success\":\"" + success + "\",\"time\":\"" + time + "\"}";
34 
35         String renderStr = callbackName + "(" + result + ")";
36         resp.setContentType("text/plain;charset=UTF-8");
37         resp.getWriter().write(renderStr);
38     }
39 
40 }

这里的success只是为了给前台做判断。。里面的time也是前台用来给聊天内容打时间标签用的,json数据是动态拼接的,然后以callbackname作为函数名,直接返回一个字符串

 

2、Model类是做数据处理的,就是把4个属性存到keyvaluepair对象中,然后在把对象存到Arraylist中,Model里有3个方法:

(1)fileinit()方法是初始化一个流,打开txt文件的开口,(其实这里我本来是想用mybatis,但是时间仓促我就说先存在txt里凑合吧,以后找时间改一下)

(2)write()是把4个属性追加到文件尾,这里遇到的问题是,写到文件里的中文变成了乱码,所以我就把他处理了一下URLDecoder.decode(username, "UTF-8");

(3)getContent()方法是用来提取数据用的,用的key就是时间

  1 public class Model {
  2     public static BasicDataSource ds = null;
  3 
  4     public final static String JDBC_DRIVER = "com.mysql.jdbc.Driver";
  5     public final static String USER_NAME = "root";
  6     public final static String PASSWORD = "123456";
  7     public final static String DB_URL = "jdbc:mysql://localhost/shen_db?useUnicode=true&characterEncoding=utf-8&useSSL=false";
  8 
  9     public static FileWriter writer = null;
 10     public static OutputStreamWriter osw = null;
 11     public static FileOutputStream fos = null;
 12     static List<KeyValuePair> list = new ArrayList<KeyValuePair>();// 创建一个arraylist,把键值对象保存在其中
 13 
 14     public Model() {
 15         fileInit();
 16     }
 17 
 18     // public static void dbcpInit() {
 19     // ds = new BasicDataSource();
 20     // ds.setUrl(DB_URL);
 21     // ds.setDriverClassName(JDBC_DRIVER);
 22     // ds.setUsername(USER_NAME);
 23     // ds.setPassword(PASSWORD);
 24     //
 25     // }
 26     public static void fileInit() {
 27         String fileName = "C:\\a.txt";
 28         try {
 29             fos = new FileOutputStream(fileName, true);
 30         } catch (FileNotFoundException e1) {
 31             e1.printStackTrace();
 32         }
 33         try {
 34             osw = new OutputStreamWriter(fos, "UTF-8");
 35         } catch (UnsupportedEncodingException e1) {
 36             e1.printStackTrace();
 37         }
 38     }
 39 
 40     public static void write(String username, String content, String time, String pic)
 41             throws ClassNotFoundException {
 42         // Connection connection = null;
 43         // PreparedStatement preparedStatement = null;
 44         String x = null;
 45         String y = null;
 46         try {
 47             x = URLDecoder.decode(username, "UTF-8");
 48             y = URLDecoder.decode(content, "UTF-8");
 49         } catch (UnsupportedEncodingException e1) {
 50             e1.printStackTrace();
 51         }
 52         String z = time;
 53         String p = pic;
 54         System.out.println("发送东西来的内容:" + y); 57 
 58         list.add(new KeyValuePair(z, x, y, p));
 59         try {
 60             osw.write(KeyValuePair.getKey());
 61             osw.write("---");
 62             osw.write(KeyValuePair.getPic(z));
 63             osw.write("---");
 64             osw.write(KeyValuePair.getName(z));
 65             osw.write("---");
 66             osw.write(KeyValuePair.getContent(z));
 67             osw.write("\r\n");
 68         } catch (IOException e) {
 69             e.printStackTrace();
 70         } finally {
 71             try {
 72                 if (osw != null) {
 73                     osw.close();
 74                 }
 75             } catch (IOException e) {
 76                 e.printStackTrace();
 77             }
 78         }
 79 
 80         // try {
 81         // connection = ds.getConnection();
 82         // preparedStatement = connection.prepareStatement("insert into Chatlog
 83         // (time,logs) values (?,?)");
 84         // preparedStatement.setString(1, currentTime);
 85         // preparedStatement.setString(2, x);
 86         // } catch (SQLException e) {
 87         //
 88         // e.printStackTrace();
 89         // }
 90 
 91     }
 92 
 93     public static KeyValuePair getContent(String time) {
 94 
 95         String time1 = time;
 96         KeyValuePair kvp = null;
 97         if (list.isEmpty()) {
 98         } else {
 99             for (KeyValuePair ss : list) {
100                 if (time1.equals(ss.getKey())) {
101                     kvp = ss;
102                 } else {
103                     kvp = null;
104                 }
105             }
106         }
107         return kvp;
108     }
109 
110     public static void main(String[] args) {
111 
112         new Model();
113     }
114 
115 }

 

3、GetCurrentTime这个类就是用来返回当前时间的

public class GetCurrentTime extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        String callbackName = req.getParameter("jsoncallback");
        System.out.println("get current time");
        String time = null;
        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
        time=df.format(new Date());
        String result=null;
        result="{\"time\":\""+time+"\"}";
        String renderStr = callbackName + "(" + result + ")";
        resp.setContentType("text/plain;charset=UTF-8");
        resp.getWriter().write(renderStr);
        
    }

}

 

4、SendServlet这个类是用来提取聊天数据的,前台在GetCurrentTime那个servlet中接收到我的系统时间后,把这个系统时间当成一个参数然后发送一个请求到SendServlet,然后我就去调用Model的getcontent(),返回一个keyvaluepair对象,

利用这个对象调出所有数据,可以看到json数据都是动态拼接的方法做成的,甚是拙劣

 1 public class SendServlet extends HttpServlet {
 2 
 3     @Override
 4     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 5         doPost(req, resp);
 6     }
 7 
 8     @Override
 9     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
10 
11         
12         String time = req.getParameter("time");
13         System.out.println("时间"+time);
14         KeyValuePair kvp = null;
15         String result = "{\"content\":\"" + null + "\",\"time\":\"" + null + "\",\"name\":\"" + null
16                 + "\",\"picture\":\"" + null + "\"}";
17         String callbackName4 = req.getParameter("jsoncallback");
18 
19         try {
20             kvp = Model.getContent(time);
21             System.out.println(kvp);
22             if (kvp != null) {
23                 result = "{\"content\":\"" + kvp.getContent(time) + "\",\"time\":\"" + kvp.getKey() + "\",\"name\":\""
24                         + kvp.getName(time) + "\",\"picture\":\""+kvp.getPic(time) +"\"}";
25             }
26             kvp = null;
27             String renderStr = callbackName4 + "(" + result + ")";
28             resp.setContentType("text/plain;charset=UTF-8");
29             resp.getWriter().write(renderStr);
30 
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34     }
35 
36 }

 

5、keyvaluepair对象时用来保存那4个属性的bean,就一个构造函数和4个get方法

public class KeyValuePair {

    public static String Key;
    public static String Name;
    public static String Content;
    public static String Pic;

    public KeyValuePair(String k, String n,String c,String p) {
        Key = k;
        Name = n;
        Content =c;
        Pic=p;
    }
    
    public static String getName(String k){
        return Name;
    }
    public static String getPic(String k){
        return Pic;
    }
    public static String getKey(){
        return Key;
    }
    public static String getContent(String k){
        return Content;
    }
    
    public static void main(String[] args) {

    }
}

 

三、还存在的问题

1、当用户输入很快的时候有时候会丢失聊天数据

2、里面没有把聊天数据保存到数据库,而是单纯保存在Arraylist中和txt中,一旦宕机重启,后果很严重。。。关于mysql数据库,以前用的都是解压版,在windowserver2012好像不能用,反正我试了好多次都不行,到最后迫不得已下载了安装版,才把mysql搞定。(虽然我里面没用到数据库。。。==)安装版数据库教程

3、servlet怎么跟ajax异域通讯,那时候还没有学spring,所以纠结了很久,查了资料到最后发现是通过一个很不“优雅”的方式进行通信的,就是强行拼接一个json数据类型,不知道还有没有更好的方法

4、不能查看聊天记录

5、在学习sockets中。。

 

推荐阅读