Java聊天软件 | Project

1、项目基本描述:

1.1项目名称:

Java聊天工具

1.2开发工具:

相关技术:MySQL + Swing + Socket 开发工具:Eclipse

1.3项目描述:

该软件能快速的注册一个账号,简单几步就可以查找好友并添加好友,以及系统处理结果的合理的提示,发送软件自带的一套兔斯基的gif图片,震屏效果,和传送任何类型的文件,基本上符合了现在人们对于即时聊天的需求。

1.4项目技术要点:

Java IO的操作 Java基于TCP的网络编程 MySQL在项目中的使用 Java Swing界面的设计

2、项目功能说明:

基本数据流图: 系统总体结构图: 层次功能图:

3、项目工程

(1) 客户端程序文件说明:

类名 功能 FriendData 保存每个好友的数据类 FriendList 保存好友列表类 FriendMap 保存好友图类 PersonalData 保存自己的数据类 UserManager 管理数据库处理相关函数的类 ChatMainMap 管理主界面的图类 ChatWinMap 管理聊天窗口的图类 ClientConnServerThread 客户端连接到服务器的线程类 ClientThreadMap 管理客户端的线程类 FileClient 接收文件的客户端类 FileServer 发送文件的服务器类 LoginCheck 客户端登录检验类 ConnMySQL 建立连接数据库类 ChatLogin 登录界面类 ChatMain_center 主界面中间部分面板类 ChatMain 主界面类 ChatWindow_right 聊天窗口右侧面板类 ChatWindow 聊天窗口类 ConfirmRequestMessage 确认消息框 MessageBox 自定义普通消息框 Onli① 用户表ne_message 上线消息框 ReceiverFileTransMessage 接收文件确认消息框 ReceiverMessage 消息管理器类 ReceiverRequestMessage 好友请求显示框 Register 注册面板 TransportFile 发送文件的文件选择器 FileTranMes 发送文件携带信息类 Message 发送信息类 MessageType 信息类型 User 用户 ColorTools 自定义颜色工具 FontTools 自定义字体工具 ImagePanel 图片面板

(2) 服务器端程序文件说明:

类名 功能 ChatServer 服务器处理类 ServerConnClientThread 服务器接收线程类 ThreadMap 管理客户端连接到服务器的线程类 ServerWindow 服务器窗口类 Message 发送信息类 MessageType 信息类型 User 用户

(3) 数据库文件结构

① 用户表

+----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +———-+————-+——+—–+———+——-+ | userId | int(11) | NO | PRI | NULL | | | username | varchar(50) | YES | | NULL | | | password | varchar(20) | YES | | NULL | | | picNo | varchar(10) | YES | | NULL | | +———-+————-+——+—–+———+——-+

② 心情表

+-------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +————-+————–+——+—–+———+——-+ | moodId | int(11) | NO | PRI | NULL | | | moodcontent | varchar(280) | YES | | NULL | | | pid | int(11) | YES | | NULL | | | moodtime | varchar(20) | YES | | NULL | | +————-+————–+——+—–+———+——-+

③ 好友关系表

+------------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +————+———+——+—–+———+——-+ | relationid | int(11) | NO | PRI | NULL | | | pid | int(11) | YES | | NULL | | | friendid | int(11) | YES | | NULL | | +————+———+——+—–+———+——-+

④ 主键维护表

+------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +————+————-+——+—–+———+——-+ | gen_name | varchar(20) | YES | | NULL | | | gen_number | int(11) | YES | | NULL | | +————+————-+——+—–+———+——-+

4、项目运行截图:

程序登录,注册和使用界面

5、关键代码:

(1) 数据库处理源代码:

/*
\
在数据库中查询用户的资料,保存在本地的PersonalData中
* @return
/
public void checkPersonalData(String id){
PersonalData pd = PersonalData.getInstance();
Connection conn = null;
ResultSet rs = null;
PreparedStatement pstmt = null;
String sql = “select
from user where userid=?”;
try {
conn = ConnMySQL.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if (rs.next()) {
pd.setUserId(rs.getString(“userId”));
pd.setUserName(rs.getString(“username”));
pd.setPicNo(rs.getString(“picNo”));

        }
    }catch(SQLException e) {
        e.printStackTrace();
    }finally {
        ConnMySQL.close(rs);
        ConnMySQL.close(pstmt);
        ConnMySQL.close(conn);
    }
}

(2) 其他数据处理关键语句:

/*
\
在数据库中查询用户的资料,保存在本地的PersonalData中
* @return
/
String sql = “select
from user where userid=?”;

/**

* 在数据库中查询最新的心情
* @return
*/
String sql = “select moodcontent from moodlist where moodid = (select max(moodid)from moodlist where pid=?)”;

