最近在做JAVA课设,选题是局域网聊天室的实现与设计
忘记了很多知识点,所以整体来说是为了快速应付学校的课设任务⭐期间借鉴了许多资料,主要知识点:GUI图形化界面、IO输入输出流、网络socket编程⭐
public class LoginFrame extends JFrame {
// 设置窗体宽度常量
private static final Integer FRAME_WIDTH = 600;
// 设置窗体高度常量
private static final Integer FRAME_HEIGHT = 400;
//构造方法
public LoginFrame() {
//下面对LoginFrame的设置加不加this.都行
setTitle("❤CHAT ROOM❤"); //设置标题
setSize(FRAME_WIDTH, FRAME_HEIGHT); //设置尺寸
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭模式
setResizable(false); //窗口是否可缩放(不行)
// 获取屏幕像素并确定计算窗口位置居中,两种方法
setLocationRelativeTo(null);
// Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
// int screenWidth = screenSize.width;
// int screenheight = screenSize.height;
// setLocation((screenWidth - FRAME_WIDTH) / 2, (screenheight - FRAME_HEIGHT) / 2);
//标题图标,把咖啡杯换成嘉然的头像
Toolkit toolkit=Toolkit.getDefaultToolkit();
Image topIcon=toolkit.getImage("src/image/bg/login-icon.jpg");
setIconImage(topIcon);
// 背景图片,把图片放在JLabel标签里
ImageIcon imageBg = new ImageIcon("src/image/bg/JRbg.jpg");
JLabel jlbBg = new JLabel(imageBg);
// 图片的位置和大小【不设置也不影响】
jlbBg.setBounds(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
jlbBg.setLayout(null); // 布局为空布局
add(jlbBg); //LoginFrame加入标签组件
// 标题
JLabel lblTitle = new JLabel("❤ CHAT ROOM ❤");
lblTitle.setBounds(150, 35, 350, 55); // x,y,宽,高
lblTitle.setFont(new Font("PingFang SC", Font.BOLD, 36)); //苹方字体,加粗,36尺寸
lblTitle.setForeground(Color.RED); //字体红色
jlbBg.add(lblTitle); //大背景图加入标题组件
// 账户
JLabel lblUid = new JLabel("ACCOUNT:");
lblUid.setBounds(150, 120, 110, 30); //x,y,宽,高
lblUid.setFont(new Font("PingFang SC", Font.BOLD, 16));
lblUid.setForeground(Color.BLACK);
jlbBg.add(lblUid);
//账户文本框
JTextField textUid = new JTextField();
textUid.setBounds(260, 120, 160, 30);
jlbBg.add(textUid);
// 密码【和账户设置差不多】
JLabel lblPwd = new JLabel("PASSWORD:");
lblPwd.setBounds(150, 180, 110, 30);
lblPwd.setFont(new Font("PingFang SC", Font.BOLD, 16));
lblPwd.setForeground(Color.BLACK);
jlbBg.add(lblPwd);
//密码文本框
JPasswordField textPwd = new JPasswordField();
textPwd.setBounds(260, 180, 160, 30);
jlbBg.add(textPwd);
// 登录按钮
JButton login = new JButton("LOGIN");
login.setBounds(175, 250, 103, 30);
login.setBackground(Color.PINK); //背景粉色
login.setForeground(Color.WHITE); //字体白色
login.setFont(new Font("PingFang SC", Font.BOLD, 16));
//登录按钮监听
login.addActionListener(new ActionListener() { //匿名内部类,只在登录时使用一次
@Override
public void actionPerformed(ActionEvent e) {
String username = textUid.getText(); //获取用户名
String password = textPwd.getText(); //获取密码
TransferInfo transferInfo = new TransferInfo(); //实例化传输信息对象
transferInfo.setUsername(username); //设置用户名
transferInfo.setPassword(password); //设置密码
transferInfo.setStatusEnum(ChatStatus.LOGIN); //设置信息为登录
connectionServer(transferInfo); //与服务器连接
}
});
jlbBg.add(login);
// 取消按钮
JButton cancel = new JButton("CANCEL");
cancel.setBounds(355, 250, 103, 30);
cancel.setBackground(Color.PINK);
cancel.setForeground(Color.WHITE);
cancel.setFont(new Font("PingFang SC", Font.BOLD, 16));
jlbBg.add(cancel);
setVisible(true); //设置可视化
//连接服务器的方法
public void connectionServer(TransferInfo transferInfo) {
try {
Socket socket = new Socket("127.0.0.1", 8888); //创建socket(主机,端口)
//写一个消息
IOStream.writeMessage(socket, transferInfo);
//开启客户端子线程,接收消息
ClientHandler clientHandler = new ClientHandler(socket, this);
clientHandler.start();
} catch (UnknownHostException e1) { //捕获一下异常
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("点击了login按钮");
}
//主函数:启动登录界面
public static void main(String[] args) {
new LoginFrame();
}
}
}
// 客户端开启一个线程,来一起读消息
public class ClientHandler extends Thread {
Socket socket; //声明socket
LoginFrame loginFrame; //登录界面
ChatFrame chatFrame; //聊天界面
//含参构造方法(socket,登录界面)
public ClientHandler(Socket socket, LoginFrame loginFrame) {
this.socket = socket;
this.loginFrame = loginFrame;
}
@Override
public void run() {
while (true) {
// 模拟一直读消息
Object object = IOStream.readMessage(socket);
//如果读到的对象属于传输消息这类
//if (object instanceof TransferInfo) {
TransferInfo transferInfo = (TransferInfo) object;
if (transferInfo.getStatusEnum() == InfoType.LOGIN) {
//登录消息
loginResult(transferInfo);
}else if (transferInfo.getStatusEnum() == InfoType.CHAT) {
//聊天消息
chatResult(transferInfo);
}else if (transferInfo.getStatusEnum() == InfoType.NOTICE) {
//系统消息
noticeResult(transferInfo);
}else if (transferInfo.getStatusEnum() == InfoType.ULIST) {
//刷新当前在线用户列表
onlineUsersResult(transferInfo);
}
//}
}
}
/**
* 登录消息处理
*/
public void loginResult(TransferInfo transferInfo) {
if (transferInfo.getLoginSuccess()) {
//登录成功,跳转主页面
String username = transferInfo.getUsername();
chatFrame = new ChatFrame(username, socket);
//关闭登录窗口
loginFrame.dispose();
}else{
//登录失败
System.out.println("客户端接收到登录失败");
System.out.println(transferInfo.getNotice());
}
}
/**
* 系统消息处理
*/
public void noticeResult(TransferInfo transferInfo) {
//在公屏上显示系统消息
String originText = chatFrame.acceptPane.getText();
if (!originText.isEmpty()) {
chatFrame.acceptPane.setText(originText + "\n" + transferInfo.getNotice());
}else{
chatFrame.acceptPane.setText(transferInfo.getNotice());
}
}
/**
* 聊天消息处理
*/
public void chatResult(TransferInfo transferInfo) {
String sender = transferInfo.getSender();
String originText = chatFrame.acceptPane.getText();
chatFrame.acceptPane.setText(originText + "\n" + "> " + sender + ":" + transferInfo.getContent());
}
/**
* 刷新当前界面的用户列表
*/
public void onlineUsersResult(TransferInfo transferInfo) {
String[] userOnlineArray = transferInfo.getUserOnlineArray();
ImageListModel model = new ImageListModel();
for (String username: userOnlineArray){
//头像
User user = new User();
user.setUserName(username);
user.setUiconPath("src/image/" + username + ".jpg");
// System.out.println(user.getUiconPath());
user.setMotto("❤然然可爱捏❤");
model.addElement(user);
}
//JList的模型,给我们存放数据
chatFrame.lstUser.setModel(model);
//提供给我们自定义想要的皮肤或样式
chatFrame.lstUser.setCellRenderer(new ImageCellRenderer());
// chatFrame.lstUser.setListData(userOnlineArray);
}
}
//聊天界面
public class ChatFrame extends JFrame {
private static final long serialVersionUID = 1709267049032639256L;
// 聊天窗体宽度
public static final Integer FRAME_WIDTH = 800;
// 聊天窗体高度
public static final Integer FRAME_HEIGHT = 700;
//消息接受框
public JTextPane acceptPane;
//当前在线用户列表
public JList lstUser;
String username;
Socket socket;
ChatFrame chatFrame;
JTextPane sendPane;
JComboBox reciverBox;
public ChatFrame(String username, Socket socket) {
setTitle("CHAT ROOM");
this.username = username;
this.socket = socket;
chatFrame = this;
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//固定在屏幕中间
setLocationRelativeTo(null);
// Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
// int width = screenSize.width;
// int height = screenSize.height;
// setLocation((width - FRAME_WIDTH) / 2, (height - FRAME_HEIGHT) / 2);
// 加载窗体的背景图片
ImageIcon imageIcon = new ImageIcon("src/image/bg/JRbg.jpg");
JLabel frameBg = new JLabel(imageIcon);
frameBg.setBounds(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
add(frameBg);
//标题图标,把咖啡杯换成嘉然的头像
Toolkit toolkit=Toolkit.getDefaultToolkit();
Image topIcon=toolkit.getImage("src/image/bg/chatframe-icon.jpg");
setIconImage(topIcon);
// 接收框
acceptPane = new JTextPane();
acceptPane.setOpaque(true); // 不透明
acceptPane.setFont(new Font("PingFang SC",Font.BOLD, 16));
// 接收滚动条
JScrollPane scrollPaneOne = new JScrollPane(acceptPane);
scrollPaneOne.setBounds(225, 20, 500, 332);
scrollPaneOne.setOpaque(false);
scrollPaneOne.getViewport().setOpaque(false);
frameBg.add(scrollPaneOne);
// 当前在线用户列表
lstUser = new JList();
lstUser.setFont(new Font("PingFang SC",Font.BOLD, 14));
lstUser.setVisibleRowCount(17);
lstUser.setFixedCellWidth(180);
lstUser.setFixedCellHeight(60);
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem privateChat = new JMenuItem("PRIVATE");
privateChat.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Object reciverObj = lstUser.getSelectedValue();
if (reciverObj instanceof User) {
User user = (User) reciverObj;
String reciver = user.getUserName();
reciverBox.removeAllItems();
reciverBox.addItem("ALL");
reciverBox.addItem(reciver);
reciverBox.setSelectedItem(reciver);
}
}
});
popupMenu.add(privateChat);
// JMenuItem blackList = new JMenuItem("BLACK");
// blackList.addActionListener(new ActionListener() {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// // TODO Auto-generated method stub
//
// }
// });
// popupMenu.add(blackList);
//添加点击事件,需要确认是右键。
lstUser.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
//监听左键|右键
if (e.isMetaDown() && lstUser.getSelectedIndex() >= 0) {
//弹出菜单
popupMenu.show(lstUser, e.getX(), e.getY());
}
}
});
JScrollPane spUser = new JScrollPane(lstUser);
spUser.setFont(new Font("PingFang SC", Font.BOLD, 15));
spUser.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
spUser.setBounds(15, 17, 200, 507);
frameBg.add(spUser);
// 输入框
sendPane = new JTextPane();
sendPane.setOpaque(true);
sendPane.setFont(new Font("PingFang SC", Font.BOLD, 16));
JScrollPane scoPane = new JScrollPane(sendPane);// 设置滚动条
scoPane.setBounds(225, 400, 500, 122);
scoPane.setOpaque(false);
scoPane.getViewport().setOpaque(false);
frameBg.add(scoPane);
//私聊标签
JLabel chatLabel = new JLabel("CHAT TO:");
chatLabel.setBounds(505, 362, 80, 25);
chatLabel.setFont(new Font("PingFang SC", Font.BOLD, 13));
frameBg.add(chatLabel);
//ALL、私聊下拉选择框
reciverBox = new JComboBox();
reciverBox.setSelectedItem("ALL");
reciverBox.addItem("ALL");
reciverBox.setBounds(580, 362, 150, 25);
frameBg.add(reciverBox);
/*
* 发送按钮
*/
JButton send = new JButton("SEND");
send.setBounds(605, 545, 125, 30);
send.setFont(new Font("PingFang SC", Font.BOLD, 16));
send.setForeground(Color.WHITE);
send.setBackground(Color.PINK);
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String content = sendPane.getText();
TransferInfo transferInfo = new TransferInfo();
transferInfo.setContent(content);
//发送人
transferInfo.setSender(username);
String reciver = "ALL";
Object reciverObj = reciverBox.getSelectedItem();
if (reciverObj != null) {
reciver = String.valueOf(reciverObj);
}
System.out.println("MESSAGE:" + reciver);
//接收人
transferInfo.setReciver(reciver);
transferInfo.setStatusEnum(InfoType.CHAT);
IOStream.writeMessage(socket, transferInfo);
sendPane.setText("");
}
});
frameBg.add(send);
//客户端关闭窗体退出
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
System.out.println(username + "CLOSE");
TransferInfo tfi = new TransferInfo();
tfi.setStatusEnum(InfoType.EXIT);
tfi.setUsername(username);
tfi.setNotice(username + " LEAVING.....");
IOStream.writeMessage(socket, tfi);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
//切换背景图片按钮
ImageIcon alterBtn=new ImageIcon("src/image/bg/alterbtn.jpg");
JButton alterBg=new JButton(alterBtn);
// Image temp=alterBtn.getImage().getScaledInstance(alterBg.getWidth(),alterBg.getHeight(),
// alterBtn.getImage().SCALE_DEFAULT);
// alterBtn=new ImageIcon(temp);
// alterBg.setIcon(alterBtn);
alterBg.setBounds(36, 535, 136, 136);
alterBg.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tapCnt++;
if(tapCnt%3==1){
frameBg.setIcon(new ImageIcon("src/image/bg/alterBg-1.jpg"));
}else if(tapCnt%3==2){
frameBg.setIcon(new ImageIcon("src/image/bg/alterBg-2.jpg"));
}else{
frameBg.setIcon(new ImageIcon("src/image/bg/JRbg.jpg"));
}
}
});
frameBg.add(alterBg);
setVisible(true);
}
}
//服务器界面
public class ServerFrame extends JFrame {
//随机生成序列号
private static final long serialVersionUID=-8235369520375669451L;
//服务器窗体宽度
public static final Integer FRAME_WIDTH = 600;
//服务器窗体高度
public static final Integer FRAME_HEIGHT = 600;
//声明用户列表【选项卡2】
public OnlineUserPanel onlineUserPanel;
//声明服务器信息【选项卡1】
public ServerInfoPanel serverInfoPanel;
//构造方法
public ServerFrame() {
setTitle("❤SERVER❤"); //标题
setSize(FRAME_WIDTH, FRAME_HEIGHT); //窗口大小
setResizable(false); //不可缩放窗口
setLocationRelativeTo(null); // 窗口居中
// Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
// int screenWidth = screenSize.width;
// int screenheight = screenSize.height;
// setLocation((screenWidth - FRAME_WIDTH) / 2, (screenheight - FRAME_HEIGHT) / 2);
//标题图标,把咖啡杯换成嘉然的头像
Toolkit toolkit=Toolkit.getDefaultToolkit();
Image topIcon=toolkit.getImage("src/image/bg/server-icon.jpg");
setIconImage(topIcon);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //退出应用程序
// 选项卡(服务器信息+在线用户面板)
JTabbedPane tpServer = new JTabbedPane(JTabbedPane.TOP); //标签位于上方
tpServer.setBackground(Color.WHITE); //设置背景颜色
tpServer.setFont(new Font("PingFang SC",Font.BOLD,20));
//实例化两个选项卡
serverInfoPanel = new ServerInfoPanel();
onlineUserPanel = new OnlineUserPanel();
//选项卡加入服务器信息和在线用户面板
tpServer.add("SERVER INFO", serverInfoPanel.getServerInfoPanel()); //方法是返回一个面板
tpServer.add("ONLINE USER", onlineUserPanel.getUserPanel());
add(tpServer); //服务器界面加入选项卡
setVisible(true);
}
}
//【第一个服务器信息选项卡】
public class ServerInfoPanel {
public JTextField txtNumber; //人数
public JTextField txtServerName; //服务器名称
public JTextField txtIP; //IP地址
public JTextField txtPort; //端口号
public JTextPane txtLog; //日志文本
public JLabel getServerInfoPanel() {
// 第一个服务选项卡面板,包括日志区域
JPanel pnlServer = new JPanel();
pnlServer.setOpaque(false);
pnlServer.setLayout(null);
pnlServer.setBounds(0, 0, ServerFrame.FRAME_WIDTH, ServerFrame.FRAME_HEIGHT);
// 日志标签
JLabel lblLog = new JLabel("❤LOG❤");
lblLog.setForeground(Color.RED);
lblLog.setFont(new Font("PingFang SC", Font.BOLD, 20));
lblLog.setBounds(150, 10, 100, 30);
pnlServer.add(lblLog); //选项卡加入日志标签组件
// 日志区域
txtLog = new JTextPane();
txtLog.setBackground(Color.BLACK);
txtLog.setForeground(Color.PINK);
txtLog.setOpaque(true);
txtLog.setFont(new Font("PingFang SC", Font.BOLD, 18));
//日志显示屏
JScrollPane scoPaneOne = new JScrollPane(txtLog);// 设置滚动条,把txtLog塞进去
scoPaneOne.setBounds(155, 40, 390, 390);
scoPaneOne.setOpaque(false);
//设置聊天框与滚动条像素透明,露出下方背景像素
//【JSCrollPane有两个面板层,一个是他本身,而另外一个则是他的viewport(视口)】
scoPaneOne.getViewport().setOpaque(false);
//面板加入日志显示屏
pnlServer.add(scoPaneOne);
//停止按钮
pnlServer.add(stopBtn());
//保存按钮
pnlServer.add(saveLogBtn());
//左边四行参数
pnlServer.add(getServerParam());
// 加载窗体的背景图片
ImageIcon imageIcon = new ImageIcon("src/image/bg/JRbg.jpg");
// 创建一个标签并将图片添加进去
JLabel lblBackground = new JLabel(imageIcon);
// 设置图片的位置和大小
lblBackground.setBounds(0, 0, 300, 300);
// 添加到当前窗体中
lblBackground.add(pnlServer);
//返回标签背景
return lblBackground;
}
public JPanel getServerParam() {
// 左边服务器参数信息面板,不包括日志区域
JPanel serverParamPanel = new JPanel();
serverParamPanel.setOpaque(false); //设置透明
serverParamPanel.setBounds(12, 35, 120, 360);
serverParamPanel.setFont(new Font("PingFang SC", Font.BOLD, 15));
//在线人数标签
JLabel lblNumber = new JLabel("ONLINE:");
lblNumber.setForeground(Color.ORANGE);
lblNumber.setFont(new Font("PingFang SC", Font.BOLD, 15));
serverParamPanel.add(lblNumber);
//在线人数文本框
txtNumber = new JTextField("0", 14);
txtNumber.setFont(new Font("PingFang SC", Font.BOLD, 15));
txtNumber.setEditable(false);
txtNumber.setHorizontalAlignment(JTextField.CENTER); //文本框居中
serverParamPanel.add(txtNumber);
//主机名标签
JLabel lblServerName = new JLabel("NAME:");
lblServerName.setForeground(Color.ORANGE);
lblServerName.setFont(new Font("PingFang SC", Font.BOLD, 15));
serverParamPanel.add(lblServerName);
//主机名文本框
txtServerName = new JTextField(14);
txtServerName.setFont(new Font("PingFang SC", Font.BOLD, 15));
txtServerName.setEditable(false);
txtServerName.setHorizontalAlignment(JTextField.CENTER); //文本框居中
serverParamPanel.add(txtServerName);
//IP标签
JLabel lblIP = new JLabel("IP:");
lblIP.setForeground(Color.ORANGE);
lblIP.setFont(new Font("PingFang SC", Font.BOLD, 15));
serverParamPanel.add(lblIP);
//IP文本框
txtIP = new JTextField(14);
txtIP.setFont(new Font("PingFang SC", Font.BOLD, 15));
txtIP.setEditable(false);
txtIP.setHorizontalAlignment(JTextField.CENTER); //文本框居中
serverParamPanel.add(txtIP);
//端口号标签
JLabel lblPort = new JLabel("PORT:");
lblPort.setForeground(Color.ORANGE);
lblPort.setFont(new Font("PingFang SC", Font.BOLD, 15));
serverParamPanel.add(lblPort);
//端口号文本框
txtPort = new JTextField(Port.SERVER_PORT + "", 14);
txtPort.setFont(new Font("PingFang SC", Font.BOLD, 15));
txtPort.setEditable(false); //禁止编辑
txtPort.setHorizontalAlignment(JTextField.CENTER); //文本框居中
serverParamPanel.add(txtPort);
return serverParamPanel;
}
//服务器关闭按钮
public JButton stopBtn() {
JButton stopBtn = new JButton("CLOSE");
stopBtn.setBackground(Color.PINK);
stopBtn.setForeground(Color.WHITE);
stopBtn.setFont(new Font("PingFang SC", Font.BOLD, 15));
stopBtn.setBounds(180, 450, 120, 35);
return stopBtn;
}
//保存日志按钮
public JButton saveLogBtn() {
JButton saveLogBtn = new JButton("SAVE");
saveLogBtn.setBackground(Color.PINK);
saveLogBtn.setForeground(Color.WHITE);
saveLogBtn.setFont(new Font("PingFang SC", Font.BOLD, 15));
saveLogBtn.setBounds(390, 450, 120, 35);
return saveLogBtn;
}
}
//【第二个在线用户选项卡】
public class OnlineUserPanel {
//用户
public JList lstUser;
//在线用户标签
public JLabel getUserPanel() {
JPanel pnlUser = new JPanel();
pnlUser.setLayout(null);
pnlUser.setBackground(Color.PINK);
pnlUser.setBounds(30, 5, 480, 400);
pnlUser.setOpaque(false);// 设置透明
JLabel lblUser = new JLabel("❤ ONLINE LIST ❤");
lblUser.setFont(new Font("PingFang SC", Font.BOLD, 20));
lblUser.setBounds(20, 10, 200, 30);
lblUser.setForeground(Color.PINK);
pnlUser.add(lblUser); //标题标签加到大面板
// 用户列表
lstUser = new JList();
lstUser.setFont(new Font("PingFang SC", Font.BOLD, 16));
lstUser.setVisibleRowCount(17); //设置列表可见行数
lstUser.setFixedCellWidth(180); //单元宽度
lstUser.setFixedCellHeight(35); //单元高度
lstUser.setOpaque(false);
JScrollPane spUser = new JScrollPane(lstUser); //实例化含用户列表的滚动面板
spUser.setFont(new Font("PingFang SC", Font.BOLD, 14));
spUser.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
spUser.setBounds(30, 45, 440, 360);
spUser.setOpaque(false);
pnlUser.add(spUser); //滚动面板加到大面版
// 加载窗体的背景图片
ImageIcon imageIcon = new ImageIcon("src/image/bg/JRbg.jpg");
// 创建一个标签并将图片添加进去
JLabel lblBackground = new JLabel(imageIcon);
// 设置图片的位置和大小
lblBackground.setBounds(0, 200, 300, 300);
// 添加到当前窗体中
lblBackground.add(pnlUser);
//返回大面板
return lblBackground;
}
}
//服务器启动一个线程,一直读消息
public class ServerHandler extends Thread {
Socket socket;
ServerFrame serverFrame;
public ServerHandler(Socket socket, ServerFrame serverFrame) {
this.socket = socket;
this.serverFrame = serverFrame;
}
static ArrayList<String> onlineUsers = new ArrayList<>();
static ArrayList<Socket> onlineSockets = new ArrayList<>();
@Override
public void run() {
// 默认重复拿
while (true) {
// 模拟一直拿消息
Object object = IOStream.readMessage(socket); //从socket当中读取消息
System.out.println("Server receive:" + object);
// if (object instanceof TransferInfo) { //如果读取的对象是TransferInfo的实例化
TransferInfo transferInfo = (TransferInfo) object; //将对象强整形
if (transferInfo.getStatusEnum() == InfoType.LOGIN) {
//登录消息类型
loginHandler(transferInfo);
}else if (transferInfo.getStatusEnum() == InfoType.CHAT) {
//聊天信息类型
chatHandler(transferInfo);
}else if (transferInfo.getStatusEnum() == InfoType.EXIT) {
//退出聊天类型
logout(transferInfo);
try {
Thread.sleep(1000);
socket.close(); //关闭socket连接
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.interrupt();//关闭当前线程
break;
}
// }
}
}
//客户端登录处理
public void loginHandler(TransferInfo transferInfo) {
boolean flag = checkUserLogin(transferInfo);
transferInfo.setLoginSuccess(false);
if (flag) {
//返回登录成功给客户端(登录消息)
transferInfo.setLoginSuccess(true);
transferInfo.setStatusEnum(InfoType.LOGIN);
IOStream.writeMessage(socket, transferInfo);
String username = transferInfo.getUsername();
//统计在线人数
onlineUsers.add(username);
onlineSockets.add(socket);
ChatServer.userSocketMap.put(username, socket);
//返回用户上线信息给所有用户(系统消息)
transferInfo = new TransferInfo();
transferInfo.setStatusEnum(InfoType.NOTICE);
String notice = ">> ❤ Welcome " + username + " ❤";
transferInfo.setNotice(notice);
sendAll(transferInfo);
//发送最新的用户列表给客户端
transferInfo = new TransferInfo();
transferInfo.setUserOnlineArray(onlineUsers.toArray(new String[onlineUsers.size()]));
transferInfo.setStatusEnum(InfoType.ULIST);
sendAll(transferInfo);
//刷新在线用户列表
flushOnlineUserList();
//发送信息给服务器日志
log(notice);
}else{
//返回登录失败给客户端
IOStream.writeMessage(socket, transferInfo);
log(transferInfo.getUsername() + "LOGIN FAILED!");
}
}
public void log(String log) {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = simpleDateFormat.format(date);
JTextPane txtLog = serverFrame.serverInfoPanel.txtLog;
String oldLog = txtLog.getText();
txtLog.setText(oldLog + "\n" + dateStr + ":" + log);
}
//刷新用户列表(当一个用户上线时,便刷新)
public void flushOnlineUserList() {
JList lstUser = serverFrame.onlineUserPanel.lstUser;
String[] userArray = onlineUsers.toArray(new String[onlineUsers.size()]);
lstUser.setListData(userArray);
serverFrame.serverInfoPanel.txtNumber.setText(userArray.length + "");
}
//广播给所有人
public void sendAll(TransferInfo transferInfo) {
for (int i = 0; i < onlineSockets.size(); i++){
Socket tempSocket = onlineSockets.get(i);
IOStream.writeMessage(tempSocket, transferInfo);
}
}
//私聊
public void send(TransferInfo transferInfo) {
String reciver = transferInfo.getReciver();
String sender = transferInfo.getSender();
Socket socket1 = ChatServer.userSocketMap.get(reciver);
IOStream.writeMessage(socket1, transferInfo);
Socket socket2 = ChatServer.userSocketMap.get(sender);
IOStream.writeMessage(socket2, transferInfo);
}
// 处理客户端聊天请求
public void chatHandler(TransferInfo transferInfo) {
String reciver = transferInfo.getReciver();
if ("ALL".equals(reciver)) {
//发送给所有人
sendAll(transferInfo);
}else{
//私聊
send(transferInfo);
}
}
//验证登录
public boolean checkUserLogin(TransferInfo transferInfo) {
try {
String username = transferInfo.getUsername();
String password = transferInfo.getPassword();
FileInputStream fileInputStream = new FileInputStream(new File("src/user.txt"));
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
String row = null;
while ((row = dataInputStream.readLine()) != null) {
//从文件中读取的行
String fileUser = row;
if ((username + "@" + password).equals(row)) {
System.out.println("Name and Password are correct!");
return true;
}else{
System.out.println("Login failed!");
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
//用户退出处理,清理在线人数,刷新用户列表,告诉所有人,你已经离开
private void logout(TransferInfo transferInfo) {
String userName = transferInfo.getUsername();
//将该用户从用户集合移除
Iterator<String> userIter = onlineUsers.iterator();
while(userIter.hasNext()) {
if(userIter.next().equals(userName)) {
userIter.remove();
}
}
//将该用户从socket集合移除
Iterator<Socket> socketIter = onlineSockets.iterator();
while(socketIter.hasNext()) {
Socket next = socketIter.next();
if(socket == next) {
socketIter.remove();
}
}
//将user与Socket的关系从Map中移除
ChatServer.userSocketMap.remove(userName);
//刷新服务器面板的用户列表
flushOnlineUserList();
//给所有在线的用户发送下线消息
transferInfo.setStatusEnum(InfoType.NOTICE);
sendAll(transferInfo);
//告诉其他人刷新用户列表
transferInfo.setUserOnlineArray(onlineUsers.toArray(new String [onlineUsers.size()]));
transferInfo.setStatusEnum(InfoType.ULIST);
sendAll(transferInfo);
}
}
//服务器启动
public class ChatServer {
static HashMap<String, Socket> userSocketMap = new HashMap<>();
public ServerFrame serverFrame;
public ChatServer() {
try{
//建立服务器Socket监听
ServerSocket serverSocket = new ServerSocket(Port.SERVER_PORT); //端口号:8888
//打开服务器界面
serverFrame = new ServerFrame();
ServerInfoBean serverInfo = getServerIP();
loadServerInfo(serverInfo);
//解决多客户端连接的循环
while(true){
//等待连接,阻塞实现,会得到一个客户端连接
Socket socket = serverSocket.accept();
//启动一个线程来一直接收消息
ServerHandler serverHandler = new ServerHandler(socket, serverFrame);
serverHandler.start();
System.out.println("CONNECTED:" + socket);
}
}catch (IOException e) {
e.printStackTrace();
}
}
//获取服务器的主机名和IP地址,返回服务器IP等信息
public ServerInfoBean getServerIP() {
ServerInfoBean sib = null;
try {
InetAddress serverAddress = InetAddress.getLocalHost();
byte[] ipAddress = serverAddress.getAddress();
sib = new ServerInfoBean();
sib.setIp(serverAddress.getHostAddress());
sib.setHostName(serverAddress.getHostName());
sib.setPort(Port.SERVER_PORT);
System.out.println("Server IP is:" + (ipAddress[0] & 0xff) + "."
+ (ipAddress[1] & 0xff) + "." + (ipAddress[2] & 0xff) + "."
+ (ipAddress[3] & 0xff));
} catch (Exception e) {
System.out.println("CouLd not get Server IP." + e);
}
return sib;
}
public void loadServerInfo(ServerInfoBean serverInfo) {
serverFrame.serverInfoPanel.txtIP.setText(serverInfo.getIp());
serverFrame.serverInfoPanel.txtServerName.setText(serverInfo.getHostName());
serverFrame.serverInfoPanel.txtLog.setText("❤ SERVER SUCCESS ❤");
}
//主函数
public static void main(String[] args) {
new ChatServer();
}
}
随便设置,只要不被占用即可
public class Port {
//服务器端口8888
public final static Integer SERVER_PORT = 8888;
}
public class IOStream {
//读消息
public static Object readMessage(Socket socket) {
Object object = null;
try {
InputStream inputStream = socket.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
object = objectInputStream.readObject();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object; //返回读到的对象
}
//写消息
public static void writeMessage(Socket socket, Object message) {
try {
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(message);
objectOutputStream.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public enum InfoType {
LOGIN(1, "登录"),
NOTICE(2, "系统消息"),
CHAT(3, "聊天消息"),
ULIST(4, "在线用户列表"),
EXIT(5, "退出");
private Integer status;
private String desc;
private InfoType(int status, String desc) {
this.status = status;
this.desc = desc;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
public class ServerInfoBean implements Serializable {
private static final long serialVersionUID = 4800399407766443229L;
private String hostName;
private String ip;
private Integer port;
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
}
package com.xy.chatting.entity;
import java.io.Serializable;
public class TransferInfo implements Serializable {
private static final long serialVersionUID = -8501366066504250232L;
private String username; //用户名
private String password; //密码
private String content; //聊天内容
private Boolean loginSuccess; //登录成功标志
private String notice; //系统消息
private InfoType statusEnum; //消息类型
private String[] userOnlineArray; //在线用户列表
private String sender; //消息发送人
private String reciver; //消息接收者
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getLoginSuccess() {
return loginSuccess;
}
public void setLoginSuccess(Boolean loginSuccess) {
this.loginSuccess = loginSuccess;
}
public String getNotice() {
return notice;
}
public void setNotice(String notice) {
this.notice = notice;
}
public InfoType getStatusEnum() {
return statusEnum;
}
public void setStatusEnum(InfoType statusEnum) {
this.statusEnum = statusEnum;
}
public String[] getUserOnlineArray() {
return userOnlineArray;
}
public void setUserOnlineArray(String[] userOnlineArray) {
this.userOnlineArray = userOnlineArray;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getReciver() {
return reciver;
}
public void setReciver(String reciver) {
this.reciver = reciver;
}
}
public class User implements Serializable{
private static final long serialVersionUID = 5126205470509431771L;
private String userName;
private String motto;
// private String nickName;
private String uiconPath;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getMotto() {
return motto;
}
public void setMotto(String motto) {
this.motto = motto;
}
// public String getNickName() {
// return nickName;
}
// public void setNickName(String nickName) {
// this.nickName = nickName;
// }
public String getUiconPath() {
return uiconPath;
}
public void setUiconPath(String uiconPath) {
this.uiconPath = uiconPath;
}
}
public class ImageCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = -6233481640415228808L;
@Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if(value instanceof User) {
User user = (User) value;
String uiconPath = user.getUiconPath();
String userName = user.getUserName();
String motto = user.getMotto();
ImageIcon icon = new ImageIcon(uiconPath);
icon.setImage(icon.getImage().getScaledInstance(55, 55, Image.SCALE_DEFAULT));
setIcon(icon);
String text = "" + userName + "
" + motto + "";
setText(text);
if (isSelected) { //当某个元素被选中时
setBackground(Color.LIGHT_GRAY); //设置背景色
}else {
setForeground(Color.GRAY);
}
setVerticalTextPosition(SwingConstants.TOP);
setHorizontalTextPosition(SwingConstants.RIGHT);
}
return this;
}
}
package com.xy.chatting.ulist;
import java.util.List;
import java.util.ArrayList;
import javax.swing.AbstractListModel;
import com.xy.chatting.entity.User;
/**
* JList的模型类
*/
public class ImageListModel extends AbstractListModel<User> {
private static final long serialVersionUID = 8116378668465150072L;
private ArrayList<User> list = new ArrayList<User>();
public void addElement(User str) {
list.add(str);
}
@Override
public User getElementAt(int index) {
return list.get(index);
}
@Override
public int getSize() {
// TODO Auto-generated method stub
return list.size();
}
}