前面间学习了java io的编程,后来感觉光只是看这些收获甚微,于是就自己做了一个简单的聊天室。基于java socket的聊天室,实现了客户端,实现了[b]群聊,私聊,发送表情,互相发送文件,查看聊天记录,以及一些相关的设置[/b];服务器端实现了[b]发送系统公告,以及踢人[/b]的功能。具体的代码,我上传在附件里面。
首先,介绍一个系统的总体架构,基于c/s模式的java聊天室,采用socket编程,当然,传输数据,我采用的是tcp协议,在服务器端进行监听,每次加入一个新的用户,就开辟一个新的线程用于监听这个用户的动态。当然,这种方式可能不是很科学,但由于知识有限,只能简单的应用。
/**
* 功能:启动服务器
*/
public static void startServer() {
try {
server = new ServerSocket(port);
flag = true;
System.err.print("服务器已经启动,正在监听用户线程.....");
} catch (Exception e) {
System.out.println("异常");
System.err.println(e);
}
while (flag) { // 死循环
Socket socket = null;
try {
socket = server.accept();
ServerThread cp = new ServerThread(socket); // 启动一个用户线程
System.out.println("新进入一个用户");
cp.setIndex(count + 1);
Thread ct = new Thread(cp);
ct.start();
addConnection(socket, cp);
count++;
} catch (IOException e) {
System.err.println(e);
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
另外还有一个服务器新建的线程类,ServerThread 由于过长,就不粘贴了。ServerThread 是实现Runnable接口的,里面含有,线程的名称(我这里用的用户的昵称作为参数),线程的索引(也就是在用户列表中的位置),以及ip地址(为了实现俩个聊天用户发送文件),以及socket。
[b]需要说明的我的整体思路[/b]
用户端能够进行登录,注册,以及其他一些功能,ServerThread用户监听用户发来的数据。我在这里采用的字符流来进行发送(开始的时候,我采用的是ObjectStream,后来发现这样的传输效率很低,而且经常容易出错,这里不知道为什么),所以后来我就采用了字符流来进行传输数据。
当然,java 是面向对象的思想,我还是将一些东西创建了实体类,如MessageModel
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package chatroom.com.entity;
/**
*
* @author Administrator
*/
import java.io.Serializable;
import java.util.Date;
public class MessageModel{
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String fromWho;// 谁说的
private String toWho;// 对谁说
private String dongzuo;// 动作是什么
private int biaoqing;// 表情是什么
private String ziti;// 字体
private String yanse;// 颜色
private String daxiao;// 大小
private String yangshi;// 样式
private String content;// 内容
private int isSiliao;// 是否私聊
private Date sendTime;
/**
* 功能:将字符串转换后MessageModel对象
* @param str
* @return
*/
public static MessageModel getMsgByString(String str) {
String rs[] = str.split("&");
MessageModel msg = new MessageModel();
msg.setFromWho(rs[1]);
msg.setToWho(rs[2]);
msg.setDongzuo(rs[3]);
msg.setBiaoqing(Integer.parseInt(rs[4]));
msg.setZiti(rs[5]);
msg.setYanse(rs[6]);
msg.setDaxiao(rs[7]);
msg.setYangshi(rs[8]);
msg.setContent(rs[9]);
msg.setIsSiliao(Integer.parseInt(rs[10]));
return msg;
}
/**
* 功能:将MessageModel对象转换成字符串
* @param msg
* @return
*/
public static String getStringByMessage(MessageModel msg) {
return msg.getFromWho() + "&" + msg.getToWho() + "&" + msg.getDongzuo()
+ "&" + msg.getBiaoqing() + "&" + msg.getZiti() + "&"
+ msg.getYanse() + "&" + msg.getDaxiao() + "&"
+ msg.getYangshi() + "&" + msg.getContent() + "&"
+ msg.getIsSiliao();
}
@Override
public String toString() {
return "MessageModel [id=" + id + ", fromWho=" + fromWho + ", toWho="
+ toWho + ", dongzuo=" + dongzuo + ", biaoqing=" + biaoqing
+ ", ziti=" + ziti + ", yanse=" + yanse + ", daxiao=" + daxiao
+ ", yangshi=" + yangshi + ", content=" + content
+ ", isSiliao=" + isSiliao + ", sendTime=" + sendTime + "]";
}
还有一些setter,geter方法
}
[b]另外,对于聊天记录的读写,我采用的是文件的操作,主要是按行写入文件,按行读取文件,这里,我稍微做了一些改动,能够实现分页读取聊天记录。[/b]
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package chatroom.com.util;
import chatroom.com.chatEvent.Chat;
import java.io.*;
import javax.swing.JTextPane;
/**
*功能:将记录按行写入文件中, 另外可以实现从文本文件中按行读取记录,同时能够实现分页读取文本文件的内容
* @author 李朋飞
*/
public class FileForJiluUtil {
public static void createNewFile(String fileName) throws IOException {
File myFilePath = new File(fileName);
if (!myFilePath.exists()) {
myFilePath.createNewFile();
}
}
public static void appendJiluToFile(String fileName, String jilu) {
try {
createNewFile(fileName);
// write string to file
FileWriter writer = new FileWriter(fileName, true);
BufferedWriter bw = new BufferedWriter(writer);
bw.write(jilu);
// bw.newLine();//如果是加了这个,会在文本文件里面显示了另外一行,不加的话,看到是连续的,也就是不是换行的,即使我的jilu字符串后面加了 \n
bw.flush();
bw.close();
writer.close();
} catch (IOException e) {
}
}
private static int pageSize = 16;
/**
* anhang分页读取文件里面的内容
*
* @param pageNo
* @param fileName
*/
public static int readFileByPage(int pageNo, String fileName, JTextPane pane) {
File file = new File(fileName);
BufferedReader reader = null;
try {
System.out.println("以行为单位读取文件内容,一次读一整行:");
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 0;
int index = 1;
//一次读入一行,直到读入null为文件结束,由于我在写入文本文件的时候,在每个字符串后面都加了 \n,所以查看的时候,会在基数行显示内容,偶数行显示空字符串。所以加了一个偶数行的判断
while ((tempString = reader.readLine()) != null) {
//显示行号
if (index % 2 != 0) {
line++;
if (line > (pageNo - 1) * pageSize && line <= pageNo * pageSize) {
System.out.println("line " + line + ": " + tempString);
Chat.insertIntoHistoryPane(pane, line+": " + tempString);
}
}
index = index + 1;
if (line > pageNo * pageSize) {
break;
}
}
reader.close();
} catch (IOException e) {
}
return pageNo;
}
/**
* 以行为单位读取文件,常用于读面向行的格式化文件
*
* @param fileName 文件名
*/
public static void readFileByLines(String fileName) {
File file = new File(fileName);
BufferedReader reader = null;
try {
System.out.println("以行为单位读取文件内容,一次读一整行:");
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
//一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
//显示行号
System.out.println("line " + line + ": " + tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
}
[b]关于发送表情,我这里发送的不是表情文件,而是发送表情对应的一些特殊的编号,这个可能有点搓,思路也很垃圾,但还能用[/b]
剩下最后一个问题,就是俩个聊天用户进行互相发送文件,由于对于java io编程以及java 网络编程,都不是很熟悉这个问题困扰了我一天,后来通过查阅资料,结合聊天室整个的流程,终于实现了用户互相传送文件,我这里的思路是当服务器端收到一个用户发来,我要发送文件的请求时,判断这个用户要发给谁,然后,使这俩个用户之间建立连接。发送文件的一方暂时作为服务器,接受方作为客户端。当文件传输成功之后,断开俩人的连接,具体的实现请参考附件源代码
今天终于有机会上传项目源文件了,另外里面包含了系统所需要的jar包。主要是一个mysql的jdbc驱动jar,和一个java mail的jar文件。为了节省空间,只上传了java mail的jar文件,另外mysql的驱动jar,网上太多。
项目运行主要是chatroom里面的server ,及client,先运行server。里面自己做了个找回密码的功能,找回密码是采用的发送邮件的方式