当前位置: 首页 > article >正文

Java多用户通信系统

多用户通信系统总结

使用面向对象、多线程、网络编程,基于终端完成一个多用户通信系统。

完成功能

1、用户登录、退出
2、获取所有在线用户列表
3、私聊
4、群发消息
5、发送文件
6、私聊对方离线时,系统缓存消息,对方上线时发送

项目结构总结

使用了User类来表示用户登录时的信息
使用了Message类来表示客户端和服务器端之间发送的所有信息
客户端完成连接时,创建一个线程持续接收服务器的信息
服务器端完成连接时,创建一个线程持续接收客户端的信息,并处理客户端发送的信息

代码实现

Message类,其中包含了所有客户端和服务器端之间发送消息所需要的所有信息

import java.io.Serializable;

public class Message implements Serializable {
    private static final long serialVersionUID = 1L;
    private String sender;
    private String recevier;
    private String content;
    private String sendTime;
    private String messageType;
    private byte[] bytes;

    public byte[] getBytes() {
        return bytes;
    }

    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }

    public Message() {
    }

    public String getSender() {
        return sender;
    }

    public void setSender(String sender) {
        this.sender = sender;
    }

    public String getRecevier() {
        return recevier;
    }

    public void setRecevier(String recevier) {
        this.recevier = recevier;
    }

    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 getMessageType() {
        return messageType;
    }

    public void setMessageType(String messageType) {
        this.messageType = messageType;
    }

    public Message(String sender, String recevier, String content, String sendTime, String messageType) {
        this.sender = sender;
        this.recevier = recevier;
        this.content = content;
        this.sendTime = sendTime;
        this.messageType = messageType;
    }
}

MessageType类,这个类用于定义所有消息的类型,方便客户端和服务器端根据消息类型进行对应的操作

public interface MessageType {
    String MESSAGE_LOGIN_SUCCEED = "1";  // 成功登录
    String MESSAGE_LOGIN_FAIL = "2";    // 失败登录
    String MESSAGE_CHAT = "3";          // 聊天信息
    String MESSAGE_GET_ONLINELIST = "4";    // 获取在线用户列表
    String MESSAGE_RET_ONLINELIST = "5";    // 返回在线用户列表
    String MESSAGE_LOG_OUT = "6";       // 退出系统
    String MESSAGE_TOALL = "7";          //群发消息
    String MESSAGE_FILE = "8";         // 发送文件
}

User类,这个类包含了用户登录时用于验证账户所需要的信息

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String userId;
    private String passwd;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public User(String userId, String passwd) {
        this.userId = userId;
        this.passwd = passwd;
    }
}

这几个类被客户端和服务器端共享

客户端代码

ClientView类,这个类定义了客户端的用户界面,完成和用户之间的交互操作
import java.util.Scanner;

public class ClientView {
    private boolean loop = true;
    private String input;
    ConnectService connectService = new ConnectService();

    public static void main(String[] args) {
        new ClientView();
    }

