目录
一。项目前的准备
1.为什么选择这个项目
没有Mysql所以使用一个集合来存储信息
UI没有刻意写,界面写的是控制台
2.项目开发的流程
1.需求阶段
需求分析师来做,出一个需求分析的报告(白皮书的格式),项目的功能,客户的要求。
需求分析师的要求:1.有技术。2.懂行业。 例如:银行,税务,海关。
2.设计阶段
项目经理或者是架构师来处理
工作:制作类图,流程图,模块,数据库,架构,流量,用户访问量,组建团队(挑选团队成员)等。
工资:基本工资+项目提成
3.实现阶段
程序员,码农来进行实现。刚进入工作基本上都是实现岗位。
4.测试阶段
测试工程师,找到模块可能出现的bug 。(可能是引用模块的问题。耦合性高的问题)。测试和实现是相互交叉的
5.部署阶段
实施工程师,主要是对环境的配置,要经常出差,将项目部署到客户指定的机子上面。
6.维护阶段
项目部署到对方平台,出现问题之后,进行处理。 项目升级,项目扩展之类的要求。
图示
项目越大设计阶段花的时间越多
3.项目的需求
1.图示
2.界面设计
用户登录
拉取在线用户列表
私聊
群聊
发文件
服务器推送新闻
推图片,文件和推文字的基本原理是相同的
3.通信功能的整体分析
传输对象,对象当中包含传递的信息,从管道当中运输信息。
Message类来进行装载信息,Socket作为传送信息两端的基站。 线程持有一个socket。socket是线程的一个属性。
因为群发的需求,所以需要一个线程集合来进行管理。可以查找集合当中都有那些线程,确定与服务器链接的用户。
一个客户端也可能与服务端有多个线程的链接。例如:发送文件,视频聊天,文件下载。是不同的。 所以客户端也应该有一个线程的集合来对线程进行统一的管理。
客户端使用对象流来进行读写信息。
图例
二。开发阶段
1.登录功能实现
1.先创建三个类一个接口(服务端客户端都要有)
User:用于存储用户账号密码信息的
package com.qqcommon;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1l;
private String userId; //用户Id
private String Password; //用户密码
public User() {
}
public User(String userId, String password) {
this.userId = userId;
Password = password;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return Password;
}
public void setPassword(String password) {
Password = password;
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", Password='" + Password + '\'' +
'}';
}
}
Message:用于存放用户信息
package com.qqcommon;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 1l;
private String sender; // 发送者
private String getter; //接收者
private String content; //消息内容
private String sendTime; //发送时间
private String mesType; //消息类型
// 传送文件的成员变量
private byte[] fileByte;
private int fileLen =0;
private String dest;//文件输入地址
private String src;//文件输出地址
public byte[] getFileByte() {
return fileByte;
}
public void setFileByte(byte[] fileByte) {
this.fileByte = fileByte;
}
public int getFileLen() {
return fileLen;
}
public void setFileLen(int fileLen) {
this.fileLen = fileLen;
}
public String getDest() {
return dest;
}
public void setDest(String dest) {
this.dest = dest;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public Message() {
}
public Message(String sender, String getter, String content, String sendTime, String mesType) {
this.sender = sender;
this.getter = getter;
this.content = content;
this.sendTime = sendTime;
this.mesType = mesType;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getGetter() {
return getter;
}
public void setGetter(String getter) {
this.getter = getter;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSendTime() {
return sendTime;
}
public void setSendTime(String sendTime) {
this.sendTime = sendTime;
}
public String getMesType() {
return mesType;
}
public void setMesType(String mesType) {
this.mesType = mesType;
}
}
MessageType:用于存放消息类型的接口(Message当中的一个属性)
package com.qqcommon;
public interface MessageType {
String MESSAGE_LOGIN_SUCCESS = "1"; //登录验证成功
String MESSAGE_LOGIN_FAIL = "2"; //验证登录失败
String MESSAGE_COMM_MES = "3"; //消息类型为普通消息
String MESSAGE_GET_ONLINE_FRIEND = "4"; //请求得到在线用户信息
String MESSAGE_RET_ONLINE_FRIEND = "5"; //返回在线用户信息
String MESSAGE_CLIENT_EXIT = "6"; //退出消息
String MESSAGE_TO_ALL_MES = "7";//群发文件
String MESSAGE_FILE_MES = "8";//发送文件
String MESSAGE_GET_NOT_ONLINE_MES = "9"; //接收离线消息
String MESSAGE_SET_NOT_ONLINE_MES = "10"; //发送离线消息
}
//可以扩展功能
Utility类
package com.utils;
/**
工具类的作用:
处理各种情况的用户输入,并且能够按照程序员的需求,得到用户的控制台输入。
*/
import java.util.Scanner;
/**
*/
public class Utility {
//静态属性。。。
private static Scanner scanner = new Scanner(System.in);
/**
* 功能:读取键盘输入的一个菜单选项,值:1——5的范围
* @return 1——5
*/
public static char readMenuSelection() {
char c;
for (; ; ) {
String str = readKeyBoard(1, false);//包含一个字符的字符串
c = str.charAt(0);//将字符串转换成字符char类型
if (c != '1' && c != '2' &&
c != '3' && c != '4' && c != '5') {
System.out.print("选择错误,请重新输入:");
} else break;
}
return c;
}
/**
* 功能:读取键盘输入的一个字符
* @return 一个字符
*/
public static char readChar() {
String str = readKeyBoard(1, false);//就是一个字符
return str.charAt(0);
}
/**
* 功能:读取键盘输入的一个字符,如果直接按回车,则返回指定的默认值;否则返回输入的那个字符
* @param defaultValue 指定的默认值
* @return 默认值或输入的字符
*/
public static char readChar(char defaultValue) {
String str = readKeyBoard(1, true);//要么是空字符串,要么是一个字符
return (str.length() == 0) ? defaultValue : str.charAt(0);
}
/**
* 功能:读取键盘输入的整型,长度小于2位
* @return 整数
*/
public static int readInt() {
int n;
for (; ; ) {
String str = readKeyBoard(10, false);//一个整数,长度<=10位
try {
n = Integer.parseInt(str);//将字符串转换成整数
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的 整数或默认值,如果直接回车,则返回默认值,否则返回输入的整数
* @param defaultValue 指定的默认值
* @return 整数或默认值
*/
public static int readInt(int defaultValue) {
int n;
for (; ; ) {
String str = readKeyBoard(10, true);
if (str.equals("")) {
return defaultValue;
}
//异常处理...
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 功能:读取键盘输入的指定长度的字符串
* @param limit 限制的长度
* @return 指定长度的字符串
*/
public static String readString(int limit) {
return readKeyBoard(limit, false);
}
/**
* 功能:读取键盘输入的指定长度的字符串或默认值,如果直接回车,返回默认值,否则返回字符串
* @param limit 限制的长度
* @param defaultValue 指定的默认值
* @return 指定长度的字符串
*/
public static String readString(int limit, String defaultValue) {
String str = readKeyBoard(limit, true);
return str.equals("")? defaultValue : str;
}
/**
* 功能:读取键盘输入的确认选项,Y或N
* 将小的功能,封装到一个方法中.
* @return Y或N
*/
public static char readConfirmSelection() {
System.out.println("请输入你的选择(Y/N): 请小心选择");
char c;
for (; ; ) {//无限循环
//在这里,将接受到字符,转成了大写字母
//y => Y n=>N
String str = readKeyBoard(1, false).toUpperCase();
c = str.charAt(0);
if (c == 'Y' || c == 'N') {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
/**
* 功能: 读取一个字符串
* @param limit 读取的长度
* @param blankReturn 如果为true ,表示 可以读空字符串。
* 如果为false表示 不能读空字符串。
*
* 如果输入为空,或者输入大于limit的长度,就会提示重新输入。
* @return
*/
private static String readKeyBoard(int limit, boolean blankReturn) {
//定义了字符串
String line = "";
//scanner.hasNextLine() 判断有没有下一行
while (scanner.hasNextLine()) {
line = scanner.nextLine();//读取这一行
//如果line.length=0, 即用户没有输入任何内容,直接回车
if (line.length() == 0) {