Java实战:实现用户的登录注册功能

系列文章目录

Java文件 I/O流的操作实战和高级UI组件和事件监听的综合


文章目录

  • 系列文章目录
  • 前言
  • 一、大致流程思路分析:
  • 二、定义用户类:
  • 服务层的实现:
    • 1.保护用户数据功能的实现
    • 2.登录操作的实现
  • 实现用户的注册界面:
    • 大体流程:
  • 实现用户的登录界面(在这里面相当于总界面)
    • 大体流程:
  • 在实现时的易错点:
    • 以我自己举例:
  • 总结

前言

在学习完文件和IO流的操作后,包括事件监听机制和UI组件以后,我们可能会想这些知识可以用来干什么,今天我们就用一个实战案例来帮大家将学过的知识运用起来。(但是这个实战案例本来是可以用数据库与Java进行连接,但是这篇我们也可以用将用户数据存储到文件当中来实现,因为像MySQL等数据库,本质都是存储在文件当中的)。


一、大致流程思路分析:

我将用最通俗易懂的话向大家解释一下这个的具体流程:

首先我们想要实现用户的注册和登录功能,就要先定义出来用户类,把用户的数据当作成员属性定义出来,然后我们需要建一个窗口来实现登录,注册,重置的操作,注册和登录需要我们输入文本,这些都是基础的,最关键的操作是什么呢?

**就是要定义一个能实现注册和登录的类作为服务层,注册的时候就是把在窗口得到的数据写到文件当中存储起来,那文件当中肯定会有一个又一个的用户的数据,因此我们实现登录的功能就需要把这些个用户全都读取出来,和登录窗口得到的文本核对,看是否能登录成功,**大体流程就是这些,反正就是服务层和窗口层的连接,包括数据库的连接也是如此,这个我们后来再讲。

二、定义用户类:

首先我们需要把用户当成一个用户类,它的属性就是我们理解的用户的数据。

这里面的用户数据包括了:用户名,密码,性别,爱好,地址,学历。

以下是代码:

java 复制代码
public class User {
    //用户实体
    private int id;   //用户
    private String userName;  //用户名
    private String passWord;   //密码
    private int sex;  //性别
    private String hobby;   //爱好
    private String address;   //地址
    private String degree;  //学历

    public User(String userName, String passWord, int sex, String hobby, String address, String degree) {
        this.userName = userName;
        this.passWord = passWord;
        this.sex = sex;
        this.hobby = hobby;
        this.address = address;
        this.degree = degree;
    }

    public User(int id, String userName, String passWord, int sex, String hobby, String address, String degree) {
        this.id = id;
        this.userName = userName;
        this.passWord = passWord;
        this.sex = sex;
        this.hobby = hobby;
        this.address = address;
        this.degree = degree;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public void setDegree(String degree) {
        this.degree = degree;
    }

    public int getId() {
        return id;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassWord() {
        return passWord;
    }

    public String getHobby() {
        return hobby;
    }

    public int getSex() {
        return sex;
    }

    public String getAddress() {
        return address;
    }

    public String getDegree() {
        return degree;
    }

}

三、服务层的实现:

java 复制代码
public static String filePath = "E:\\User.txt";
    private static final String DELIMITER = "|";

先创建出来文件路径,以方便下面的操作。

1.保存用户数据功能的实现:

这个方法是用来将用户的数据读取到文件当中的、

以下是代码实现:

java 复制代码
public boolean saveUser(User user) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            if (!file.createNewFile()) {
                System.out.println("存储用户文件创建失败");
                return false;
            }
        }
        //下面开始对文件进行输入保存
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));
        //这是我们在注册窗口时通过输入的文本框的内容放在一个User对象
        // 得到我们在注册时的用户信息
        String userData = String.join(DELIMITER, String.valueOf(user.getId()), user.getUserName(),
                user.getPassWord(), String.valueOf(user.getSex()), user.getHobby(),
                user.getAddress(), user.getDegree());
        bufferedWriter.write(userData);
        bufferedWriter.newLine();
        bufferedWriter.close();
        return true;
    }