    public ClientView(){
        Scanner scanner = new Scanner(System.in);
        while(loop){
            System.out.println("================用户登录界面=================");
            System.out.println("\t\t1. 登录");
            System.out.println("\t\t2. 退出");
            System.out.println("===========================================");
            System.out.println("输入:");
            input = scanner.next();
            switch (input){
                case "1":
                    String name;
                    String passwd;
                    System.out.print("请输入您的用户名:");
                    name = scanner.next();
                    System.out.print("请输入您的密码:");
                    passwd = scanner.next();


                    if(connectService.checkSign(name,passwd)){
                        System.out.println("***********************************************");
                        System.out.println("++++++++++++恭喜" + name + "登陆成功捏!++++++++++");
                        System.out.println("***********************************************");

                        while(loop){
                            System.out.println("***************您想干些什么捏?^_^");
                            System.out.println("\t\t1. 查看所有在线用户");
                            System.out.println("\t\t2. 私聊");
                            System.out.println("\t\t3. 群发");
                            System.out.println("\t\t4. 发个文件玩玩");
                            System.out.println("\t\t9. 累了,退了");
                            System.out.println("请告诉奴家您想要做的事:");
                            input = scanner.next();

                            switch (input){
                                case "1":
                                    //System.out.println("\t\t1. 查看所有在线用户");
                                    connectService.getUserList(name);
                                    break;
                                case "2":
                                    System.out.println("您想要跟谁说悄悄话呢?");
                                    String getter = scanner.next();
                                    System.out.println("您想要跟他说些什么呢?");
                                    String content = scanner.next();
                                    connectService.privateChat(name,getter,content);
                                    break;
                                case "3":
                                    System.out.println("您想要对其他人说些什么呀?");
                                    String content1 = scanner.next();
                                    connectService.toAll(name,content1);
                                    break;
                                case "4":
                                    System.out.println("您想发给哪位友人呢?");
                                    String getterForFile = scanner.next();
                                    System.out.println("您想发些什么有意思的小东西(路径)呀?");
                                    String fileSrc = scanner.next();
                                    System.out.println("您想发给对方的那个位置呀?");
                                    String fileDes = scanner.next();
                                    connectService.sendFile(name,getterForFile,fileSrc,fileDes);
                                    break;
                                case "9":
                                    System.out.println("主人辛苦啦~期待您的下次使用哟(*❦ω❦)");
                                    connectService.logOut(name);
                                    loop = false;
                                    System.exit(0); // 正常退出进程
                                    break;
                            }
                        }
                    }else {
                        System.out.println("亲亲,登录失败了呢,请重试一下吧~");
                    }
                    break;
                case "2":
                    loop = false;
                    break;
            }

        }
    }

}
ConnectionThread类,这个类定义了客户端的线程,用于帮助客户端接收并处理服务器端发送来的消息
import java.io.*;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class ConnectionThread extends Thread{
    private Socket socket;
    private boolean loop = true;

    public ConnectionThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            while(loop){
                // 循环读取服务器端的消息
                InputStream inputStream = socket.getInputStream();
                ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
                Message message = (Message) objectInputStream.readObject();

                switch (message.getMessageType()){
                    case MessageType.MESSAGE_FILE:
                        String senderFile = message.getSender();
                        byte[] bytes = message.getBytes();
                        System.out.println("叮咚,主人,收到来自" + senderFile + "发给您的一个小文件呢!");
                        System.out.println("吾已经帮您暂存到" + message.getContent() + "了,您注意查收呦(*^▽^*)");

                        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(message.getContent()));
                        outputStream.write(bytes);
                        //outputStream.flush();
                        outputStream.close();
                        break;
                    case MessageType.MESSAGE_RET_ONLINELIST :
                        // 获取到在线用户列表
                        if(message.getContent().equals("")){
                            System.out.println("主人,暂时没有其他在线用户呢~");
                        }else{
                            List<String> userIds = Arrays.stream(message.getContent().split(" ")).toList();
                            System.out.println("亲亲,这是您请求的在线列表捏~(づ ̄3 ̄)づ╭❤~");
                            for(int i = 0;i < userIds.size();++i){
                                System.out.println(i + "[  " + userIds.get(i) +"  ]");
                            }
                        }
                        System.out.println("继续告诉吾您想要些什么吧~(#^.^#)");
                        break;
                    case MessageType.MESSAGE_CHAT:
                        String sender = message.getSender();
                        String content = message.getContent();
                        System.out.println("叮咚,主人,收到来自" + sender + "的一条信息呢!");
                        System.out.println("他对主人您说: " + content);
//                        System.out.println("1-查看 \t 2-忽略");
//                        Scanner scanner = new Scanner(System.in);
//                        String input = scanner.next();
//                        switch (input){
//                            case "1":
//                                System.out.println(sender + ": " + content);
//                                break;
//                            case "2":
//                                break;
//                            default:
//                                break;
//                        }
                        break;
                    default:
                        break;
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
        }
    }
}
ConnectionThreadHashMap类,这个类用于收纳所有客户端的线程,方便客户端后续的功能扩展
import java.util.HashMap;

public class ConnectionThreadHashMap {
    private static HashMap<String,ConnectionThread> hm = new HashMap<>();

    public static void put(String name,ConnectionThread connectionThread){
        hm.put(name,connectionThread);
    }

    public static ConnectionThread get(String name){
        return hm.get(name);
    }
}
ConnectService类,这个类用于客户端的功能实现,完成客户端和服务器端之间的交互
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class ConnectService {
    private User user = null;
    private Socket socket = null;

    // 发送文件
    public void sendFile(String sender, String  getter, String fileSrc, String fileDes){
        byte[] bytes = new byte[(int)(new File(fileSrc).length())];
        try {
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(fileSrc));
            bufferedInputStream.read(bytes);
            Message message = new Message();
            message.setMessageType(MessageType.MESSAGE_FILE);
            message.setBytes(bytes);
            message.setSender(sender);
            message.setRecevier(getter);
            message.setContent(fileDes);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
        }

    }


    // 群发消息
    public void toAll(String sender, String content){
        Message message = new Message();
        message.setSender(sender);
        message.setContent(content);
        message.setMessageType(MessageType.MESSAGE_TOALL);

        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);


        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {

        }
    }


    // 私聊消息
    public void privateChat(String sender,String getter,String content){
        Message message = new Message();
        message.setSender(sender);
        message.setRecevier(getter);
        message.setContent(content);
        message.setMessageType(MessageType.MESSAGE_CHAT);

        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);


        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {

        }
    }

    // 登出系统
    public void logOut(String name){
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_LOG_OUT);
        message.setSender(user.getUserId());


        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);


        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {

        }
    }

    // 获取在线用户列表
    public void getUserList(String name){
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_GET_ONLINELIST);

        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);


        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {

        }
    }

    public boolean checkSign(String name, String passwd){
        user = new User(name,passwd);
        boolean ret = false;
        try {
            // 和服务器进行登录判断
            socket = new Socket(InetAddress.getByName("127.0.0.1"),6666);

            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

            objectOutputStream.writeObject(user);

            InputStream inputStream = socket.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

            Message message = (Message) objectInputStream.readObject();

           // System.out.println("回收到服务器的一条回复:" + message.getMessageType());


            // 登录成功
            if(message.getMessageType().equals(MessageType.MESSAGE_LOGIN_SUCCEED)){
                //System.out.println("获取到可以登陆许可");
                ConnectionThread connectionThread = new ConnectionThread(socket);
                connectionThread.start();
                ConnectionThreadHashMap.put(name,connectionThread);
                //System.out.println("可以执行完成put");
                ret = true;
            }else{
                socket.close();
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            return  ret;
        }

    }


    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

}

服务器端

ConnectionThread类,用于帮助服务器端接收并处理来自客户端的消息
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Iterator;
import java.util.Set;

public class ConnectionThread extends Thread{
    private Socket socket;
    private String userId;
    private boolean loop = true;

