我正在使用JSF创建一个Timesheet应用程序,目前正在处理登录部分。这是一个直接登录,它获取登录ID和密码,并检查它是否是一个有效的组合(虽然此时我只是在管理员登录)。
我的问题似乎是JSF在调用verify操作方法之前没有更新我的loginID和密码字段,因为当我单击login时,它会抛出NullPointerException。这是我的验证方法。
/**
* Verifies that the loginID and password is the super user combination.
* @return true if it is, false if it is not.
*/
public String verifyUser() {
ResourceBundle login = getSuperUserLogin();
String user = getLoginID();
String checkPassword = getPassword();
if(!login.containsKey(user) || !checkPassword.equals(login.getString(user))) {
return "regular";
}
return "super";
}
和我的登录页面
<body>
<div class = "content" align = "center">
<h:form>
<h3>#{msgs.loginTitle}</h3>
<h:panelGrid columns="2" cellpadding = "4">
<h:outputText value = "#{msgs.userID}" styleClass="title" />
<h:inputText value="#{user.loginID}" styleClass="rounded" />
<h:outputText value = "#{msgs.password}" styleClass="title" />
<h:inputSecret value="#{user.password}" styleClass="rounded" />
</h:panelGrid>
<p><h:commandButton value="#{msgs.login}" styleClass="button" action="#{superUser.verifyUser}"/></p>
</h:form>
</div>
现在,如果我将登录ID和密码硬编码到用户和checkPassword字段中,那么它没有问题。所以我认为问题在于loginID和密码字段为空(因为getLoginID()和getPassword()只是返回这些字段的常规旧getter)。我知道答案是愚蠢的,我会因为错过而感到尴尬,但此时我正在撞墙。
信息完成后,loginID和密码字段位于User类中(提供了适当的setter),而verifyUser方法位于子类SuperUser中。我不知道为什么这一点很重要,但这将是我第一个使用超级和子类的JSF应用程序,所以你永远不会知道。
修改 根据要求,这是我的用户类代码
package ca.bcit.infosys.timesheet.model;
import java.util.ResourceBundle;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
@Named
@ApplicationScoped
public class User implements java.io.Serializable {
/** The user's name */
private String name;
/** The user's employee number */
private int empNumber;
/** The user's login ID */
private String loginID;
/** The user's password */
private String password;
/** Is the user currently in an editable state (i.e. the user's information can be edited on the webpage) */
private boolean editable;
private ResourceBundle superUserLogin = ResourceBundle.getBundle("ca.bcit.infosys.timesheet.model.messages");
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the empNumber
*/
public int getEmpNumber() {
return empNumber;
}
/**
* @param empNumber the empNumber to set
*/
public void setEmpNumber(int empNumber) {
this.empNumber = empNumber;
}
/**
* @return the loginID
*/
public String getLoginID() {
return loginID;
}
/**
* @param loginID the loginID to set
*/
public void setLoginID(String loginID) {
this.loginID = loginID;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the isEditable
*/
public boolean isEditable() {
return editable;
}
/**
* @param isEditable the isEditable to set
*/
public void setEditable(boolean editable) {
this.editable = editable;
}
/**
* @return the Property containing the super user login information.
*/
public ResourceBundle getSuperUserLogin() {
return superUserLogin;
}
}
答案 0 :(得分:3)
您目前的方法存在很多误解。我建议首先学习并掌握JSF的基本概念来实现这一目标。
为了使这项工作,您需要一个只需要为服务器的每个请求活动的bean。该bean将负责从JSF表单获取数据并执行验证操作。然后,您只需将字段和登录方法绑定到JSF表单。
Java代码
//Looks like you use CDI (or probably you just think this is what you need)
@Named
//The bean just needs to be alive on each request
//Since you're using CDI, make sure this annotation comes from
//javax.enterprise.context package
@RequestScoped
//Usually, the managed beans used in JSF are named with "Bean" suffix
//Since it is for learning purposes, I'll name this bean UserBean
public class UserBean {
//fields to hold username and password
//they both are Strings
private String username;
private String password;
//getters and setters methods
//I won't add them since it is boilerplate code for this sample
//...
//Method to handle your login action
//If successful login, then returns the name of the next view
//If unsuccessful, returns null to stay in the current view
public String login() {
//Sample implementation, remember to change it for A REAL ONE
if ("admin".equals(username) &&
"adminPass".equals(password)) {
//Successful login
//Make sure to have a file index.xhtml in the same folder
//where the login JSF page resides (for sample purposes)
return "index";
}
//Unsuccessful login
//Also, it is a good idea to show a message for end user
FacesMessage message = new FacesMessage("Invalid login.");
FacesContext.getCurrentInstance().addMessage(null, message);
return null;
}
}
JSF代码
<h:form>
<h3>Login Title</h3>
<h:panelGrid columns="2">
<h:outputText value="User Id" />
<h:inputText value="#{userBean.username}" />
<h:outputText value="Password" />
<h:inputSecret value="#{userBean.password}" />
</h:panelGrid>
<h:commandButton value="Login" action="#{userBean.login}" />
<br />
<h:messages />
</h:form>
在开始之前,您需要了解的一些事情:
@ApplicationScoped
,这意味着整个应用程序有一个用户bean,这意味着两个不同的最终用户将具有相同的用户对象(现在你开始担心)。您可以在此处了解有关此内容的更多信息:How to choose the right bean scope? org.omnifaces.cdi
包中的自定义@ViewScoped
注释来解决此问题。