Как получить доступ к управляемым bean и сеансу bean от сервлета

Вот как работает мой commandLink

 <p:dataTable value="#{myBean.users}" var="item">
     <p:column>
         <h:commandLink value="#{item.name}" action="#{myBean.setSelectedUser(item)}" />     
     </p:column>
 </p:dataTable>

то в myBean.java

 public String setSelectedUser(User user){
     this.selectedUser = user;
     return "Profile";
 }

Предположим, что имя пользователя Peter. Затем, если я нажму на Peter, я установил selectedUser как пользовательский объект Peter, а затем перенаправляется на страницу профиля, которая теперь отображает информацию из selectedUser. Я хочу создать тот же эффект только с помощью <h:outputText>, поэтому на этот вопрос приходит запрос GET. Поэтому я делаю это

 <h:outputText value="{myBean.text(item.name,item.id)}" />

то метод text(String name, Long id) возвращает

"<a href=\"someURL?userId=\"" + id + ">" + name + "</a>"

все, что осталось, это создание сервлета, поймать id, запросить базу данных, чтобы получить объект user, установить на selectedUser, перенаправление. Итак, вот мой сервлет

public class myServlet extends HttpServlet { 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Long userId = Long.parseLong(request.getParameter("userId"));
    }
}

Теперь у меня есть id, как мне получить доступ к сеансу bean, чтобы запросить базу данных для user, а затем получить доступ к управляемому bean, чтобы установить user в selectedUser, а затем перенаправить на profile.jsf?

Ответ 1

JSF хранит управляемый сеанс beans как атрибут сеанса с использованием управляемого bean имени в качестве ключа. Таким образом, следующее должно работать (предполагая, что JSF уже создал bean раньше в сеансе):

MyBean myBean = (MyBean) request.getSession().getAttribute("myBean");

Тем не менее, я чувствую, что вы ищете неправильное направление решения. Вы также можете просто сделать следующее:

<a href="profile.jsf?userId=123">

со следующим в области запроса bean, связанной с profile.jsf

@ManagedProperty(value="#{param.userId}")
private Long userId;

@ManagedProperty(value="#{sessionBean}")
private SessionBean sessionBean;

@PostConstruct
public void init() {
    sessionBean.setUser(em.find(User.class, userId));
    // ...
}

Ответ 2

Вы можете добавить аннотации Inject и EJB в поля сервлета, если вы используете сервер приложений Java EE 6, например Glassfish v3. Некоторым это нравится:

@Inject
private AppManagedBean appmanaged;
@EJB
private SessionBean sessbean;

Помните, эти аннотации являются частью Injection Context и Dependecy или CDI, поэтому вы должны добавить дескриптор развертывания beans.xml.

Но если вы не можете использовать аннотации CDI, найдите интерфейс BeanManager в java: comp/BeanManager и используйте его для доступа (только) управляемого beans (внутри управляемого bean можно добавить сеанс beans с помощью аннотации @EJB). Также не забудьте добавить дескриптор развертывания beans.xml.

Класс полезности для поиска java: comp/BeanManager:

package mavenproject4;

import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ManagedBeans {

    private static final BeanManager beanManager;

    static {
        try {
            InitialContext ic = new InitialContext();
            beanManager = (BeanManager) ic.lookup("java:comp/BeanManager");
        } catch (NamingException ex) {
            throw new IllegalStateException(ex);
        }
    }

    private ManagedBeans() {
    }

    public static <T> T getBean(Class<T> clazz, String name) {
        Set<Bean<?>> beans = beanManager.getBeans(name);
        Bean<? extends Object> resolve = beanManager.resolve(beans);
        CreationalContext<? extends Object> createCreationalContext = beanManager.createCreationalContext(resolve);
        return (T) beanManager.getReference(resolve, clazz, createCreationalContext);
    }
}

Использование класса утилиты в методе сервлета processRequest или эквиваленте:

response.setContentType("text/html;charset=UTF-8");

AppManagedBean appmanaged = ManagedBeans.getBean(AppManagedBean.class, "app");

PrintWriter out = response.getWriter();
try {
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Servlet BeanManager</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>" + appmanaged.getHelloWorld() + "</h1>");
    out.println("</body>");
    out.println("</html>");
} finally {
    out.close();
}

Пример управляемого bean с вложенным сеансом bean:

package mavenproject4;

import java.io.Serializable;
import javax.annotation.ManagedBean;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

@ManagedBean
@ApplicationScoped
@Named("app")
public class AppManagedBean implements Serializable {

    private int counter = 0;
    @EJB
    private SessionBean sessbean;

    public AppManagedBean() {
    }

    public String getHelloWorld() {
        counter++;
        return "Hello World " + counter + " times from Pachuca, Hidalgo, Mexico!";
    }
}

Я не знаю, правильно ли работает код в классе утилиты, но работает. Также код не проверяет исключение NullPointerException и друзей.