Получение контекста сервлета, сеанса и запроса в POJO вне контейнера

Есть ли способ получить сессию из POJO? Или, в конечном итоге, получить боб из POJO.

Чтобы уточнить:

По сути, я создаю bean-компонент из сервлета, и мне нужно получить доступ к свойствам этого bean-компонента снаружи веб-контейнера (из POJO). Я не могу передать просьбу в Pojo; и запрос необходим для получения сеанса.

В частности, у меня есть веб-приложение, которое использует инфраструктуру Cactus для запуска тестов JUnit из веб-интерфейса. Однако сервлет, который вызывает тестер JUnit, скомпилирован в jar; Я добавил дополнительные выпадающие меню для изменения настроек, из которых будет считываться тест JUnit, для переключения между различными средами (кластерами WLI), поэтому, учитывая, что сервлет бегуна уже скомпилирован, я не могу изменить его для обработки дополнительных параметров из нескольких сред. Я попробовал постоянный подход записи в файл.dat, из которого тест JUnit будет читать с помощью класса Reader; также я попробовал бобовый подход, который в конечном итоге не был доступен из теста JUnit.

4 ответа

Решение

Только и только если ваш POJO работает в том же потоке, что и HttpServletRequest работает, то вы сможете достичь этого с помощью ThreadLocal<T>,

Создайте следующий класс:

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).    
}

Воплощать в жизнь javax.servlet.Filter что делает следующее в doFilter() метод и отображается на url-pattern представляющих интерес, например /* или на 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);
    }
}

Обратите внимание на важность оператора try-with-resources. Это гарантирует, что YourContext#close() будет вызван после того, как фильтр выполнил свою работу и ThreadLocal ресурс будет очищен. В противном случае поток все равно будет содержать его при повторном использовании для другого HTTP-запроса.

А вот как вы можете использовать его в POJO:

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

Это все в основном также, как Context объекты среднего MVC работает, как JSF FacesContext и тот, что в калитке.

Сказал, что вы смотрели на CDI? Возможно, проще сделать артефакты управляемыми CDI, так что вы можете просто @Inject их друг в друге.

Да, есть.

Если вы используете веб-фреймворк, например, Wicket, часто есть способ получить текущий HttpSession. Оттуда вы можете получить Spring ApplicationContext и, если у вас есть, вы можете получить Spring Beans из него. Это работает в любом месте, так как мы используем только статические служебные методы.

Пример кода:

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");

Однако обратите внимание, что Spring Filter и Wicket Filter должны быть на месте и обрабатывать текущий запрос, иначе утилиты не будут работать.

Если вы не имеете в виду Spring Beans, то вам придется хранить их в HTTP-сессии самостоятельно. Если у вас нет веб-фреймворка, вы можете сделать то, что предлагает rfeak, и реализовать свой собственный ThreadLocal.

Pojo - это простой старый Java-объект. POJOS не имеет ничего общего с сессиями.

Сеанс https доступен для объекта запроса.

Проверьте это

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

в частности, интерфейс HttpServletRequest и метод getSession().

Для "бобовой" части вашего вопроса. Боб - это Java-класс, соответствующий 3 стандартам.

  1. Нет аргумент конструктор
  2. сеттеры и геттеры для доступа к приватным полям
  3. Реализует сериализуемость.

POJO - это боб, если он следует этим правилам.

Предполагая, что вы имеете в виду программирование сервлетов....

Нет прямого способа добраться из POJO на сессию. Вам необходимо получить сеанс из объекта HttpServletRequest.

Есть 2 популярных решения, которые я видел для решения этой проблемы.

Первый вариант - создать некоторый объект контекста, который содержит Session. Этот контекст затем передается на ваш бизнес-уровень, чтобы ваши POJO могли получить эту информацию, если она им нужна.

Второй вариант - использовать хранилище ThreadLocal. Часто сеанс помещается в хранилище ThreadLocal с помощью фильтра или перехватчика. Тогда любой объект в вашей системе может получить его из потока. Этот шаблон обнаруживается во многих веб-фреймворках, таких как Spring и Struts.

Другие вопросы по тегам