2.登录操作的实现(即从文件中读取数据)

这里面最关键的一点是:

复制代码
我们要想对登录的用户进行验证,首先肯定要得到存储在文件中的所有用户资源
因此我们肯定需要写一个ReadAllUsers的方法,然后再对每一个对象进行一一遍历

以下是代码实现:

java 复制代码
//这个方法用来完成登录的操作
    // 首先我们肯定要得到用户名和密码,这个应该是在界面层通过输入的文本来得到
    // 相应的用户名和密码进行验证
    public boolean vaildateLogin(String inputUserName,String inputPassWord) throws IOException {
        //我们要想对登录的用户进行验证,首先肯定要得到存储在文件中的所有用户资源
        //因此我们肯定需要写一个ReadAllUsers的方法,然后再对每一个对象进行一一遍历
             List<User> users = readAllUsers();
                //下面开始对文件当中的每一个用户数据进行验证判断是否能登陆成功
             for(User user:users){
                    if(user.getUserName().equals(inputUserName)
                            &&user.getPassWord().equals(inputPassWord)){
                         return true;
                    }
             }

          return false;

    }

    public List<User> readAllUsers() throws IOException {
        //先创建一个列表来存放每一个用户数据对象
        List<User> list = new ArrayList<>();
        File file = new File(filePath);
        if (file.exists()) {
            //开始进行读操作
            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                String[] parts = line.split("\\" + DELIMITER);
                //下面开始创建User对象并传入到列表当中
                if (parts.length == 7) {
                    list.add(new User(
                            Integer.parseInt(parts[0]), // ID
                            parts[1],                   // 用户名
                            parts[2],                   // 密码
                            Integer.parseInt(parts[3]), // 性别
                            parts[4],                   // 爱好
                            parts[5],                   // 地址
                            parts[6]                    // 学历
                    ));
                }


            }
        }
        return list;
    }

四、实现用户的注册界面:

大体流程:

对于注册界面我们肯定要设置标签和文本框,还需要设置布局方式,并且对确认和重置按钮作监听。

下面是代码的实现:

java 复制代码
public class RegistFrame extends JFrame {
    //这是实现用户注册界面

    //主面板
    private JPanel p;
    //标签
    private JLabel lblName, lblPwd, lblRePwd, lblSex, lblHobby,
            lblAdress, lblDegree;
    //用户名文本框
    private JTextField txtName;
    //密码共和确认密码文本框
    private JPasswordField txtPwd, txtRepwd;
    //性别,单选按钮
    private JRadioButton rbMale, rbFemale;
    //爱好,多选框
    private JCheckBox ckbRead, ckbNet, ckbSwim, ckbTour;
    //地址,文本框
    private JTextArea txtAdress;
    //学历,组合框
    private JComboBox<String> cmbDegree;
    //确认和取消,按钮
    private JButton btnOk, btnCancle;
    //注册的用户
    private static User user;
    //用户业务类
    private UserService userService;

