【问题标题】:How do I "extract" a variable from other classes or methods?如何从其他类或方法中“提取”变量?
【发布时间】:2016-12-23 05:22:20
【问题描述】:

在使用 Python 很长一段时间后,我最近回到了 Java,我正在努力再次适应它。我想要的第一个项目是制作一个可以(首先)登录的小型应用程序。我正在使用 mySQL 来保存用户名和密码的数据库。

到目前为止,我已经使用 Java 的 swing GUI 制作了一个弹出框,询问登录信息。输入的用户名和密码将根据 SQL 表中的用户名和密码进行测试。

问题是我正在使用 while 循环来测试 SQL 表的输入。因此,输入的信息会根据 SQL 表创建的 Hashmap 中的每个键和值进行检查。

我不确定如何从 while 循环和 SQL 的 try 语句中“提取”我的变量 g(Hashmap),以便在它被来自 mySQL 的数据填充后使用它。

我正在使用 Eclipse (Java Neon)。

我不知道如何“提取”哈希图,当我尝试让 while 循环或 try 语句返回哈希图时,Eclipse 告诉我 void 方法无法返回值(很明显)。但是,我无法将返回类型从 void 更改为 HashMap)String, String>,因为“返回类型与 ActionListener.actionPerformed(ActionEvent e) 不兼容”和“实现了 java.awt.event.ActionListener.actionPerformed”。

这是我的代码:

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;

public class Hello0 extends JFrame {
    private static final long serialVersionUID = 1487932324102279819L;

    public static void main(String[] args) {
        JFrame frame = new JFrame("Frame Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(350, 200);

        JPanel panel = new JPanel();
        frame.add(panel);
        placeComponents(panel);

        frame.setVisible(true);
    }


    private static void placeComponents(JPanel panel) {

        panel.setLayout(null);
        JLabel userLabel = new JLabel("Username");
        userLabel.setBounds(10, 20, 80, 25);
        panel.add(userLabel);

        JTextField userText = new JTextField(20);
        userText.setBounds(100, 20, 165, 25);
        panel.add(userText);

        JLabel passwordLabel = new JLabel("Password");
        passwordLabel.setBounds(10, 50, 80, 25);
        panel.add(passwordLabel);

        JPasswordField passwordText = new JPasswordField(20);
        passwordText.setBounds(100, 50, 165, 25);
        panel.add(passwordText);

        JButton loginB = new JButton("Login");
        loginB.setBounds(10, 80, 80, 25);
        panel.add(loginB);

        loginB.addActionListener(new ActionListener() {

            public HashMap<String, String> actionPerformed(ActionEvent e) {
                String username0 = "root";
                String password = "javaSQLmy98";
                try {

                    String url = "jdbc:mysql://localhost:3306/javabase?useSSL=false";
                    Connection connection = DriverManager.getConnection(url, username0, password);
                    PreparedStatement stmt0 = connection.prepareStatement("SELECT * from userids");

                    String pass0 = null;
                    String user1 = userText.getText().toString();
                    char[] pass1 = passwordText.getPassword();
                    pass0 = String.valueOf(pass1);
                    System.out.println(user1);
                    System.out.println(pass1);

                    ResultSet rs = stmt0.executeQuery();
                    rs = stmt0.executeQuery("SELECT * from userids ");
                    while (rs.next()) {

                        String user = rs.getString("username");
                        String pass = rs.getString("paswrd");

                        Map<String, String> g = new HashMap<>();
                        g.put(user, pass);
                        return g;
                        // This was the alternative: if(g.keySet().contains("Jacob") && g.values().contains("root")) {


                        /*This code below was originally outside the while loop but I could not
                        figure out how to make it work without it being inside, and accessible 
                        to the hashmap g. Now it is being checked each time the while loop 
                        is ran, with a new pair of usernames and passwords on each loop. */

                        if (user1.equals(user) && pass0.equals(pass)) {
                            System.out.println("Good!");
                        }

                        /*The problem here is that the checker IS inside the loop, so it 
                         tests the input against each of the entries in the SQL table. */
                        else {
                            System.err.println("The username or password is incorrect.");
                        }
                    }

                    connection.close();
                } catch (Exception e1) {
                    System.err.println(e1.getMessage());
                }

            }
        });

    }

}

干杯!

【问题讨论】:

