How to get data from the controller model to the view - jsf

hi guys sorry to post again but this is really confusing me
i have a query that i can get to run, the user enters a string and then the application will search for this in the database connected to the application, this bit i have working, however now i have successfully run the queury i am unsure of how to retrieve the data from it and be able to use it in the view in a h:datatable
currently to do the search, this is what is in the view, the faclet page the user enters
<h:inputText id="search" value="#{userdetailsController.search}" />
<p:commandButton value="Search" action="#{userdetailsController.submit}" ajax="true" />
this then goes to
#Named("userdetailsController")
#SessionScoped
public class UserdetailsController implements Serializable {
#EJB
private String search;
private List<Userdetails> item; // No need for DataModel here.
public String submit() {
item = ejbFacade.searchByString(search);
return ""; //change this !, testing only
}
public String getSearch() {
return search;
}
public void setSearch(String search) {
this.search = search;
}
then
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
private List userList;
/* trying out a search function */
public List<T> searchByString(String string) {
System.out.println("in SearchByString");
return getEntityManager().createNamedQuery("Userdetails.findByUsername").setParameter("username", "%" + string + "%").getResultList();
}
which does the search in
#Entity
#Table(name = "USERDETAILS")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Userdetails.findAll", query = "SELECT u FROM Userdetails u"),
#NamedQuery(name = "Userdetails.findById", query = "SELECT u FROM Userdetails u WHERE u.id = :id"),
#NamedQuery(name = "Userdetails.findByUsername", query = "SELECT u FROM Userdetails u WHERE u.username = :username")})
How can i once this process has been completed retrieve the data to print out in the console for example, what do i need to call to do this ?

i am unsure of how to retrieve the data from it
Your code already does that in the submit() method.
and be able to use it in the view in a h:datatable
Just add the following to your view, maybe below the command button in the same form, in order to present it:
<h:dataTable value="#{userdetailsController.item}" var="userdetails">
<h:column>#{userdetails.username}</h:column>
</h:dataTable>
And make sure that this is covered in the ajax update of the command button:
<p:commandButton ... update="#form" />
Unrelated to the concrete problem, I'd only rename the confusing property name item to items as it represents a collection of items, not a single item. Also, your submit() method doesn't need to return an empty string. It can also just be declared void. Also, ajax="true" is the default already for <p:commandButton>, you can just omit it.

Related

Set instance variables of ManagedBean from database after login

I am starting to learn JSF and I am not sure if this is the right approach, but what I want to do is allow a user to login and validate from a database and then have a welcome message with the user's first name e.g. Welcome Bob. The database will have all the user info and login will consist of only the email and password.
Currently I have a ManagedBean with all the getters and setters plus a validation method, which calls a method in the DAO.
#Named(value = "custBean")
#SessionScoped
public class CustomerManagedBean implements Serializable {
/**
* Creates a new instance of CustomerManagedBean
*/
public CustomerManagedBean() {
}
private int custId;
private String firstname;
private String lastname;
private String email;
private String password;
private String address;
private String city;
private String state;
private int zip;
public int getCustId() {
return custId;
}
public void setCustid(int custId) {
this.custId = custId;
}
// More getters/setters here, not shown
public String validateEmailPassword() {
boolean valid = LoginDAO.validate(email, password);
if (valid) {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
session.setAttribute("email", email);
session.setAttribute("firstname", firstname); // I can't set this because user did not input this on login so how do I set it from database?
session.setAttribute("lastname", lastname); // and this
session.setAttribute("address", address); // and this
session.setAttribute("state", state); // and this
session.setAttribute("zip", zip); // and this
return "index";
} else {
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_WARN,
"Incorrect Email and Password",
"Please enter correct Email and Password"));
return "login";
}
}
Login.xhtml is very simple
<h:form>
<h3>Login</h3>
<h:outputText value="Username" />
<h:inputText id="username" value="#{custBean.email}"></h:inputText>
<h:message for="username"></h:message>
<br></br>
<h:outputText value="Password" />
<h:inputSecret id="password" value="#{custBean.password}"></h:inputSecret>
<h:message for="password"></h:message>
<br></br>
<h:commandButton action="#{custBean.validateEmailPassword}" value="Login"></h:commandButton>
</h:form>
Am I correct in that the bean gets initialized in the login.xhtml by user input on #{custBean.email} and #{custBean.password}? So can I set that bean's other variables after a database call? I hope I am making sense, but what I am able to do is after I login, I'm able to have #{custBean.email} displayed. It's just the firstname and the others I'm not able to show.
Here's my validate method in my DAO.
public static boolean validate(String email, String password) {
Connection con = null;
PreparedStatement ps = null;
try {
con = DataConnect.getConnection();
ps = con.prepareStatement("SELECT * FROM customer WHERE email = ? AND password = ?");
ps.setString(1, email);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return true;
}
} catch (SQLException ex) {
System.out.println("Login error -->" + ex.getMessage());
return false;
} finally {
DataConnect.close(con);
}
return false;
}
UPDATE
I added an Customer entity from database and a CustomerController along with a generic AbstractFacade and CustomerFacade generated by Netbeans. My CustomerController is below. Is this a better way to interact with the DB?
#Named(value = "customerController")
#SessionScoped
public class CustomerController implements Serializable {
#EJB
CustomerFacade custFacade;
#Inject
CustomerManagedBean custBean;
public CustomerController() {
}
public String validateCustomer() {
Customer c = new Customer();
c = custFacade.getValidUser(custBean);
if (c != null) {
custBean.setEmail(c.getEmail());
custBean.setFirstname(c.getFirstname());
custBean.setLastname(c.getLastname());
custBean.setAddress(c.getAddress());
custBean.setCity(c.getCity());
custBean.setState(c.getState());
custBean.setZip(c.getZip());
}
}
The basic idea is, that you hold your model within your java class and link the model's values to your XHTML page via EL expressions.
So you can either get variables in your model filled from input elements of your page after submit or set them in your backend code and display them, both by having the value attribure reference your models member (which will go via getter/setter).
Your model gets initialized depending on the context you choose. As you went with SessionScope, it will be initialized on first usage and last as long as your HTTP session will last. In the meantime, you can for example read input after submitting your login data, query a database, fill your other members accordingly and display more data on this or another page, so in other words you have several roundtrips between your browser and your backend bean.
In your backing bean you don't have to fill any session attributes, you just fill your own model members after e.g. a database call and your index view (which I assume holds output elements for the data) will display the newly set model data when referred by EL expressions (just like you did with your input elements values).

Primefaces tree and how to navigate based on TreeNode leaf entity ID

I have 3 entities - markets, topics and items. Markets is the parent of topics which is the parent of items. I'm hoping to find a simple way to invoke an action by selecting a value from the the final child node (items) and being taken to the page where the selected item can be viewed. The JSF:
<p:tree value="#{treeTestBean.treeTest}" var="tree"
dynamic="true"
selectionMode="single"
selection="#{treeTestBean.selectednode}">
<p:ajax event="select" listener="#{treeTestBean.onNodeSelect}"/>
<p:treeNode>
<h:outputText value="#{tree}"/>
</p:treeNode>
</p:tree>
The managed bean:
#Named(value = "treeTestBean")
#SessionScoped
public class TreeTestBean implements Serializable {
private TreeNode treetest;
private TreeNode selectednode;
private TreeNode node0;
private TreeNode node1;
private TreeNode node2;
private List<Enmarkets> markList;
private List<Entopic> topList;
private ListDataModel<Enitem> itList;
private Enitem selItem;
public TreeNode getTreeTest() {
treetest = new DefaultTreeNode("Root", null);
markList = rootFacade.findAll();
for (Enmarkets m : markList) {
node0 = new DefaultTreeNode(m.getMarketname(), treetest);
int marketid = m.getMarketid();
topList = topfac.marketTopNorm(marketid);
for (Entopic t : topList) {
node1 = new DefaultTreeNode(t.getTopicname(), node0);
int topicid = t.getTopicid();
itList = itfac.itemFroTopic(topicid);
for (Enitem i : itList) {
node2 = new DefaultTreeNode(i.getItemname(), node1);
}
}
}
return treetest;
}
The onNodeSelect method used in the ajax is also in the managed bean. If the selected node is a leaf it will search the item name and return that in the navigated page:
public void onNodeSelect(NodeSelectEvent event) {
this.setSelectednode(event.getTreeNode());
String somekey = selectednode.getRowKey();
if(selectednode.isLeaf()){
String itemName = selectednode.getData().toString();
// Standard JPA call to search for item name here (omitted because this is not how i want to do it)
FacesContext
.getCurrentInstance()
.getApplication()
.getNavigationHandler()
.handleNavigation(FacesContext.getCurrentInstance(), null, "/Main/Starter.xhtml?faces-redirect=true");
}
else {
doNothing();
}
}
onNodeSelect is supposed to search the item name and navigates to the page with details of the selected item. The above method does this by searching for the Item name String and matching this to the name in a list of the item entity values created from the persistence layer. This will allow matching the selectednode String to the correct item name, so that the navigated jsf page is populated with the entity details (for example using a standard h:outputText tag). For several reasons, i prefer to search based on the entity ID instead of a String.
Comments from Kukeltje greatly helped me in the right direction. First I include a Map(String, int) when creating the leaf node:
for (Enitem i : itList) {
node2 = new DefaultTreeNode(i.getItemname(), node1);
String rowK = node2.getRowKey();
int itid = i.getItemid();
rowMap.put(rowK, itid);
Then, in the onNodeSelect method I use this map to match the rowKey of the selectednode to the corresponding entity Id:
public void onNodeSelect(NodeSelectEvent event) {
if(selectednode.isLeaf()){
String rKey = selectednode.getRowKey();
if(rowMap.containsKey(rKey)) {
String xKey = rowMap.get(rKey).toString();
Integer rKeyint = Integer.parseInt(xKey);
selItem = itfac.find(rKeyint);
FacesContext
.getCurrentInstance()
.getApplication()
.getNavigationHandler()
.handleNavigation(FacesContext.getCurrentInstance(), null, "/Main/Client/ItemDetails.xhtml?faces-redirect=true");
}
}
else {
doNothing();
}
This navigates to the page showing the detail of the selected node leaf. I suspect there might be an easier or more efficient way of doing this and would welcome any views. Like, I don't know if it's really necessary to make the string to integer conversions and I didn't think through a simpler way.
For now, this seems to solve my concrete problem. thanks

List<Object []> in JSF dataTable

I have two entities , Employee and publication :
I want to show in a data table the publication title, date, and it's author stored in database :
this is my query using JPQL :
private static EntityManager em;
private static EntityManagerFactory factory;
public PublicationDAO() {
if(factory==null)
factory=Persistence.createEntityManagerFactory("mavenTest");
if(em==null)
em=factory.createEntityManager();
}
public List<Object[]> getAllPublication() {
em.getTransaction().begin();
List<Object[]> pubs = em.createQuery("SELECT c.titrePublication, p.login FROM Publication c JOIN c.employee p ").getResultList();
em.getTransaction().commit();
return pubs;
}
so I want to show this information in XHTML page's data table.
Currently the query would return Array and what you need is a Construct return type..
create custom class (this will be your return type and it must have constructor which takes result values you define in query string. )
public class publicationModel
{
public String publicationName;
public String author;
public publicationModel (String publicationName, String author)
{
this.publicationName= publicationName;
this.author= author;
}
}
use typedQuery
String queryStr ="SELECT NEW example.publicationModel (c.titrePublication, p.login) " +
"FROM Publication c JOIN c.employee p ";
TypedQuery query =
em.createQuery(queryStr, publicationModel .class);
List <publicationModel> results = query.getResultList();
m not able to format the answer.. but i hope this helps..
I wonder why you make the type of the list "array of objects". Rendering it as type of your entity class is enough :
public List<Publication> getAllPublication() {
...
List<Publication> pubs = ...
...
}
Specify a managedBean class in your presentation tier, to do the job :
#RequestScoped
#ManagedBean
public class PublicationBean {
// Inject your PublicationDAO here
private PublicationDAO publicationDao;
private List<Publication> publications;
#PostConstruct
public retrievePublications () {
try {
publications = publicationDao.getAllPublication();
} catch (Exception e) {
}
}
public List<Publication> getPublications() {
return this.publications;
}
public void setPublications(List<Publication> publications) {
this.publications= publications;
}
// getters/setters
}
Then, display the data with <h:dataTable> like this :
<h:dataTable value="#{publicationBean.publications}" var="p" rules="all">
<h:column>
<f:facet name="header">Publication title</f:facet>
#{p.titrePublication}
</h:column>
<h:column>
<f:facet name="header">Publication author</f:facet>
#{p.employee.name}
</h:column>
</h:dataTable>
hi finally I find the solution :
the correct query should be :
List<Publication>=em.createQuery("select p from Publication p",Publication.Class).getResultList();
in the managed bean I should declare The author which is The Employee entity with getter and setter.
then create a method called getAllpublications as :
public List<Publication> getAllpublications (){
publicationDao.getAllPublication();//this method is declared and specified in the DAO class
}
after that the xhtml page should look like:
<h:dataTable value="#{publicationBean.publications}" var="p" rules="all">
<h:column>
<f:facet name="header">Publication title</f:facet>
<h:outputText value="#{p.titrePublication}"></h:outputText>
</h:column>
<h:column>
<f:facet name="header">Publication author</f:facet>
<h:outputText value="#{p.employee.name}"></h:outputText>
</h:column>
</h:dataTable>
so the solution is very close to your answer Omar thanks a lot for your help.

JSF calling methods in JPA populated list

I have a database table with some oneToMany relations.
this is fragment of the entity:
#OneToMany(mappedBy="auction")
private List<Biding> bidings;
now i want to print higher bid on my jsf website:
<ui:repeat var="singleAuction" value="#{auctionListBean.auctionList}" varStatus="status">
<h:outputLabel value="#{singleAuction.getHigherBid()}"/>
</ui:repeat>
this my aucListBean
#ManagedBean
public class AuctionListBean
{
#PersistenceContext()
EntityManager entityManager;
public List<AuctionBean> getAuctionList() {
Query query = entityManager.createQuery("SELECT e FROM Auction e");
#SuppressWarnings("unchecked")
List<AuctionBean> resultList = (List<AuctionBean>) query.getResultList();
return resultList;
}
}
I also have AuctionBean class which I used before to add new auction. Now I want to create a bean which has one property: list of auctionBean. I populate it using my entity and cast it to AuctionBean. In AuctionBean class I implemented mentioned method:
public double getHigherBid()
{
double higherBid = 0;
for(Biding a : bidings)
{
if(a.getCurrentPrice() > higherBid)
higherBid = a.getCurrentPrice();
}
return higherBid;
}
The problem is "Method not found". It seems like it still dont even use AuctionBean class for some reason. It may be a problem why it cannot see the method. I am doing it right and where is the problem exactly? Could you help?
I have two suggestions:
1. Use singleAuction.higherBid, not singleAuction.getHigherBid()
2. Specify the target class of your query. Here's an example:
return entityManager.createQuery("SELECT e FROM Auction e", AuctionBean.class)
.getResultList();

Dynamic action construction

I have a basic JSF question. I have a loop where I am trying to create mutile command link depending on the list value. and that command link will call the corresponding action from the list filed.
Basically I have this bean:
public class FavoriteTasks implements Serializable {
private static final long serialVersionUID = -8702569738872927728L;
private String key;
private String action;
private String widget;
private String name;
public FavoriteTasks(String key, String action, String widget, String name) {
super();
this.key = key;
this.action = action;
this.widget = widget;
}
And then populating it using properties file:
private void setUpFavTasks(UserUIPreferencesVO uiPref) {
List<String> fTaskList = uiPref.getFavoriteTasks();
favTasks =new ArrayList<FavoriteTasks>();
for(String var:fTaskList){
FavoriteTasks ft = new FavoriteTasks(var,
ConfigurationData.getValue(var+".action"),
ConfigurationData.getValue(var+".widget"),
ConfigurationData.getValue(var+".name"));
favTasks.add(ft);
}
}
Now the issue is the action is not understanding that it needs to get the value first and read that and then make the method call depending on the value.
<ui:repeat value="#{userSessionBean.favTasks}" var="favTasks" >
<li><ice:commandLink styleClass="shortcut-menu" action="#{favTasks.action}">
<f:param name="filterByContentWidget" value="#{favTasks.widget}" />
<f:param name="filterByContentGroup" value="#{favTasks.key}" />
<f:param name="menuName" value="#{favTasks.name}" />
<h:outputText value="#{msgs[favTasks.key]}" />
</ice:commandLink>
</li>
</ui:repeat>
action is trying to get favTasks.action and failing as there are no such method. it needs to read the value stored in favTasks.action and then go to the method that value is saying... for example if the favTasks.action = catalogHandler.showCatalog. it needs to invoke catalogHandler.showCatalog not favTasks.action
The action attribute is used to indicate the next view when you click the commandLink. It is a method expression that returns a String.
For example:
public String method() {
//do something
return "success";
}
and in your commandLink as
<ice:commandLink value="Submit" action="#{bean.method}" />
when clicked will take you to success.xhtml
Also you need to declare public setters/getters you just can't get/set any private variables that you have in your code:
private String key;
private String widget;
private String name;

Resources