    //构造方法
    public RegistFrame() {
        super("用户注册");
        //实例化用户业务类对象
        userService = new UserService();
        //设置窗体的icon
//.......
        //设置面板布局,网格布局
        p = new JPanel(new GridLayout(8, 1, 0, 10));
        //实例化组件
        lblName = new JLabel("用  户   名:");
        lblPwd = new JLabel("密  码:");
        lblRePwd = new JLabel("确认密码:");
        lblSex = new JLabel("性  别:");
        lblHobby = new JLabel("爱  好:");
        lblAdress = new JLabel("地   址:");
        lblDegree = new JLabel("学  历");
        txtName = new JTextField(25);
        txtPwd = new JPasswordField(25);
        txtRepwd = new JPasswordField(25);
        rbMale = new JRadioButton("男");
        rbFemale = new JRadioButton("女");
        //性别的单选逻辑
        ButtonGroup bg = new ButtonGroup();
        bg.add(rbMale);
        bg.add(rbFemale);
        ckbRead = new JCheckBox("阅读");
        ckbNet = new JCheckBox("上网");
        ckbSwim = new JCheckBox("游泳");
        ckbTour = new JCheckBox("旅游");
        txtAdress = new JTextArea(3, 20);
        //组合框显示学历数组
        // 正确初始化组合框
       cmbDegree = new JComboBox<>(new String[]{"小学", "初中", "高中", "本科", "硕士", "博士"});
        //设置组合框可编辑

            cmbDegree.setSelectedIndex(0);// 默认选中第一项
        cmbDegree.setPreferredSize(new Dimension(200, 30));
        cmbDegree.setEditable(true);
        btnOk = new JButton("确定");
        btnCancle = new JButton("重置");
        btnOk.setPreferredSize(new Dimension(120, 35));   // 宽度120,高度35
        btnCancle.setPreferredSize(new Dimension(120, 35));
        Font bigFont = new Font("宋体", Font.PLAIN, 16);

// 统一设置组件字体
        txtName.setFont(bigFont);
        txtPwd.setFont(bigFont);
        txtRepwd.setFont(bigFont);
        rbMale.setFont(bigFont);
        rbFemale.setFont(bigFont);
        ckbRead.setFont(bigFont);
        ckbNet.setFont(bigFont);
        ckbSwim.setFont(bigFont);
        ckbTour.setFont(bigFont);
        txtAdress.setFont(bigFont);
        cmbDegree.setFont(bigFont);
        btnOk.setFont(bigFont);
        btnCancle.setFont(bigFont);
        //这一步需要注册监听器,监听确定按钮
        btnOk.addActionListener(new RegisterListener());
        //还需要注册监听器,监听重置按钮
        btnCancle.addActionListener(new ResetListener());
     /*
      将组件分组放入面板,然后将小面板放入主面板

      */
        JPanel p1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p1.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p1.add(lblName);
        p1.add(txtName);
        p.add(p1);
        JPanel p2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p2.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p2.add(lblPwd);
        p2.add(txtPwd);
        p.add(p2);
        JPanel p3 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p3.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p3.add(lblRePwd);
        p3.add(txtRepwd);
        p.add(p3);
        JPanel p4 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p4.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p4.add(lblSex);
        p4.add(rbMale);
        p4.add(rbFemale);
        p.add(p4);
        JPanel p5 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p5.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p5.add(lblHobby);
        p5.add(ckbRead);
        p5.add(ckbNet);
        p5.add(ckbSwim);
        p5.add(ckbTour);
        p.add(p5);
        JPanel p6 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p6.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p6.add(lblAdress);
        p6.add(txtAdress);
        p.add(p6);
        JPanel p7 = new JPanel(new FlowLayout(FlowLayout.LEFT));
        p7.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p7.add(lblDegree);
        p7.add(cmbDegree);
        p.add(p7);
        JPanel p8 = new JPanel(new FlowLayout(FlowLayout.CENTER));
        p8.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
        p8.add(btnOk);
        p8.add(btnCancle);
        p.add(p8);
        //主面板放入窗体中
        this.add(p);
        //设置窗体的大小和位置居中
        this.setSize(450, 500);
        this.setLocationRelativeTo(null);
        //设置窗体不可改变大小
        this.setResizable(false);
        //设置窗体初始可见
        this.setVisible(true);
    }

    //监听类,负责处理确认按钮的业务逻辑
    private class RegisterListener implements ActionListener {


        @Override
        public void actionPerformed(ActionEvent e) {
            //获取用户输入的数据
            String userName = txtName.getText().trim();
            String passWord = new String(txtPwd.getPassword());
            String rePassWord = new String(txtRepwd.getPassword());
            //将性别"男""女"对应转化为"1""0"
            int sex = Integer.parseInt(rbFemale.isSelected() ? "0" : "1");
            String hobby = (ckbRead.isSelected() ? "阅读" : "")
                    + (ckbNet.isSelected() ? "上网" : "")
                    + (ckbSwim.isSelected() ? "游泳" : "")
                    + (ckbTour.isSelected() ? "旅游" : "");
            String address = txtAdress.getText();
            Object selectedDegree = cmbDegree.getSelectedItem();
            String degree = (selectedDegree != null) ? selectedDegree.toString().trim() : "";
            //判断两次输入密码是否一致
            if (passWord.equals(rePassWord)) {
                //将数据封装到对象当中
                user = new User(userName, passWord, sex, hobby, address, degree);
                //保存数据
                try {
                    if (userService.saveUser(user)) {
                        System.out.println("注册成功!");
                    }
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            } else {
                System.out.println("两次密码输入的不一致!");
            }
        }
    }

    public class ResetListener implements ActionListener {


        @Override
        public void actionPerformed(ActionEvent e) {
            //清空姓名,密码,确认密码等内容
            txtName.setText("");
            txtPwd.setText("");
            txtRepwd.setText("");
            //重置单选按钮为未选择
            rbMale.setSelected(false);
            rbFemale.setSelected(false);
            //重置所有复选按钮为未选择
            ckbRead.setSelected(false);
            ckbNet.setSelected(false);
            ckbSwim.setSelected(false);
            ckbTour.setSelected(false);
            //清空地址栏
            txtAdress.setText("");
            //重置组合框为未选择状态
            cmbDegree.setSelectedIndex(0);

        }
    }


}

五、实现用户的登录界面(在这里面相当于总界面)

大体流程:

这里的用户登录肯定也需要多个组件,用户名和密码的标签和文本框,然后登录,注册,重置按钮,并对其实现监听机制,这里面需要和服务层的登录方法匹配

以下是代码实现:

java 复制代码
/**
 * @author 袁敬尧
 * @version 1.0
 */
public class LoginFrame extends JFrame {
    //这是用户登录 注册界面,我们需要多个组件

    //主面板
    private JPanel p;
    //标签
    private JLabel lblName, lblPwd;
    //用户名,文本框
    private JTextField txtName;
    //密码,密码框
    private JPasswordField txtPwd;
    //确认,取消和注册,按钮
    private JButton btnOk, btnCancle, btnRegist;
    //登录用户
    private static User user;
    //用户业务类
    private UserService userService;

    //构造方法
    public LoginFrame() {
        super("登录");
        //实例化用户业务类对象
        userService = new UserService();
        //实例化组件
        p = new JPanel();
        Font inputFont = new Font("微软雅黑", Font.PLAIN, 16);
        //使用null布局
        p.setLayout(null);
        lblName = new JLabel("用户名:");
        lblPwd = new JLabel("密码:");
        txtName = new JTextField(20);
        txtPwd = new JPasswordField(20);
        txtPwd.setEchoChar('*');

        btnOk = new JButton("登录");
        btnOk.addActionListener(new LoginListener());

        btnCancle = new JButton("重置");
        btnCancle.addActionListener(new ResetListener());

        btnRegist = new JButton("注册");
        btnRegist.addActionListener(new RegistListener());

        lblName.setBounds(30, 30, 80, 30);          // 增大标签宽度
        lblPwd.setBounds(30, 80, 80, 30);          // 下移密码标签位置
        txtName.setBounds(120, 30, 200, 30);       // 宽度200 → 300
        txtPwd.setBounds(120, 80, 200, 30);         // 同用户名框对齐
        btnOk.setBounds(50, 130, 80, 35);          // 增大按钮尺寸
        btnCancle.setBounds(150, 130, 80, 35);
        btnRegist.setBounds(250, 130, 80, 35);

        p.add(lblName);
        p.add(txtName);
        p.add(lblPwd);
        p.add(txtPwd);
        p.add(btnOk);
        p.add(btnCancle);
        p.add(btnRegist);
        txtName.setFont(inputFont);
        txtPwd.setFont(inputFont);
        //主面板放入窗体中
        this.add(p);
        //设置窗体的大小和位置
        this.setSize(420, 300);
        //设置窗口在屏幕中央
        this.setLocationRelativeTo(null);
        //设置窗体的默认关闭按钮
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置窗体初始可见
        this.setVisible(true);


    }

