Внедрить объект в компонент с областью просмотра

#java #cdi #jboss-weld

#java #cdi #jboss-weld

Вопрос:

Я новичок в CDI и хочу использовать это для приложения JSF2. Класс MyUser является простым @Entity компонентом, и объект создается в @PostConstruct методе в bean:

 @Stateful
@Named @javax.faces.bean.SessionScoped
public class UserBean implements Serializable
{
    @Named
    private MyUser user;

    //setter and getter
    //@PostConstruct
}
  

Доступ к пользователю на страницах JSF работает как по волшебству: #{user.lastName} . Но теперь я хочу получить доступ к этому объекту из других компонентов, например, в этом @ViewScopedBean :

 @Named @javax.faces.bean.ViewScoped
public class TestBean implements Serializable
{       
    @Inject private MyUser user;
}
  

Я хочу, чтобы текущий (зарегистрированный) MyUser user был доступен в паре других компонентов, но я не уверен, как это сделать. Просто @Inject отредактировать это не сработало (и я почти уверен, что это было бы немного просто).

 13:56:22,371 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController]
Error installing to Start: name=vfs:///Applications/Development/
jboss-6.0.0.Final/server/default/deploy/test.ear_WeldBootstrapBean state=Create:
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied
dependencies for type [MyUser] with qualifiers [@Default] at injection
point [[field] @Inject private test.controller.mbean.TestBean.user]
  

Каков наилучший подход для доступа к user из других компонентов? Код в стиле JSF1.2, подобный UserBean bean = (UserBean)FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("UserBean"); , кажется, кажется старомодным!

Ответ №1:

Прежде всего: Вы не хотите напрямую внедрять объекты. Объекты довольно независимо управляются ORM-фреймворком и имеют свой собственный жизненный цикл. Не используйте их как управляемые компоненты.

Согласно этому определению, объекты JPA являются технически управляемыми bean-компонентами. Однако объекты имеют свой собственный особый жизненный цикл, состояние и модель идентификации и обычно создаются с помощью JPA или с использованием new. Поэтому мы не рекомендуем напрямую вводить класс entity. Мы особенно не рекомендуем назначать классу объектов область, отличную от @Dependent, поскольку JPA не может сохранять введенные прокси CDI.

Подробности смотрите здесь.

Чтобы ответить на ваш вопрос: вы не можете «извлечь» что-то вроде (аутентифицированного) пользователя, даже если это было возможно в Seam 2, весь механизм прокси CDI больше этого не допускает. Что вам нужно сделать, так это следующее:

  • Напишите управляемый компонент, который обрабатывает аутентификацию, и поместите его в правильную область (возможно, область сеанса).
  • Если вход в систему выполнен успешно, используйте атрибут этого компонента для сохранения аутентифицированного пользователя.
  • Используйте метод производителя (возможно, с таким определителем, как @LoggedIn ), чтобы сделать пользователя доступным в вашем приложении

Внедрить пользователя следующим образом:

 @Inject
@LoggedIn
private User user
  

Это способ CDI 😉

Комментарии:

1. Спасибо за этот ответ, помогающий мне понять CDI. С помощью предоставленных вами ключей я также нашел это oracle.com/technetwork/articles/javaee /… и это работает как в вашем примере. Единственное, что мне интересно, это @LoggedIn аннотация. Это не может быть разрешено здесь! @Poduces разрешается в javax.enterprise.inject.Produces .

2. @LoggedIn — это квалификатор — ваша собственная аннотация :-). Вот как работает защита типов в CDI: всякий раз, когда существует более одного компонента определенного типа (скажем, User), вам нужно сообщить контейнеру, какого пользователя вы хотите внедрить — и это достигается с помощью квалификаторов. Смотрите здесь для получения более подробной информации: docs.jboss.org/weld/reference/latest/en-US/html /…

Ответ №2:

Является ли компонент @Inject ed также компонентом @Named?

Если это так, имеет ли компонент MyUser меньшую область видимости, чем testBean. Помните, что управляемыми свойствами компонента @ViewScoped bean должны быть @ViewScoped, @SessionScoped или @ApplicationScoped

Комментарии:

1. Да, смотрите код. Оба компонента являются @Named . Я хочу получить доступ к свойству @SessionScoped компонента из @ViewScoped компонента.

2. Вы правы с чистым JSF, вы должны позаботиться об этом вопросе. Если вы используете CDI и, например, MyFaces CODI, вам больше не нужно заботиться об этом.

Ответ №3:

CDI не определяет @ViewScoped аннотацию. Это аннотация JSF2. Единственными разрешенными аннотациями являются: @RequestScoped , @SessionScoped , @ApplicationScoped @Dependent и @ConversationScoped . Первые три являются единственными областями JSF, разрешенными CDI.

Если вам нужно поддерживать @ViewScope аннотацию, вам нужно будет написать ее самостоятельно. К счастью, кто-то другой делал это раньше.

Комментарии:

1. Обе области импортируются из пакета javax.faces.bean (приведенный выше код обновлен) К счастью, модуль SeamFaces доступен, и я попытаюсь его использовать. Мне все еще интересно, разрешен ли в этом случае подход к @Inject свойству в другом компоненте.

2. Ну, по крайней мере, доступны seam-faces, потому что у меня есть зависимость maven для этого…

3. Как MyFaces CODI, так и SeamFaces преобразуют аннотацию ViewScoped в область CDI. Позаботьтесь о том, какой из них вы используете прямо сейчас, потому что конвертер SeamFaces поврежден с помощью Weld ( issues.jboss.org/browse/SEAMFACES-44 )