如何从Servlet访问托管Bean和会话Bean

10

这是我的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>"

现在我们只需要创建一个servlet,获取id,查询数据库以获取user对象并将其设置为selectedUser,然后进行重定向。

以下是我的servlet代码:

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

2个回答

20

JSF使用托管bean的名称作为键将会话范围的托管bean存储为会话属性。因此,以下内容应该可以正常工作(假设JSF之前已经在会话中创建了该bean):

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

话虽如此,我有一种感觉你正在寻找错误的解决方案。你也可以按照以下方式操作:

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

在与profile.jsf相关联的请求范围Bean中使用以下内容:

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

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

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

可以的。这个问题不太清楚 :) 这只是一个启动示例,展示如何利用@ManagedProperty@PostConstruct来应用和处理请求参数。 - BalusC
1
只需在视图中引用它。例如:欢迎,#{bean.sessionBean.user.name} - BalusC
谢谢。它与requestScoped一起工作,但与viewScoped一起使用时,会生成错误“表达式#{param.userId}引用的对象的范围(即request)短于视图Profile管理bean的范围”。感谢BalusC。 - Thang Pham
有没有办法在ViewScoped中从URL获取参数,或者你必须像上面建议的那样在RequestScoped中执行?如果JSF只允许在RequestScoped bean中执行,那似乎有点太受限制了。 - Thang Pham
没关系,我可以通过getRequestParameterMap()获取它。 - Thang Pham
显示剩余3条评论

4

如果您正在使用像Glassfish v3这样的Java EE 6应用服务器,那么可以在Servlet的字段中添加InjectEJB注释。如下所示:

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

请注意,这些注释是上下文和依赖注入CDI的一部分,因此您必须添加beans.xml部署描述符。
但是,如果您无法使用CDI注释,请查找BeanManager接口,位于java:comp / BeanManager并将其用于访问(仅)托管bean(在托管bean中,您可以使用@EJB注释注入会话bean)。还要记得添加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);
    }
}

在servlet的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!";
    }
}

我不知道实用类中的代码是否100%正确,但是它能正常工作。此外,该代码没有检查NullPointerException等错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接