Java实战之管家婆记账系统(4)——用户注册及登录功能实现

首先使用IDEA创建一个普通的JavaFX项目,并按照下图创建文件夹。

接着是引入要使用的第三方包,需要用到的包在file文件夹下的jar包中,引入即可。

在引入成功后,数据库表的创建已经在第二节文章中讲述了,并且file文件夹下的sql包中存在着可以直接执行的SQL语句,以此来创建数据库表。

第一步:根据数据库表结构创建实体类,如下图所示。

同时tools包下有两个在项目中要使用到的工具类DateTools.java和SimpleTools.java。

这些文件都在源码中,不在此写明。

第二步:在view包下创建一个名为logupFrame.fxml的视图文件并通过Scene Builder进行设计。

(关于fxml文件中各个控件的属性配置和事件设定都可以使用Scene Builder进行查看,不在此处一一说明)。

<?xml version="1.0" encoding="UTF-8"?>
​
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<HBox alignment="CENTER" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8"
      xmlns:fx="http://javafx.com/fxml/1" fx:controller="AccountSystem.controller.LogupFrameController">
    <children>
        <VBox alignment="CENTER" prefHeight="371.0" prefWidth="327.0" spacing="20.0">
            <children>
                <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
                    <children>
                        <ImageView fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true">
                            <image>
                                <Image url="@../images/welcome.png"/>
                            </image>
                        </ImageView>
                    </children>
                </HBox>
                <HBox alignment="CENTER" prefHeight="12.0" prefWidth="327.0" spacing="15.0">
                    <children>
                        <Label fx:id="nameLabel" contentDisplay="CENTER" styleClass="class_label" text="昵称:"
                               textAlignment="CENTER" textOverrun="CENTER_WORD_ELLIPSIS"/>
                        <TextField fx:id="nameTextField" promptText="请填入您的昵称:" styleClass="class_textField"/>
                    </children>
                </HBox>
                <HBox alignment="CENTER" prefHeight="0.0" prefWidth="327.0" spacing="15.0">
                    <children>
                        <Label fx:id="passwordLabel" contentDisplay="CENTER" styleClass="class_label" text="密码:"
                               textAlignment="CENTER" textOverrun="CENTER_WORD_ELLIPSIS"/>
                        <PasswordField fx:id="passwordTextField" promptText="请填入您的密码:" styleClass="class_textField"/>
                    </children>
                </HBox>
                <HBox alignment="CENTER" prefHeight="21.0" prefWidth="327.0" spacing="25.0">
                    <children>
                        <Button fx:id="loginButton" mnemonicParsing="false" onAction="#loginButtonEvent"
                                styleClass="class_button" text="注册"/>
                        <Button fx:id="logupButton" mnemonicParsing="false" onAction="#logupButtonEvent"
                                styleClass="class_button" text="登录"/>
                    </children>
                </HBox>
            </children>
            <opaqueInsets>
                <Insets/>
            </opaqueInsets>
            <HBox.margin>
                <Insets/>
            </HBox.margin>
        </VBox>
    </children>
</HBox>

接着是在controller包创建LogupFrameController.java即是登录界面fxml文件对应的控制器类,并且从Scene Builder中将对应界面的控件属性复制到该类中。

package AccountSystem.controller;
​
import AccountSystem.bean.Session;
import AccountSystem.bean.User;
import AccountSystem.dao.UserDao;
import AccountSystem.tools.SimpleTools;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
​
/**
 * 登录控制器
 *
 * @author lck100
 */
public class LogupFrameController {
​
    @FXML
    private PasswordField passwordTextField;
​
    @FXML
    private TextField nameTextField;
​
    /**
     * “注册”按钮事件监听器
     */
    @FXML
    void loginButtonEvent() {
       
    }
​
    /**
     * “登录”按钮事件监听器
     */
    @FXML
    void logupButtonEvent() {
        
    }
​
}

接着是在MainApp类中将代码改为如下,即启动程序。

