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

101

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

http://host/app/myBean/myProperty

кому:

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

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

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

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

Ответы:

263

В артефакте на основе сервлета, таком как @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потому что компонент может быть идентифицирован только по состоянию представления 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");

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

BalusC
источник
9
Ваше второе предложение о том, чтобы просто ввести фасоль, было настолько удивительно простым, что я полностью упустил его из виду. Как всегда, ваш ответ абсолютно точен. Большое спасибо за вашу работу над SO.
jnt30
2
Между тем (если говорить о JSF 2.2) кажется, что метод AssessmentExpressionGet был расширен третьим параметром, который позволяет указать ожидаемый класс, поэтому приведение типов больше не потребуется. PostBean bean = context.getApplication().evaluateExpressionGet(context, "#{beanName}", PostBean.class);
Марк Джучли 08
1
@Marc: Был там с самого начала. Думаю, это был всего лишь остаток ошибки с копировальной пастой. Ответ исправлен. Спасибо, что сообщили.
BalusC 08
FacesContextдоступен, даже если staticслужебный метод findBean()определен внутри простого класса Java. Как он доступен в простом классе Java, который не управляется JSF?
Tiny
1
@Tiny: он, в свою очередь, вызывается артефактом JSF в том же потоке.
BalusC
11

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

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);
}

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

Джон Гайри
источник
3
Это уже покрыто принятым в настоящее время ответом и даже более удобным способом ( Classаргумент в этой конструкции не нужен).
BalusC
3

Вы пробовали подход, подобный этой ссылке? Я не уверен, что 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);
Джеймс П.
источник
Вероятно, это не сработает в обычном сервлете. FacesContext - это локальный артефакт потока для каждого запроса, настраиваемый жизненным циклом JSF (обычно FacesServlet).
McDowell
7
ValueBinding устарел с JSF 1.2 более 4 лет назад.
BalusC
@BalusC: Это показывает, насколько я в курсе, лол. Кстати, использование поисковой системы для исследования методов оказывается контрпродуктивным, учитывая всю старую информацию. @McDowell: Это действительно имеет смысл. Я сделаю тест, чтобы посмотреть, что произойдет.
Джеймс П.
3

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

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;
}
Суджанья
источник
Я пытаюсь сделать это из сервлета, но это не работает.
Fernando Pie
0

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

Я использовал способ, указанный ниже.

У меня был компонент с ограниченным сеансом.

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

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

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

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

Анил
источник
Какой сервлет вы используете? mate
Fernando Pie
1
Это HttpServlet.
Anil
-1

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

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);

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

ChRoNoN
источник