简体   繁体   English

在容器外的 POJO 中检索 servlet 上下文、会话和请求

[英]Retrieving servlet context, session and request in a POJO outside container

Is there any way to retrieve a session from a POJO?有没有办法从 POJO 中检索会话? Or ultimately to retrieve a bean from a POJO.或者最终从 POJO 中检索 bean。

To clarify:澄清:

Basically I am creating a bean from a servlet and I need to access the properties of that bean from outside of the web container (from a POJO).基本上,我正在从 servlet 创建一个 bean,我需要从 Web 容器外部(从 POJO)访问该 bean 的属性。 I cannot pass the request to the pojo;我无法将请求传递给 pojo; and the request is needed to retrieve the session.并且需要请求来检索会话。

More specifically I have a web application that uses the Cactus framework to run JUnit tests from a web interface.更具体地说,我有一个 Web 应用程序,它使用 Cactus 框架从 Web 界面运行 JUnit 测试。 However the servlet that invokes the JUnit test runner is compiled in a jar;但是,调用 JUnit 测试运行程序的 servlet 是在 jar 中编译的; I added extra drop down menus to change settings from which the JUnit test will read from to switch between different environments (WLI clusters), so given that the runner servlet is already compiled I cannot modify it to handle the extra parameters from the multiple environments.我添加了额外的下拉菜单来更改 JUnit 测试将从中读取以在不同环境(WLI 集群)之间切换的设置,因此鉴于 runner servlet 已经编译,我无法修改它以处理来自多个环境的额外参数。 I have tried the persistence approach of writing to a .dat file fro which the JUnit test will read from by way of a Reader class;我尝试了写入 .dat 文件的持久性方法,JUnit 测试将通过 Reader 类从中读取; also I have have tried the bean approach which ultimately was not accessible from the JUnit test.我也尝试过最终无法从 JUnit 测试访问的 bean 方法。

Only and only if your POJO is running in the same thread as the HttpServletRequest is running in, then you'll be able to achieve this with help of ThreadLocal<T> .仅当您的 POJO 与HttpServletRequest同一线程中运行时,您才能在ThreadLocal<T>帮助下实现这一点。

Create the following class:创建以下类:

public final class YourContext implements AutoCloseable {

    private static ThreadLocal<YourContext> instance = new ThreadLocal<>();

    private HttpServletRequest request;
    private HttpServletResponse response;