    public class LoginListener implements ActionListener {


        @Override
        public void actionPerformed(ActionEvent e) {
            //这里我在服务层里面已经写好了验证的数据
            String userName = txtName.getText().trim();
            String passWord = new String(txtPwd.getPassword());
            try {
                if (userService.vaildateLogin(userName,passWord)) {
                         LoginFrame.this.setVisible(false);
                    JOptionPane.showMessageDialog(null,
                            "登录成功!欢迎您:" + userName,
                            "系统提示",
                            JOptionPane.INFORMATION_MESSAGE);
                }
                else{
                    //输出提示信息
                    System.out.println("密码错误,请重新输入");
                    //清空密码框
                    txtPwd.setText("");
                    txtName.setText("");
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
    //监听类,负责处理重置按钮
    public class ResetListener implements ActionListener{


        @Override
        public void actionPerformed(ActionEvent e) {
               txtName.setText("");
               txtPwd.setText("");
        }
    }
    //监听类,负责处理注册按钮
    public class RegistListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            new RegistFrame();
        }
    }
    public static void main(String[] args){
        new LoginFrame();
    }

}

六、在实现时的易错点:

以我自己举例:

我在实现这个功能的时候,就报了空指针异常的错误,包括像我当时写坦克大战的时候也犯了空指针异常的错误,因为可能我们使用的类还没有分配内存就被使用了,那肯定会抛异常的,

java 复制代码
private JComboBox<String> cmbDegree;
...
cmbDegree.setEditable(true); // 未初始化直接调用方法

我这里面未初始化就直接调用方法了

java 复制代码
// 正确初始化组合框
private JComboBox<String> cmbDegree = new JComboBox<>(new String[]{"小学", "初中", "高中", "本科", "硕士", "博士"});

密码字段也错了

java 复制代码
// LoginFrame.java
String userPwd = txtPwd.getPassword().toString(); // 错误!得到的是数组地址

// RegistFrame.java
String passWord = new String(txtPwd.getPassword()); // 正确但未去空格

具体改正:

java 复制代码
// LoginFrame.java
String userPwd = new String(txtPwd.getPassword()).trim(); // 转换为字符串并去空格

// RegistFrame.java
String passWord = new String(txtPwd.getPassword()).trim();

还有最关键的一点就是使用文件流一定要记得关流。


总结

以上就是我要讲的内容了,这是一个实现用户登录和注册的基本功功能,其实这个还有很多可以扩充功能的,具体怎么实现我会和大家一起思考的,下面两周我会持续更新蓝桥杯算法题的,希望大家多多关注,我们一起加油,谢谢大家。

相关推荐
serendipity_hky4 分钟前
【go语言 | 第2篇】Go变量声明 + 常用数据类型的使用
开发语言·后端·golang
遇见火星16 分钟前
常见Systemctl语句
linux·服务器·网络·systemctl
报错小能手23 分钟前
STL_unordered_map
开发语言·c++·哈希算法
疯狂的程序猴25 分钟前
App Store上架完整流程与注意事项详解
后端
专家大圣32 分钟前
摆脱局域网束缚!Neko+cpolar 让跨网共享成日常
服务器·网络·docker·内网穿透·cpolar
爱笑的眼睛1133 分钟前
超越剪枝与量化:下一代AI模型压缩工具的技术演进与实践
java·人工智能·python·ai
开心就好202536 分钟前
把 H5 应用上架 App Store,并不是套个壳这么简单
后端
CreasyChan38 分钟前
C#特性(Attributes)详解
开发语言·c#
阿里云云原生38 分钟前
Android App 崩溃排查指南:阿里云 RUM 如何让你快速从告警到定位根因?
android·java
历程里程碑40 分钟前
C++ 9 stack_queue:数据结构的核心奥秘
java·开发语言·数据结构·c++·windows·笔记·算法