/**

   * 查找用户的所有好友,保存在本地程序中
* @param id
* @return
/
String sql = “select
from user where userId in (select friendid from relationlist where pid=?)”;

/**

   * 修改用户的昵称
* @return
*/
String sql = “update user set username=? where userId=?”;

/**

* 修改用户的密码
   * @return
   */
String sql = “update user set password=? where userId=?”;

/**

* 获取自动编号ID
* @param gen_name
* @return
*/
String sql = “select gen_number from generator where gen_name =?”;

/**

* 更新Id维护列表,此方法给此类别的函数调用
* @param gen_name
   * @param current_id
* @param conn
*/
String sql = “update generator set gen_number =? where gen_name = ?”;

/**

   * 添加心情
* @param userId
* @param mood
* @return
*/
String sql = “insert into moodlist values(?,?,?,?);”;

String sql = "select * from moodlist order by moodId desc limit 20";

/**

* 加好友
* @param args
*/
String sql = “insert into relationlist values(?,?,?);”;

String sql = "insert into user values(?,?,?,?);";

(3) 客户端接收线程的run()函数:

public void run() {

while(run1){
    try {
        ObjectInputStream ois = new ObjectInputStream(sk.getInputStream());
        Message mes = (Message)ois.readObject();
        String messageType = mes.getMessageType();
        String sender = mes.getSender();
        String receiver = mes.getReceiver();
        if(messageType.equals(MessageType.CONTENT) || messageType.equals(MessageType.EXPRESSION)) {

// System.out.println(receiver);
ChatWindow cw = ChatWinMap.getChatWindow(sender);
// System.out.println(“来自用户”+cw);
if(null == cw){
if(null != FriendMap.getFriendData(mes.getSender())) {
ReceiverMessage rm = new ReceiverMessage(mes);
Thread th = new Thread(rm);
th.start();
}
} else {
cw.showMessage(mes);
}

        } else if(messageType.equals(MessageType.ON_LINE)) {
            System.out.println("更新在线好友");
            String \[\]all\_online\_ip = mes.getAll\_online\_id().split(",");
            ChatMainMap.getChatMain(mes.getReceiver()).getJp\_center().changeOnlineState(all\_online_ip);
            Online\_message on\_mes = new Online_message(mes.getSender());
            Thread th = new Thread(on_mes);
            th.start();
        } else if(messageType.equals(MessageType.SHAKE_WIN)) {
            ChatWindow cw = ChatWinMap.getChatWindow(sender);
            Thread th = new Thread(cw);
            th.start();
            cw.showMessage(mes);
        } else if(messageType.equals(MessageType.REQUEST)){
            //把该好友的资料丛数据库中取出并保存在客户端程序中

            ReceiverRequestMessage rsm = new ReceiverRequestMessage(mes);
            Thread th = new Thread(rsm);
            th.start();
        } else if(messageType.equals(MessageType.REQUEST_CONFIRM)) {

            //把双边的关系加入数据库
            UserManager.getInstance().addFriend(mes.getSender(), mes.getReceiver());
            System.out.println("保存好友:"+mes.getSender());
            System.out.println(mes.getReceiver());
            UserManager.getInstance().addFriend(mes.getReceiver(),mes.getSender());
            //把该好友资料从数据库中取得并保存在客户端程序中
            String \[\]fds = UserManager.getInstance().checkUser(mes.getSender());
            FriendData fd = new FriendData();
            fd.setFriendId(fds\[0\]);
            fd.setFriendName(fds\[1\]);
            fd.setFriendPic(fds\[2\]);
            FriendList.getFriendList().add(fd);
            FriendMap.addFriendData(fds\[0\], fd);
            //更新好友列表
            String all\_ip = mes.getAll\_online_id();
            ChatMainMap.getChatMain(PersonalData.getUserId()).updataCenter(all_ip);

            ConfirmRequestMessage rm = new ConfirmRequestMessage(mes);
            Thread th = new Thread(rm);
            th.start();
        } else if(messageType.equals(MessageType.REQUEST_REFUSE)){
            ConfirmRequestMessage rm = new ConfirmRequestMessage(mes);
            Thread th = new Thread(rm);
            th.start();
        } else if(messageType.equals(MessageType.NOT_ONLINE)) {
            MessageBox msb = new MessageBox("对方不在线");
            Thread th = new Thread(msb);
            th.start();
        } else if(messageType.equals(MessageType.OFF_LINE)) {
            System.out.println("有人下线了");
            //更新好友列表
            if(sender.equals(PersonalData.getUserId())) {
                break;
            }
            String all\_ip = mes.getAll\_online_id();
            System.out.println("当前在线好友:"+mes.getAll\_online\_id());
            ChatMainMap.getChatMain(PersonalData.getUserId()).updataCenter(all_ip);
        } else if(messageType.equals(MessageType.FILE_TRAN)) {
            ReceiverFileTransMessage rftm = new ReceiverFileTransMessage(mes);
            Thread th = new Thread(rftm);
            th.start();
        } else if(messageType.equals(MessageType.FILE\_TRAN\_CONFIRM)) {
            ConfirmRequestMessage rm = new ConfirmRequestMessage(mes);
            Thread th = new Thread(rm);
            th.start();
        } else if(messageType.equals(MessageType.FILE\_TRAN\_REFUSE)) {
            ConfirmRequestMessage rm = new ConfirmRequestMessage(mes);
            Thread th = new Thread(rm);
            th.start();
        }
    }catch (Exception e) {
        e.printStackTrace();
    }
}

}