    @Override
    public void run() {
        try {
            while(loop){
                // 循环读取客户端的消息
                InputStream inputStream = socket.getInputStream();
                ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
                Message message = (Message) objectInputStream.readObject();

                switch (message.getMessageType()){
                    case MessageType.MESSAGE_FILE:
                        System.out.println(message.getSender() + "想跟" +
                                message.getRecevier() + "发小文件");
                        System.out.println(message.getContent());
                        Message messageFile = new Message();
                        messageFile .setMessageType(MessageType.MESSAGE_FILE);
                        messageFile .setRecevier(message.getRecevier());
                        messageFile .setSender(message.getSender());
                        messageFile.setBytes(message.getBytes());
                        messageFile.setContent(message.getContent());
                        try {
                            Socket tos = ConnectionThreadHashMap.get(messageFile .getRecevier()).getSocket();
                            ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(tos.getOutputStream());
                            objectOutputStream2.writeObject(messageFile );
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        } finally {
                        }
                        break;
                    case MessageType.MESSAGE_GET_ONLINELIST :
                        String ret = "";
                        Set<String> strings = ConnectionThreadHashMap.hm.keySet();
                        for(String s : strings){
                            if(userId.equals(s)) continue;
                            ret += s + " ";
                        }
                        Message message1 = new Message();
                        message1.setMessageType(MessageType.MESSAGE_RET_ONLINELIST);
                        if(ret.equals("")){
                            message1.setContent(ret);
                        }else{
                            message1.setContent(ret.substring(0,ret.length() - 1));
                        }
                        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                        objectOutputStream.writeObject(message1);
                        break;
                    case MessageType.MESSAGE_LOG_OUT:
                        System.out.println(userId + "登出系统");
                        socket.close();
                        ConnectionThreadHashMap.remove(userId);
                        loop = false;
                        break;
                    case MessageType.MESSAGE_CHAT:
                        if(!ConnectionThreadHashMap.hm.containsKey(message.getRecevier())){
                            OutLineSender.putMessage(message);
                            continue;
                        }
                        System.out.println(message.getSender() + "想跟" +
                                message.getRecevier() + "说: " + message.getContent());
                        Message message2 = new Message();
                        message2.setMessageType(MessageType.MESSAGE_CHAT);
                        message2.setRecevier(message.getRecevier());
                        message2.setSender(message.getSender());
                        message2.setContent(message.getContent());

                        try {
                            Socket tos = ConnectionThreadHashMap.get(message2.getRecevier()).getSocket();
                            ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(tos.getOutputStream());
                            objectOutputStream2.writeObject(message2);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        } finally {
                        }
                        break;
                    case MessageType.MESSAGE_TOALL:
                        System.out.println(message.getSender() + "想跟所有人" + "说: " + message.getContent());
                        Message message3 = new Message();
                        message3.setMessageType(MessageType.MESSAGE_CHAT);
                        message3.setSender(message.getSender());
                        message3.setContent(message.getContent());

                        Iterator<ConnectionThread> iterator = ConnectionThreadHashMap.hm.values().iterator();
                        while(iterator.hasNext()){
                            ConnectionThread connectionThread = iterator.next();
                            if(connectionThread.userId.equals(message.getSender())) continue;

                            Socket socket1 = connectionThread.getSocket();
                            try {
                                ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(socket1.getOutputStream());
                                objectOutputStream2.writeObject(message3);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            } finally {
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
        }
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public ConnectionThread(Socket socket, String userId) {
        this.socket = socket;
        this.userId = userId;
    }

    public ConnectionThread() {
    }
}
ConnectionThreadHashMap类,用于收纳和查询所有服务器端的线程
import java.util.HashMap;

public class ConnectionThreadHashMap {
    public static HashMap<String,ConnectionThread> hm = new HashMap<>();

    public static void put(String name, ConnectionThread connectionThread){
        hm.put(name,connectionThread);
    }

    public static ConnectionThread get(String name){
        return hm.get(name);
    }

    public static void remove(String name){
        hm.remove(name);
    }
}
OutLineSender类,用于完成离线消息的暂存与发送
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class OutLineSender extends Thread{
    private ConcurrentHashMap<String,String> allUser;
    private HashMap<String,ConnectionThread> onlineUser;
    private static Vector<Message> messages = new Vector<>();
    private ArrayList<Message> readyMessages = new ArrayList<>();

    public static void putMessage(Message message){
        synchronized (messages){messages.add(message);}
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            synchronized (messages){
                if(!messages.isEmpty()){
                    for(Iterator<Message> it = messages.iterator();it.hasNext();){
                        Message message = it.next();
                        if(onlineUser.containsKey(message.getRecevier())){
                            readyMessages.add(message);
                            System.out.println(message.getSender() + "想跟" +
                                    message.getRecevier() + "说: " + message.getContent());
                            try {
                                Socket tos = ConnectionThreadHashMap.get(message.getRecevier()).getSocket();
                                ObjectOutputStream objectOutputStream2 = new ObjectOutputStream(tos.getOutputStream());
                                objectOutputStream2.writeObject(message);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            } finally {
                            }
                        }
                    }
                    for(Iterator<Message> it = readyMessages.iterator();it.hasNext();){
                        messages.remove(it.next());
                    }
                    readyMessages.clear();
                }
            }
        }
    }

    public OutLineSender() {
    }

    public OutLineSender(ConcurrentHashMap<String, String> allUser, HashMap<String, ConnectionThread> onlineUser) {
        this.allUser = allUser;
        this.onlineUser = onlineUser;
    }

    public ConcurrentHashMap<String, String> getAllUser() {
        return allUser;
    }

    public void setAllUser(ConcurrentHashMap<String, String> allUser) {
        this.allUser = allUser;
    }

    public HashMap<String, ConnectionThread> getOnlineUser() {
        return onlineUser;
    }

    public void setOnlineUser(HashMap<String, ConnectionThread> onlineUser) {
        this.onlineUser = onlineUser;
    }
}
ServerService类,用于接收客户端的连接请求,并且在登录验证通过后,创建一个线程完成后续服务器端和客户端之间的通信
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

public class ServerService {
    public static void main(String[] args) {
        new ServerService();
    }

    ServerSocket serverSocket;
    private boolean loop = true;

    private static ConcurrentHashMap<String,String> hm = new ConcurrentHashMap<>();

    public static ConcurrentHashMap<String, String> getHm() {
        return hm;
    }

    public static void setHm(ConcurrentHashMap<String, String> hm) {
        ServerService.hm = hm;
    }

    static {
        hm.put("1", "123");
        hm.put("2", "123456");
        hm.put("人才", "123456");
        hm.put("萧炎", "666666");
        hm.put("陈平安", "888888");

    }

    boolean checkLoginIn(String name,String passwd){
        if(hm.get(name) == null || !hm.get(name).equals(passwd)){
            return false;
        }else{
            return true;
        }
    }


    ServerService(){
        try {
            serverSocket = new ServerSocket(6666);
            OutLineSender outLineSender = new OutLineSender();
            outLineSender.setAllUser(hm);
            outLineSender.setOnlineUser(ConnectionThreadHashMap.hm);
            outLineSender.start();
            // 循环接收客户端连接
            while (loop){
                Socket socket = serverSocket.accept();

                InputStream inputStream = socket.getInputStream();
                ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);


                OutputStream outputStream = socket.getOutputStream();
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);


                User user = (User) objectInputStream.readObject();
                Message message = new Message();
                // 检验客户端提交的用户名和密码
                // 假设这种状况验证成功
                if(checkLoginIn(user.getUserId(), user.getPasswd())){
                    System.out.println("收到一条登录,但令其成功:" + user.getUserId());

                    message.setMessageType(MessageType.MESSAGE_LOGIN_SUCCEED);
                    objectOutputStream.writeObject(message);

                    ConnectionThread connectionThread = new ConnectionThread(socket,user.getUserId());
                    connectionThread.start();
                    ConnectionThreadHashMap.put(user.getUserId(),connectionThread);

                }else{
                    System.out.println("收到一条登录,但令其失败:" + user.getUserId());

                    message.setMessageType(MessageType.MESSAGE_LOGIN_FAIL);
                    objectOutputStream.writeObject(message);
                    socket.close();
                }

            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                serverSocket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }


    }
}

项目源于视频:https://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.788.videopod.episodes&vd_source=16bf0c507e4a78c3ca31a05dff1bee4e&p=686


http://www.kler.cn/a/526921.html

相关文章:

  • 计算机网络一点事(22)
  • 《DeepSeek-R1 问世,智能搜索领域迎来新变革》
  • 【线上问题定位处理】及【性能优化】系列文章
  • 当当网近30日热销图书的数据采集与可视化分析(scrapy+openpyxl+matplotlib)
  • 项目测试之Postman
  • 从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(动态菜单组件实现)
  • 【自然语言处理(NLP)】多头注意力(Multi - Head Attention)原理及代码实现
  • C++中实现全排列方法
  • 10.6 LangChain提示工程终极指南:从基础模板到动态生成的工业级实践
  • JAVA实战开源项目:在线文档管理系统(Vue+SpringBoot) 附源码
  • JavaScript图像处理,腐蚀算法和膨胀算法说明和作用介绍
  • 愿景:做机器视觉行业的颠覆者
  • 刷题记录 贪心算法-4:53. 最大子数组和
  • 从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(协议层封装)
  • 前端学习-事件解绑,mouseover和mouseenter的区别(二十九)
  • 【MySQL】MySQL客户端连接用 localhost和127.0.0.1的区别
  • SQLAlchemy 2.0的简单使用教程
  • 互斥锁/信号量实现5个线程同步
  • Redis|前言
  • FreeRTOS从入门到精通 第十六章(任务通知)
  • 玄武计划--干中学,知行合一
  • 全网首发,MacMiniA1347安装飞牛最新系统0.8.36,改造双盘位NAS,超详细.36,改造双盘位nas,超详细
  • Teleporters( Educational Codeforces Round 126 (Rated for Div. 2) )
  • 爬虫基础(六)代理简述
  • jvisualvm工具使用
  • 哈工大:屏蔽LLM检索头训练忠实性