Java Learning - 5. 登录/注册

        在实际应用或业务中往往需要用户注册以及登录,需要用Swing构造相关的界面以及背后运行的服务器,另外还需要有一个数据结构来保存用户信息

        甚至需要链接数据库(MySQL)来进行用户信息的存储和读取

目录

需求分析

模块编写

        User类

        Server类

        UI类


需求分析

        1. 一个User类,表示一个用户,内含有用户信息

        2. 一个Server类,表示服务器,用于处理用户的操作

                - 登录操作,判断用户名是否存在,密码是否正确

                - 注册操作,判断注册信息的合法性,注册成功要将一个User类插入到数据库中

        3. 一个UI类,用于创建登录和注册界面,并提供交互功能和交互信息

        4. 创建一个数据库user_info,用于存储用户信息

        需求分析过后就可以按部就班地编写这些模块了

模块编写

        User类

        这里作为一个学习记录,只创建一个简单的用户类,里面有用户信息:用户名、密码、用户ID、最近登录时间、是否在线。这六个基本的数据结构构成了用户类

public class User {
    private String user_name;
    private String user_pwd;
    private String user_id;
    private String user_login_time;
    private boolean user_if_online;
}

        除此之外,还需要编写构造函数,用于用不同的参数创建用户类

        - 在注册时没有最近登录时间,并且在线状态设置为离线

public User(String user_name, String user_pwd, String user_id) {
        this.user_name = user_name;
        this.user_pwd = user_pwd;
        this.user_id = user_id;
        this.user_login_time = "";
        this.user_if_online = false;
}

        还需要注意的是,为了便于用户哈希结构的运算,重写hashCode

public int hashCode() {
        return Objects.hash(user_name, user_pwd, user_id);
}

        Server类

        首先Server类要有一个能够存储用户信息的数据结构,考虑到用户数量可能相当庞大,为搜索性能考虑,采用哈希表的结构,以用户名作Key,User类作Value

HashMap<String, User> user_info = new HashMap<>();

        每次运行Server时都会创建新的HashMap,而之前注册和登录过的用户信息就不能够保存,为了提供非易失性,这里链接一个存储用户信息的数据库,每次运行都从数据库中读取用户信息,这里为了方便测试,直接连接本地的数据库

    public Connection connection;
    public Statement statement;
    public ResultSet rs_query;
    public int rs_update;
    String dbURL = "jdbc:mysql://localhost:3306/user_info";
    String name_sql = "root";
    String pwd_sql = "...";

        在server的构造函数中,加入连接数据库并且读取相关数据的方法块

        值得注意的是,这里不要在读取完后就关闭连接,因为后续用户操作还可能会更新数据库,这样可以避免重复的连接操作,相当于长连接

Server() throws SQLException {
        String sql = "select * from user_info";
        connection = DriverManager.getConnection(dbURL, name_sql, pwd_sql);
        statement = connection.createStatement();
        rs_query = statement.executeQuery(sql);
        while (rs_query.next()) {
            String user_num = rs_query.getString("user_num");
            String user_name = rs_query.getString("user_name");
            String user_pwd = rs_query.getString("user_pwd");
            String user_id = rs_query.getString("user_id");
            String user_login_time = rs_query.getString("user_login_time");
            boolean user_if_online = rs_query.getBoolean("user_if_online");
            System.out.println(user_num+" "+user_name+" "+user_pwd+" "+user_id+" "+user_login_time+""+user_if_online);
            user_info.put(user_name,new User(user_name,user_pwd,user_id,user_login_time,user_if_online));
        }
        rs_query.close();
        //statement.close();
        //connection.close();
}

        server需要提供登录服务,并且对用户名和密码进行判断,所以写上login方法

        login有两个参数,分别是用户名和密码,在哈希表中查找是否有这个用户,如果没有则返回响应错误信息,如果有则判断用户是否在线以及密码是否正确

        需要注意在判断用户登陆成功前,需要将用户的登录信息上传到数据库,更新最近登录时间以及在线状态

