我的程序是一个模拟网上购物系统。该程序在运行时会显示登录屏幕,如果用户忘记了登录信息,可以单击“忘记密码”按钮。单击此按钮后,程序会打开一个框架,用户可以在其中输入他们的电子邮件地址。当用户输入此电子邮件地址并点击“发送密码恢复电子邮件”时,应该会出现一个消息对话框,通知用户电子邮件已成功发送(如果用户输入的电子邮件地址实际与他们的 ID)或未发送(如果用户输入的地址在数据库中不存在或不存在或与其他用户绑定)。但是,当我运行该程序时,没有弹出消息对话框,我也不知道为什么。没有返回异常 - 程序只是拒绝显示对话框。
这里是程序所有相关部分的代码。很抱歉提供了这么多代码,但由于程序没有返回异常,所以我不知道导致程序出现故障的代码在哪里。该程序还有其他部分,但它们与“忘记密码”屏幕没有直接关系。
应用:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
public class Application {
private static Application instance; // Singleton pattern
private static boolean checkEmail = false;
private static String email;
public static Application getInstance() {
if (instance == null) {
instance = new Application();
}
return instance;
}
// Main components of this application
private Connection connection;
public Connection getConnection() {
return connection;
}
public static void setCheckEmail() {
checkEmail = true;
}
public static void setEmail(String theEmail) {
email = theEmail;
}
private DataAdapter dataAdapter;
private User currentUser = null;
public void setCurrentUser(User user) {
this.currentUser = user;
}
public User getCurrentUser() {
return currentUser;
}
// Create the Product View and Controller here!
private ProductView productView = new ProductView();
private CheckoutScreen checkoutScreen = new CheckoutScreen();
private MainScreen mainScreen = new MainScreen();
public MainScreen getMainScreen() {
return mainScreen;
}
public ProductView getProductView() {
return productView;
}
public CheckoutScreen getCheckoutScreen() {
return checkoutScreen;
}
public LoginScreen loginScreen = new LoginScreen();
public LoginScreen getLoginScreen() {
return loginScreen;
}
public LoginController loginController; // = new LoginController(loginScreen, dataAdapter);
private ProductController productController;
public ProductController getProductController() {
return productController;
}
private CheckoutController checkoutController;
public CheckoutController getCheckoutController() {
return checkoutController;
}
public DataAdapter getDataAdapter() {
return dataAdapter;
}
private ForgotPasswordScreen forgotPasswordScreen = new ForgotPasswordScreen();
public ForgotPasswordScreen getForgotPasswordScreen() {
return forgotPasswordScreen;
}
private void initializeDatabase(Statement stmt) throws SQLException { // CHANGE: Added initialization code
// create the tables and insert sample data here!
stmt.execute("create table Product (ProductID int PRIMARY KEY, ProductName char(30), Price double, Quantity double);");
stmt.execute("create table Orders (ProductID int PRIMARY KEY, ProductName char(30), Price double, Quantity double);");
stmt.execute("create table OrderLine (OrderID INT NOT NULL, ProductID INT NOT NULL, Quantity double, Cost double, PRIMARY KEY (ProductID, OrderID);");
stmt.execute("create table User (UserID INT NOT NULL, UserName CHAR(30) NOT NULL, Password CHAR(30) NOT NULL, DisplayName CHAR(30), IsManager BOOL DEFAULT FALSE, PRIMARY KEY(UserID));");
stmt.execute("create table sqlite_sequence (name, seq);");
stmt.execute("INSERT INTO Product VALUES (1, 'Apple', 1.0, 257.0), (2, 'Chair', 100.0, 38.0), (3, 'Smartphone', 699.99, 486.0), (4, 'T-shirt', 20.0, 244.0), (5, 'TV', 250.0, 43.0);");
stmt.execute("INSERT INTO User VALUES (1, 'admin', 'password', 'Admin', TRUE);");
}
private void initializeEmailList(Statement stmt) throws SQLException {
stmt.execute("CREATE TABLE Email (Email CHAR(30) NOT NULL, UserID int NOT NULL);");
stmt.execute("INSERT INTO Email VALUES('[email protected]', 1);");
}
private Application() {
// create SQLite database connection here!
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:store.db");
Statement stmt = connection.createStatement();
if (!stmt.executeQuery("select * from product").next()) // product table do not exist
initializeDatabase(stmt);
if (!stmt.executeQuery("select * from email").next()) // product table do not exist
initializeEmailList(stmt);
if(checkEmail == true) {
Statement stmt2 = connection.createStatement();
ResultSet resultSet = stmt2.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");
//Application.getInstance().checkEmail(email);
checkEmail = false;
}
}
catch (ClassNotFoundException ex) {
System.out.println("SQLite is not installed. System exits with error!");
System.exit(1);
}
catch (SQLException ex) {
System.out.println("SQLite database is not ready. System exits with error!" + ex.getMessage());
System.exit(2);
}
// Create data adapter here!
dataAdapter = new DataAdapter(connection);
productController = new ProductController(productView, dataAdapter);
checkoutController = new CheckoutController(checkoutScreen, dataAdapter);
loginController = new LoginController(loginScreen, dataAdapter);
}
public static void main(String[] args) {
Application.getInstance().getLoginScreen().setVisible(true);
}
}
忘记密码控制器:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
public class ForgotPasswordController implements ActionListener {
private ForgotPasswordScreen forgotPasswordScreen;
public ForgotPasswordController(ForgotPasswordScreen forgotPasswordScreen) {
this.forgotPasswordScreen = forgotPasswordScreen;
this.forgotPasswordScreen.getSendEmail().addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == forgotPasswordScreen.getSendEmail()) {
String email = forgotPasswordScreen.getEmailAddress().getText().trim();
Application.setEmail(email);
Application.setCheckEmail();
/*Connection forgotPasswordConnection = Application.getInstance().getConnection();
Statement stmt = forgotPasswordConnection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");*/
//Application.getInstance().checkEmail(email);
Application application = Application.getInstance();
}
}
}
忘记密码屏幕:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ForgotPasswordScreen extends JFrame {
private JTextField emailAddress = new JTextField(30);
private JButton sendEmail = new JButton("Send Password Recovery Email");
public JButton getSendEmail() {
return sendEmail;
}
public JTextField getEmailAddress() {
return emailAddress;
}
public ForgotPasswordScreen() {
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 200);
JPanel panelForgotPasswordScreen = new JPanel();
JLabel emailAddressLabel = new JLabel("Email address:");
panelForgotPasswordScreen.add(emailAddressLabel);
panelForgotPasswordScreen.add(emailAddress);
this.getContentPane().add(panelForgotPasswordScreen);
JPanel panelSendEmailButton = new JPanel();
panelSendEmailButton.add(sendEmail);
this.getContentPane().add(sendEmail);
}
}
登录控制器:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginController implements ActionListener {
private LoginScreen loginScreen;
private DataAdapter dataAdapter;
public LoginController(LoginScreen loginScreen, DataAdapter dataAdapter) {
this.loginScreen = loginScreen;
this.dataAdapter = dataAdapter;
this.loginScreen.getBtnLogin().addActionListener(this);
this.loginScreen.getBtnForgotPassword().addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == loginScreen.getBtnLogin()) {
String username = loginScreen.getTxtUserName().getText().trim();
String password = loginScreen.getTxtPassword().getText().trim();
System.out.println("Login with username = " + username + " and password = " + password);
User user = dataAdapter.loadUser(username, password);
if (user == null) {
JOptionPane.showMessageDialog(null, "This user does not exist!");
}
else {
Application.getInstance().setCurrentUser(user);
this.loginScreen.setVisible(false);
Application.getInstance().getMainScreen().setVisible(true);
}
}
if(e.getSource() == loginScreen.getBtnForgotPassword()) {
Application.getInstance().getForgotPasswordScreen().setVisible(true);
}
}
}
登录屏幕:
import javax.swing.*;
import java.awt.*;
public class LoginScreen extends JFrame {
private JTextField txtUserName = new JTextField(10);
private JTextField txtPassword = new JTextField(10);
private JButton btnLogin = new JButton("Login");
private JButton btnForgotPassword = new JButton("Forgot Password"); //CHANGE: Added a mechanism for the user to recover a forgotten password
public JButton getBtnLogin() {
return btnLogin;
}
public JTextField getTxtPassword() {
return txtPassword;
}
public JTextField getTxtUserName() {
return txtUserName;
}
public JButton getBtnForgotPassword() {
return btnForgotPassword;
}
public LoginScreen() {
this.setSize(300, 400);
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
this.getContentPane().add(new JLabel ("Store Management System"));
JPanel panelUserName = new JPanel();
panelUserName.add(new JLabel("Username:"));
panelUserName.add(txtUserName);
this.getContentPane().add(panelUserName);
JPanel panelPassword = new JPanel();
panelPassword.add(new JLabel("Password:"));
panelPassword.add(txtPassword);
this.getContentPane().add(panelPassword);
JPanel panelLogin = new JPanel();
panelLogin.setAlignmentX(Component.CENTER_ALIGNMENT); //CHANGE: Centered the login and "forgot password" buttons
panelLogin.add(btnLogin);
JPanel panelForgotPassword = new JPanel();
panelLogin.setAlignmentX(Component.CENTER_ALIGNMENT);
panelForgotPassword.add(btnForgotPassword);
this.getContentPane().add(panelLogin);
this.getContentPane().add(panelForgotPassword);
}
}
编辑:按照 MadProgrammer 的建议,我从 Application 类中删除了测试用户输入的电子邮件地址有效性的代码,并将其添加到 actionPerformed 方法内的 ForgotPasswordController 类中;但是,我现在收到一个新错误:“未报告的异常 java.sql.SQLException;必须被捕获或声明为被抛出”。
在 actionPerformed 方法中添加“throws SQLException”在诊断问题时不起作用,因为它覆盖的方法不包括“throws SQLException”;这样做只会产生一个新错误,提示“java: actionPerformed(java.awt.event.ActionEvent) in ForgotPasswordController cannot implement actionPerformed(java.awt.event.ActionEvent) in java.awt.event.ActionListener 重写的方法不会抛出 java.sql.SQLException”。
这是我的 actionPerformed 方法的新代码:
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == forgotPasswordScreen.getSendEmail()) {
String email = forgotPasswordScreen.getEmailAddress().getText().trim();
//Application.setEmail(email);
//Application.setCheckEmail();
/*Connection forgotPasswordConnection = Application.getInstance().getConnection();
Statement stmt = forgotPasswordConnection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");*/
//Application.getInstance().checkEmail(email);
//Application application = Application.getInstance();
Connection connection = DriverManager.getConnection("jdbc:sqlite:store.db");
Statement stmt = connection.createStatement();
ResultSet resultSet = stmt.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next())
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
else if (resultSet.getString(1) != email) JOptionPane.showMessageDialog(null, "Incorrect email!");
else JOptionPane.showMessageDialog(null, "Email sent!");
}
}
让我们去掉一些噪音,仔细看看这个……
public class Application {
private static Application instance; // Singleton pattern
private static boolean checkEmail = false;
private static String email;
public static Application getInstance() {
if (instance == null) {
instance = new Application();
}
return instance;
}
public Connection getConnection() {
return connection;
}
private Application() {
// create SQLite database connection here!
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:store.db");
Statement stmt = connection.createStatement();
if (!stmt.executeQuery("select * from product").next()) // product table do not exist
{
initializeDatabase(stmt);
}
if (!stmt.executeQuery("select * from email").next()) // product table do not exist
{
initializeEmailList(stmt);
}
if (checkEmail == true) {
Statement stmt2 = connection.createStatement();
ResultSet resultSet = stmt2.executeQuery("SELECT * from Email WHERE UserID = " + Application.getInstance().getCurrentUser().getUserID());
if (!resultSet.next()) {
JOptionPane.showMessageDialog(null, "This email does not belong to any registered user!");
} else if (resultSet.getString(1) != email) {
JOptionPane.showMessageDialog(null, "Incorrect email!");
} else {
JOptionPane.showMessageDialog(null, "Email sent!");
}
//Application.getInstance().checkEmail(email);
checkEmail = false;
}
} catch (ClassNotFoundException ex) {
System.out.println("SQLite is not installed. System exits with error!");
System.exit(1);
} catch (SQLException ex) {
System.out.println("SQLite database is not ready. System exits with error!" + ex.getMessage());
System.exit(2);
}
// Create data adapter here!
dataAdapter = new DataAdapter(connection);
productController = new ProductController(productView, dataAdapter);
checkoutController = new CheckoutController(checkoutScreen, dataAdapter);
loginController = new LoginController(loginScreen, dataAdapter);
}
public static void main(String[] args) {
Application.getInstance().getLoginScreen().setVisible(true);
}
}
所以,在
main
方法中你调用Application.getInstance().getLoginScreen().setVisible(true);
这将:
Application
的新实例(在getInstance
中)checkEmail
默认为false
,它不会执行该工作流最终,我们发现自己在这里......
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == forgotPasswordScreen.getSendEmail()) {
String email = forgotPasswordScreen.getEmailAddress().getText().trim();
Application.setEmail(email);
Application.setCheckEmail();
Application application = Application.getInstance();
}
}
现在,问题是,当你调用
Application.getInstance()
时,你将取回之前创建的实例(回到调用 main
时,有点像单例),所以构造函数是从来没有叫过。
相反,你应该有一个专门的方法来处理忘记的密码,也许更像是......
public enum Application {
INSTANCE;
private Connection connection;
private User currentUser = null;
private Application() {
// Setup and initialisation
}
public Connection getConnection() {
return connection;
}
// Not sure this makes sense to me, unless the authentication
// workflow is seperate from the Application, I'd probably not
// allow the user to be set here, but that's me
public void setCurrentUser(User user) {
this.currentUser = user;
}
public User getCurrentUser() {
return currentUser;
}
public void recoverAccount(String email) throws Exception {
try (PreparedStatement stmt = connection.prepareStatement("SELECT * from Email WHERE UserID = ?")) {
// How do you get the current userId for a user whose not logged in?
// I smell a NullPointerException in your future
stmt.setInt(1, getCurrentUser().getUserID());
try (ResultSet rs = stmt.executeQuery()) {
// Personally, I'd throw customised exceptions here, as they are
// easier to deal with
if (!resultSet.next()) {
throw Exception("This email does not belong to any registered user!");
} else if (resultSet.getString(1) != email) {
throw Exception("Incorrect email!");
}
}
}
}
// Other functionality not implemented
}
然后你只需调用
Application.INSTANCE.recoverAccount(someEmailAddress);
...但请注意,这会抛出一个 Exception