工程训练
基于 JAVA 的聊天工具开发 Solomon1558
工程训练报告
——基于 JAVA 的聊天工具开发
Name:Solomon1558
StuNo:**********
Class:CS.4
Mentor:陈波
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
前言:
写作目的:
本届工程训练历时两周,行将结束。本报告将以项目的进展顺序架构,梳理
项目层次,整理项目思路,从而加深对项目的理解,提出自己的感悟与思考。
行文思路:
本次工程训练主要涉及 3 大方面:网络编程、数据库访问、图形界面。我将
以这 3 方面综合项目进度组织报告的层次、内容。在正文部分力求抓住主要问题,
阐明项目的思路与具体实现,做到层次清晰,简洁准确。同时我还会在附录部分
针对项目中提到的知识、模式加以补充,达到拓展思维、深刻认识的效果。
第一章. 网络编程
1.1 C/S 结构的编写
作为一个 IM 软件,最基本的工作就是编写 client 与 server。本项目采用基于
TCP 的 Socket 进行两个程序之间的双向通信。其基本工作原理如下:
•在服务器端通过指定一个用来等待的连接的端口号创建一个 ServerSocket
实例。
•在客户端通过规定一个主机和端口号创建一个 socket 实例,连到服务器上。
•ServerSocket 类的 accept 方法使服务器处于阻塞状态,等待用户请求。
我们需要考虑的问题有:
两个或多个程序之间的通信,涉及到请求和回复,并且通信所传输的内容根
据请求的不同而不同。因此在实际设计、编程时要考虑的复用问题与多线程。
为了解决以上问题,我们在客户端与服务器端建立一个通道,用来传输可串
行化(Serializable)的对象,这个对象有两个参量:类型与对象的内容。
因而我们需要定义两个继承了 Serializable 接口的实体类:RequsetObject
和 ResponseObject。这两个实体类具有两个私有成员:int 型的 xType(表示请求/
回复类型),Object 型的 xBody(表示内容)。这两个实体类都有 set(),get(),toString()
方法和构造函数。
编程实现:
client 端的网络编程初步编写非常简单:只需 new 一个 Socket 类的对象
server,规定一个主机和端口号,连到服务器上。
实际上,我们对 client 端的要求很简单:就是信息的发送与接收,并不涉及
复杂的处理过程。一种较好的方法是在类中写一个返回类型为 ResponseObject
的静态方法:sendRequest(),并将输入输出封装为 ObjectInputStream 、
ObjectInputStream 对象,将对象串行化[1]。在这个静态方法中创建 Socket 实例
与服务器连接,并在对象流中 write 请求,read 回复,即 send 与 receive 功能。
这种设计称作“信封模式”,或“门面模式”(Façade Pattern)。[2]
其优点是:建立连接、发送、接收对象等操作被封装到门面方法 sendRequest()
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
中,使用时直接调用门面的方法就可以与服务器通信,不用了解具体的实现方法以及相关
的业务顺序。
以下是 NetAccessHelper 类的主体框架。
public static ResponseObject sendRequest(RequestObject reqObject) {
ResponseObject resObject = null;
try {
// 1.connect to the server
// 2.get oos,ois
// 3.send
// 4.receive
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return resObject;
}
现 在 考 虑 服 务 器 端 : 通 过 指 定 一 个 用 来 等 待 连 接 的 端 口 号 创 建 一 个
ServerSocket 实例,ServerSocket 类的 accept 方法使服务器处于阻塞状态,等待用
户请求。ChatServer 类的代码如下:
public class ChatServer {
public static void main(String[] args) {
// TODO Auto-generated method stub
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(10000);
System.out.println("Server is running....");
Socket clientSocket;
WorkerThread worker;
for (;;) {
clientSocket = serverSocket.accept();
worker = new WorkerThread(clientSocket);
worker.start();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
1.2 多线程创建
在 for 循环中,每有一个客户端的连接,就实例化一个 WorkerThread 对象。
WorkerThread 类有两个私有的成员变量 clientSocket , handler,构造函数和 run()
函数。
此处采用了“策略模式”(Strategy Pattern) [3]:
需要定义一个策略接口 RequestHandler,其后的实现类都继承这个接
口。
从 对 象 流 中 读 取 请 求 信 息 RequestObject requestObject =
(RequestObject) ois.readObject();
因为 RequestObject/ResponseObject 实体都含有 X-Type,X-Body 的私
有成员变量。使用 switch case 对 ReqType 进行判断,选相应的实现
类 X-RequestHandler 的构造函数初始化 RequestHandler 类型的对象
handler。
最后调用实现方法,将返回对象赋予 responseObject,将其 write 进对
象流。
采用策略模式的好处在于:具有高内聚低耦合的特点,还有很好扩展性,也
就是 OCP 原则,策略类可以继续增加下去,这对支持后续的多种请求-响应非常
重要。
1.3 实体类
请求/回复
为了支持策略模式,实现不同请求的响应回复,创建实体类 RequestObject,
ResponseObject 类是有必要的。
这两个类为了使其对象可串行化,需要实现 Serialization 接口。它们都有静
态成员变量表示状态,int 型 reqType、Object 型 reqBody 的私有成员变量,以
及 get(),set(),toString() 和构造函数。
package entity;
import java.io.Serializable;
public class RequestObject implements Serializable {
public static final int XXXX = 999999;
. . . . . .
private int reqType;
private Object reqBody;
public RequestObject(int reqType, Object reqBody) {
super();
this.reqType = reqType;
this.reqBody = reqBody;
}
getXXX(){} …
setXXX(){}…
toString(){}
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
}
第二章.数据库的建立与访问
2.1 创建数据库
使用 Navicat for MySQL,建立数据库 chatdb,新建 contacts 表,chatstore 表。
contaccts 表 存 储 用 户 信 息 。 属 性 分 别 uid , uname , email
, age ,
pass ,online ,peerip , peerport ,其中 uid 是主键。如下图所示:
chatstore 表 存 储 会 话 信 息 , 属 性 :chatid , senderid ,receiverid , content ,
sendtime, 主键 chatid。
2.2 数据库的访问
为了将数据库的访问、查询封装起来,我们需要写一个 DBAccessHelper 类。
这个类成员有:
*私有类成员 dao,只能实例化一次。
*私有构造函数 DBAccessHelper(),加载驱动。
*公共类方法 getDao(),检查类对象是否实例化,返回类 DBAccessHelper 对象
dao。
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
*私有成员方法 getConnection() , 返回Connection类型对象。将连接连接到
MySQL的url以及pass、name作为参数传入DriverManager类getConnection
方法中,建立与数据库连接。
*成员方法 excute(),无结果返回的查询。
*成员方法excuteQuary(),有查询值返回。需要ResultSet rs作为结果集,
返回结果集对象rs 。
public class DBAccessHelper {
private static DBAccessHelper dao;
// 加载驱动
private DBAccessHelper() { // private构造函数
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 希望只执行一次
public static DBAccessHelper getDAO() {
if (dao == null)
dao = new DBAccessHelper();
return dao;
}
private Connection getConnection() {
Connection conn=null;
String url = "jdbc:mysql://localhost:3306/chatdb";
String pass = "1992919";
String name = "root";
try {
conn = DriverManager.getConnection(url, name, pass);
System.out.println(conn);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//无结果返回的查询execute()
public void execute(String sqlString) {
try {
Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(sqlString);// 变量
在try外初始化
stmt.execute();
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 查询语句
// excuteQuary有返回值,execute返回值!
public ResultSet executeQuery(String sqlString) {
ResultSet rs = null;
try {
Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(sqlString);// 变量
在tyr外初始化
rs=stmt.executeQuery();
//出错了,打印成了.execute
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rs;
}
}
2.3 数据库连接测试
现在写一个测试类 DAOTest,测试数据库的连接。
将 sql 插入语句以 String 类型传入 DBAccessHelper 类的 excute()方法中,该方法由
私有类方法 getDAO()返回的对象 dao 调用。
String sqlString = " Insert into contacts (uid,uname,age,pass,email) "
+ "values("+uid+",'"+tempString+"',21,'1234','123@wjq.com')";
DBAccessHelper.getDAO().execute(sqlString);
将contacts数据库中用户信息全部显示,使用excuteQuery()方法。
sqlString = "select uid,uname,age,email,online from contacts";
System.out.println(sqlString);
ResultSet rs = DBAccessHelper.getDAO().executeQuery(sqlString);
工程训练
基于 JAVA 的聊天工具开发 Solomon1558
第三章.图形化界面
在网络编程,数据库建立、访问工作完成后,现在进行图形化界面的编写。
图形化界面主要包括:注册界面、登录界面、主界面、对话框。
登录
显示信息
注册
在线消息
离线消息
聊天
这里所涉及的功能较多,比如访问、操作数据库,从数据库插入、提取信息,
信息刷新,端与端用户间的离线消息、即时通讯等等,每一个问题又有很多具体
的子问题需要逐步去完善。根据增量开发的原则,作者将不在开头部分将所有的
设计细节一一罗列,而是以项目的进程分别阐述。
3.1 注册界面
3.1.1 简述
注册界面工作流程: