Получение контекста сервлета, сеанса и запроса в 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 стандартам.
- Нет аргумент конструктор
- сеттеры и геттеры для доступа к приватным полям
- Реализует сериализуемость.
POJO - это боб, если он следует этим правилам.
Предполагая, что вы имеете в виду программирование сервлетов....
Нет прямого способа добраться из POJO на сессию. Вам необходимо получить сеанс из объекта HttpServletRequest.
Есть 2 популярных решения, которые я видел для решения этой проблемы.
Первый вариант - создать некоторый объект контекста, который содержит Session. Этот контекст затем передается на ваш бизнес-уровень, чтобы ваши POJO могли получить эту информацию, если она им нужна.
Второй вариант - использовать хранилище ThreadLocal. Часто сеанс помещается в хранилище ThreadLocal с помощью фильтра или перехватчика. Тогда любой объект в вашей системе может получить его из потока. Этот шаблон обнаруживается во многих веб-фреймворках, таких как Spring и Struts.