关于java:访问servlet外部的会话变量

Accessing session variables outside servlet

我正在研究一个JavaWebApp,在这里我需要根据用户登录ID访问数据库中的记录。在登录成功后,我在会话变量中设置登录细节。

我想做的就是这样的事

从项目记录中选择*,其中user_id=user_id(来自会话)

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

小服务程序

1
2
3
4
5
6
7
8
9
10
11
12
13
    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;
        }
}

在数据层包中

1
2
3
4
5
public Accrual getAccruals(String accrualID,String userid) throws AccrualNotFoundException{

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

}

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


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

您可以开始阅读http://VErasundAR.com /博客/ 2010/11 / Java线程本地如何使用和代码采样/。使用这里的示例,您需要创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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中,执行以下操作:

1
2
3
4
5
6
7
8
9
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();
    }
}

在数据层中,可以通过执行以下操作来检索用户:

1
2
3
public void dataLayerMethod(ExistingParameters parameters) {
    User user = MyThreadLocal.get();
}

注意,您不需要更改数据层的方法签名。

起初,线程局部有点混乱,但一旦阅读了本文,您将很快熟悉它。


我觉得你很容易使用

SecurityUtils.getSubject().getSession().getAttribute("userInfo");

所以不需要更改签名。这样,您就可以使用Shiros内置实用程序,而不是依赖您自己的逻辑和可能性。

1
2
3
4
5
6
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;

}


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

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

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

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


您总是可以从servlet内的会话中获取用户ID并将其传递给数据层,在数据层中直接使用会话是没有意义的。提取对象并将buck传递到下一层。在数据层中使用特定于HTTP的对象实际上是不好的做法。