Java 在servlet外部访问会话变量

Java 在servlet外部访问会话变量,java,session,servlets,Java,Session,Servlets,我正在开发一个java webapp,需要根据用户登录id访问数据库中的记录。成功登录后,我在会话变量中设置登录详细信息 我想做的就是这样的事情 选择*从项目记录,其中用户id=用户id(从会话) 现在我将用户名作为参数传递,但我认为这不是一个好的做法。有没有更好的方法访问servlet之外的会话变量 Servlet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws

我正在开发一个java webapp,需要根据用户登录id访问数据库中的记录。成功登录后,我在会话变量中设置登录详细信息

我想做的就是这样的事情

选择*从项目记录,其中用户id=用户id(从会话)

现在我将用户名作为参数传递,但我认为这不是一个好的做法。有没有更好的方法访问servlet之外的会话变量

Servlet

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

        User user = (User) request.getSession().getAttribute("userInfo");

        System.out.println(user);

        if(user != null){
            Gson gson = new Gson();
            returnJsonResponse(response,gson.toJson(user));
            return;
        }
}
public Accrual getAccruals(String accrualID,String userid) throws AccrualNotFoundException{

    String sql = Select * from db_acc where acc_id= accrualID and user_id=userid;

}
在数据层包中

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

        User user = (User) request.getSession().getAttribute("userInfo");

        System.out.println(user);

        if(user != null){
            Gson gson = new Gson();
            returnJsonResponse(response,gson.toJson(user));
            return;
        }
}
public Accrual getAccruals(String accrualID,String userid) throws AccrualNotFoundException{

    String sql = Select * from db_acc where acc_id= accrualID and user_id=userid;

}

问题是我必须用userid修改我的所有方法。有没有一种方法可以在不修改方法签名的情况下,将用户详细信息设置到某个静态类中,并在应用程序中随时访问详细信息?但是我相信静态类在不同的用户请求之间是共享的。

您总是可以从servlet中的会话获取用户id并将其传递到您的数据层,直接在数据层中使用会话是没有意义的。提取对象并将责任转移到下一层。在数据层中使用特定于HTTP的对象实际上是一种糟糕的做法。

在严格分离关注点的情况下,数据层应该与会话或请求无关。但您需要在服务层或数据层中使用用户名(
user\u id
)。最简单的方法是在控制器中有效地收集它(控制器可以访问请求和会话),将其传递到服务层,然后将其转发到数据层

另一种方法(由SpringSecurity或ApacheShiro等安全框架使用)是在请求处理开始时将其存储在线程存储中,并在结束时(在过滤器中)仔细清理。然后,实用程序类的静态方法可以将其提供给应用程序的任何部分。但是,每次使用实用程序类时,都会获得对框架的依赖。 为了减少不必要的依赖性,您可以拥有自己的Holder类,并使用一个调用框架之一的静态方法:依赖性仅限于Holder类

如果使用Spring,还有第三种解决方案。您可以有一个会话范围的bean,带有aop代理,您可以将它注入任何需要访问变量的bean中。由于aop代理,您将能够从当前会话访问数据,甚至可以从单例bean访问数据


在我自己的应用程序中,我在简单的情况下(少数类)使用第一种方法,在许多方法中避免重复相同的参数时使用第三种方法。

您正在寻找的解决方案是线程本地(google it)。它允许您使用静态方法访问特定于线程的数据

你可以开始阅读了。使用其中的示例,您需要创建:

public class MyThreadLocal {

    public static final ThreadLocal userThreadLocal = new ThreadLocal();

    public static void set(User user) {
        userThreadLocal.set(user);
    }

    public static void unset() {
        userThreadLocal.remove();
    }

    public static User get() {
        return userThreadLocal.get();
    }
}
在servlet中,执行以下操作:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    User user = (User) request.getSession().getAttribute("userInfo");
    MyThreadLocal.set(user);
    try {
       // call data layer
    } finally {
        MyThreadLocal.unset();
    }
}
在数据层中,可以通过执行以下操作检索用户:

public void dataLayerMethod(ExistingParameters parameters) {
    User user = MyThreadLocal.get();
}
请注意,您不需要更改数据层的方法签名


“线程本地”一开始有点让人困惑,但一旦你读了这篇文章,你就会很快熟悉它。

我认为你可以很容易地使用它

SecurityUtils.getSubject().getSession().getAttribute(“userInfo”)

所以不需要更改签名。通过这种方式,您可以使用shiros内置实用程序,而不是依赖于您自己的逻辑和概率

public Accrual getAccruals(String accrualID) throws AccrualNotFoundException{
    User user = (User) SecurityUtils.getSubject().getSession().getAttribute("userInfo");
    String userid= user.getUserId();
    String sql = Select * from db_acc where acc_id= accrualID and user_id=userid;

}

您希望在何处访问会话变量?在客户那里?JSP?您可以在应用程序的数据层中使用代码示例进行详细说明吗