面向对象课程设计--QQ聊天室
一、团队介绍
团队名称:
团队成员 | 职务 | 负责部分 | 博客链接 |
---|---|---|---|
汪月月 | 组长 | 网络编程和多线程 | 汪月月个人博客 |
姜芳华 | 组员 | 网络编程和多线程 | 姜芳华个人博客 |
曹卉潼 | 组员 | 客户端页面设计和数据库 | 曹卉潼个人博客 |
骆梦钒 | 组员 | 客户端页面设计和数据库 | 骆梦钒个人博客 |
二、项目Git地址及提交记录
三、前期调查
我们熟悉的客户端QQ主要有以下三个界面,分别是登录注册界面、好友列表界面、聊天窗口界面
在好友列表界面点开某个好友后可以查看他的基本信息
在聊天窗口点击表情按钮可以选择不同的QQ表情发送,也可以发送文字、文件
四、项目功能架构图及主要功能流程图
五、项目UML图
六、项目运行截图
登录注册界面
好友列表界面
聊天窗口界面
七、项目关键代码(分模块)
登录与注册
- 客户端
- 服务端
接收与发送信息
- 客户端线程
public void run(){
while(true){
//不停的读取从服务器端发来的消息
try {
ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
Message m=(Message)ois.readObject();
ManageQqFriendList qqFriendList = new ManageQqFriendList();
switch (m.getMesType()) {
case MessageType.messageCommes://普通信息包
//把从服务器获得消息,显示到该显示的聊天界面
Chat.showMessage(m);//显示
break;
case MessageType.messageRetOnLineFriend: //在线用户包
String userOnLine = (String) m.getMesgText();
//暂未开发
break;
case MessageType.messageRetFriend: //接收到好友包
String mesgText = (String) m.getMesgText();
String getterId = m.getGetterId();
if (mesgText != null) {
String[] friend = mesgText.split(",");
List<User> userFriends = new ArrayList<>();
for (String value : friend) {
userFriends.add(qqFriendList.getUserMap().get(value));
}
//添加到好友列表中
qqFriendList.setFriendMap(getterId, userFriends);
FriendList.upateFriend(qqFriendList.getUserMap().get(getterId));
}
else qqFriendList.setFriendMap(getterId, null);
break;
case MessageType.messageRetUser://返回所有用户与Id的映射关系
qqFriendList.setUserMap((HashMap<String, User>) m.getMesgText());
break;
case MessageType.messageInquiryFriend://8添加好友询问
System.out.println("添加者得到服务器返回的结果");
if (m.getMesgText().equals("同意")) {
JOptionPane.showMessageDialog(null, "对方同意添加好友啦!快去聊天吧~");
System.out.println("通过了好友验证");
} else {
JOptionPane.showMessageDialog(null, "对方未同意您的请求");
}
break;
case MessageType.messageGetInquiry://9接收好友询问的信息
Message me=new Message();
me.setMesType(MessageType.messageGetInquiry);
me.setGetterId(m.getGetterId());
me.setSenderId(m.getSenderId());
int option=JOptionPane.YES_NO_OPTION;
option = JOptionPane.showConfirmDialog(null, m.getSenderId() + "想添加您为好友", "加好友", JOptionPane.YES_NO_OPTION);
if (option == JOptionPane.YES_OPTION){
me.setMesgText("同意");
}
else me.setMesgText("不同意");
ClientConServerThread cost = ManageClientConServerThread.getClientConServerThread(m.getGetterId());
ObjectOutputStream oos = new ObjectOutputStream(cost.getS().getOutputStream());
oos.writeObject(me);
oos.flush();
break;
default:
throw new IllegalStateException("Unexpected value: " + m.getMesType());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 服务端线程
public void run(){
while(true) {
//这里该线程就可以接收客户端的信息.
try {
ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
Message m=(Message)ois.readObject();
//对从客户端取得的消息进行类型判断,然后做相应的处理
if(m.getMesType().equals(MessageType.messageCommes)) {//聊天信息
//取得接收人的通信线程
System.out.println(m.getSenderId()+" 对 "+m.getGetterId()+" 说:"+m.getMesgText());
SerConClientThread sc=ManageClientThread.getClientThread(m.getGetterId());
ObjectOutputStream oos=new ObjectOutputStream(sc.getS().getOutputStream());
oos.writeObject(m);
oos.flush();
}
else if(m.getMesType().equals(MessageType.messageGetOnLineFriend)) {//要在线好友信息
System.out.println(m.getSenderId()+" 要他的在线好友");
//把在服务器的好友给该客户端返回.
String res=ManageClientThread.getAllOnLineUserid();
Message m2=new Message();
m2.setMesType(MessageType.messageRetOnLineFriend);
m2.setMesgText(res);
m2.setGetterId(m.getSenderId());
ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
oos.writeObject(m2);
oos.flush();
}
else if(m.getMesType().equals(MessageType.messageInquiryFriend)){//询问接收者是否同意添加为好友
m.setMesType(MessageType.messageGetInquiry);
SerConClientThread sc=ManageClientThread.getClientThread(m.getGetterId());
ObjectOutputStream oos=new ObjectOutputStream(sc.getS().getOutputStream());
oos.writeObject(m);
oos.flush();
System.out.println("询问接收者是否同意添加为好友并发送成功");
}
else if(m.getMesType().equals(MessageType.messageGetInquiry)){//被加用户返回的数据
if(m.getMesgText().equals("同意")){//接收者同意请求
m.setMesType(MessageType.messageInquiryFriend);//发送给请求者请求结果
SerConClientThread scSend=ManageClientThread.getClientThread(m.getSenderId());
ObjectOutputStream oos=new ObjectOutputStream(scSend.getS().getOutputStream());
oos.writeObject(m);
oos.flush();
QQMysql qqMysql = new QQMysql();
qqMysql.updateSQLFriend(m.getSenderId(),m.getGetterId());
sengUserFriend(m.getGetterId());
sengUserFriend(m.getSenderId());
}
else{
m.setMesType(MessageType.messageInquiryFriend);
SerConClientThread scSend=ManageClientThread.getClientThread(m.getSenderId());
ObjectOutputStream oos=new ObjectOutputStream(scSend.getS().getOutputStream());
oos.writeObject(m);
oos.flush();
}
}
else if(m.getMesType().equals(MessageType.messageClosed)){//关闭线程
SerConClientThread scSend=ManageClientThread.getClientThread(m.getSenderId());
scSend.close();
ManageClientThread.removeUserThread(m.getSenderId());
}
} catch (Exception e) {
//throw new RuntimeException(e);
e.printStackTrace();
// TODO: handle exception
}
}
}
数据库访问
- JDBCUtil类
public class JDBCUtil {
private static final String user;//用户名
private static final String password;//密码
private static final String url;//url
private static final String driver;//驱动
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//建立连接
public static Connection getConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//不为空就关闭
public static void close(ResultSet set, Statement statement,Connection connection){
//判断是否为空
try {
if(set!=null) set.close();
if(statement!=null)statement.close();
if(connection!=null)connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
- JDBCDao接口
- QQMysql类
package com.qq.server.db;
import com.qq.common.User;
import java.sql.*;
import java.util.HashMap;
/**
* 该类用于实现JDBCDao接口
*/
public class QQMysql implements JDBCDao {
private Connection connect;
public Connection getConnect() {
return connect;
}
public void setConnect(Connection connect) {
this.connect = connect;
}
public QQMysql() {
this.connect=JDBCUtil.getConnection();
}
public User findUser(User u ) throws SQLException {//查找用户
boolean b=false;
User user=new User();
Statement statement = this.connect.createStatement();
String sql = "select id,name,password,gender,headImage,statue,friend from usermessage";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
String userId = resultSet.getString(1);
String name=resultSet.getString(2);
String userPassword = resultSet.getString(3);
if (u.getUserId().equals(userId) && u.getPasswd().equals(userPassword)) {
u.setUserId(u.getUserId());
u.setUserName(name);
u.setPasswd(userPassword);
u.setGender(resultSet.getString(4));
u.setHeadImage(resultSet.getString(5));
u.setStatue(resultSet.getInt(6));
u.setFriendId(resultSet.getString(7));
//b=true;
}
}
JDBCUtil.close(resultSet,statement,null);
return u;
}
public boolean addUser(User u) throws SQLException {//添加用户
boolean b=true;
String sql = "insert into usermessage(id,name,password,gender,headImage,statue,friend) values (?,?,?,?,?,?,?)";
PreparedStatement preparedStatement = this.connect.prepareStatement(sql);
preparedStatement.setString(1,u.getUserId());
preparedStatement.setString(2,u.getUserName());
preparedStatement.setString(3,u.getPasswd());
preparedStatement.setString(4,u.getGender());
preparedStatement.setString(5, u.getHeadImage());
preparedStatement.setInt(6, u.getStatue());
preparedStatement.setString(7 ,u.getFriendId());
preparedStatement.executeUpdate();
preparedStatement.close();
return b;
}
public void updateSQLFriend(String userId,String friendId) throws SQLException {
System.out.println(userId+","+friendId);
String userFriend = getUserFriend(userId);//用户的好友列表
String friend = getUserFriend(friendId);//好友的好友表
String friendList=null;
if(userFriend!=null)friendList=userFriend+","+friendId;
else friendList=friendId;
System.out.println(userId+friendList);
String sql="update usermessage set friend = '"+friendList+"' where id = '"+userId+"'";
Statement statement = this.connect.createStatement();
statement.executeUpdate(sql);
System.out.println("数据库写入成功");
if(friend!=null)friendList=friend+","+userId;
else friendList=userId;
System.out.println(friendId+friendList);
String sql1="update usermessage set friend = '"+friendList+"' where id = '"+friendId+"'";
statement.executeUpdate(sql1);
JDBCUtil.close(null,statement,null);
System.out.println("数据库写入成功");
}
public void close(){
JDBCUtil.close(null,null,this.connect);
}
@Override
public String getUserFriend(String userId) throws SQLException {
String friends = null;
Statement statement = this.connect.createStatement();
String sql = "select id,friend from usermessage";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
String id = resultSet.getString(1);
if(id.equals(userId)){
friends=resultSet.getString(2);
System.out.println(friends);
}
}
JDBCUtil.close(resultSet,statement,null);
return friends;
}
public HashMap<String,User> getAllUser() throws SQLException {//获取用户的id与User的映射关系
HashMap<String,User> userHashMap=new HashMap<>();
Statement statement = this.connect.createStatement();
String sql = "select id,name,password,gender,headImage,statue,friend from usermessage";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
String id=resultSet.getString(1);
User user=new User(id,resultSet.getString(2),resultSet.getString(3),
resultSet.getString(4),resultSet.getString(5),resultSet.getInt(6),resultSet.getString(7));
userHashMap.put(id,user);
}
JDBCUtil.close(resultSet,statement,null);
return userHashMap;
}
}
八、项目总结不足与展望
总结
- 本次课程设计主要完成了QQ的登录、注册、显示好友列表、显示个人信息、加好友、好友聊天功能,设计了登录,注册,好友列表,个人信息主页,聊天框等界面。
- 模拟数据包在网络中的传输,封装成对象,通过网络编程中流的输入输出以对象的形式在客户端与服务器之间传输。在服务器与客户端之间将用户(User)类与信息(Message)类以及信息类型实现共享,让客户端与服务器之间可以正常交流。
- 用户信息(Uaer)数据存储在数据库中,添加JDBCUtil类与JDBCDao接口,让访问数据库的信息更快捷。
不足和展望
- 客户端
- 由于时间的不足以及部分成员对相关知识的学习和理解不深入的原因,还未实现多人在一个聊天框里聊天(群聊),
- 对于已经实现的功能只是做到了基本还原,但是很多细节方面并没有优化到极致,例如:登录界面上的记住密码和自动登录的功能,这些功能无疑需要继续投入更多的时间和精力
- 图形界面加入图片、样式等对现有界面进行美化有待提升。
- 对聊天内容只仅限于文字,表情,文件等功能还需要进一步优化
- 服务器
- 由于没有租用服务器,现在是以一台电脑作为服务器,导致聊天仅限于一个局域网之间;
- 服务器的界面尚未完成优化,后序将会添加显示在线人数,每个用户的操作,将会在一个可视化界面中进行显示。