package AccountSystem;
​
import AccountSystem.controller.LogupFrameController;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
​
import java.io.IOException;
​
public class MainApp extends Application {
​
    @FXML
    private Stage primaryStage;
​
    @FXML
    private HBox rootLayout;
​
    @Override
    public void start(Stage primaryStage) {
        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("管家婆系统");
        initLogupFrame();
    }
​
    /**
     * 操作结果:登录界面
     */
    private Scene initLogupFrame() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(getClass().getResource("view/logupFrame.fxml"));
            rootLayout = (HBox) loader.load();
​
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            primaryStage.setResizable(false);
​
            LogupFrameController controller = loader.getController();
            controller.setLogupStage(primaryStage);
​
            primaryStage.show();
            return scene;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
​
    public static void main(String[] args) {
        launch(args);
    }
​
}

同时在LogupFrameController中添加如下代码,创建Stage属性,来传递stage以便用来在登录成功后关闭登录stage。

    private Stage logupStage;
​
    public Stage getLogupStage() {
        return logupStage;
    }
​
    public void setLogupStage(Stage logupStage) {
        this.logupStage = logupStage;
    }

运行程序,出现如下界面,但是如果点击“注册”和“登录”按钮没有任何事件处理。

所以要为注册和登录按钮添加事件处理,由于需要使用数据库,所以在dao包下创建JDBCUtils.java和UserDao.java类。其中JDBCUtils.java类是数据库链接和释放资源公共方法类,而UserDao.java类是处理用户的注册、登录及增删改查和数据库备份恢复的操作类。

JDBCUtils.java

package AccountSystem.dao;
​
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
​
/**
 * 连接JDBC类
 */
public class JDBCUtils {
    /**
     * 加载驱动,并建立数据库连接
     *
     * @return 返回数据库链接对象
     * @throws SQLException           抛出SQLException
     * @throws ClassNotFoundException 抛出ClassNotFoundException
     * @throws IOException            抛出IOException
     */
    static Connection getConnection() throws SQLException, ClassNotFoundException, IOException {
        // 实例化Properties对象
        Properties properties = new Properties();
        // 加载properties配置文件
        properties.load(new FileInputStream(new File("src\\AccountSystem\\properties\\db.properties")));
        // 通过键名获取对应的值
        String driverName = properties.get("driverName").toString();
        String url = properties.get("url").toString();
        String user = properties.get("user").toString();
        String password = properties.get("password").toString();
        // 数据库驱动
        Class.forName(driverName);
        // 获取数据库链接对象
        Connection connection = DriverManager.getConnection(url, user, password);
        return connection;
    }
​
    /**
     * 关闭数据库连接,释放资源
     *
     * @param stmt Statement对象
     * @param conn Connection对象
     */
    static void release(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            stmt = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            conn = null;
        }
    }
​
    /**
     * 关闭数据库连接,释放资源
     *
     * @param rs   ResultSet对象
     * @param stmt Statement对象
     * @param conn Connection对象
     */
    static void release(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
        release(stmt, conn);
    }
