Java Swing& Postgres用户认证:当新连接打开时关闭旧连接 [英] Java Swing & Postgres user authentication: Close old connection when new connection opened

查看:205
本文介绍了Java Swing& Postgres用户认证:当新连接打开时关闭旧连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Java Swing应用程序,它使用一个简单的Singleton模式访问一个Postgres数据库:

I have a Java Swing application that accesses a Postgres database using a simple Singleton Pattern:

public class DatabaseConnection {
    private static final String uname = "*******";
    private static final String pword = "*******";
    private static final String url = "*******************************";

    Connection connection;
    // load jdbc driver
    public DatabaseConnection(){
        try{
            Class.forName("org.postgresql.Driver");
            establishConnection();
        } catch (ClassNotFoundException ce) {
            System.out.println("Could not load jdbc Driver: ");
            ce.printStackTrace();
        }
    }
    public Connection establishConnection() {
        // TODO Auto-generated method stub
        try{
            connection = DriverManager.getConnection(url, uname, pword);
        } catch (SQLException e){
            System.out.println("Could not connect to database: ");
            e.printStackTrace();
        }
        return connection;
    }
}

public class SingletonConnection {

    private static DatabaseConnection con;

    public SingletonConnection(){}

    public static DatabaseConnection instance(){

        assert con == null;
            con = new DatabaseConnection();
        return con;
    }
}

这是我的用户表,由Pgadmin3创建丑陋的大写字母):

This is my user table created by Pgadmin3 (hence the ugly upper cases):

