Сервлет Java и JSP обращаются к одному и тому же сеансовому компоненту

Допустим, у меня есть простой сервлет входа в систему, который проверяет переданный name и создает объект User и сохраняет его в сеансе.

User user = new User();
user.setId(name);

request.getSession().setAttribute("user", user);
response.sendRedirect("index.jsp");

На странице index.jsp я получаю доступ к объекту пользователя через jsp:useBean

<jsp:useBean id="user" scope="session"
             class="package.name.User"/>

<div class="panel">
    Welcome ${user.id}
</div>

Это работает до сих пор.

Из документации jsp beans

Чтобы найти или создать экземпляр Bean, выполните следующие шаги в указанном порядке:

  1. Пытается найти Bean с указанной вами областью действия и именем.
  2. Определяет переменную ссылки на объект с указанным вами именем.
  3. Если он находит Bean, сохраняет ссылку на него в переменной. Если вы указали тип, присваивает Бину этот тип.
  4. Если он не находит Bean, создает его экземпляр из указанного вами класса, сохраняя ссылку на него в новой переменной. Если имя класса представляет собой сериализованный шаблон, экземпляр Bean создается с помощью java.beans.Beans.instantiate.
  5. Если был создан (а не обнаружен) объект Bean, и если он имеет теги или элементы body (между и ), выполняет теги body.

Вопросы:

Попытки найти Bean с указанной вами областью действия и именем

Он не определяет процесс «найти». Означает ли это, что он проверит HttpServletRequest.getSession() или просто проверит, создали ли другие страницы этот компонент или нет?

Если он не находит Bean, создает его экземпляр из указанного вами класса, сохраняя ссылку > на него в новой переменной.

На самом деле это означает, что Jsp может связать вновь созданный компонент с сеансом, используя jsp_internal_name_user. Нет ни слова о том, как Jsp хранит и находит bean-компоненты в сеансе.

Существует возможность доступа к объектам сеанса с помощью ${sessionScope.user}, что гарантирует получение «пользователя» из объекта сеанса Java. Тот самый, который я поставил сам.

Пример Java EE 5 "Книжный магазин" доступ к объектам сеанса с использованием подхода ${sessionScope.name}.

Использование только ${user} работает. И вот что меня беспокоит. Я хотел бы увидеть в спецификации конкретное предложение о процессе locate и о том, должен ли работать ${user} или это зависит от эталонной реализации JSP и/или JSTL.


person Mykola Golubyev    schedule 18.04.2010    source источник


Ответы (3)


В случае контроллера (сервлета), который заботится о модели, jsp:useBean полезен только в том случае, если экземпляр по умолчанию (созданный с помощью конструктора без аргументов) предоставляет поведение/состояние, отличное от несуществующего экземпляра. Например. если вы хотите иметь имя пользователя по умолчанию «Неизвестный пользователь», вы должны сделать:

public User {
    this.id = "Unknown User";
}

В противном случае конечный пользователь может увидеть «Добро пожаловать» вместо «Добро пожаловать, неизвестный пользователь». В вашем конкретном случае вы можете смело удалить его. Это лишнее.

Однако я также видел аргумент, что это полезно для чистой документации. Вы можете объявить «бесполезные» экземпляры jsp:useBean в верхней части страницы JSP, чтобы у вас был обзор, какие именно модели использовались на конкретной странице JSP. Хотя я нахожу это довольно умным, у меня самого никогда не было необходимости в таком способе документирования модели в JSP. Согласно комментариям, еще один аргумент заключается в том, что таким образом IDE, такие как IDEA и Eclipse, могут автоматически заполнять свойства bean-компонентов в EL.

Обновление: для определения местоположения используется PageContext#findAttribute() для этого, а затем использует рефлексию/самоанализ javabean для вызова на нем методов получения. Например.

${user.name}

примерно решает

out.print(pageContext.findAttribute("user").getName())

См. также спецификацию JSP и спецификация JSP EL.

Обновление 2: <jsp:useBean> конечно не использует внутреннее имя или около того в качестве префикса атрибута сеанса. Прокрутите все атрибуты сеанса самостоятельно, чтобы увидеть фактические ключи и значения:

<c:forEach items="${sessionScope}" var="entry">
    ${entry.key} = ${entry.value}<br>
</c:forEach>

или в сервлете