public int login(String name, String pwd) throws SQLException {
        User user = user_info.get(name);
        if (user == null) {
            return USER_LOGIN_USERNAME_NOT_EXIST;
        }
        if (user.getUser_pwd().equals(pwd)) {
            if (user.isUser_if_online()) {
                return USER_LOGIN_USER_ONLINE;
            }
            user.setUser_if_online(true);
            //获取登录时间
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String datetime = df.format(new Date());
            user.setUser_login_time(datetime);
            String sql_update = "update user_info set user_if_online = true,user_login_time = now() where user_name='"+name+"'";
            System.out.println(sql_update);
            rs_update=statement.executeUpdate(sql_update);
            //statement.close();
            //connection.close();
            return USER_LOGIN_SUCCESS;
        }
        return USER_LOGIN_PASSWORD_ERROR;
    }

        server提供注册服务与登录服务类似,这里不做过多解释,只需要进行判断并且成功后将新用户的信息添加到数据库中即可

public int register(String name, String pwd, String repwd,String id) throws SQLException {
        //用户名长度不合规
        if (name.length() < 5 || name.length() > 12) {
            return USER_REGISTER_FAIL_WRONG_NAME_LENGTH;
        }
        //用户名存在空格
        if (name.contains(" ")) {
            return USER_REGISTER_FAIL_CONTAIN_SPACE;
        }
        User user = user_info.get(name);
        //用户不存在
        if (user != null) {
            return USER_REGISTER_USERNAME_EXIST;
        }
        //密码长度不合规
        if (pwd.length() < 6 || pwd.length() > 20) {
            return USER_REGISTER_FAIL_WRONG_PWD_LENGTH;
        }
        if(!pwd.equals(repwd)){
            return USER_REGISTER_FAIL_WRONG_REPWD;
        }
        else {
            user = new User(name, pwd, id);
            user_info.put(name, user);
            connection = DriverManager.getConnection(dbURL, name_sql, pwd_sql);
            statement = connection.createStatement();
            String sql_insert = "insert into user_info(user_name, user_pwd, user_id,  user_if_online) values ('"     +name+ "','"+pwd+"','"+id+"',"+"false)";
            System.out.println(sql_insert);
            rs_update=statement.executeUpdate(sql_insert);
            //statement.close();
            //connection.close();
            return USER_REGISTER_SUCCESS;
        }
}

        为了方便测试,这里还写了一个方法用于显示所有用户信息,这个方法在用户登录后才会调用,相当于一个测试方法,它代表的是用户登录成功后的主程序,这是一个Demo

        因此,在关闭这个窗口后,用户相应的应该是下线状态,所以在这个方法里还需要在关闭窗口时向数据库更新用户在线信息