​
    /**
     * Java代码实现MySQL数据库导出
     *
     * @param userName     进入数据库所需要的用户名
     * @param password     进入数据库所需要的密码
     * @param savePathName 数据库导出文件保存路径加名字
     * @param databaseName 要导出的数据库名
     * @return 返回true表示导出成功,否则返回false。
     */
    public static boolean backup(String userName, String password, String savePathName, String databaseName) {
        try {
//            String stmt = "mysql -uroot -padmin myDB < " + "c:/sql.sql";
            String stmt = "mysqldump -u" + userName + " -p" + password + " " + databaseName + " > " + savePathName;
            String[] cmd = {"cmd", "/c", stmt};
            Process process = Runtime.getRuntime().exec(cmd);
            if (process.waitFor() == 0) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }
​
    /**
     * 操作结果:恢复数据库,前提是数据库里有该数据库名字,否则无法恢复(所以应该先创建一个数据库)
     *
     * @param username     用户名
     * @param password     用户数据库密码
     * @param databasename 数据库名字
     * @param filePathName 数据库文件路径及名字加后缀
     * @return boolean 如果恢复成功则返回true,否则返回false
     */
    public static boolean recover(String username, String password, String databasename, String filePathName) {
        try {
//            String stmt = "mysql -uroot -padmin myDB < " + "c:/sql.sql";
            String stmt = "mysql -u" + username + " -p" + password + " " + databasename + " < " + filePathName;
            String[] cmd = {"cmd", "/c", stmt};
            Process process = Runtime.getRuntime().exec(cmd);
            if (process.waitFor() == 0) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }
​
}

UserDao.java

package AccountSystem.dao;
​
import AccountSystem.bean.User;
​
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
​
public class UserDao {
    private Connection connection = null;
​
    /**
     * 操作结果:实现按用户名与密码查询用户的方法
     *
     * @param userName 用户名
     * @param password 用户密码
     * @return Users Users对象
     */
    public User login(String userName, String password) {
        User user = new User();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            connection = JDBCUtils.getConnection();
            String sql = "select * from tb_users where uName=? and uPassword=?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, userName);
            preparedStatement.setString(2, password);
            // 执行查询
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                user.setUserId(resultSet.getInt(1));
                user.setUserName(resultSet.getString(2));
                user.setUserPassword(resultSet.getString(3));
                user.setUserImagePath(resultSet.getString(4));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(resultSet, preparedStatement, connection);
        }
        return user;
    }
​
    /**
     * 实现用户注册
     *
     * @param user 用户
     * @return 用户注册成功返回true,否则返回false
     */
    public boolean register(User user) {
        PreparedStatement preparedStatement = null;
        int num = 0;
        try {
            connection = JDBCUtils.getConnection();
            String sql = "insert into tb_users(uName,uPassword,uImagePath) values(?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, user.getUserName());
            preparedStatement.setString(2, user.getUserPassword());
            preparedStatement.setString(3, user.getUserImagePath());
            // 执行插入,返回受影响行数
            num = preparedStatement.executeUpdate();
            // 判断是否注册成功
            return num > 0;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(preparedStatement, connection);
        }
        return false;
    }
​
    /**
     * 根据用户ID查询用户信息
     *
     * @param userId 用户id
     * @return 返回查询到的用户信息
     */
    public User selectUserById(int userId) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        User user = new User();
        try {
            //获得数据的连接
            conn = JDBCUtils.getConnection();
            //获得Statement对象
            stmt = conn.createStatement();
            // 拼装SQL语句
            String sql = "select * from tb_users where uId=" + userId;
            //发送SQL语句
            rs = stmt.executeQuery(sql);
            // 循环添加数据
            while (rs.next()) {
                user.setUserId(rs.getInt(1));
                user.setUserName(rs.getString(2));
                user.setUserPassword(rs.getString(3));
                user.setUserImagePath(rs.getString(4));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(rs, stmt, conn);
        }
        return user;
    }
​
    /**
     * 更新用户数据
     *
     * @param user 要更新的用户数据
     * @return 如果更新成功则返回true,否则返回false
     */
    public boolean updateUser(User user) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //获得数据的连接
            conn = JDBCUtils.getConnection();
            //获得Statement对象
            stmt = conn.createStatement();
            // 拼接SQL语句
            String sql = "update tb_users set uName='" + user.getUserName() + "',uPassword='" + user.getUserPassword() + "',uImagePath='" + user.getUserImagePath() + "' where uId=" + user.getUserId() + ";";
            //发送SQL语句,获取受影响行数
            int num = stmt.executeUpdate(sql);
            //判断是否更改成功
            return num > 0;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(rs, stmt, conn);
        }
        return false;
    }
}

注意:由于一次性将dao类中的所有方法都给了出来,后续将不再说明调用的方法。

即使上面写了方法也不能使用因为还没有配置数据库的基本信息,所以在properties文件夹下创建一个名为db.properties的文件。

driverName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_bookkeepingSystem
user=root
password=admin

其中driverName是驱动名称,连接的是MySQL数据库,而url指的是连接URL其中db_bookkeepingSystem是你要连接的数据库名称,而user和password分别是MySQL数据库登录的用户和密码。