for (String name : Collections.list(session.getAttributeNames())) {
   System.out.println(name + " = " + session.getAttribute(name));
}
person BalusC    schedule 18.04.2010
comment
Есть ли какая-то документация, которая явно описывает процесс разрешения переменных на странице jsp? - person Mykola Golubyev; 18.04.2010
comment
Intellij IDEA дополняет поля переменных только в случае явного объявления. - person Mykola Golubyev; 18.04.2010
comment
1) Ты про ЭЛ? Ознакомьтесь с спецификацией JSP EL. В двух словах, он выполняет PageContext#findAttribute() поиск атрибутов в любой области. 2) Это действительно еще один аргумент, который я видел раньше. - person BalusC; 18.04.2010
comment
Спасибо, что указали на вещи. Я имел в виду спецификацию JSP и не нашел там ничего полезного. Глядя в EL Spec. - person Mykola Golubyev; 18.04.2010
comment
Не могли бы вы указать раздел, в котором вы нашли примерное решение для...? - person Mykola Golubyev; 18.04.2010
comment
Ну, это в ячейке мозга # 1875129. Нет, извините, я больше говорю из › 7-летнего опыта JSP / Servlet и знаю, как это работает под капотом. Приведенный выше пример наиболее логичен для тех, кто не знает JSP/EL. Спецификация EL немного более абстрактна. ELResolver и так далее. Но простой способ (который делают практически все разработчики EL — Sun, Apache, JBoss и т. д.) — начать с PageContext#findAttribute(), чтобы найти атрибут по имени в любой из областей, а затем перейти к разрешению с использованием отражения/самоанализа/ и Т. Д. - person BalusC; 18.04.2010
comment
Итак, использование сессионного компонента в примере моего вопроса допустимо? - person Mykola Golubyev; 19.04.2010
comment
Это функционально и технически правильно, да. Но технически это лишнее. - person BalusC; 19.04.2010
comment
Извините, я все еще задаю вопросы. Но только что заметил, что даже пример BookStore EE5 использует sessionScope.cart вместо корзины. - person Mykola Golubyev; 21.04.2010
comment
Проверьте java.sun.com/javaee/5/docs /tutorial/doc/bnahq.html#bnahw. Что касается примера с книжным магазином, то это просто явная ссылка, гарантирующая, что он не вернет случайный экземпляр cart на странице или в области запроса (которые сканируются до области сеанса). ). Это просто практика, но не обязательно. - person BalusC; 22.04.2010
comment
Я случайно снова поставил плюс на ответ, и это стало действием удаления оценки. Я редактирую ваш ответ, чтобы иметь возможность вернуть баллы. Пожалуйста, отмените мои изменения. Большое спасибо за указание на текст. Я искал в спецификациях, и это было только на странице учебника. - person Mykola Golubyev; 22.04.2010

Цитирование спецификации JSP JSP.5.1

Базовая семантика пытается найти существующий объект, используя идентификатор и область действия. Если объект не найден, он попытается создать объект, используя другие атрибуты.

Другими словами,

<jsp:useBean id="user" scope="session" class="package.name.User"/>

будет примерно переведено в java как:

package.name.User user = (package.name.User)session.getAttribute("user");
if (user == null){
  user = new package.name.User();
  session.setAttribute("user", user);
}
person evnafets    schedule 19.04.2010
comment
Эй, рад видеть вас здесь :) Ваш ответ действительно правильный для конкретной строки jsp:usebean, вы только забыли session.setAttribute("user", user); в блоке if ;) - person BalusC; 20.04.2010
comment
Я хотел бы увидеть описание поиска существующего процесса. На самом деле jsp может хранить объект, используя имя user_jsp_internal. - person Mykola Golubyev; 20.04.2010
comment
Нет, это не так. Объект сохраняется с ключом атрибута, указанным в id. Как еще вы могли бы получить к нему доступ в простом EL с помощью ${user} и так далее? - person BalusC; 20.04.2010
comment
Из-за текущей реализации. Почему тогда у нас есть явное выражение ${scopeSession.user}, доступное для использования. Укажите, где вы обнаружили, что он будет хранить его в сеансе с помощью идентификатора? Я думаю, что ребята из реализации JSR могут решить сами. - person Mykola Golubyev; 21.04.2010
comment
См. JSP.5.1. Там все черно-белое. - person evnafets; 22.04.2010

Из документации:

Элемент <jsp:useBean> находит или создает экземпляр компонента JavaBeans. <jsp:useBean> сначала пытается найти экземпляр Bean. Если Бин не существует, <jsp:useBean> создает его экземпляр из класса или сериализованного шаблона.

Поскольку «обнаружение» bean-компонента совершенно нормально, мы можем предположить, что bean-компонент может быть сделан доступным с помощью средств, отличных от создания экземпляра через <jsp:useBean>. Например, создав его в сервлете.

person lexicore    schedule 18.04.2010