public String show_all_user_info(String name){
        String info="";
        JFrame jf = new JFrame("所有用户信息");
        jf.setSize(500,500);
        jf.setLocationRelativeTo(null);
        int user_num=user_info.size();
        jf.setLayout(new GridLayout(user_num,1));
        jf.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                String sql_update = "update user_info set user_if_online = false where user_name='"+name+"'";
                System.out.println(sql_update);
                String dbURL = "jdbc:mysql://localhost:3306/user_info";
                String name = "root";
                String pwd = "wujiayi0303";
                Connection connection = null;
                try {
                    connection = DriverManager.getConnection(dbURL, name, pwd);
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
                Statement statement = null;
                try {
                    statement = connection.createStatement();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
                try {
                    int rs_update=statement.executeUpdate(sql_update);
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
                try {
                    statement.close();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
                try {
                    connection.close();
                } catch (SQLException ex) {
                    throw new RuntimeException(ex);
                }
                super.windowClosing(e);

            }
        });
        for(String key : user_info.keySet ()){
            User user = user_info.get (key);
            String sinfo = user.getUser_name () + " - " + user.getUser_id () + " - " + user.getUser_login_time ()+"-"+user.isUser_if_online();
            info += sinfo + " ";
            jf.add (new JLabel (sinfo));
        }
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
        return info;
    }

        UI类

        首先要有一个登录界面和一个注册界面,两个窗体

JFrame login_frame = new JFrame("登录");
JFrame register_frame = new JFrame("注册");

        提供一个创建登录界面的方法,添加登录按钮和注册按钮,这里先讲登录按钮

        按下登录按钮,应该用server对用户名和密码进行判断,按下注册按钮,应该弹出注册界面,因此,在登录按钮和注册按钮的事件监听中加入相关方法

        创建一个Login_Listener类,编写actionPerformed函数,如果按下的是注册,则显示注册界面,并且隐藏登录界面;如果按下的是登录按钮,则获取文本框的数据,并且调用server的login方法,进行数据检验,根据返回的内容做出相应的交互信息显示

@Override
    public void actionPerformed(ActionEvent e) {
        //获取按钮上的字符串
        String action = e.getActionCommand();
        if (action.equals("注册")) {
            ui.login_frame.setVisible(false);
            ui.register_frame.setVisible(true);
        }

        if (action.equals("登录")) {
            String name = ui.login_info[0].getText();
            String pwd = ui.login_info[1].getText();
            System.out.println(name + " " + pwd);

            int login_state;
            try {
                login_state = server.login(name, pwd);
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            switch (login_state) {
                case USER_LOGIN_SUCCESS : {
                    System.out.println("登陆成功");
                    JOptionPane.showMessageDialog(null, "登陆成功");
                    server.show_all_user_info(name);
                    ui.login_frame.setVisible(false);

                }
                break;
                case USER_LOGIN_USERNAME_NOT_EXIST : {
                    System.out.println("用户不存在");
                    JOptionPane.showMessageDialog(null, "用户不存在");
                }
                break;
                case USER_LOGIN_PASSWORD_ERROR : {
                    System.out.println("密码错误");
                    JOptionPane.showMessageDialog(null, "密码错误");
                }
                break;
                case USER_LOGIN_USER_ONLINE : {
                    System.out.println("该用户已在线");
                    JOptionPane.showMessageDialog(null, "该用户已在线");
                }
                break;
                case USER_LOGIN_UNKNOWN_ERROR : {
                    System.out.println("登陆出错");
                    JOptionPane.showMessageDialog(null, "登陆错误,请稍后再试");
                }
                break;
            }
        }


    }

        同理,Register_Listener是监听注册界面按钮的,道理相同,这里直接给出代码

@Override
    public void actionPerformed(ActionEvent e) {
        String action = e.getActionCommand();

        if (action.equals("注册")) {
            String name = ui.register_info.get(0).getText();
            String pwd = ui.register_info.get(1).getText();
            String repwd = ui.register_info.get(2).getText();
            String id = ui.register_info.get(3).getText();
            System.out.println(name + " " + pwd + " " + id);
            int register_state = 0;
            try {
                register_state = server.register(name, pwd, repwd,id);
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            switch (register_state) {
                case USER_REGISTER_SUCCESS : {
                    System.out.println("注册成功");
                    JOptionPane.showMessageDialog(null, "注册成功");
                    ui.register_frame.setVisible(false);
                    ui.login_frame.setVisible(true);
                }
                break;
                case USER_REGISTER_USERNAME_EXIST : {
                    System.out.println("用户已存在");
                    JOptionPane.showMessageDialog(null, "用户已存在");
                }
                break;
                case USER_REGISTER_FAIL_CONTAIN_SPACE : {
                    System.out.println("用户名含有空格");
                    JOptionPane.showMessageDialog(null, "用户名含有空格");
                }
                break;
                case USER_REGISTER_FAIL_WRONG_NAME_LENGTH : {
                    System.out.println("用户名长度不满足条件");
                    JOptionPane.showMessageDialog(null, "用户名长度不满足条件");
                }
                break;
                case USER_REGISTER_FAIL_WRONG_PWD_LENGTH : {
                    System.out.println("密码不满足条件");
                    JOptionPane.showMessageDialog(null, "密码不满足条件");
                }
                break;
                case USER_REGISTER_FAIL_WRONG_REPWD : {
                    System.out.println("两次密码不一致");
                    JOptionPane.showMessageDialog(null, "两次密码不一致");
                }
                break;
            }
        }
    }

        有了监听器,就可以创建相关按键并且将监听器加入了,这里先看登录界面的创建

        首先要设置登录界面的窗体的一些属性

        login_frame.setSize(400,300);
        login_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        login_frame.setResizable(false);
        login_frame.setLocationRelativeTo(null);
        login_frame.setLayout(new FlowLayout());

        然后创建需要的两个按键:登录、注册,并添加登录监听器

        JButton button_login = new JButton ("登录");
        button_login.addActionListener(login_listener);
        JButton button_register = new JButton ("注册");
        button_register.addActionListener(login_listener);

        创建两个文本输入框

        JTextField name_in = new JTextField ();
        JPasswordField pwd_in = new JPasswordField ();

        设置好信息提示的文本以及大小

        JLabel label_name = new JLabel ("账号:");
        JLabel label_pwd = new JLabel ("密码:");
        name_in.setPreferredSize(new Dimension(300,35));
        pwd_in.setPreferredSize(new Dimension(300,35));

        接下来组装登录界面即可

        login_frame.add(label_name);
        login_frame.add(name_in);
        login_frame.add(label_pwd);
        login_frame.add(pwd_in);
        login_frame.add(button_login);
        login_frame.add(button_register);

        除此之外,登录信息需要传递!因此UI类提供了login_info用来装用户名和密码

        JTextField[] login_info = new JTextField[2];
        login_info[0] = name_in;
        login_info[1] = pwd_in;

        不仅如此,还要传递一下UI类和Server类给两个监听器

        login_listener.ui= this;
        login_listener.server=this.server;

        最后设置登录界面窗体可视

        login_frame.setVisible(true);

        注册界面是完全一样的道理,这里直接附上代码

   public void create_register_ui(){
        register_frame.setSize(400,300);
        register_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        register_frame.setResizable(false);
        register_frame.setLocationRelativeTo(null);
        register_frame.setLayout(new FlowLayout());
        //注册界面信息框
        JLabel label_name = new JLabel ("账号:");
        JLabel label_pwd = new JLabel ("密码:");
        JLabel label_repwd = new JLabel("确认:");
        JLabel label_id = new JLabel("学号:");
        //注册界面输入框
        JTextField name_in = new JTextField ();
        JTextField pwd_in = new JTextField ();
        JTextField repwd_in = new JTextField ();
        JTextField id_in = new JTextField ();
        name_in.setPreferredSize(new Dimension(300,35));
        pwd_in.setPreferredSize(new Dimension(300,35));
        repwd_in.setPreferredSize(new Dimension(300,35));
        id_in.setPreferredSize(new Dimension(300,35));
        //注册界面按钮
        JButton button_confirm = new JButton("注册");
        JButton button_cancel = new JButton("取消");
        button_confirm.addActionListener(register_listener);
        button_cancel.addActionListener(register_listener);
        //组装注册界面
        register_frame.add(label_name);
        register_frame.add(name_in);
        register_frame.add(label_pwd);
        register_frame.add(pwd_in);
        register_frame.add(label_repwd);
        register_frame.add(repwd_in);
        register_frame.add(label_id);
        register_frame.add(id_in);
        register_frame.add(button_confirm);
        register_frame.add(button_cancel);

        register_frame.setVisible(false);

        //保存注册信息到register_info
        register_info.add(name_in);
        register_info.add(pwd_in);
        register_info.add(repwd_in);
        register_info.add(id_in);

        Register_Listener.ui =this;
        Register_Listener.server =this.server;
    }

        至此客户端和服务端的内容就编写完了,还需要进行数据库的创建,这里不作展示了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值