(4) 接收文件的客户端run()函数

public void run() {
Socket server;
try {
server = new Socket(msg.getFileTranMes().getServerIp(), Integer.parseInt(msg.getFileTranMes().getServerPort()));
//创建网络接受流接受服务器文件数据
InputStream netIn = server.getInputStream();

InputStream in = new DataInputStream(new BufferedInputStream(netIn));
//创建缓冲区缓冲网络数据

// System.out.println(“传输文件的长度:”+in.available());
byte[] buf = new byte[2048];
int num = in.read(buf);
while (num != (-1)) {
//是否读完所有数据
raf.write(buf, 0, num);//将数据写往文件
raf.skipBytes(num);//顺序写文件字节
num = in.read(buf);//继续从网络中读取文件
width = width+1;
width_1 = width/size 180;
jl2.setBounds(10,40,(int)(width_1),20);
jl2.setText(“ “+(int)(width/size
100)+”%”);
}
jl2.setText(“传送完成”);
in.close();
raf.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

(5) 发送文件的服务器run()函数

public void run() {
//创建网络服务器接受客户请求
ServerSocket ss;
Socket client = null;
try {
ss = new ServerSocket(5678);
client = ss.accept();
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}

//创建网络输出流并提供数据包装器
OutputStream netOut;
try {
    netOut = client.getOutputStream();
    OutputStream doc = new DataOutputStream(
    new BufferedOutputStream(netOut));

    //创建文件读取缓冲区
    byte\[\] buf = new byte\[2048\];
    int num = fos.read(buf);

    while (num != (-1)) {//是否读完文件
        doc.write(buf, 0, num);//把文件数据写出网络缓冲区
        doc.flush();//刷新缓冲区把数据写往客户端
        num = fos.read(buf);//继续从文件中读取数据
        width = width+1;
        width_1 = width/size * 180;
        jl2.setBounds(10,40,(int)(width_1),20);
        jl2.setText(" "+(int)(width/size*100)+"%");
    }
    jl2.setText("传送完成");
    fos.close();
    doc.close();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

}

(6) 客户端登录验证的函数

public boolean CheckUser (Message msg) {
boolean check = false;
try {
sk = new Socket(ip,port);
System.out.println(“获取socket”);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

try {
    ObjectOutputStream oos = new ObjectOutputStream(sk.getOutputStream());
    oos.writeObject(msg);
    ObjectInputStream ois=new ObjectInputStream(sk.getInputStream());
    Message mss=(Message)ois.readObject();
    if(mss.getMessageType().equals(MessageType.ON_LINE)){
        ClientConnServerThread ccst = new ClientConnServerThread(sk);
        System.out.println("赋给ClietThreadMap的id:" \+ mss.getUser().getUserId());
        ClientThreadMap.setClientThreadHm(mss.getUser().getUserId(), ccst);
        ccst.start();
        User u = mss.getUser();

        //在这里查询数据库中用户的信息,并保存在客户端程序中
        UserManager.getInstance().checkPersonalData(u.getUserId());
        PersonalData.setMood(UserManager.getInstance().checkMood(u.getUserId()));
        UserManager.getInstance().checkAllFriend(u.getUserId());

        ChatMain cm = new ChatMain(u,mss);
        ChatMainMap.addChatMain(u.getUserId(), cm);
        check = true;

    } else if(mss.getMessageType().equals(MessageType.ON\_LINE\_FAIL)) {

// JOptionPane.showMessageDialog(null, “用户名或密码错误”);
MessageBox msgb = new MessageBox(“用户名或密码错误!”);
Thread th = new Thread(msgb);
th.start();
ois.close();
oos.close();
sk.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return check;

}

(7) 连接数据库的函数

public static Connection getConnection() {
Connection conn = null;
try {
Class.forName(“com.mysql.jdbc.Driver”);
conn = DriverManager.getConnection(“jdbc:mysql://localhost/chatdata?user=user1&password=m123”);

} catch (Exception ex) {
    ex.printStackTrace();
}
return conn;

}

(8) 发送消息的响应事件:

if(e.getSource() == jb_send) {
if(cardNo == 0) {
Date time = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(“hh:mm:ss”);
String sendtime = sdf.format(time);
Document doc = jta.getDocument();
try {
doc.insertString(jta.getDocument().getLength(),PersonalData.getUserName()+”(“+this.userId+”) “+sendtime+”\n”, null);
doc.insertString(jta.getDocument().getLength(),” “+jta_send.getText()+”\n”, null);
} catch (BadLocationException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}

String sendMes = jta_send.getText();
jta_send.setText("");

Message mes = new Message();
mes.setSender(this.userId);
mes.setReceiver(this.receiveId);

// System.out.println(“发送前receiverId的值:”+receiveId);
mes.setContent(sendMes);
mes.setSendtime(sendtime);
mes.setPic_no(PersonalData.getPicNo());
mes.setMessageType(MessageType.CONTENT);
try {
ObjectOutputStream oos = new ObjectOutputStream(ClientThreadMap.getClientThreadHm(this.userId).getSocket().getOutputStream());
oos.writeObject(mes);
} catch (Exception e1) {
e1.printStackTrace();
}
} else {
Date time = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(“MM-DD hh:mm:ss”);
String sendtime = sdf.format(time);
Document doc = jta.getDocument();
try {
doc.insertString(jta.getDocument().getLength(),PersonalData.getUserName()+”(“+this.userId+”) “+sendtime+”\n”, null);
doc.insertString(jta.getDocument().getLength(), “ “, null);
jta.setCaretPosition(doc.getLength());
jta.insertIcon(new ImageIcon(“images/“+faceNo+”.gif”));
doc.insertString(jta.getDocument().getLength(), “\n”, null);
} catch (BadLocationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

System.out.println("send picture:"+faceNo);
String sendMes = faceNo;

Message mes = new Message();
mes.setSender(this.userId);
mes.setReceiver(this.receiveId);
mes.setContent(sendMes);
mes.setSendtime(sendtime);
mes.setMessageType(MessageType.EXPRESSION);
try {

// System.out.println(“==============准备发送消息================”);
ObjectOutputStream oos = new ObjectOutputStream(ClientThreadMap.getClientThreadHm(this.userId).getSocket().getOutputStream());
// System.out.println(oos+”:”+mes.getMessageType());
oos.writeObject(mes);
} catch (Exception e1) {
e1.printStackTrace();
}
}

}

(9) 显示消息的函数:

public void showMessage(Message ms) {
try {
Document doc = chat_window.jta.getDocument();
doc.insertString(chat_window.jta.getDocument().getLength(),FriendMap.getFriendData(this.receiveId).getFriendName()+”(“+ms.getSender()+”) “+ms.getSendtime()+”\n”, null);
if(ms.getMessageType().equals(MessageType.CONTENT)){
doc.insertString(chat_window.jta.getDocument().getLength(),” “+ms.getContent()+”\n”, null);
} else if(ms.getMessageType().equals(MessageType.EXPRESSION)){
//插入图片
doc.insertString(chat_window.jta.getDocument().getLength(), “ “, null);
chat_window.jta.setCaretPosition(doc.getLength());
chat_window.jta.insertIcon(new ImageIcon(“images/“+ms.getContent()+”.gif”));
doc.insertString(chat_window.jta.getDocument().getLength(), “\n”, null);
} else if(ms.getMessageType().equals(MessageType.SHAKE_WIN)){
doc.insertString(chat_window.jta.getDocument().getLength(),” “+ms.getContent()+”\n”, null);
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}

(10) 服务器端等待和验证客户端信息函数

public void run() {
while (true) {
try {
System.out.println(“服务器正在等待客户端的连接”);
Socket sk = ssk.accept();
ObjectInputStream ois=new ObjectInputStream(sk.getInputStream());
Message ms = (Message)ois.readObject();
User u = ms.getUser();
String password = UserManager.getInstance().checkPersonalData(u.getUserId());
if(null != password){
if(u.getPassword().equals(password)) {
System.out.println(“验证密码”);
ServerConnClientThread sct = new ServerConnClientThread(sk);
sct.start();
ThreadMap.addThread(u.getUserId(), sct);

/*验证成功后,把所有在线用户返回给所有的用户*/
Iterator it = ThreadMap.hm.entrySet().iterator();
String all_id = "";
while(it.hasNext()){
    Entry entry = (Entry) it.next();
    all_id+=entry.getKey();
    if(it.hasNext()){
        all_id+=",";
    }

// System.out.println(all_id);
}
ms.setAll_online_id(all_id);
Iterator it2 = ThreadMap.hm.entrySet().iterator();
while(it2.hasNext()) {
Entry entry = (Entry) it2.next();
ServerConnClientThread st = (ServerConnClientThread) entry.getValue();
ObjectOutputStream oos = new ObjectOutputStream(st.sk.getOutputStream());
ms.setReceiver(entry.getKey()+””);
oos.writeObject(ms);
}
} else {
//密码错误
Message mss = new Message();
mss.setMessageType(MessageType.ON_LINE_FAIL);
mss.setContent(“用户密码错误!”);
ObjectOutputStream oos=new ObjectOutputStream(sk.getOutputStream());
oos.writeObject(mss);
sk.close();
}
} else {
//用户不存在
Message mss = new Message();
mss.setMessageType(MessageType.ON_LINE_FAIL);
mss.setContent(“该用户不存在”);
ObjectOutputStream oos=new ObjectOutputStream(sk.getOutputStream());
oos.writeObject(mss);
sk.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

(11) 服务器转发消息函数

public void run() {
boolean run = true;
Message m = null;
while(true){
try {
ObjectInputStream ois = new ObjectInputStream(sk.getInputStream());
m=(Message)ois.readObject();
System.out.println(“开始接收数据”);
String messageType = m.getMessageType();
String sender = m.getSender();
String receiver = m.getReceiver();

if(m.getMessageType().equals(MessageType.OFF_LINE)) {

    //重新获取在线ID
    Iterator it = ThreadMap.hm.entrySet().iterator();
    String all_id = "";
    while(it.hasNext()){
        Entry entry = (Entry) it.next();
        if(!(entry.getKey().toString().equals(sender))){
            all_id+=entry.getKey();
            if(it.hasNext()){
                all_id+=",";
            }
        }
    }
    String all\_id2 = all\_id.substring(0, all_id.length());
    System.out.println(all_id2);
    //把消息传给每个人
    Iterator it2 = ThreadMap.hm.entrySet().iterator();
    ObjectOutputStream oos = null;
    ServerConnClientThread scct = null;
    while(it2.hasNext()){
        Entry entry = (Entry) it2.next();
        scct = (ServerConnClientThread) entry.getValue();
        oos = new ObjectOutputStream(scct.sk.getOutputStream());
        m.setAll\_online\_id(all_id2);
        oos.writeObject(m);
    }
    ThreadMap.hm.remove(sender);
    break;

} else {
    if(messageType.equals(MessageType.REQUEST)||messageType.equals(MessageType.REQUEST_CONFIRM)) {
        Iterator it = ThreadMap.hm.entrySet().iterator();
        String all_id = "";
        while(it.hasNext()){
            Entry entry = (Entry) it.next();
            all_id+=entry.getKey();
            if(it.hasNext()){
                all_id+=",";
            }

// System.out.println(all_id);
}
m.setAll_online_id(all_id);
}
ObjectOutputStream oos = new ObjectOutputStream(ThreadMap.getThread(receiver).sk.getOutputStream());
System.out.println(“开始转发数据”);
oos.writeObject(m);
}

    }catch(Exception ex){
        ex.printStackTrace();
    }
}

}

arthinking wechat
欢迎关注itzhai公众号