I am using JSF 2.0 in a simple application. I have three beans 1st which is login is in request scope while other 2 in view scope. I have configured in faces-config.xml.
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>loginSuccess</from-outcome>
<to-view-id>/pages/ReportSubmit.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>reportStatus</from-outcome>
<to-view-id>/pages/ReportStatus.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>logout</from-outcome>
<to-view-id>/pages/logout.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>UserBean</managed-bean-name>
<managed-bean-class>com.cognizant.reportgen.LoginBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>ReportBean</managed-bean-name>
<managed-bean-class>com.cognizant.reportgen.ReportGeneratorBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>ReportStatus</managed-bean-name>
<managed-bean-class>com.cognizant.reportgen.ReportStatusBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
</faces-config>
I have a menu.jsp which has below code
menu item1 <h:commandLink action="loginSuccess" value="Generate Reports"></h:commandLink>
menu item 2<h:commandLink action="reportStatus" value="Report Status"></h:commandLink>
In 2 beans, I have methods whose return type is void.
On Login request, I am creating session and setting user detail in session attribute.
Now The problem which I am facing is that
I login with user1, select menu item 1, so corresponding data is displayed.
I login with user2 in next browser window, select menu item 1, so corresponding data is displayed.
I go back to browser window1 (user1), select menu item 1 again, but now in header it displays the user2 name., Also it displays data corresponding to user2.
Please help me with this issue.
//ReportStatusBean.java
public class ReportStatusBean {
private List<ReportAttrDO> reportList;
private HtmlDataTable reportStatusTable;
// getters and setter for above included....
public void checkReportStatus(ActionEvent event) {
ReportGenService reportGenObj = new ReportGenServiceImpl();
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
UserDetail user = (UserDetail)session.getAttribute("user");
List<ReportAttrDO> reportList = reportGenObj.getReportStatusList(user.getUserId());
setReportList(reportList);
if(reportList.isEmpty())
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "No Records to display.", null));
}
public void viewReport(ActionEvent event) {
ReportAttrDO reportAttrDO = (ReportAttrDO)getReportStatusTable().getRowData();
System.out.println(reportAttrDO.getRequestHeaderId());
}
}
// ReportStatus.jsp
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%# taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<html>
<head>
....some script functions..
</head>
<body onload="noBack();" onpageshow="if (event.persisted) noBack();" onunload="">
<center>
<div class="wrapper">
<%#include file="../include/pageheader.jsp"%>
<%#include file="../include/menu.jsp"%>
<h:form id="form2">
<table border="0">
<tr>
<td colspan="2"><h:messages style="color:red;margin:8px;" /></td>
</tr>
<tr>
<td colspan="2"><h:commandButton value="Check Status" actionListener="#{ReportStatus.checkReportStatus}" /></td>
</tr>
</table>
<c:if test="${not empty ReportStatus.reportList}" >
<div style="height:200px;width:600px;overflow:auto;">
<h:dataTable id="table" border="1"
var="row" value="#{ReportStatus.reportList}" cellpadding="5" cellspacing="5"
binding="#{ReportStatus.reportStatusTable}">
<h:column>
<f:facet name="header">
<f:verbatim>
<h:outputText value="Application Name" />
</f:verbatim>
</f:facet>
<h:outputText id="applName" value="#{row.applicationName}" ></h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>
<h:outputText value="Report Name" />
</f:verbatim>
</f:facet>
<h:outputText id="reportReqName" value="#{row.reportRequestName}"></h:outputText>
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>
<h:outputText value="Generated Report" />
</f:verbatim>
</f:facet>
<h:commandLink id="viewReport" value="View" rendered="#{row.status == 'Completed'}" actionListener="#{ReportStatus.viewReport}"></h:commandLink>
</h:column>
</h:dataTable>
</div>
</c:if>
</h:form>
</div>
</center>
</body>
</html>
</f:view>
HTTP session is shared among browser's tabs, so what you're experiencing is an expected behaviour. When you did login in a next tab you most probably replaced the existing session attribute.
You can as well try it in different browsers, but not different tabs of the same browser, to see it work as you expect it to work. In the end, session is a per user construct and should be viewed as such. You must define the proper scopes for your beans for the application to run in accordance with your expectations and for good user experience.
Unrelated to your concrete problem, using command links that use POST requests for plain page-to-page navigation is considered to be a bad practice: you should use <h:link> instead. For details see the third reference below.
Also, using faces-config.xml to solely configure navigation rules and declare managed beans in a JSF 2.0 application is somewhat old-school, in my opinion. The last but not the least, JSP is a deprecated view technology nowadays, that was superseded by facelets, so developing new application using JSP as a view technology should be carefully rethought.
See also:
How to choose the right bean scope?;
Communication in JSF 2.0, section on bean scopes;
When should I use h:outputLink instead of h:commandLink?.
You need to render your menu conditionnaly of your session user and not your login result, for example :
<h:form>
<h:panelGroup rendered="#{not userbean.isLogged}">
<h:inputText value="#{userBean.username}" />
<h:inputText value="#{userBean.password}" />
<h:commandButton actionListener="#{userBean.login}" />
</h:panelGroup>
<h:panelGroup rendered="#{userBean.isLogged}">
<h:commandLink rendered="#{userBean.user eq "user1"}" action="loginSuccess" value="Generate Reports"></h:commandLink>
<h:commandLink rendered="#{userBean.user eq "user2"}" action="reportStatus" value="Report Status"></h:commandLink>
</h:panelGroup>
</h:form>
Of course it will require some function inside userBean to get the username for example.
Also you mean that you have configured your bean using ViewScoped, they are all RequestScoped in the code provided.
I suggest you to use .xhtml file name extensions, which is the standard in JavaServer Faces views.
Related
I have a JSF file (characters.xhtml) that is not rendering properly, and I suspect it has to do with the backing bean (CharactersController) not being instantiated. I can render the page (meaning all the HTML code is generated), but without any details contained by the bean, such as my "msg" property data being displayed. At minimum, "msg" should display "hello", or ideally "list size is: 0".
Ultimately, I want to pull data from my database with this bean (the DAO itself works separately in a REST resource, so I don't think that is the problem). But as it stands, my CharactersController bean does not appear to be instantiating. I have a #PostConstruct that should log an output when the bean is created, but it is not appearing anywhere, which is why I suspect issue there.
On a related note, I have another managed bean for a different JSF file that does load correctly. It is also ViewScoped. I am able to see the log from its respective #PostConstruct. (From other older posts, ViewScoped may have been a culprit, but it doesn't seem to be here since it does work for my other bean.)
Lastly, I get a null pointer error if I try creating a component referencing any methods. I bring this up because I tried loading my data via <f:viewAction> tag.
Other details:
I'm using Jakarta EE 9, Glassfish 6.1 RC1, Java 11, IntelliJ, Maven build.
I do have getters and setters for all fields in CharactersController except for "dao". I omitted the code for brevity.
CharactersController - Managed Bean
import jakarta.annotation.PostConstruct;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import xxx.dao.CharactersDao;
import xxx.CharactersEntity;
import java.io.Serializable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
#Named("cc")
#ViewScoped
public class CharactersController implements Serializable {
private static final long serialVersionUID = 1L;
public CharactersController() {
}
#Inject
private CharactersDao dao;
private List<CharactersEntity> chars;
private CharactersEntity newChar;
private String msg = "hello";
private static final Logger logger = Logger.getLogger("CharactersController");
#PostConstruct
public void init(){
chars = dao.getAll();
msg = "list size is: " + chars.size();
logger.log(Level.INFO, "CC constructed: " + msg);
}
characters.xhtml - facelet
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
>
<h:head>
</h:head>
<h:body>
<ui:composition template="/WEB-INF/templates/adminTemplate.xhtml">
<ui:define name="dataTable">
<h3>Msg: <h:outputText value="#{cc.msg}"/></h3>
<h:form>
<h:dataTable value="#{cc.chars}" var="char">
<f:facet name="header">
<h:outputText value="Characters"/>
</f:facet>
<h:column>
<f:facet name="header">
<h:outputText value="ID"/>
</f:facet>
<h:outputText value="#{char.characterId}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Avatar"/>
</f:facet>
<h:outputText value="#{char.avatar}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText value="#{char.name}"/>
</h:column>
</h:dataTable>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</html>
HTML output
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head id="j_idt2">
<title>RPG Admin</title></head><body>
<header>
<h1>admin</h1>
</header>
<nav>
<div class="admin-nav-row">
<div>Home
</div>
<div>Characters
</div>
</div>
</nav>
<main>
<h3>Msg: </h3>
<form id="j_idt13" name="j_idt13" method="post" action="/rpg_xe/admin/characters.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_idt13" value="j_idt13" />
<table>
<thead>
<tr><th colspan="3" scope="colgroup">Characters</th></tr>
<tr>
<th scope="col">ID</th>
<th scope="col">Avatar</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
<tr><td></td><td></td><td></td></tr></tbody>
</table>
<input type="hidden" name="jakarta.faces.ViewState" id="j_id1:jakarta.faces.ViewState:0" value="-7288672771663122896:-6269118426931924221" autocomplete="off" />
</form>
</main>
<footer>footer</footer></body>
</html>
Ok, now that you have confirmed:
"cc" cannot be used as a managed bean name because there is a conflict with builtin object "cc" (Composite Component).
"The word cc in JavaServer Faces is a reserved word for composite components."
https://javaee.github.io/tutorial/jsf-facelets005.html
I have a button, when i click a modal panel opened - it's work fine. Now i tried to add a button to hide the panel - it's work also, but the problem is when i tried to show a text "panel closed" after button click it doesn't work. I use Jsf 1.2 and richfaces 3.3.3.
I have the following error message:
org.apache.jasper.el.JspELException: /index.jsp(35,7) 'javascript:Richfaces.hideModalPanel('myModalPanel');#{welcomeBean.showText(true)}' Method not found: class com.firstjsf.backingbeans.WelcomeBean.showText(java.lang.Boolean) at org.apache.jasper.el.JspValueExpression.getValue(JspValueExpression.java:123)
above the code:
index.jsp
<%#taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%#taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%# taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
<%# taglib uri="http://richfaces.org/rich" prefix="rich"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<f:view>
<h:form>
<rich:panel>
<f:facet name="header">
<h:outputText value="Product"></h:outputText>
</f:facet>
<h:form>
<a4j:commandButton
id="newWid"
value="New Widget..."
immediate="true" ajaxSingle="true"
reRender="text"
oncomplete="javascript:Richfaces.showModalPanel('myModalPanel');"
styleClass="verboseButton noprint" />
</h:form>
<rich:modalPanel id="myModalPanel">
<f:facet name="header">
<h:outputLabel value="123" />
</f:facet>
From Modal Panel
<a4j:commandButton value="Hide" id="btn_hide"
oncomplete="javascript:Richfaces.hideModalPanel('myModalPanel');#{welcomeBean.setShowText(true)}" />
</rich:modalPanel>
<h:outputText id="text"
value="Panel closed"
rendered="#{helloMessage.showText eq true}">
</h:outputText>
</rich:panel>
</h:form>
</f:view>
</html>
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<managed-bean>
<managed-bean-name>welcomeBean</managed-bean-name>
<managed-bean-class>com.firstjsf.backingbeans.WelcomeBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>helloMessageBean</managed-bean-name>
<managed-bean-class>com.firstjsf.backingbeans.HelloMessageBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<description>Welcome page to message page</description>
<from-view-id>/index.jsp</from-view-id>
<navigation-case>
<from-outcome>helloMessage</from-outcome>
<to-view-id>/message.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<description>Welcome page to message page</description>
<from-view-id>/message.jsp</from-view-id>
<navigation-case>
<from-outcome>back</from-outcome>
<to-view-id>/index.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
BeanAction
public class WelcomeBean {
private boolean showText =false;
public String sayHello(){
return "helloMessage";
}
public boolean isShowText() {
return showText;
}
public void setShowText(boolean showText) {
this.showText = showText;
}
}
You're mixing JavaScript and EL expressions, #oncomplete is for executing JavaScript, if you want to do something on the server use #action or #actionListener. Otherwise the expression will be evaluated and the browser will try to execute the return value as if it was JavaScript.
By the way, your code shows you're using setShowText(true) (which is correct), but the exception says you're using just showText(true), which is it then?
I have a JSF application with a Data Table. Each row has a 'commandLink'. When the commandLink of a row is clicked then row data must be displayed on console.
I am getting an error when I click on the commandLink, the error is as follows:
component with duplicate id "dataTable1:col1" found
viewId=/UserHome.xhtml
location=E:\workspaces_eclipse\webService\.metadata\.plugins \org.eclipse.wst.server.core\tmp2\wtpwebapps\JSF_Demo\UserHome.xhtml
phaseId=RENDER_RESPONSE(6)
Caused by:
java.lang.IllegalStateException - component with duplicate id "dataTable1:col1" found
at org.apache.myfaces.view.facelets.compiler.CheckDuplicateIdFaceletUtils.checkIds(CheckDuplic ateIdFaceletUtils.java:100)
The error shows that components have same IDs, however I tried to give different 'id' to each element of the data table.
The source code of JSF file 'UserHome.xhtml' is as follows:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Resource Net 1.0</title>
<h:outputStylesheet library="css" name="table-style.css"></h:outputStylesheet>
</h:head>
<h:body>
<div align="center">
<table width="90%" height="100%" border="0" style="cellspacing:0; border-radius:10px ;box-shadow: 0px 0px 15px 10px #888888">
<tr>
<td>
<h2><div align="center">Resource Net 1.0</div></h2>
</td>
</tr>
<tr>
<td>
2. Generated by Map :
<h:selectOneMenu value="#{userHomeListener.favCoffee2}">
<f:selectItems value="#{userHomeListener.allDomains}" />
</h:selectOneMenu>
</td>
</tr>
<tr>
<td>
<h:dataTable value="#{userHomeListener.documents}" var="doc"
binding="#{userHomeListener.documentsTable}"
id="dataTable1"
styleClass="order-table"
headerClass="order-table-header"
rowClasses="order-table-odd-row,order-table-even-row"
border="1">
<h:column id="col1">
<f:facet name="header1">Document ID</f:facet>
#{doc.docID}
</h:column>
<h:column id="col2">
<f:facet name="header2">Document Name</f:facet>
#{doc.docName}
</h:column>
<h:column id="col3">
<f:facet name="header3">Document Link</f:facet>
<h:form id="form1">
<h:commandLink id="link" value="#{doc.docLink}" action="#{userHomeListener.getRowData}"></h:commandLink>
</h:form>
</h:column>
<h:column id="col4">
<f:facet name="header4">Upload Date</f:facet>
#{doc.uploadDate}
</h:column>
</h:dataTable>
<h:commandButton value="get row data" ></h:commandButton>
</td>
</tr>
</table>
</div>
</h:body>
Is there some problem with my code? Kindly suggest solutions to this issue.
Thanks in advance.
The binding attribute of the <h:dataTable> is the suspect here. It may lead to this kind of problems when the bean is in a too broad scope and/or when you're doing "wrong things" in the getter/setter of that attribute.
Putting the bean in the request scope and/or looking for alternative ways so that you can get rid of the binding altogether should solve this problem.
The combination of the binding attribute and the name of the command link action method getRowData suggests that you're merely using it to get the current table row. This was indeed the way when using the old JSF 1.x, but not anymore when using the new JSF 2.x. This can be done much better and simpler when you're running a Servlet 3.0 / EL 2.2 capable container (Tomcat 7, Glassfish 3, etc).
<h:dataTable value="#{userHomeListener.documents}" var="doc">
<h:column>
<h:form>
<h:commandLink value="#{doc.docLink}" action="#{userHomeListener.getRowData(doc)}" />
</h:form>
</h:column>
</h:dataTable>
with
public void getRowData(Document doc) {
// ...
}
You see, you can just pass the #{doc} straight as method argument.
See also:
How can I pass selected row to commandLink inside dataTable?
Recommended JSF 2.0 CRUD frameworks
I am looking for a another way of JSF navigation other than mentioning navigation-cases in faces-config.xml.
At present i am using faces-config.xml to navigate. I want to clean it up.
Please suggest all other ways so that i can use whatever suits my need.
For simple page-to-page navigation (without submitting anything) you should be using <h:outputLink> instead of <h:commandLink>.
So, instead of
<h:form>
<h:commandLink value="Page 1" action="page1" />
<h:commandLink value="Page 2" action="page2" />
<h:commandLink value="Page 3" action="page3" />
</h:form>
and those navigation cases
<navigation-rule>
<navigation-case>
<from-outcome>page1</from-outcome>
<to-view-id>page1.jsf</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>page2</from-outcome>
<to-view-id>page2.jsf</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>page3</from-outcome>
<to-view-id>page3.jsf</to-view-id>
</navigation-case>
</navigation-rule>
you should use
<h:outputLink value="page1.jsf">Page 1</h:outputLink>
<h:outputLink value="page2.jsf">Page 2</h:outputLink>
<h:outputLink value="page3.jsf">Page 3</h:outputLink>
For real form submits you should rewrite the action methods to return void or null instead of an outcome. So, instead of
<h:form>
<h:inputText value="#{bean.query}" />
<h:commandButton value="Search" action="#{bean.search}" />
</h:form>
with
public String search() {
results = searchService.find(query);
return "results";
}
on one page and
<h:dataTable value="#{bean.results}" var="result">
...
</h:dataTable>
on other page and this navigation case
<navigation-rule>
<from-view-id>search.jsf</from-view-id>
<navigation-case>
<from-outcome>results</from-outcome>
<to-view-id>results.jsf</to-view-id>
</navigation-case>
</navigation-rule>
you should use
<h:form rendered="#{empty bean.results}">
<h:inputText value="#{bean.query}" />
<h:commandButton value="Search" action="#{bean.search}" />
</h:form>
<h:dataTable value="#{bean.results}" var="result" rendered="#{not empty bean.results}">
...
</h:dataTable>
with
public void search() {
results = searchService.find(query);
}
You can if necessary include page fragments by <jsp:include>.
See also:
When should I use h:outputLink instead of h:commandLink?
//JSF
<h:outputLink value="login.xhtml" >
Login page
</h:outputLink>
//HTML output
<a href="login.xhtml">
Login page
</a>
Refer this URL for more info:-
commandLink and outputLink example
You can set the return value of a navigation action to the name of the page you want to go to (e.g. return "page2"; to switch to page2.jsf). But as far as I know, this feature has been implemented first in JSF 2.0.
I have what I thought was simple JSF navigation setup but when I hit the h:commandButton the page reloads, not the page I want to load. The faces-config snippet is here:
<navigation-rule>
<from-view-id>/index.jsf</from-view-id>
<navigation-case>
<from-outcome>hello</from-outcome>
<to-view-id>/next.jsf</to-view-id>
</navigation-case>
</navigation-rule>
the index.xhtml file contains this:
<f:view>
<a4j:region id="topRegion">
<rich:page pageTitle="myapp" markupType="xhtml" id="top">
<f:facet name="header">
<h:form>
<rich:toolBar height="45" itemSeparator="disc">
<rich:toolBarGroup location="left">
<h:form name="selectForm">
<h:panelGrid columns="5" style="padding: 2px;">
<h:outputText style="text-align: center" value="Node Select " />
<h:selectOneMenu id="nodes" value="#{MyBacking.chosenNode}">
<f:selectItems value="#{MyBacking.nodes}" />
</h:selectOneMenu>
<h:commandButton value="Retrieve" styleClass="ctrlBtn"
id="retrieveBtn" style="margin-bottom: 2px;"
action="hello"
image="/img/btnRetrieve26.png" />
</h:panelGrid>
</h:form>
</rich:toolBarGroup>
</rich:toolBar>
</h:form>
It's as simple as that. Can anyone tell me why it's not working?
As far as I'm aware, the from-outcome of hello should be used by the h:commandbutton and load next.xhtml file.
Your files are .xhtml not .jsf
have you tried:
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-outcome>hello</from-outcome>
<to-view-id>/next.xhtml</to-view-id>
</navigation-case>
</navigation-rule>