【发布时间】:2019-01-26 22:04:28
【问题描述】:
我正在学习 JSF 2.2 并尝试制作单页应用程序 (SPA)。使用版本 2.2.8。我做了一个简单的SPA,只显示文字和图片。我是通过使用 f:ajax、ui:include 和 ui:composition 实现的。
一切从 index.xhtml 文件开始:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<h:head>
<title>Project S - SPA</title>
<link href="./css/styles.css" rel="stylesheet" type="text/css"/>
</h:head>
<h:body>
<h1 class="title">Project S - Single Page Application</h1>
<h:form>
<f:ajax render="content">
<h:commandLink value="Login" action="#{navController.setToPage('login')}"/>
<h:commandLink value="Create user" action="#{navController.setToPage('create-user')}"/>
<h:commandLink value="Reset password" action="#{navController.setToPage('reset-password')}"/>
</f:ajax>
</h:form>
<hr/>
<div jsf:id="content">
<ui:include src="#{navController.page}.xhtml"/>
</div>
</h:body></html>
从这里我加载像login.xhtml这样的页面:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h1>Login page</h1>
<h:form>
Please log in.<br/>
<h:panelGrid columns="2">
User name: <h:inputText value="#{loginController.name}"/>
Password: <h:inputSecret value="#{loginController.password}"/>
</h:panelGrid>
<h:commandButton value="Login" action="#{loginController.login}"/>
</h:form>
</ui:composition>
和 create-user.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h1>Create user page</h1>
<h:form>
<h:panelGrid columns="3" styleClass="formTable">
User name:
<h:inputText value="#{registerController.userName}"
id="uname"
required="true"
requiredMessage="Please enter your User Name">
</h:inputText>
<h:message for="uname"/>
Password:
<h:inputSecret value="#{registerController.password}"
id="pass"
required="true"
requiredMessage="Please enter your Password">
</h:inputSecret>
<h:message for="pass"/>
Hint:
<h:inputText value="#{registerController.hint}"
id="hint"
required="true"
requiredMessage="Please enter a hint">
</h:inputText>
<h:message for="hint"/>
</h:panelGrid>
<h:commandButton value="Register" action="#{registerController.register}"/>
</h:form>
</ui:composition>
我使用 NavController.java 托管 bean 来导航它们:
package controllers;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class NavController implements Serializable {
private static final long serialVersionUID = 1L;
private String page = "login";
public String getPage() {
return page;
}
public void setToPage(String page) {
this.page = page;
}
}
这些页面可以很好地显示和切换到它们。将加载的第一个页面,在这种情况下登录,将没有问题。但其他页面没有。不要我的意思是,无论我在单击 h:commandButton 时输入什么内容,都不会激活验证,也不会创建用户。我刚刚被送回 index.jsf 页面。这是创建用户的控制器类:
package controllers;
import javax.faces.bean.ManagedBean;
import database.UsersDataBaseSimulator;
import models.User;
@ManagedBean
public class RegisterController {
private String userName, password, hint;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
}
public String register() {
if(UsersDataBaseSimulator.USERS.containsKey(userName)) {
return "user-exists";
}
User user = new User(userName, password, hint);
UsersDataBaseSimulator.USERS.put(userName, user);
return "user-created-successfully";
}
}
以及登录的控制器类:
package controllers;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import database.UsersDataBaseSimulator;
@ManagedBean(name="loginController")
@SessionScoped
public class LoginController implements Serializable{
private static final long serialVersionUID = 1L;
private String name, password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String login() {
if(UsersDataBaseSimulator.USERS.get(name) != null) {
if(UsersDataBaseSimulator.USERS.get(name).getPassword().equals(password)) {
return "main-page?faces-redirect=true";
}
}
return "error";
}
}
我已将此页面创建为非 SPA,它运行良好。我尝试将初始页面从登录切换到创建用户,在这种情况下,只有创建用户页面有效。在这一点上,我不知道这是否可能,以及我是否以正确的方式进行。我正在学习这门课程http://www.coreservlets.com/JSF-Tutorial/jsf2/。到目前为止,我已经完成了复合组件第 1 部分。我将提供您可能需要的任何其他信息,以便深入了解这个问题。提前感谢任何花时间解决此问题的人。
【问题讨论】:
-
在我看来,JSF 不太适合单页应用程序。如果您真的想要一个 SPA,那么众多前端框架(Angular、React、Vue 等数百个)中的一个很可能是更好的选择。 JSF 是在 SPA 还没有真正成为事物的时候发明的。所以这可能是可能的,但这并不是 JSF 的真正设计目的,这意味着这并不容易。
-
@Jesper 这就是我害怕的。不幸的是,我不得不在 JSF 中这样做。首先是因为这是我的任务,其次是因为 Java 是我唯一合理知道的语言。我刚刚开始学习 JavaScript,现在学习框架对我来说还有很长的路要走。
-
JSF 可用于 SPA 和 afaics,您采用的方法是正确的。看不到导致您所经历的事情的原因,但我也无法运行它。你能减少代码并使其成为真正的minimal reproducible example。然后我很乐意进一步调查。哦,请发布 jsf 版本和实现
-
题外话:如果您从头开始,我建议使用 cdi 托管 bean (
@Named) 而不是已弃用的@ManagedBean -
@Kukeltje 谢谢你的建议。你能告诉我你所说的实施是什么意思吗?
标签: java jsf single-page-application jsf-2.2