CREATE TABLE "user"
(
  id serial NOT NULL,
  "userRoleId" integer NOT NULL,
  "employeeId" bigint NOT NULL,
  "subjectId" bigint NOT NULL,
  username text NOT NULL,
  cryptpwd text NOT NULL,
  "userStatusId" integer NOT NULL,
  md5pwd text NOT NULL,
  CONSTRAINT pk_user PRIMARY KEY (id),
  CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
      REFERENCES subject (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
      REFERENCES employee (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
      REFERENCES "userRole" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
      REFERENCES "userStatus" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "unique_user_userName" UNIQUE (username)
)

由于此应用程序将在许多机器上运行本地网络,我希望每个特定用户只有一个连接实例。也就是说,如果用户A从一台机器登录,并且用户A稍后从另一台机器登录,则通知应该出现在两台机器上,第二次登录具有继续连接的选项 - 在这种情况下,现有连接被丢弃/ lost。

Since this application will be run on many machines in a local network, I would like to have only a single connection instance per specific user. That is, if userA logs in from one machine, and userA logs in from another machine moments later, notifications should appear on both machines with the second log in having the option to continue with the connection - in which case, the existing connection is dropped/lost.

我想我必须在我的用户表中添加一个新列(logged_on boolean)...在这种情况下,第二个登录由找到logged_on的值并适当地执行。我的问题是,我怎么能够关闭第一个连接?

I imagine I'd have to add a new column (logged_on boolean) in my user table ... in which case the second log in is handled by finding the value of logged_on and acting appropriately. My question is, how then will I be able to close the first connection? How can I maintain a maximum of one connection - per user - at database level?

推荐答案

确定,这是我在数据库级别上的最大连接数工作。令人惊讶的是,我正在考虑沿着你提到的Zamezela的一些东西...我还没有工作,但我认为这应该工作。

Ok, this is what I'm working on. Surprisingly, I was thinking of something along the lines you mentioned Zamezela ... I haven't got it working yet, but I think this should work.

我的用户表:

CREATE TABLE "user"
(
  id serial NOT NULL,
  "userRoleId" integer NOT NULL,
  "employeeId" bigint NOT NULL,
  "subjectId" bigint NOT NULL,
  username text NOT NULL,
  cryptpwd text NOT NULL,
  "userStatusId" integer NOT NULL,
  md5pwd text NOT NULL,
  "loggedIn" boolean NOT NULL DEFAULT false,
  CONSTRAINT pk_user PRIMARY KEY (id),
  CONSTRAINT "subjectId" FOREIGN KEY ("subjectId")
      REFERENCES subject (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT user_employee_id FOREIGN KEY ("employeeId")
      REFERENCES employee (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userRole_id" FOREIGN KEY ("userRoleId")
      REFERENCES "userRole" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "user_userStatus_id" FOREIGN KEY ("userStatusId")
      REFERENCES "userStatus" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE,
  CONSTRAINT "unique_user_userName" UNIQUE (username)
)



< ve创建了一个表,记录每个用户登录。将帮助跟踪用户活动:

I've created a table that records each and every user login. Will help track down on user activity:

CREATE TABLE "userLoginHistory"
(
  "userId" integer NOT NULL,
  _datetime timestamp without time zone NOT NULL,
  hostname text NOT NULL,
  "osUsername" text NOT NULL,
  id bigserial NOT NULL,
  CONSTRAINT "pk_userLoginHistory" PRIMARY KEY (id),
  CONSTRAINT "userLoginHistory_user_id" FOREIGN KEY ("userId")
      REFERENCES "user" (id) MATCH FULL
      ON UPDATE RESTRICT ON DELETE RESTRICT DEFERRABLE INITIALLY IMMEDIATE
)



现在我有三个主要的存储函数...可以添加到他们明天。迟到。

I now have three main Stored functions thus far ... may add on to them tomorrow. Getting late.

第一个涉及请求用户登录。这会返回用户ID,角色,某人是否登录此用户帐户以及此用户是否处于活动状态:

First one involves requesting for a user login. This returns the user id, role, whether someone is logged on on this user account, and whether this user is active:

create type userLoginRequestReturnType as
(
  userId integer, -- user.id
  userRoleId integer, -- user.roleId
  loggedIn boolean, -- user.loggedIn
  userActive boolean -- whether user is active
);

CREATE OR REPLACE FUNCTION "user_login_request"(usernameIn text, passwordIn text)
returns setof userLoginRequestReturnType as
$$
declare
    user_Id integer;
    user_RoleId integer;
    user_StatusId integer;
    user_loggedIn boolean;
    user_Active boolean;

    sql text;
begin
      user_Active = false;
      select into user_Id, user_RoleId, user_StatusId, user_loggedIn id, "userRoleId", "userStatusId", "loggedIn" from "user" where username = usernameIn and cryptpwd = crypt(passwordIn, cryptpwd);
      if (user_id > 0) then -- record found
    select into user_Active "user_is_active"(user_StatusId);
      else
    user_id = 0;
    user_RoleId = 0;
    user_loggedIn = false;
    user_Active = false;
      end if;
      sql =  'select ' || user_Id || ', ' || user_RoleId || ', ' || user_loggedIn || ', ' || user_Active ||';';
      return query execute sql;
end;
$$ language 'plpgsql';

这被传递到前端。如果user_loggedIn为true,并且所有其他属性支持成功登录,则前端将通知用户有现有连接,以及是否继续(断开现有连接)。如果它是false,那么它只是继续(没有任何提示)到此函数:

This is passed to the front end. If user_loggedIn is true, and all the other attributes support a successful log in, then the front end will notify the user that there is an existing connection, and whether to continue (disconnecting the existing connection). If it is false, then it just continues (without any prompt) to this function:

CREATE OR REPLACE FUNCTION "user_login_complete"(userIdIN integer, hostnameIN text, osUsernameIN text)
returns bigint as
$$
declare
    currentTime timestamp without time zone;
    userLoginHistoryId bigint;
begin
      -- update user.loggedIn
      update "user" set "loggedIn" = true where id = userIdIN;
      -- insert into userLoginHistory
      currentTime = NOW()::timestamp without time zone;
      insert into "userLoginHistory" ("userId", _datetime, hostname, "osUsername") values (userIdIN, currentTime, hostnameIN, osUsernameIN);
      select into userLoginHistoryId currval('"userLoginHistory_id_seq"');
      return userLoginHistoryId;
end;
$$ language 'plpgsql';

userLoginHistoryId存储在前端,因为我使用MVC架构用于我的Java Swing项目,我的抽象模型类将在其构造函数中调用以下函数。我已采取了您的建议,并将在每种方法中关闭连接。

The userLoginHistoryId is stored on the front end, since I'm using an MVC architecture for my Java Swing project, my abstract Model Class will call the following function in its constructor. I have taken your advice and will close the connection in each method.

-- function to check if the current logged in session is the last one recorded in database
-- to be run before each connection to the database as per userId
-- new userLoginHistoryId must be inserted into table userLoginHistory, and the id PK value stored in the front end
--
-- returns: true, if current session is the last session recorded in table userLoginHistory for this user_autosuggest_by_ID
--    : false, if another login session has been recorded.
-- MUST BE EXECUTED BEFORE EACH AND EVERY DATABASE TRANSACTION!!!!!
CREATE OR REPLACE FUNCTION "user_login_session_check"(userIdIN integer, userLoginHistoryIdIN bigint)
returns boolean as
$$
declare
    results boolean;
    userLoginHistoryId bigint;
begin
      results = true;
      select into userLoginHistoryId id from "userLoginHistory" where "userId" = userIdIN ORDER BY id DESC LIMIT 1;
      if (userLoginHistoryIdIN = userLoginHistoryId) then
    results = true;
      else
    results = false;
      end if;
end;
$$ language 'plpgsql';

将测试明天,希望它工作正常。请随时评论。

Will test tomorrow and hopefully it works fine. Please feel free to comment.

感谢。

这篇关于Java Swing&amp; Postgres用户认证:当新连接打开时关闭旧连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