java - 使用日期显示以前的登录

标签 java mysql date

我有一个使用 MySql 数据库的 Java 应用程序。在我的应用程序中,我有一个 JInternalFrame,我用它来显示当前用户信息,例如“登录为:”和“上次登录:”。

    loggedInUserLabel.setText("Logged in as: ");
    getContentPane().add(loggedInUserLabel);
    loggedInUserLabel.setBounds(30, 30, 80, 30);

    loggedInUser.setText("Admin");
    getContentPane().add(loggedInUser);
    loggedInUser.setBounds(140, 30, 80, 30);

    lastLoginLabel.setText("Last Login:");
    getContentPane().add(lastLoginLabel);
    lastLoginLabel.setBounds(30, 60, 80, 30);

    lastLogin.setText("14-03-2015");
    getContentPane().add(lastLogin);
    lastLogin.setBounds(140, 60, 80, 30);

如何设置日期,我目前已将其设置为虚拟值“14-03-2015”以显示我的上次登录?有没有办法通过 MySql 做到这一点?

更新

我创建了一个新表来存储一些登录详细信息:

CREATE TABLE IF NOT EXISTS `last_login`(
`username` varchar(20) NOT NULL,
`date` varchar(20) NOT NULL
);

登录的地方是这样的:

if (rs.next()) {
        if (rs.getString("usertype").equals("Admin")) {
            setLoggedInUser(userBox.getText());
            insertData();
            AdminMenu adminMenu = new AdminMenu();
            adminMenu.setVisible(true);
            setVisible(false);
        } else if (rs.getString("usertype").equals("Employee")) {
            setLoggedInUser(userBox.getText());
            insertData();
            EmployeeMenu employeeMenu = new EmployeeMenu();
            employeeMenu.setVisible(true);
            setVisible(false);
        }

使用“insertData”将新数据插入到我的表中,如下所示

public static void insertData() {
    String user = "root";
    String pass = "pass";
    String schmea = "db";

    Date date = new Date();
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    String currentDate = dateFormat.format(date);

    try {
        Connection conn = MySql.getConnection(user, pass, "/" + schmea);

        try {
            String q = "insert into last_login(username,date) values(?,?)";
            PreparedStatement stmt = conn.prepareStatement(q);
            stmt.setString(1, loggedInUser);
            stmt.setString(2, currentDate);
            stmt.execute();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

但是问题:我使用这段代码从数据库中检索日期

public void internalFrameActivated(InternalFrameEvent e) {

            String user = "root";
            String pass = "pass";
            String schema = "db";
            String loggedInUser = Login.getLoggedInUser();

            try {
                Connection conn = MySql.getConnection(user, pass, "/" + schema);

                try {
                    String q = "select date from last_login where username=?";
                    PreparedStatement stmt = (PreparedStatement) conn.prepareStatement(q);
                    stmt.setString(1, loggedInUser);
                    ResultSet rs = stmt.executeQuery();

                    if (rs.next()) {
                        lastLogin.setText(rs.getString(1));
                    } else {
                        JOptionPane.showMessageDialog(rootPane, "Unable to retrieve information for user: " + loggedInUser + "!");
                    }
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(rootPane, "Error in Query: " + ex.getMessage());
                }
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(rootPane, "Error in Database Connection: " + ex.getMessage());
            }

        }

我知道我总是会返回该用户的当前日期。我如何确定该用户之前的日期?

最佳答案

使用日期时间类型

不要将字符串用于日期时间值。对日期时间值使用日期时间类型。

在 Java 8 及更高版本中,使用 java.time Instant 等类型(UTC 时间轴上的一个时刻)。如果 Java 8 技术不可用(Android 等),则使用古老的 Joda-Time图书馆。

要将数据传入和传出数据库,请使用 java.sql 类型,例如 java.sql.Timestamp .希望 JDBC 驱动程序将更新为直接支持 java.time 类型,但在那之前使用 java.time-java.sql 转换方法,例如 from( Instant )toInstant .

在您的数据库中,了解其日期时间类型。 SQL 规范定义了一些类型,但对这些类型的支持差异很大。一些数据库,例如 Postgresexcellent date-time support .一些如 SQLite有一周的支持。一些如 H2在中间。仔细研究数据库的文档。然后进行实验以确保您了解它的行为。日期时间工作可能很棘手。

我不明白您使用没有时间的仅日期来跟踪登录。为什么您只关心一整天的登录?此外,仅日期是模糊的,因为日期的定义因时区而异。通常我们在 UTC 中跟踪此类业务数据作为日期时间值时区。然后,为了演示,调整到用户预期/期望的特定时区。

示例应用

以下是将登录尝试存储在数据库中的完整应用程序的源代码。此应用程序是人为设计的,旨在用于演示而非部署。使用风险自负。

Swing你的应用程序的一部分是一个很大的分心。这个示例应用程序更简单,没有用户界面。每次运行应用程序的 main 方法时,它都会报告之前的登录尝试,然后进行新的尝试。新的尝试随机选择一个用户名。

package com.example.logintracker;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

/**
 * Contrived app to demonstrate saving login attempts to a database.
 *
 * This source code available via the Free Public License 1.0.0. http://opensource.org/licenses/FPL-1.0.0
 *
 * @author Basil Bourque
 */
public class App {

    public static void main ( String[] args ) {
        App app = new App ();

        // Report the most recent login attempt.
        Authenticator authenticator_Reporter = new Authenticator ();
        LoginAttempt loginAttempt_Recent = authenticator_Reporter.getMostRecentAttempt ();
        System.out.println ( "Recent loginAttempt: " + loginAttempt_Recent );

        // Attempt a login.
        Authenticator authenticator_Login = new Authenticator ();
        ArrayList<String> userNames = new ArrayList<> ( Arrays.asList ( "Wendy" , "Lisa" , "Jesse" , "Oliver" , "Jasmine" , "Jean-Luc" , "Jarrod" , "Evonne" , "Elise" ) ); // Pick a name at random.
        String userName = userNames.get ( new Random ().nextInt ( userNames.size () ) ); // From user-interface.
        String password = "pw"; // From user-interface.
        LoginAttempt loginAttempt_Now = authenticator_Login.authenticate ( userName , password );
        System.out.println ( "Fresh loginAttempt: " + loginAttempt_Now );
        if ( loginAttempt_Now.getSuccessful () ) {
            // Run the app for this user.
            // TODO: implement.
        } else {
            // Else block this user from running this app.
            // TODO: implement.
        }
    }
}

Authenticator 是主要业务逻辑的网关。

package com.example.logintracker;

import java.time.Instant;
import java.util.UUID;

/**
 * The business logic for handling login attempts. Called by separate user interface code.
 *
 * This source code available via the Free Public License 1.0.0. http://opensource.org/licenses/FPL-1.0.0
 *
 * @author Basil Bourque
 *
 */
public class Authenticator {

    // User-interface makes this call to execute a user’s login attempt.
    public LoginAttempt authenticate ( String userName , String password ) {
        Boolean successful = Boolean.FALSE;

        // TODO: Add business logic to perform authentication. Hard-coded here to always succeed for this demonstration code.
        successful = Boolean.TRUE;
        LoginAttempt loginAttempt = new LoginAttempt ( userName , Instant.now () , successful , UUID.randomUUID () );

        // Remember this attempt.
        Persister persister = new Persister ();
        persister.saveLoginAttempt ( loginAttempt );

        return loginAttempt;
    }

    public LoginAttempt getMostRecentAttempt () {
        Persister persister = new Persister ();
        LoginAttempt loginAttempt = persister.fetchMostRecentLoginAttempt ();
        return loginAttempt;
    }

}

每次登录尝试的数据存储在一个简单的 LoginAttempt 类中,如 value objects .

package com.example.logintracker;

import java.time.Instant;
import java.util.UUID;

/**
 *
 * Value object holding the data describing each login attempt: who was the user, when attempted, was the login successful.
 *
 * This source code available via the Free Public License 1.0.0. http://opensource.org/licenses/FPL-1.0.0
 *
 * @author Basil Bourque
 *
 */
public class LoginAttempt {

    private String userName;
    private Instant whenAttempted;
    private Boolean successful;
    private UUID uuid = null;

    public LoginAttempt ( String userNameArg , Instant whenAttemptedArg , Boolean successfulArg , UUID uuidArg ) {
//        System.out.println ( "Constructor of LoginAttempt: " + whenAttemptedArg + " user: " + userNameArg );
        this.userName = userNameArg;
        this.whenAttempted = whenAttemptedArg;
        this.successful = successfulArg;
        this.uuid = uuidArg;
    }

    // Getters. Read-only object.
    public String getUserName () {
        return this.userName;
    }

    public Instant getWhenAttempted () {
        return this.whenAttempted;
    }

    public Boolean getSuccessful () {
        return this.successful;
    }

    public UUID getUuid () {
        return this.uuid;
    }

    // Override Object.
    @Override
    public String toString () {
        return "LoginAttempt{ " + "userName=" + this.userName + " | whenAttempted=" + this.whenAttempted + " | successful=" + this.successful + " | uuid=" + this.uuid + " }";
    }

}

这些登录尝试存储在一个基本的 SQL 表中。

CREATE TABlE IF NOT EXISTS login_attempt_
(
    uuid_ UUID DEFAULT RANDOM_UUID() PRIMARY KEY,
    when_written_ TIMESTAMP DEFAULT NOW() NOT NULL,
    username_ VARCHAR_IGNORECASE(255) NOT NULL,
    when_attempted_ TIMESTAMP NOT NULL,
    success_ BOOLEAN NOT NULL
)
;

每次运行此应用程序时,它都会检查该表是否存在。如果找不到,应用程序会自动创建该表。包含该表的数据库以及数据库用户和密码也都是自动创建的。因此,只需运行此应用程序即可查看演示。无需额外设置。

此示例数据库使用 H2 database ,一个免费的开源纯 Java SQL 数据库。 H2 可以在嵌入式模式或客户端/服务器模式下运行。在这个应用程序中,我们使用嵌入式模式。在 Maven 项目中,只需添加对 com.h2database 的依赖。

Persister 类处理与数据库的所有交互,保存和检索登录尝试。

package com.example.logintracker;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Handles all persisting of data to database or other storage mechanism. Called from other code handling business logic.
 *
 * This source code available via the Free Public License 1.0.0. http://opensource.org/licenses/FPL-1.0.0
 *
 * @author Basil Bourque
 *
 */
public class Persister {

    public void saveLoginAttempt ( LoginAttempt loginAttempt ) {
        // Get database connection.
        // Make prepared statement.
        // Transfer pieces of data from LoginAttempt into PreparedStatement.
        // Execute database transaction.

        StringBuilder sql = new StringBuilder ();
        sql.append ( "INSERT INTO login_attempt_ ( username_ , when_attempted_ , success_ , uuid_ ) " + " \n" );
        sql.append ( "VALUES ( ? , ? , ? , ? )" + " \n" );
        sql.append ( ";" + " \n" );

        try ( Connection conn = this.fetchConnection (); ) {
//            System.out.println ( "conn: " + conn );

            try ( PreparedStatement ps = conn.prepareStatement ( sql.toString () ); ) {
                ps.setString ( 1 , loginAttempt.getUserName () );
                java.sql.Timestamp ts = java.sql.Timestamp.from ( loginAttempt.getWhenAttempted () );  // Converting from java.time.Instant to java.sql.Timestamp.
                ps.setTimestamp ( 2 , ts );
                ps.setBoolean ( 3 , loginAttempt.getSuccessful () );
                ps.setObject ( 4 , loginAttempt.getUuid () );
                ps.executeUpdate ();

            } catch ( SQLException ex ) {
                System.err.println ( "SQLException: " + ex.getMessage () );
                // TODO: Handle exception.
            }
        } catch ( SQLException ex ) {
            System.err.println ( "SQLException on this.fetchConnection: " + ex.getMessage () );
            // TODO: Handle exception.
        }

    }

    public LoginAttempt fetchMostRecentLoginAttempt () {
        // Get database connection.
        // Make prepared statement.
        // Execute query.
        // Transfer pieces of data from ResultSet to new LoginAttempt object.
        // Return object (or null if failure occurred).

        StringBuilder sql = new StringBuilder ();
        sql.append ( "SELECT * " + " \n" );
        sql.append ( "FROM login_attempt_" + " \n" );
        sql.append ( "ORDER BY when_attempted_ DESC" + " \n" );
        sql.append ( "LIMIT 1" + " \n" );
        sql.append ( ";" + " \n" );

        LoginAttempt loginAttempt = null;
        try ( Connection conn = this.fetchConnection (); ) {
//            System.out.println ( "conn: " + conn );

            try ( Statement stmt = conn.createStatement (); ) {
                ResultSet rs = stmt.executeQuery ( sql.toString () );
                int count = 0;
                while ( rs.next () ) {
                    count ++;
                    String userName = rs.getString ( "username_" );
                    java.sql.Timestamp whenWritten = rs.getTimestamp ( "when_attempted_" );
                    Boolean success = rs.getBoolean ( "success_" );
                    UUID uuid = ( UUID ) rs.getObject ( "uuid_" );
                    loginAttempt = new LoginAttempt ( userName , whenWritten.toInstant () , success , uuid );  // Converting from java.sql.Timestamp to java.time.Instant.
                }
                if ( count > 1 ) {
                    // TODO: Handle problem where more than one row returned.
                }

            } catch ( SQLException ex ) {
                System.err.println ( "SQLException: " + ex.getMessage () );
                // TODO: Handle exception.
            }
        } catch ( SQLException ex ) {
            System.err.println ( "SQLException on this.fetchConnection: " + ex.getMessage () );
            // TODO: Handle exception.
        }
        return loginAttempt;
    }

    private Connection fetchConnection () throws SQLException {
        Connection conn = null;

        try {
            Class.forName ( "org.h2.Driver" );
        } catch ( ClassNotFoundException e ) {
            // TODO: Handle exception.
            System.out.println ( "Database failure: " + e );
            return null;
        }

        // Specify a database named 'LoginTracker.mv.db' in the Unix user’s home folder.
        String dbFolderPath = "~/";
        String dbName = "LoginTracker";
        String dbUrl = "jdbc:h2:" + dbFolderPath + dbName;
        String dbUserName = "h2";
        String dbPassword = "pw";

        try {
            // If database does not yet exist, it is automatically created.
            conn = DriverManager.getConnection ( dbUrl , dbUserName , dbPassword );
        } catch ( SQLException ex ) {
            System.out.println ( "SQLException on DriverManager.getConnection: " + ex.getMessage () );
            // TODO: Handle exception when no Connection is made.
        }

        if ( null == conn ) {
            System.out.println ( "Database error. No Connection." );
            // TODO: Handle exception when no Connection is made.
        } else {
            // ELSE got database connection. Normal.
            this.updateDatabaseStructureIfNeedBe ( conn );
        }

        return conn;
    }

    private void updateDatabaseStructureIfNeedBe ( Connection conn ) {
        // Update database structure if needed.

        // 'login_attempt_' Table.
        StringBuilder sql = new StringBuilder ();
        sql.append ( "CREATE TABlE IF NOT EXISTS login_attempt_" + " \n" );
        sql.append ( "(" + " \n" );
        sql.append ( "uuid_ UUID DEFAULT RANDOM_UUID() PRIMARY KEY," + " \n" );  // Primary key, UUID type.
        sql.append ( "when_written_ TIMESTAMP DEFAULT NOW() NOT NULL," + " \n" );  // Record when this record was written to database. Apparently H2 only provides txn start time, not current time.
        sql.append ( "username_ VARCHAR_IGNORECASE(255) NOT NULL," + " \n" );  // User’s name. Case-insensitive.
        sql.append ( "when_attempted_ TIMESTAMP NOT NULL," + " \n" );  // When this login attempt was made.
        sql.append ( "success_ BOOLEAN NOT NULL" + " \n" );  // Did this login attempt succeed or fail?
        sql.append ( ")" + " \n" );
        sql.append ( ";" + " \n" );

        try ( Statement stmt = conn.createStatement () ) {
            stmt.executeUpdate ( sql.toString () );
            stmt.close ();

        } catch ( SQLException ex ) {
            System.err.println ( "SQLException: " + ex.getMessage () );
            // TODO: Handle exception.
        }

    }

}

关于java - 使用日期显示以前的登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34463267/

相关文章:

java - Primefaces5 如何更改图表中的背景颜色(纯 java,无 jqplot)

MySql - 根据偏好左连接但没有重复项

java - 异常,表未映射

java - 将 UTC 日期转换为不同时区的日期

java - JSP项目中的JDBC SQL Server连接错误

java - Optaplanner项目作业调度: weekends and holidays

java - 如何在 Undertow 中启用 Access-Control-Allow-Origin?

mysql - 为什么在 MySQL 触发器查询中出现语法错误?

mysql - MySQL中如何将字符串转换为日期?

sql - 使用 YYYY-MM-DD 格式更新 mssqlserver 中的 sql 日期字段