首先使用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();”。