赞
踩
目录
使用 java swing 开发多人聊天室,分为服务端和客户端,属于BS架构。
功能包括:注册、登录、单聊、群聊、窗口抖动、发送文件、选头像。
服务器:可以看到全部已注册用户的列表,用户登录之后也可以在服务器看到在线信息。
客户端:可以注册新用户,注册时可以填写昵称、密码、性别、头像。
登录成功之后会进入聊天室,在聊天室可以看到其他在线用户,也可以选择某个具体用户进行单聊。
也可以给其他用户发送窗口抖动。
也可以给其他用户发送文件。
可以选择头像
这是服务器启动的主程序,在这里监听了网络端口,循环接收客户端的连接请求。
-
- package server;
-
- import java.io.IOException;
- import java.net.*;
-
- import javax.swing.*;
-
- import server.controller.RequestProcessor;
- import server.ui.ServerInfoFrame;
-
- /** 服务器入口程序 */
- public class ServerMain {
- public static void main(String[] args) {
- try {//设置外观样式
- UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
- } catch (Exception e) {
- e.printStackTrace();
- }
- int port = Integer.parseInt(DataBuffer.configProp.getProperty("port"));
- //初始化服务器套节字
- try {
- DataBuffer.serverSocket = new ServerSocket(port);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- new Thread(new Runnable() {//启动新线程进行客户端连接监听
- public void run() {
- try {
- while (true) {
- // 监听客户端的连接
- Socket socket = DataBuffer.serverSocket.accept();
- System.out.println("客户来了:"
- + socket.getInetAddress().getHostAddress()
- + ":" + socket.getPort());
-
- //针对每个客户端启动一个线程,在线程中调用请求处理器来处理每个客户端的请求
- new Thread(new RequestProcessor(socket)).start();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }).start();
-
-
- //启动服务器监控窗体
- new ServerInfoFrame();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
服务器对收到的消息进行处理,例如注册、登录、窗口震动、发送文件、接收文件、聊天、拒收文件,以及其他类型的消息都在这进行处理。
-
- package server.controller;
-
- import java.io.*;
- import java.net.Socket;
- import java.text.*;
- import java.util.concurrent.CopyOnWriteArrayList;
- import server.*;
- import server.model.service.UserService;
- import common.model.entity.*;
-
- /** 服务器端请求处理器 */
- public class RequestProcessor implements Runnable{
- private Socket currentClientSocket; //当前正在请求服务器的客户端Socket
-
- public RequestProcessor(Socket currentClientSocket){
- this.currentClientSocket = currentClientSocket;
- }
-
- public void run() {
- boolean flag = true; //是否不间断监听
- try{
- OnlineClientIOCache currentClientIOCache = new OnlineClientIOCache(
- new ObjectInputStream(currentClientSocket.getInputStream()),
- new ObjectOutputStream(currentClientSocket.getOutputStream()));
- while(flag){ //不停地读取客户端发过来的请求对象
- //从请求输入流中读取到客户端提交的请求对象
- Request request = (Request)currentClientIOCache.getOis().readObject();
- System.out.println("Server读取了客户端的请求:" + request.getAction());
-
- String actionName = request.getAction(); //获取请求中的动作
- if(actionName.equals("userRegiste")){ //用户注册
- registe(currentClientIOCache, request);
- }else if(actionName.equals("userLogin")){ //用户登录
- login(currentClientIOCache, request);
- }else if("exit".equals(actionName)){ //请求断开连接
- flag = logout(currentClientIOCache, request);
- }else if("chat".equals(actionName)){ //聊天
- chat(request);
- }else if("shake".equals(actionName)){ //振动
- shake(request);
- }else if("toSendFile".equals(actionName)){ //准备发送文件
- toSendFile(request);
- }else if("agreeReceiveFile".equals(actionName)){ //同意接收文件
- agreeReceiveFile(request);
- }else if("refuseReceiveFile".equals(actionName)){ //拒绝接收文件
- refuseReceiveFile(request);
- }
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
-
- /** 拒绝接收文件 */
- private void refuseReceiveFile(Request request) throws IOException {
- FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");
- Response response = new Response(); //创建一个响应对象
- response.setType(ResponseType.REFUSERECEIVEFILE);
- response.setData("sendFile", sendFile);
- response.setStatus(ResponseStatus.OK);
- //向请求方的输出流输出响应
- OnlineClientIOCache ocic = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());
- this.sendResponse(ocic, response);
- }
-
- /** 同意接收文件 */
- private void agreeReceiveFile(Request request) throws IOException {
- FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");
- //向请求方(发送方)的输出流输出响应
- Response response = new Response(); //创建一个响应对象
- response.setType(ResponseType.AGREERECEIVEFILE);
- response.setData("sendFile", sendFile);
- response.setStatus(ResponseStatus.OK);
- OnlineClientIOCache sendIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());
- this.sendResponse(sendIO, response);
-
- //向接收方发出接收文件的响应
- Response response2 = new Response(); //创建一个响应对象
- response2.setType(ResponseType.RECEIVEFILE);
- response2.setData("sendFile", sendFile);
- response2.setStatus(ResponseStatus.OK);
- OnlineClientIOCache receiveIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());
- this.sendResponse(receiveIO, response2);
- }
-
- /** 客户端退出 */
- public boolean logout(OnlineClientIOCache oio, Request request) throws IOException{
- System.out.println(currentClientSocket.getInetAddress().getHostAddress()
- + ":" + currentClientSocket.getPort() + "走了");
-
- User user = (User)request.getAttribute("user");
- //把当前上线客户端的IO从Map中删除
- DataBuffer.onlineUserIOCacheMap.remove(user.getId());
- //从在线用户缓存Map中删除当前用户
- DataBuffer.onlineUsersMap.remove(user.getId());
-
- Response response = new Response(); //创建一个响应对象
- response.setType(ResponseType.LOGOUT);
- response.setData("logoutUser", user);
- oio.getOos().writeObject(response); //把响应对象往客户端写
- oio.getOos().flush();
- currentClientSocket.close(); //关闭这个客户端Socket
-
- DataBuffer.onlineUserTableModel.remove(user.getId()); //把当前下线用户从在线用户表Model中删除
- iteratorResponse(response);//通知所有其它在线客户端
-
- return false; //断开监听
- }
- /** 注册 */
- public void registe(OnlineClientIOCache oio, Request request) throws IOException {
- User user = (User)request.getAttribute("user");
- UserService userService = new UserService();
-
- userService.addUser(user);
-
- Response response = new Response(); //创建一个响应对象
- response.setStatus(ResponseStatus.OK);
- response.setData("user", user);
-
- oio.getOos().writeObject(response); //把响应对象往客户端写
- oio.getOos().flush();
-
- //把新注册用户添加到RegistedUserTableModel中
- DataBuffer.registedUserTableModel.add(new String[]{
- String.valueOf(user.getId()),
- user.getPassword(),
- user.getNickname(),
- String.valueOf(user.getSex())
- });
- }
-
- /** 登录 */
- public void login(OnlineClientIOCache currentClientIO, Request request) throws IOException {
- String idStr = (String)request.getAttribute("id");
- String password = (String) request.getAttribute("password");
- UserService userService = new UserService();
- User user = userService.login(Long.parseLong(idStr), password);
-
- Response response = new Response(); //创建一个响应对象
- if(null != user){
- if(DataBuffer.onlineUsersMap.containsKey(user.getId())){ //用户已经登录了
- response.setStatus(ResponseStatus.OK);
- response.setData("msg", "该 用户已经在别处上线了!");
- currentClientIO.getOos().writeObject(response); //把响应对象往客户端写
- currentClientIO.getOos().flush();
- }else { //正确登录
- DataBuffer.onlineUsersMap.put(user.getId(), user); //添加到在线用户
- //设置在线用户
- response.setData("onlineUsers",
- new CopyOnWriteArrayList<User>(DataBuffer.onlineUsersMap.values()));
-
- response.setStatus(ResponseStatus.OK);
- response.setData("user", user);
- currentClientIO.getOos().writeObject(response); //把响应对象往客户端写
- currentClientIO.getOos().flush();
-
- //通知其它用户有人上线了
- Response response2 = new Response();
- response2.setType(ResponseType.LOGIN);
- response2.setData("loginUser", user);
- iteratorResponse(response2);
-
- //把当前上线的用户IO添加到缓存Map中
- DataBuffer.onlineUserIOCacheMap.put(user.getId(),currentClientIO);
-
- //把当前上线用户添加到OnlineUserTableModel中
- DataBuffer.onlineUserTableModel.add(
- new String[]{String.valueOf(user.getId()),
- user.getNickname(),
- String.valueOf(user.getSex())});
- }
- }else{ //登录失败
- response.setStatus(ResponseStatus.OK);
- response.setData("msg", "账号或密码不正确!");
- currentClientIO.getOos().writeObject(response);
- currentClientIO.getOos().flush();
- }
- }
-
- /** 聊天 */
- public void chat(Request request) throws IOException {
- Message msg = (Message)request.getAttribute("msg");
- Response response = new Response();
- response.setStatus(ResponseStatus.OK);
- response.setType(ResponseType.CHAT);
- response.setData("txtMsg", msg);
-
- if(msg.getToUser() != null){ //私聊:只给私聊的对象返回响应
- OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
- sendResponse(io, response);
- }else{ //群聊:给除了发消息的所有客户端都返回响应
- for(Long id : DataBuffer.onlineUserIOCacheMap.keySet()){
- if(msg.getFromUser().getId() == id ){ continue; }
- sendResponse(DataBuffer.onlineUserIOCacheMap.get(id), response);
- }
- }
- }
-
- /** 发送振动 */
- public void shake(Request request)throws IOException {
- Message msg = (Message)request.getAttribute("msg");
-
- DateFormat df = new SimpleDateFormat("HH:mm:ss");
- StringBuffer sb = new StringBuffer();
- sb.append(" ").append(msg.getFromUser().getNickname())
- .append("(").append(msg.getFromUser().getId()).append(") ")
- .append(df.format(msg.getSendTime())).append("\n 给您发送了一个窗口抖动\n");
- msg.setMessage(sb.toString());
-
- Response response = new Response();
- response.setStatus(ResponseStatus.OK);
- response.setType(ResponseType.SHAKE);
- response.setData("ShakeMsg", msg);
-
- OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
- sendResponse(io, response);
- }
-
- /** 准备发送文件 */
- public void toSendFile(Request request)throws IOException{
- Response response = new Response();
- response.setStatus(ResponseStatus.OK);
- response.setType(ResponseType.TOSENDFILE);
- FileInfo sendFile = (FileInfo)request.getAttribute("file");
- response.setData("sendFile", sendFile);
- //给文件接收方转发文件发送方的请求
- OnlineClientIOCache ioCache = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());
- sendResponse(ioCache, response);
- }
-
- /** 给所有在线客户都发送响应 */
- private void iteratorResponse(Response response) throws IOException {
- for(OnlineClientIOCache onlineUserIO : DataBuffer.onlineUserIOCacheMap.values()){
- ObjectOutputStream oos = onlineUserIO.getOos();
- oos.writeObject(response);
- oos.flush();
- }
- }
-
- /** 向指定客户端IO的输出流中输出指定响应 */
- private void sendResponse(OnlineClientIOCache onlineUserIO, Response response)throws IOException {
- ObjectOutputStream oos = onlineUserIO.getOos();
- oos.writeObject(response);
- oos.flush();
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
首先来分析一下要实现的流程
值得一提是:该socket是同步阻塞的,因此在socket客户端需要进行创建一个线程,来分别进行向服务器输出,和接收服务器传输的数据。
窗口的左上角是原点,我们首先记录起始坐标,计算出向左上角移动的距离和右下角移动的距离,通过循环语句控制窗口位移,最终将窗口恢复到起始坐标。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。