我正在使用java webapp,我需要根据用户登录ID访问数据库中的记录。我在成功登录后在会话变量中设置登录详细信息。
我想做的就像这样
从proj_recs中选择*,其中user_id = user_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;
}
问题是我必须用userid修改我的所有方法。有没有办法可以将用户详细信息设置为某个静态类,并在不修改方法签名的情况下访问应用程序中我想要的详细信息?但我相信静态类在不同的用户请求之间共享。
答案 0 :(得分:2)
您正在寻找的解决方案是Thread Local(google it)。它允许您使用静态方法访问特定于线程的数据。
您可以开始阅读http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/。使用那里的示例,您需要创建:
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();
}
请注意,您不需要更改数据层的方法签名。
线程本地起初有点令人困惑,但是一旦你阅读这篇文章,你就会很快熟悉。
答案 1 :(得分:1)
我想你可以轻松使用
SecurityUtils.getSubject().getSession().getAttribute("userInfo");
因此无需更改签名。这样您就可以使用shiros内置实用程序,而不是依赖于您自己的逻辑和概率。</ p>
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;
}
答案 2 :(得分:0)
您始终可以从servlet中的会话中获取用户ID并将其传递给数据层,在数据层中直接使用会话是没有意义的。您提取对象并将降压传递到下一层。在数据层中使用HTTP特定对象实际上是不好的做法。
答案 3 :(得分:0)
通过严格分离关注点,数据层应该与会话或请求无关。但是您需要服务或数据层中的用户名(示例中为user_id
)。最简单的是有效地在控制器中收集它(控制器可以访问请求和会话),将其传递给服务层,并将其转发到数据层。
另一种选择(由Spring Security或Apache Shiro等安全框架使用)是在请求处理开始时将其存储在线程存储中,并在结束时(在过滤器中)仔细清理它。然后,实用程序类的静态方法可以将其提供给应用程序的任何部分。但是每次使用实用程序类时,都会获得对框架的依赖。 为了减少不必要的依赖,你可以拥有自己的Holder类,使用一个静态方法来调用框架之一:依赖只限于holder类。
如果使用Spring,还有第三种解决方案。您可以使用具有aop代理的会话范围bean,您可以在任何需要访问您的变量的bean中注入。感谢aop代理,您可以访问当前会话中的数据,甚至可以访问单个bean。
在我自己的应用程序中,我在简单情况下使用第一种方法(少数类)和第三种方法,当我想避免在许多方法中重复使用相同的参数时。