    private YourContext(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    public static YourContext create(HttpServletRequest request, HttpServletResponse response) {
        YourContext context = new YourContext(request, response);
        instance.set(context);
        return context;
    }

    public static YourContext getCurrentInstance() {
        return instance.get();
    }

    @Override    
    public void close() {
        instance.remove();
    }

    public HttpServletRequest getRequest() {
        return request;
    }

    public HttpSession getSession() {
        return request.getSession();
    }

    public ServletContext getServletContext() {
        return request.getServletContext();
    }

    // ... (add if necessary more methods here which return/delegate the request/response).    
}

Implement javax.servlet.Filter which does the following in doFilter() method and is mapped on an url-pattern of interest, eg /* or on the servlet-name of your front controller servlet.实现javax.servlet.Filter ,它在doFilter()方法中doFilter()以下操作,并映射到感兴趣的url-pattern ,例如/*或前端控制器 servlet 的servlet-name

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    try (YourContext context = YourContext.create(request, response)) {
        chain.doFilter(request, response);
    }
}

Note the importance of try-with-resources statement.请注意 try-with-resources 语句的重要性。 It guarantees that the YourContext#close() will be called after the filter has done its job and the ThreadLocal resource will be cleared.它保证在过滤器完成其工作后将调用YourContext#close()并且ThreadLocal资源将被清除。 Otherwise the thread will still contain it when recycled for another HTTP request.否则线程在为另一个 HTTP 请求回收时仍将包含它。

And here's how you could use it in the POJO:以下是在 POJO 中使用它的方法:

YourContext context = YourContext.getCurrentInstance();
HttpSession session = context.getSession();

This all is basically also how the Context objects of the average MVC framework works, like JSF's FacesContext and the one in Wicket.这一切基本上也是普通 MVC 框架的Context对象的工作方式,例如 JSF 的FacesContext和 Wicket 中的那个。

Said that, have you looked at CDI ?说了这么多,你看过CDI吗? Perhaps it's easier to make the artifacts CDI-managed so you can just @Inject them in each other.也许让工件由 CDI 管理更容易,这样您就可以在彼此中@Inject了。

Yes, there is.就在这里。

If you're using a web framework, for example Wicket, there is often a way to get the current HttpSession.如果您使用的是 Web 框架,例如 Wicket,通常有一种方法可以获取当前的 HttpSession。 From there, you can get the Spring ApplicationContext and if you have that, you can get Spring Beans from it.从那里,您可以获取 Spring ApplicationContext,如果有,您可以从中获取 Spring Bean。 This works in any location, as we're using static utility methods only.这适用于任何位置,因为我们仅使用静态实用程序方法。

Example code:示例代码:

import org.apache.wicket.protocol.http.WebApplication;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.WebApplicationContext;

ServletContext sc = WebApplication.getServletContext();
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(sc);

Object bean = wac.getBean("myBeanId");

Note however that the Spring Filter and the Wicket Filter must be in place and handle the current request, otherwise the utility methods won't work.但是请注意,Spring 过滤器和 Wicket 过滤器必须就位并处理当前请求,否则实用程序方法将无法工作。

If you didn't mean Spring Beans, than you would have to store them in the HTTP Session yourself.如果您不是指 Spring Beans,那么您必须自己将它们存储在 HTTP 会话中。 If you do not have a web framework, you may want to do what rfeak is suggesting and implement your own ThreadLocal.如果您没有 Web 框架,您可能想要按照rfeak的建议执行并实现您自己的 ThreadLocal。

A Pojo is a Plain Old Java Object. Pojo 是一个普通的旧 Java 对象。 POJOS have nothing to do with sessions. POJOS 与会话无关。

The https session is available on the request object. https 会话在请求对象上可用。

Check out this看看这个

http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/api/index.html http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/api/index.html

specifically the HttpServletRequest interface, and the getSession() method.特别是 HttpServletRequest 接口和 getSession() 方法。

For the 'bean' part of your question.对于您问题的“豆”部分。 A bean is a java class that conforms to 3 standards. bean 是符合 3 个标准的 Java 类。

  1. No arg constructor没有 arg 构造函数
  2. setters and getters to access private fields访问私有字段的 setter 和 getter
  3. Implements serializable.实现可序列化。

A POJO is a bean if it follows those conventions.如果 POJO 遵循这些约定,那么它就是一个 bean。

Assuming that you are referring to Servlet programming ....假设您指的是 Servlet 编程....

There's no direct way to get from a POJO to the Session.没有从 POJO 到 Session 的直接方法。 You need to get the Session from the HttpServletRequest object.您需要从 HttpServletRequest 对象中获取 Session。

There are 2 popular solutions that I've seen for dealing with this.我见过两种流行的解决方案来处理这个问题。

First option is to create a context object of some sort that contains the Session.第一个选项是创建某种包含会话的上下文对象。 This context is then passed along down into your business layer so that your POJOs can get this information if they need it.然后将此上下文向下传递到您的业务层,以便您的 POJO 可以在需要时获取此信息。

Second option is to leverage ThreadLocal storage.第二种选择是利用 ThreadLocal 存储。 Often the session is placed on ThreadLocal storage by a filter or interceptor.通常会话由过滤器或拦截器放置在 ThreadLocal 存储上。 Then any object in your system can fetch it from the thread.然后系统中的任何对象都可以从线程中获取它。 This pattern shows up in a lot of the web frameworks like Spring and Struts.这种模式出现在很多 web 框架中,比如 Spring 和 Struts。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM