Получить управляемый компонент JSF по имени в любом классе, связанном с сервлетом

Я пытаюсь написать собственный сервлет (для AJAX/JSON), в котором я хотел бы ссылаться на свой @ManagedBeans по имени. Я надеюсь сопоставить:

http://host/app/myBean/myProperty

to:

@ManagedBean(name="myBean")
public class MyBean {
    public String getMyProperty();
}

Можно ли загрузить бин по имени из обычного сервлета? Есть ли сервлет JSF или помощник, который я мог бы использовать для этого?

Кажется, я избалован Весной, в которой все это слишком очевидно.


person Konrad Garus    schedule 13.04.2010    source источник
comment
Я не уверен, что вы можете использовать эти новые аннотации вне JSF/EL, но я бы начал со спецификации JSR 299: jcp.org/en/jsr/detail?id=299   -  person McDowell    schedule 14.04.2010
comment
Другие люди, у которых есть похожие проблемы, также могут проверить bpcatalog.dev.java.net/ajax. /jsf-ajax (связанный с AJAX и отображением/обработкой запросов, без получения bean-компонентов по имени)   -  person Konrad Garus    schedule 15.04.2010


Ответы (6)


В артефакте на основе сервлета, таком как @WebServlet, @WebFilter и @WebListener, вы можете получить простой ванильный JSF @ManagedBean @RequestScoped:

Bean bean = (Bean) request.getAttribute("beanName");

и @ManagedBean @SessionScoped автор:

Bean bean = (Bean) request.getSession().getAttribute("beanName");

и @ManagedBean @ApplicationScoped автор:

Bean bean = (Bean) getServletContext().getAttribute("beanName");

Обратите внимание, что для этого необходимо, чтобы компонент уже был автоматически создан JSF заранее. В противном случае они вернут null. Затем вам нужно будет вручную создать bean-компонент и использовать setAttribute("beanName", bean).


Если вы можете использовать CDI @Named вместо поскольку JSF 2.3 устарел @ManagedBean, это еще проще, особенно потому, что вам больше не нужно вручную создавать bean-компоненты:

@Inject
private Bean bean;

Обратите внимание, что это не будет работать, когда вы используете @Named @ViewScoped, потому что bean-компонент можно идентифицировать только по состоянию представления JSF, а это доступно только при вызове FacesServlet. Таким образом, в фильтре, который запускается до этого, доступ к @Injected @ViewScoped всегда будет выдавать ContextNotActiveException.


Только когда вы находитесь внутри @ManagedBean, вы можете использовать @ManagedProperty :

@ManagedProperty("#{bean}")
private Bean bean;

Обратите внимание, что это не работает внутри @Named или @WebServlet или любого другого артефакта. Это действительно работает только внутри @ManagedBean.


Если вы не находитесь внутри @ManagedBean, но FacesContext легко доступна (т.е. FacesContext#getCurrentInstance() не возвращает null), вы также можете использовать Application#evaluateExpressionGet():

FacesContext context = FacesContext.getCurrentInstance();
Bean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", Bean.class);

что может быть удобно следующим образом:

@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
    FacesContext context = FacesContext.getCurrentInstance();
    return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}

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

Bean bean = findBean("bean");

Смотрите также:

person BalusC    schedule 13.04.2010
comment
Ваше второе предложение о том, чтобы просто вводить боб, было настолько удивительно простым, что я полностью его упустил. Как всегда, ваш ответ совершенно по делу. Большое спасибо за вашу работу здесь, на SO. - person jnt30; 27.09.2011
comment
Тем временем (говоря о JSF 2.2) кажется, что метод AssessmentExpressionGet был расширен третьим параметром, который позволяет указать ожидаемый класс, поэтому приведение больше не потребуется. PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class); - person Marc Juchli; 08.10.2014
comment
@Marc: был с самого начала. Я думаю, это был просто остаток от ошибки копипаста. Ответ исправлен. Спасибо за уведомление. - person BalusC; 08.10.2014
comment
FacesContext доступен, несмотря на то, что static служебный метод findBean() определен внутри простого класса Java. Как он доступен там в простом классе Java, который не управляется JSF? - person Tiny; 10.07.2015
comment
@Tiny: он, в свою очередь, вызывается артефактом JSF в том же потоке. - person BalusC; 10.07.2015
comment
Привет, я получаю FacesContext context = FacesContext.getCurrentInstance(); контекст = ноль, почему?? и Попытка использовать запрос HttpServletRequest, подобный этому Bean bean = (Bean) request.getSession().getAttribute(ingresoSistema); Я получил это: Servlet.service() для сервлета servletssimple выдал исключение java.lang.IllegalStateException: невозможно создать сеанс после того, как ответ был зафиксирован. Мой компонент: @ManagedBean(name = ingresoSistema) @SessionScoped - person Fernando Pie; 20.07.2016
comment
@BalusC Я ожидал, что findBean(String beanName) будет доступен в showcase.omnifaces.org/utils/Beans, но это не так. Есть ли для этого какая-либо причина (кроме строгого соблюдения CDI)? - person Jasper de Vries; 24.04.2017
comment
@Jasper: для этого вы можете использовать Faces#evaluateExpressionGet(). - person BalusC; 28.04.2017
comment
@BalusC Хорошо, но вам все равно придется использовать "#{" + beanName + "}", верно? Или я тут ленивый? ;-) - person Jasper de Vries; 18.05.2017

Я использую следующий метод:

public static <T> T getBean(final String beanName, final Class<T> clazz) {
    ELContext elContext = FacesContext.getCurrentInstance().getELContext();
    return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elContext, null, beanName);
}

Это позволяет мне получить возвращаемый объект в типизированном виде.

person John Yeary    schedule 10.12.2012
comment
Это уже покрыто принятым в настоящее время ответом и даже более удобным способом (аргумент Class именно не нужен в этой конструкции). - person BalusC; 10.12.2012

Вы пробовали подход, подобный этой ссылке? Я не уверен, что createValueBinding() все еще доступен, но такой код должен быть доступен из простого старого сервлета. Это требует, чтобы bean уже существовал.

http://www.coderanch.com/t/211706/JSF/java/access-managed-bean-JSF-from

 FacesContext context = FacesContext.getCurrentInstance();  
 Application app = context.getApplication();
 // May be deprecated
 ValueBinding binding = app.createValueBinding("#{" + expr + "}"); 
 Object value = binding.getValue(context);
person James P.    schedule 13.04.2010
comment
Это, вероятно, не будет работать в обычном сервлете. FacesContext — это локальный артефакт потока для каждого запроса, созданный жизненным циклом JSF (обычно FacesServlet). - person McDowell; 14.04.2010
comment
ValueBinding устарел, начиная с JSF 1.2 более 4 лет назад. - person BalusC; 14.04.2010
comment
@BalusC: Это показывает, насколько я в курсе, лол. С другой стороны, использование поисковой системы для исследования методов оказывается контрпродуктивным со всей старой информацией. @McDowell: Это действительно имеет смысл. Я сделаю тест, чтобы посмотреть, что произойдет. - person James P.; 14.04.2010

Вы можете получить управляемый компонент, передав имя:

public static Object getBean(String beanName){
    Object bean = null;
    FacesContext fc = FacesContext.getCurrentInstance();
    if(fc!=null){
         ELContext elContext = fc.getELContext();
         bean = elContext.getELResolver().getValue(elContext, null, beanName);
    }

    return bean;
}
person Soujanya    schedule 29.07.2014
comment
Я пытаюсь сделать это из сервлета, но это не работает. - person Fernando Pie; 22.07.2016

У меня было такое же требование.

Я использовал способ ниже, чтобы получить его.

У меня был сеансовый компонент.

@ManagedBean(name="mb")
@SessionScopedpublic 
class ManagedBean {
     --------
}

Я использовал приведенный ниже код в своем методе сервлета doPost().

ManagedBean mb = (ManagedBean) request.getSession().getAttribute("mb");

это решило мою проблему.

person Anil    schedule 27.06.2016
comment
Какой тип сервлета вы используете? приятель - person Fernando Pie; 22.07.2016
comment
Это HttpServlet. - person Anil; 23.07.2016

Я использую это:

public static <T> T getBean(Class<T> clazz) {
    try {
        String beanName = getBeanName(clazz);
        FacesContext facesContext = FacesContext.getCurrentInstance();
        return facesContext.getApplication().evaluateExpressionGet(facesContext, "#{" + beanName + "}", clazz);
    //return facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(), null, nomeBean);
    } catch (Exception ex) {
        return null;
    }
}

public static <T> String getBeanName(Class<T> clazz) {
    ManagedBean managedBean = clazz.getAnnotation(ManagedBean.class);
    String beanName = managedBean.name();

    if (StringHelper.isNullOrEmpty(beanName)) {
        beanName = clazz.getSimpleName();
        beanName = Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
    }

    return beanName;
}

А затем позвоните:

MyManageBean bean = getBean(MyManageBean.class);

Таким образом, вы можете без проблем реорганизовать свой код и отслеживать использование.

person ChRoNoN    schedule 11.09.2015