成都工业学院2022级计算机网络专周课程设计基于socket的多用户登录系统

运行环境

操作系统:Windows 11 家庭版

运行软件:IntelliJ IDEA 2023.3.6

                  Navicat Premium 16

相关配置:JDK 17.0.10

                  mysql-connector-j-8.4.0.jar

                  Mysql 8.0.38


源代码文件

数据库建表语句

CREATE TABLE `user_info` (
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `login_status` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

ServerGUI

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

// 服务器GUI类,负责显示日志信息和当前登录用户状态
public class ServerGUI extends JFrame {
    private static JTextArea logArea;
    private JButton viewUsersButton;

    public ServerGUI() {
        setTitle("基于socket的多用户登录系统服务器端");
        setSize(600, 500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // 设置布局管理器
        setLayout(new BorderLayout());

        // 创建日志显示区
        logArea = new JTextArea();
        logArea.setEditable(false);
        logArea.setFont(new Font("宋体", Font.PLAIN, 14)); // 设置字体为宋体
        JScrollPane scrollPane = new JScrollPane(logArea);
        add(scrollPane, BorderLayout.CENTER);

        // 创建查看当前用户登录状态按钮
        viewUsersButton = new JButton("查看当前用户登录状态");
        viewUsersButton.setFont(new Font("宋体", Font.BOLD, 14)); // 设置按钮字体为宋体加粗
        viewUsersButton.setBackground(new Color(255, 255, 102)); // 设置按钮背景颜色为亮黄色
        viewUsersButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                List<String> loggedInUsers = getLoggedInUsernames();
                StringBuilder userList = new StringBuilder("当前登录用户:\n");
                for (String user : loggedInUsers) {
                    userList.append(user).append("\n");
                }
                userList.append("总用户数: ").append(getLoggedInUserCount());
                JOptionPane.showMessageDialog(ServerGUI.this, userList.toString(), "用户登录状态", JOptionPane.INFORMATION_MESSAGE);
            }
        });

        // 将按钮添加到南部(底部)并横向铺满
        JPanel buttonPanel = new JPanel(new BorderLayout());
        buttonPanel.add(viewUsersButton, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);

        // 显示界面
        setVisible(true);
    }

    // 静态方法:更新日志信息
    public static void appendLog(String message) {
        logArea.append(message + "\n");
    }

    // 获取当前登录用户数
    public static int getLoggedInUserCount() {
        String sql = "SELECT COUNT(*) AS count FROM user_info WHERE login_status = true";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            if (rs.next()) {
                return rs.getInt("count");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    // 获取当前登录用户名列表
    public static List<String> getLoggedInUsernames() {
        List<String> usernames = new ArrayList<>();
        String sql = "SELECT username FROM user_info WHERE login_status = true";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs.next()) {
                usernames.add(rs.getString("username"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return usernames;
    }

    // 主方法,用于启动服务器
    public static void main(String[] args) {
        int port = 6666; // 定义服务器端口
        ServerGUI gui = new ServerGUI(); // 创建并显示服务器GUI
        try (ServerSocket serverSocket = new ServerSocket(port)) { // 创建服务器套接字
            appendLog("服务器启动,运行在端口:" + port);

            // 不断接受新的客户端连接
            while (true) {
                Socket clientSocket = serverSocket.accept(); // 接受客户端连接
                new Thread(new UserThread(clientSocket)).start(); // 为每个客户端连接启动一个新的线程
            }
        } catch (IOException e) { // 捕捉IO异常
            e.printStackTrace();
        }
    }
}

// 用户线程类,实现Runnable接口,用于处理每个客户端的请求
class UserThread implements Runnable {
    private final Socket socket; // 客户端套接字
    private DataInputStream dis; // 数据输入流
    private DataOutputStream dos; // 数据输出流
    private static List<String> loggedInUsers = new ArrayList<>(); // 存储当前登录的用户
    private static AtomicInteger clientCounter = new AtomicInteger(0); // 客户端计数器
    private String clientName; // 客户端名称

    // 构造函数,初始化客户端套接字
    public UserThread(Socket socket) {
        this.socket = socket;
        this.clientName = "客户端-" + clientCounter.incrementAndGet();
    }

    // 线程运行方法
    @Override
    public void run() {
        try {
            dis = new DataInputStream(socket.getInputStream()); // 获取输入流
            dos = new DataOutputStream(socket.getOutputStream()); // 获取输出流

            ServerGUI.appendLog(clientName + " 连接");

            // 不断读取客户端的操作请求
            while (true) {
                String action = dis.readUTF(); // 读取客户端发送的操作指令
                ServerGUI.appendLog(clientName + " 操作: " + action);
                switch (action) {
                    case "register": // 注册操作
                        String regUsername = dis.readUTF();
                        String regPassword = dis.readUTF();
                        registerUser(regUsername, regPassword); // 调用注册方法
                        break;
                    case "login": // 登录操作
                        String loginUsername = dis.readUTF();
                        String loginPassword = dis.readUTF();
                        loginUser(loginUsername, loginPassword); // 调用登录方法
                        break;
                    case "changePassword": // 修改密码操作
                        String changeUsername = dis.readUTF();
                        String oldPassword = dis.readUTF();
                        String newPassword = dis.readUTF();
                        changePassword(changeUsername, oldPassword, newPassword); // 调用修改密码方法
                        break;
                    case "logout": // 登出操作
                        String logoutUsername = dis.readUTF();
                        logout(logoutUsername); // 调用登出方法
                        break;
                    default: // 未知操作
                        dos.writeUTF("未知操作");
                        ServerGUI.appendLog(clientName + " 操作结果: 未知操作");
                }
            }
        } catch (IOException e) { // 捕捉IO异常
            ServerGUI.appendLog(clientName + " 断开连接");
        } finally {
            closeResources(); // 关闭资源
        }
    }

    // 注册用户方法
    private void registerUser(String username, String password) {
        if (username == null || username.trim().isEmpty() || password == null || password.trim().isEmpty()) {
            sendMsg("用户名或密码不能为空"); // 检查用户名和密码是否为空
            ServerGUI.appendLog(clientName + " 注册结果: 用户名或密码不能为空");
            return;
        }
        String sql = "INSERT INTO user_info (username, password, login_status) VALUES (?, ?, FALSE)";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            int result = pstmt.executeUpdate();
            if (result > 0) {
                dos.writeUTF("注册成功");
                ServerGUI.appendLog(clientName + " 注册结果: 成功");
            } else {
                dos.writeUTF("注册失败");
                ServerGUI.appendLog(clientName + " 注册结果: 失败");
            }
        } catch (SQLException e) {
            if (e.getSQLState().equals("23000")) {
                sendMsg("用户名已存在");
                ServerGUI.appendLog(clientName + " 注册结果: 用户名已存在");
            } else {
                sendMsg("数据库错误:" + e.getMessage());
                ServerGUI.appendLog(clientName + " 注册结果: 数据库错误:" + e.getMessage());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 登录用户方法
    private void loginUser(String username, String password) {
        if (username == null || username.trim().isEmpty() || password == null || password.trim().isEmpty()) {
            sendMsg("用户名或密码不能为空");
            ServerGUI.appendLog(clientName + " 登录结果: 用户名或密码不能为空");
            return;
        }
        String checkUserSql = "SELECT * FROM user_info WHERE username = ?";
        String loginSql = "SELECT * FROM user_info WHERE username = ? AND password = ?";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement checkStmt = conn.prepareStatement(checkUserSql)) {
            checkStmt.setString(1, username);
            ResultSet checkRs = checkStmt.executeQuery();
            if (checkRs.next()) {
                boolean isLoggedIn = checkRs.getBoolean("login_status");
                if (isLoggedIn) {
                    dos.writeUTF("用户已登录");
                    ServerGUI.appendLog(clientName + " 登录结果: 用户已登录");
                    return;
                }
                try (PreparedStatement loginStmt = conn.prepareStatement(loginSql)) {
                    loginStmt.setString(1, username);
                    loginStmt.setString(2, password);
                    ResultSet loginRs = loginStmt.executeQuery();
                    if (loginRs.next()) {
                        updateLoginStatus(username, true);
                        dos.writeUTF("登录成功");
                        ServerGUI.appendLog(clientName + " 登录结果: 成功");
                    } else {
                        dos.writeUTF("用户名或密码错误");
                        ServerGUI.appendLog(clientName + " 登录结果: 用户名或密码错误");
                    }
                }
            } else {
                dos.writeUTF("用户不存在");
                ServerGUI.appendLog(clientName + " 登录结果: 用户不存在");
            }
        } catch (SQLException | IOException e) {
            e.printStackTrace();
        }
    }

    // 修改密码方法
    private void changePassword(String username, String oldPassword, String newPassword) {
        if (username == null || username.trim().isEmpty() || oldPassword == null || oldPassword.trim().isEmpty() || newPassword == null || newPassword.trim().isEmpty()) {
            sendMsg("用户名、当前密码或新密码不能为空");
            ServerGUI.appendLog(clientName + " 修改密码结果: 用户名、当前密码或新密码不能为空");
            return;
        }
        if (oldPassword.equals(newPassword)) {
            sendMsg("新密码不能与当前密码相同");
            ServerGUI.appendLog(clientName + " 修改密码结果: 新密码不能与当前密码相同");
            return;
        }

        String checkUser = "SELECT * FROM user_info WHERE username = ? AND password = ?";
        String updatePw = "UPDATE user_info SET password = ? WHERE username = ?";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement checkStmt = conn.prepareStatement(checkUser)) {
            checkStmt.setString(1, username);
            checkStmt.setString(2, oldPassword);
            ResultSet rs = checkStmt.executeQuery();
            if (rs.next()) {
                boolean isLoggedIn = rs.getBoolean("login_status");
                if (!isLoggedIn) {
                    sendMsg("用户未登录,无法修改密码");
                    ServerGUI.appendLog(clientName + " 修改密码结果: 用户未登录,无法修改密码");
                    return;
                }
                try (PreparedStatement updateStmt = conn.prepareStatement(updatePw)) {
                    updateStmt.setString(1, newPassword);
                    updateStmt.setString(2, username);
                    int rowsAffected = updateStmt.executeUpdate();
                    if (rowsAffected > 0) {
                        dos.writeUTF("密码修改成功");
                        ServerGUI.appendLog(clientName + " 修改密码结果: 成功");
                    } else {
                        dos.writeUTF("密码修改失败,未知错误");
                        ServerGUI.appendLog(clientName + " 修改密码结果: 失败,未知错误");
                    }
                }
            } else {
                dos.writeUTF("当前密码错误");
                ServerGUI.appendLog(clientName + " 修改密码结果: 当前密码错误");
            }
        } catch (SQLException | IOException e) {
            e.printStackTrace();
        }
    }

    // 用户登出方法
    private void logout(String username) {
        updateLoginStatus(username, false);
        sendMsg("退出登录成功");
        ServerGUI.appendLog(clientName + " 登出结果: 成功");
        synchronized (loggedInUsers) {
            loggedInUsers.remove(username);
        }
    }

    // 更新用户登录状态方法
    private void updateLoginStatus(String username, boolean status) {
        String sql = "UPDATE user_info SET login_status = ? WHERE username = ?";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setBoolean(1, status);
            pstmt.setString(2, username);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 发送消息方法
    private void sendMsg(String msg) {
        try {
            dos.writeUTF(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 关闭资源方法
    private void closeResources() {
        try {
            if (dis != null) dis.close();
            if (dos != null) dos.close();
            if (socket != null) socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// 数据库工具类,负责获取数据库连接
class DBUtil {
    private static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; // 驱动类
    private static final String DB_URL = "jdbc:mysql://localhost/user_info?useSSL=false&serverTimezone=UTC"; // 数据库URL
    private static final String USER = "root"; // 数据库用户名
    private static final String PASS = "123456"; // 数据库密码

    // 获取数据库连接
    public static Connection getConnection() throws SQLException {
        try {
            Class.forName(JDBC_DRIVER); // 加载JDBC驱动
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return DriverManager.getConnection(DB_URL, USER, PASS); // 返回数据库连接
    }
}

ClientGUI

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.Socket;
public class ClientGUI {

    // 定义一些基本的颜色和字体,以便整个界面使用
    private final Color backgroundColor = new Color(235, 245, 251);
    private final Color textColor = Color.BLACK;
    private final Color inputFieldBackgroundColor = new Color(255, 255, 255);
    private final Font labelFont = new Font("宋体", Font.BOLD, 14);
    private final Font buttonFont = new Font("宋体", Font.PLAIN, 12);
    private final Font textAreaFont = new Font("宋体", Font.PLAIN, 12);

    private JFrame frame;
    private JPanel panel;
    private JButton btnRegister, btnLogin, btnChangePassword, btnLogout;
    private JTextField usernameField, passwordField, newPasswordField;
    private JLabel usernameLabel, passwordLabel, newPasswordLabel, resultLabel;
    private JTextArea resultTextArea;
    private Socket socket;
    private DataInputStream dis;
    private DataOutputStream dos;

    public ClientGUI(String address, int port) {
        try {
            socket = new Socket(address, port);
            dis = new DataInputStream(socket.getInputStream());
            dos = new DataOutputStream(socket.getOutputStream());
            System.out.println("已连接到服务器");
            initializeGUI();
        } catch (IOException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(null, "未连接到服务器", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void initializeGUI() {
        frame = new JFrame("基于socket的多用户登录系统客户端");
        frame.setSize(600, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        panel = new JPanel(new GridLayout(4, 3));
        panel.setBackground(backgroundColor); // 设置面板背景色
        frame.add(panel);

        // 初始化组件
        usernameLabel = new JLabel("用户名称");
        passwordLabel = new JLabel("当前密码");
        newPasswordLabel = new JLabel("新设密码");
        resultLabel = new JLabel("操作结果");
        usernameField = new JTextField();
        passwordField = new JTextField();
        newPasswordField = new JTextField();
        resultTextArea = new JTextArea(5, 20);


        // 应用字体和颜色
        setComponentStyles();

        usernameLabel.setFont(labelFont);
        passwordLabel.setFont(labelFont);
        newPasswordLabel.setFont(labelFont);
        resultLabel.setFont(labelFont);
        usernameField.setFont(textAreaFont);
        passwordField.setFont(textAreaFont);
        newPasswordField.setFont(textAreaFont);
        resultTextArea.setFont(textAreaFont);

        JScrollPane scrollPane = new JScrollPane(resultTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

        // 将组件添加到面板
        addComponentsToPanel(scrollPane);

        // 给按钮添加事件监听器
        attachEventListeners();

        frame.setVisible(true);
    }

    private void setComponentStyles() {
        btnRegister = new JButton("用户注册");
        btnLogin = new JButton("用户登录");
        btnChangePassword = new JButton("修改密码");
        btnLogout = new JButton("退出登录");

        // 为每个按钮设置独特的背景色
        btnRegister.setBackground(new Color(52, 152, 219)); // 浅蓝色
        btnLogin.setBackground(new Color(46, 204, 113)); // 浅绿色
        btnChangePassword.setBackground(new Color(155, 89, 182)); // 浅紫色
        btnLogout.setBackground(new Color(231, 76, 60)); // 浅红色

        // 设置按钮文字颜色
        Color textColor = Color.WHITE;
        JButton[] buttons = {btnRegister, btnLogin, btnChangePassword, btnLogout};
        for (JButton button : buttons) {
            button.setForeground(textColor);
            button.setFont(buttonFont);
        }

        JTextField[] textFields = {usernameField, passwordField, newPasswordField};
        for (JTextField textField : textFields) {
            textField.setBackground(inputFieldBackgroundColor);
            textField.setForeground(this.textColor);
        }

        resultTextArea.setEditable(false);
        resultTextArea.setBackground(Color.WHITE);
        resultTextArea.setForeground(this.textColor);
    }

    private void addComponentsToPanel(JScrollPane scrollPane) {
        panel.add(usernameLabel);
        panel.add(usernameField);
        panel.add(btnRegister);
        panel.add(passwordLabel);
        panel.add(passwordField);
        panel.add(btnLogin);
        panel.add(newPasswordLabel);
        panel.add(newPasswordField);
        panel.add(btnChangePassword);
        panel.add(resultLabel);
        panel.add(scrollPane);
        panel.add(btnLogout);
    }
    private void attachEventListeners() {
        btnRegister.addActionListener(e -> register());
        btnLogin.addActionListener(e -> login());
        btnChangePassword.addActionListener(e -> changePassword());
        btnLogout.addActionListener(e -> logout());
    }
    private void register() {
        String username = usernameField.getText();
        String password = passwordField.getText();
        try {
            dos.writeUTF("register");
            dos.writeUTF(username);
            dos.writeUTF(password);
            String response = dis.readUTF();
            resultTextArea.setText(response);
        } catch(IOException e) {
            resultTextArea.setText("Error during registration: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void login() {
        String username = usernameField.getText();
        String password = passwordField.getText();
        try {
            dos.writeUTF("login");
            dos.writeUTF(username);
            dos.writeUTF(password);
            String response = dis.readUTF();
            resultTextArea.setText(response);
        } catch(IOException e) {
            resultTextArea.setText("Error during login: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void changePassword() {
        String username = usernameField.getText();
        String oldPassword = passwordField.getText();
        String newPassword = newPasswordField.getText();
        try {
            dos.writeUTF("changePassword");
            dos.writeUTF(username);
            dos.writeUTF(oldPassword);
            dos.writeUTF(newPassword);
            String response = dis.readUTF();
            resultTextArea.setText(response);
        } catch(IOException e) {
            resultTextArea.setText("Error changing password: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private void logout() {
        String username = usernameField.getText();
        try {
            dos.writeUTF("logout");
            dos.writeUTF(username);
            String response = dis.readUTF();
            resultTextArea.setText(response);
        } catch(IOException e) {
            resultTextArea.setText("Error during logout: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new ClientGUI("localhost", 6666);
    }
}

源代码示例

运行结果截图

注意事项

1、请自行修改数据库相关参数配置,本人配置如代码中所示

2、本代码中并无加密等功能,主要实现的是登录功能

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值