如何在 ActionListener 中注入托管 属性

How can I inject a managed property in an ActionListener

我想在 ActionListener 方法中处理来自其他 bean 的数据,但它抛出 NullPointerException,所以我尝试在带有 @PostConstruct 注释的 init() 方法中将 bean 的实例重新安全到下一个实例,但是它仍然抛出 NullPointerException。我知道可以通过 FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(context, expression, expectedType); 获取 bean,但是可以通过 @ManagedProperty 获取 bean 吗?这是代码:

Login.java

package sklad;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

public class Login implements ActionListener{
        private Osoba os;

        @ManagedProperty(value="#{osoba}")
        private Osoba osoba;

        @PostConstruct
        public void init(){
            os = osoba;
        }

        @Override
        public void processAction(ActionEvent a) throws AbortProcessingException {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage("zprava", new FacesMessage(os.getId().toString() + " " + os.getHeslo()));

        }

        public Osoba getOsoba() {
            return osoba;
        }

        public void setOsoba(Osoba osoba) {
            this.osoba = osoba;
        }

        public Osoba getOs() {
            return os;
        }

        public void setOs(Osoba os) {
            this.os = os;
        }
    }

Osoba.java

package sklad;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

    @ManagedBean
    @SessionScoped
    public class Osoba{
        private Integer id;
        private String heslo;

        public Osoba(){}

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getHeslo() {
            return heslo;
        }

        public void setHeslo(String heslo) {
            this.heslo = heslo;
        }
    }

login.xhtml

 <!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui">

<h:head>
    <title>title</title>
    <link rel="stylesheet" type="text/css" href="../styles/login.css" />
</h:head>
<h:body>
    <p:growl id="growl" showDetail="true" life="3000" />
    <p:panel id="panel_login" header="Přihlášení" styleClass="panel">
        <p:panelGrid styleClass="panelGrid">
            <h:form>
                <p:row>
                    <p:column>
                        <h:outputText value="ID: " />
                    </p:column>
                    <p:column>
                        <h:inputText id="id_login" value="${osoba.id}" />
                    </p:column>
                </p:row>

                <p:row>
                    <p:column>
                        <h:outputText value="Heslo: " />
                    </p:column>
                    <p:column>
                        <h:inputSecret id="heslo_login" value="${osoba.heslo}" />
                    </p:column>
                </p:row>

                <p:row>
                    <p:column colspan="2">
                        <h:commandButton id="btn_login" value="Přihlásit">
                            <f:actionListener type="sklad.Login"/>
                        </h:commandButton>
                    </p:column>
                </p:row>
            </h:form>
        </p:panelGrid>
    </p:panel>
</h:body>
</html>

更传统的调用动作侦听器的方法是使用方法绑定,如下所示:

@ManagedBean
@RequestScoped
public class Login {
  ...

  public void doLogin(ActionEvent event){
    // handle action
  }
}

然后在按钮中:

<h:commandButton id="btn_login" value="Přihlásit" actionListener="#{login.doLogin}"/>

这种方法的好处是将 Login 变成了一个 ManagedBean,这将使 JSF 处理其上的注释 - 这使得 @ManagedProperty 注释按预期工作。