Как разделить объект между компонентами поддержки JSF?

Я хотел бы разбить свое приложение JSF 2.1 / Java EE на модули. У меня есть страница, состоящая из нескольких модулей. Каждый модуль должен использовать отдельный компонент поддержки JSF. Некоторым из этих модулей необходимо отображать и изменять некоторые данные из / в одном и том же объекте.

Я уже пробовал некоторые подходы, но пока не удовлетворен. Я спрашиваю себя, как лучше всего это сделать?

Все модули используют одну и ту же сущность, и им (возможно) необходимо уведомить другие компоненты поддержки, если некоторые данные изменились.

Комментарии к некоторым подходам, которые я уже пробовал:

  • Передача объекта моему компоненту (XHTML) через интерфейс не передаст его и в компонент поддержки.
  • Загрузка объекта в методе bean-компонента postContruct путем чтения идентификатора из параметров запроса обычно не рекомендуется в пользу использования подхода "viewParam".
  • Использование "viewParam", IMHO, не так хорошо, как наличие сущности после создания bean-компонента (в моем postConstruct). Я не уверен, когда вызывается установщик bean-компонентов.

person Christopher Cudennec    schedule 09.12.2013    source источник
comment
Почему бы просто не сохранить объект сущности в сеансе и не использовать его во всех bean-компонентах.   -  person Adarsh    schedule 09.12.2013
comment
Я не хочу раздувать сеанс. Я ищу решение, которое лучше вписывается в структуру JSF. Сохранение чего-либо в сеансе звучит как обходной путь.   -  person Christopher Cudennec    schedule 09.12.2013
comment
Определенно вам нужен _1 _ / _ 2_ управляемый компонент. О том, что бобы уведомляются, нужно уточнить.   -  person Xtreme Biker    schedule 09.12.2013
comment
Почему? RequestScope и ViewScope кажутся более чем достаточными для моих нужд. Я хочу добиться, чтобы все bean-компоненты работали с одним и тем же экземпляром сущности, хотя один bean-компонент может изменять некоторые его части в действии.   -  person Christopher Cudennec    schedule 09.12.2013


Ответы (2)


Несмотря на то, что это «обычно не рекомендуется» (кем?), Я использую один из следующих приемов в моих компонентах поддержки JSF-2.2 (в зависимости от того, нужен ли мне personId для чего-то еще):

@ViewScoped
public class BeanConverter {
    @Inject @Param(name = "personId")
    private ParamValue<Person> curPerson;
}

@ViewScoped
public class BeanConstruct {
    @PersistenceContext
    private EntityManager em;

    @Inject @Param
    private ParamValue<Long> personId;

    private Person curPerson;

    @PostConstruct
    public void init() {
        curPerson = em.find(Person.class, personId.getValue());
    }
}

При этом используется отличная поддержка CDI Omnifaces. Затем я использую merge() для обновления сущности, но в моем случае только один компонент может сохранять изменения в сущности, поэтому YMMV. Когда bean-компоненты должны сообщать друг другу обновления или создание сущностей, я обычно использую javax.enterprise.Events, где событие получает сущность в качестве аргумента конструктора:

public class BeanSending {
    @Inject
    private Event<PersonCreated> personCreatedEvent;

    public void constructPerson() {
        Person person = makePerson();
        personCreatedEvent.fire(new PersonCreated(person));
    }
}

public class BeanUpdater {
    public void updatePerson(@Observes PersonCreated evt) {
        doStuffWithPerson(evt.getPerson());
    }
}
person mabi    schedule 09.12.2013
comment
Я использовал не рекомендуется для чтения параметров запроса непосредственно из FacesContext. Это не относится к вашему решению, в котором свойство вводится с помощью @Param. - person Christopher Cudennec; 09.12.2013
comment
@ChristopherCudennec да, но @Param просто (очень откровенный) сахар сверху. Принцип состоит в том, что все bean-компоненты согласовывают набор имен параметров, чтобы они могли получить для работы одну и ту же сущность. - person mabi; 09.12.2013
comment
Отлично. Мне нравится, что значение вводится в bean-компонент. С другой стороны, bean-компонент знает имя параметра. - person Christopher Cudennec; 09.12.2013
comment
@ChristopherCudennec да, это обратная сторона. Но преобразование имени в значение произошло где-то. Если вы хотите оставаться действительно СУХИМ, вы, вероятно, можете собрать все эти строки имен параметров в enum. - person mabi; 09.12.2013

Я думаю, что вам нужен CDI - Внедрение контекста и зависимостей. Просто разделите свою страницу на несколько более мелких компонентов CDI и вставьте их друг в друга по мере необходимости.

person Mr.J4mes    schedule 09.12.2013
comment
Мой вопрос не интересует меня в управлении страницей. Все мои вспомогательные компоненты уже являются компонентами CDI, которые можно вводить. Я заинтересован в том, чтобы поделиться сущностью. Допустим, сущность - это покупатель, которого я получил из своей базы данных. - person Christopher Cudennec; 09.12.2013
comment
@ChristopherCudennec: если вы уже используете компоненты CDI, просто введите клиента в один компонент X, а затем введите этот компонент X в другие компоненты, чтобы совместно использовать одного и того же клиента. - person Mr.J4mes; 09.12.2013
comment
Я это уже пробовал. Я бы предпочел, чтобы бины были автономными, т.е. они не должны были знать друг друга. - person Christopher Cudennec; 09.12.2013
comment
@ChristopherCudennec: Кажется, вы пытаетесь разбить свое приложение на как можно больше небольших независимых bean-компонентов, а затем смешивать bean-компоненты в разных комбинациях для разных целей / страниц. Тем не менее, внедрение должно помочь bean-компонентам совместно использовать свои ресурсы самодокументированным образом. Если вы не хотите, чтобы они знали друг друга, вы должны использовать посредника, например атрибут HttpSession, для хранения общего клиента. Это будет некрасиво и грязно :) - person Mr.J4mes; 09.12.2013