所有的准备工作完成后就算写注册事件和登录事件。‘

将loginButtonEvent()方法的代码写为如下即处理注册:

    /**
     * “注册”按钮事件监听器
     */
    @FXML
    void loginButtonEvent() {
        // 判断用户是否输入用户名和密码
        if (nameTextField.getText().equals("") || passwordTextField.getText().equals("")) {
            SimpleTools.informationDialog(Alert.AlertType.WARNING, "提示", "警告", "请按照文本框内容提示正确填写内容!");
        } else {
            // 实例化UserDao对象
            UserDao userDao = new UserDao();
            // 封装用户输入的数据到User实体类
            User user = new User(nameTextField.getText(), SimpleTools.MD5(passwordTextField.getText()), "src\\AccountSystem\\images\\panda.png");
            // 注册用户,并返回注册结果
            boolean isLoginSuccess = userDao.register(user);
            // 对注册结果进行反馈
            if (isLoginSuccess) {
                SimpleTools.informationDialog(Alert.AlertType.INFORMATION, "提示", "信息", "恭喜您,注册成功,欢迎使用本系统!");
            } else {
                SimpleTools.informationDialog(Alert.AlertType.ERROR, "错误", "错误", "抱歉,您注册失败了,请重新尝试!");
            }
        }
    }

获取用户在界面输入框输入的用户名和密码,然后封装到实体类User中并调用dao包下UserDao.java中的register()方法进行注册,register()方法的实现即是将传过来的数据插入到数据表中。

无论注册成功还是注册失败都进行提示反馈。

运行项目,填入信息进行注册,界面如下:

接着是登录事件,处理代码如下:

    /**
     * “登录”按钮事件监听器
     */
    @FXML
    void logupButtonEvent() {
        // 判断用户是否输入用户名和密码
        if (nameTextField.getText().equals("") || passwordTextField.getText().equals("")) {
            SimpleTools.informationDialog(Alert.AlertType.WARNING, "提示", "警告", "请按照文本框内容提示正确填写内容!");
        } else {
            // 实例化UserDao对象
            UserDao userDao = new UserDao();
            // 登录用户
            User loginUser = userDao.login(nameTextField.getText(), SimpleTools.MD5(passwordTextField.getText()));
            // 对是否登录成功进行判断
            if (loginUser.getUserName() != null && loginUser.getUserPassword() != null) {
                // 设置通信对象,建立登录成功通信
                Session.setUser(loginUser);
                // 在弹出的提示框种获取用户反馈
                boolean b = SimpleTools.informationDialog(Alert.AlertType.INFORMATION, "提示", "信息", "恭喜" + Session.getUser().getUserName() + ",登录成功,欢迎使用本系统!");
                // 如果用户确定登录,则跳转到主界面
                if (b) {
                    // 打开主窗口
                    // new MainApp().initMainFrame();
                    // 跳转到主界面后,关闭登录界面
                    logupStage.close();
                }
            } else {
                SimpleTools.informationDialog(Alert.AlertType.ERROR, "错误", "错误", "用户名或密码错误!");
            }
        }
    }

首先是验证用户输入,验证成功后将获取的用户信息封装到实体类User中,调用UserDao.java中的login()方法进行验证登录,传入的是一个User实体类参数,即从数据库中查询记录,如果查询成功则返回User并给出一个登录成功的确认框,用户点击了“确定”即跳转到主界面并关闭登录界面。同时要注意的是,由于在后面的界面中也会用到登录成功的用户信息,所以要将登录成功的用户信息保存起来,即 Session.setUser(loginUser);。

运行程序,输入刚才注册的信息,点击“登录”,出现如下界面:

但是点击“确定”后,程序将结束,因为登录界面关闭了,并且还没有创建主界面,所以无法打开。即被注释的代码“// new MainApp().initMainFrame();”。

可搜索微信公众号【Java实例程序】或者扫描下方二维码关注公众号获取更多。

注意:在公众号后台回复【20200314】可获取本章的源码 。

发布了500 篇原创文章 · 获赞 77 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/cnds123321/article/details/104270855