在这里编程新手。我正在使用Swing,JDBC(Oracle)创建一个简单的登录应用程序。它在很大程度上按预期工作。该应用程序有3个类 - 逻辑,UI和DBConnection。
请参阅此处的完整代码:Full Code
1。 LoginLogic.java
public class LoginLogic {
LoginUI lu;
public LoginLogic() {
lu = new LoginUI();
}
public LoginLogic(ResultSet rs) {
process(rs);
}
private void process(ResultSet rs) {
try {
if (rs.next()) {
lu.loginSuccess();
} else {
lu.loginFailed();
}
} catch (SQLException e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
new LoginLogic();
}
}
最初,我直接显示了一个JOptionPane来代替loginSuccess()和loginFailed()方法,它按预期工作。但是我想将所有UI功能委托给UI类,所以我在UI类中创建了这两个方法
void loginSuccess() {
JOptionPane.showMessageDialog(null, "Login Successful!");
}
void loginFailed() {
JOptionPane.showMessageDialog(null, "Login Failed!");
}
但是这些方法不是使用我在构造函数中创建的UI对象调用的。没有错误,但也没有JOptionPane。
如何在process()方法中使用UI对象引用 lu 来调用UI类的方法?
答案 0 :(得分:3)
您的main方法调用no-arg构造函数。这个无参数构造函数实现为
lu = new LoginUI();
因此它创建了LoginUI对象,但不做其他任何事情。特别是,它从不调用process()
方法,即显示JOptionPane的方法。
您从不调用的其他构造函数会调用process()
方法。但它没有初始化LoginUI对象。
我也没有看到如何调用process()
方法,因为代码中没有任何内容可以创建此方法需要作为参数的ResultSet。
答案 1 :(得分:3)
正如JB Nizet解释的那样,您的代码中需要进行一些更改。尝试以下代码(它对我有用)。
public class LoginLogic {
LoginUI lu;
public LoginLogic() {
lu = new LoginUI();
}
public LoginLogic(ResultSet rs) {
lu = new LoginUI();
process(rs);
}
private void process(ResultSet rs) {
try {
if (rs.next()) {
lu.loginSuccess();
} else {
lu.loginFailed();
}
} catch (SQLException e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
/*/ Here you shld get your result rs first
con is your Connection object
Statement stmt = con.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT yourColumn FROM yourTable");
//*/
new LoginLogic(rs);
}
}
<强> EDITED 强>
根据我们的评论,问题是您正在创建一个新对象:
private void getConn(String uname, String pwd) {
...
// 4. Process the result set
new LoginLogic(rs);
...
}
这意味着您没有在if()语句中调用正确的对象。您的新对象是使用参数化构造函数构造的,该构造函数不初始化lu或更新它。
<强> EDITED2 强>
我认为你必须改变你的设计。我认为以下内容对您有用,但您必须处理异常。
public class LoginLogic {
LoginUI lu;
public LoginLogic() {
lu = new LoginUI();
}
public void process() {
try {
if (lu.getRs().next()) {
lu.loginSuccess();
} else {
lu.loginFailed();
}
} catch (SQLException e) {
// TODO: handle exception
}
}
public static void main(String[] args) {
LoginLogic loginLogic = new LoginLogic();
loginLogic.process();
}
}
loginUI将更改为:
public class LoginUI {
...
ResultSet rs;
public ResultSet getRs() {
return rs;
}
...
btnLogin.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
String uname = tfUname.getText().trim();
String pwd = tfPwd.getText().trim();
LoginDbConn loginDbConn = new LoginDbConn(uname, pwd);// startDB after user presses
rs = loginDbConn.getConn();
} catch (Exception ex) {
// TODO: handle exception
}
}
});
....
}
LoginDbConn到此:
public class LoginDbConn {
String uname;
String pwd;
ResultSet rs;
/*
* public LoginDbConn() { // TODO Auto-generated constructor stub }
*/
public LoginDbConn(String uname, String pwd) {
this.uname = uname;
this.pwd = pwd;
}
public ResultSet getConn() {
try {
// 0. Register the JDBC drivers
String driverClass = "oracle.jdbc.driver.OracleDriver";
Class.forName(driverClass);
// or DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
// 1. Get a connection to the Database
String dbUrl = "jdbc:oracle:thin:@localhost:1521:xe";
String dbuname = "scott";
String dbpwd = "tiger";
Connection conn = DriverManager.getConnection(dbUrl, dbuname, dbpwd);
// 2. Create a statement
// String sql = "SELECT * FROM users WHERE name = '"+uname+"' and
// password = '"+pwd+"'";
// Statement st = conn.createStatement();
String sql = "select * from users where name = ? and password = ?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, uname);
pst.setString(2, pwd);
// 3. Execute SQL query
rs = pst.executeQuery();
// 5. Close Connection
// conn.close();
return rs;
} catch (SQLException | ClassNotFoundException e) {
// THIS EXCEPTION MUST ABSOLUTELY BE HANDLED
}
return rs;
}
}
希望这会有所帮助(如果是的话请投票给答案)。
答案 2 :(得分:2)
您可以通过一个构造函数实现此目的,而不是使用两个构造函数:
public LoginLogic(ResultSet rs) {
lu = new LoginUI();
process(rs);
}
您刚从您想要呼叫的地方拨打此电话。您可以通过new LoginLogic(resultSet);
答案 3 :(得分:1)
感谢+Guizmoo03指出了问题的根源。
正如您在此代码中看到的,该类有2个构造函数。在创建UI时,默认构造函数首先初始化以null开头的LoginUI对象引用。
public class LoginLogic {
LoginUI lu;
public LoginLogic() {
lu = new LoginUI();
}
.....
但是,当它将要处理的ResultSet传递给参数化构造函数时,再次在DbConn类中创建Logic类的对象。此实例化取消引用UI对象变量 lu 。因此,正如我在最初的问题中所指出的那样,它不能再用于访问process()方法中UI类的方法。
...
LoginUI lu;
...
public LoginLogic(ResultSet rs) {
process(rs);
}
private void process(ResultSet rs) {
try {
if (rs.next()) {
lu.loginSuccess();
} else {
lu.loginFailed();
}
} catch (SQLException e) {
// TODO: handle exception
}
}
...
DbConn Class snippet
// 4. Process the result set
new LoginLogic(rs);
所以解决方案: 一种可能的解决方法是在构造函数之外实例化UI对象变量 lu
...
LoginUI lu = new LoginUI();
public LoginLogic() {
}
public LoginLogic(ResultSet rs) {
process(rs);
}
private void process(ResultSet rs) {
...
虽然这解决了解引用问题,但是当DbConn创建逻辑类的新对象时,它导致GUI被重新初始化。
public class LoginUI {
// Container declarations
...
// Component declarations
...
public LoginUI() {
createFrame();
}
private void createFrame() {
...
实际上没有太多副作用的另一种解决方法是使用静态方法。但是在OO代码中使用太多静态元素并不是一个好习惯。
所以我切换到 Singleton pattern with Eager initialization ,这有效地解决了问题。
<强> LoginLogic 强>
public class LoginLogic {
static final LoginUI lu = LoginUI.getInstance(); // immutable singleton
// object reference
public LoginLogic() {
// TODO Auto-generated constructor stub
}
public LoginLogic(ResultSet rs) { // parameterized constructor
process(rs);
}
void process(ResultSet rs) {...
<强> LoginUI 强>
public class LoginUI {
// Container declarations
// Component declarations
private static final LoginUI lu = new LoginUI(); // immutable singleton
// object
private LoginUI() { // prevent external instantiation
initUI();
}
static LoginUI getInstance() { // getter for the singleton object
return lu;
}...