  • 为什么要将所有内容加载到 HashMap 中,而不是在 SQL 查询中仅包含 WHERE 子句?
  • 你知道如何在 SQL 中编写查询来获取用户 ID 的单行,而不是遍历表中的所有行吗?
  • @RiaanNel 我不确定这会有什么帮助。 WHERE 关键字不只是充当过滤器吗?
  • @JimGarrison 我也不确定这会有什么帮助;但我相信你的意思是说要做这样的事情:
  • 获取提交的用户名并将其与 SQL 表中的用户名进行比较。如果匹配,请同时检查密码。 ? (事后看来,我相信这也是@RiaanNel 的建议。)

标签: java mysql methods hashmap inner-classes


【解决方案1】:

要在while 之外访问g,您需要在while 之外声明它,就像Java 范围内的每个{} 变量一样。因此,

Map<String, String> g = new HashMap<>();
while (condition) {
    // do something
    g.put(key, value);
}
// do something with g

但是在这种情况下,你可以直接在 SQL 中进行检查,这样应该会更有效。


旁注:

不要存储密码。 Don't store passwords.Hash+Salt passwords (or better, use a library).

【讨论】:

  • 感谢您的良好回答和建议。那么在while循环之外声明它会创建一个空的Hashmap吗?然后我在 while 循环中填充它,但现在可以在外面使用它,因为它是在哪里声明的?
  • @JacobAdamczyk 完全正确
【解决方案2】:

如果您在查询中添加 WHERE 子句,它将仅返回符合条件的数据。换句话说,下面的查询(显然带有正确的值)如果存在则返回指定的userid条目,否则返回一个空的结果集。

SELECT * from userids
WHERE userName = 'user1'
AND passwrd = 'pass1'

然后你可以去掉整个while循环和HashMap,代码可以简化如下:

if (rs.next()) {
    System.out.println("Good!");
} else {
    System.err.println("The username or password is incorrect.");
}

另外,如前所述,如果这不仅仅是一个编程练习,密码应该被散列而不是以纯文本形式存储。

【讨论】:

  • 这适用于特定值 'user1' 和 'pass1' 但我将如何使用用户名和密码输入?
  • 沿着“SELECT ...” + user + “ AND ...” + pass 的行(这很糟糕,因为它使您容易受到 SQL 注入)的旧字符串连接,或者您可以使用 PreparedStatement (更可取的选项)。 docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html
  • 您的问题找到解决方案了吗?如果是这样,请将答案标记为已接受。 stackoverflow.com/help/someone-answers
【解决方案3】:

试试这个:

Map<String, String> g = new HashMap<String, String>();
while(rs.next()) {
    String user = rs.getString("username");
    String pass = rs.getString("paswrd");
    g.put(user, pass);

    .....
}

注意:在 HasmMap 中以用户名作为键并不是一个好的编程方式,因为可以有多个同名用户。

【讨论】:

  • 那么你会推荐什么其他的数据结构呢?
  • 这取决于您当前的要求。你可以有一个 Set,或者如果你想使用 Map,那么你可以使用 Map。其中 key 是 long 类型的用户 ID,value 是 POJO 类。
  • 以上 POJO 类将具有 userId、userName、password 等属性。
  • 请注意;如果有两个相同的用户名,则他们的密码也可能相同。如果是这种情况,我们如何才能使这两个帐户独一无二?
  • 密码可以相同(在您的情况下,您将密码作为地图中的值)。我认为您对地图有更好的了解。如果没有,请尝试通过 Map 实现,您将了解为什么我们不应该将用户名作为 key(如果有重复用户名的机会)。
猜你喜欢
  • 2023-01-18
  • 1970-01-01
  • 1970-01-01
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多