14

(我不确定如何在这里准确地表达标题,因此我也不确定如何去寻找答案。)

我有一个处理请求的 Java servlet 引擎。假设我们有一个doGet()请求:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //set up user data

    //do whatever the user requested
    SomeClass c = new SomeClass();
    c.doSomething();
}

现在doSomething(),我希望能够访问提出请求的用户。现在我通过在方法中创建一个 Java 对象并将它传递到我需要的任何地方来做到这一点:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //set up user data
    MyUserObj userObj = new MyUserObj();
    userObj.setId('123');

    //do whatever the user requested
    SomeClass c = new SomeClass(userObj);
    c.doSomething();
}

通过这样做,我可以访问 的实例MyUserObj,并且可以根据需要在应用程序中进一步传递。

我知道在 ASP.NET MVC3 中,我可以通过为当前线程存储项目/属性来实现这一点,如下所示 HttpContext.Current.Items.Add("myId", "123")HttpContext然后在其他函数中可用,而无需显式传递对象。

Java中有没有办法在不将对象作为参数传递的情况下为每个请求设置一些变量(甚至设置MyUserObject稍后访问)?

4

2 回答 2

22

servlet API 中没有,但您可以很容易地制作自己的 API。(一些框架如 spring-mvc、struts 提供了这样的功能)

只需使用 apublic static ThreadLocal来存储和检索对象。您甚至可以将其HttpServletRequest本身存储在 threadlocal 中并使用它的setAttribute()/getAttribute()方法,或者您可以存储一个 threadlocal Map,以与 servlet API 无关。一个重要的注意事项是您应该在请求之后清理线程本地(例如使用过滤器)。

另请注意,将对象作为参数传递被认为是一种更好的做法,因为您通常将其从 Web 层传递到服务层,而服务层不应依赖于与 Web 相关的对象,例如HttpContext.

如果您认为可以将它们存储在线程本地中,而不是传递它们:

public class RequestContext {
    private static ThreadLocal<Map<Object, Object>> attributes = new ThreadLocal<>();
    public static void initialize() {
        attributes.set(new HashMap<Map<Object, Object>>());
    }
    public static void cleanup() {
        attributes.set(null);
    }
    public static <T> T getAttribute(Object key) {
        return (T) attributes.get().get(key);
    }
    public static void setAttribute(Object key, Object value) {
        attributes.get().put(key, value);
    }
}

还有一个必要的过滤器:

@WebFilter(urlPatterns="/")
public class RequestContextFilter implements Filter {
     public void doFilter(..) {
         RequestContext.initialize();
         try {
             chain.doFilter(request, response);
         } finally {
             RequestContext.cleanup();
         }
     }
}
于 2012-04-17T18:43:10.357 回答
5

您可以使用 将对象附加到当前请求setAttribute。此 API 主要用于内部路由,但也可以安全地用于您自己的目的,只要您为属性名称使用适当的命名空间。

于 2012-04-17T18:50:39.507 回答