Set instance variables of ManagedBean from database after login - jsf

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).

Related

How to get the values from multiple dynaforms?

I have been following this tutorial
http://www.primefaces.org/showcase-ext/sections/dynaform/basicUsage.jsf
I have been able to create tree Dynaform objects and send it to the page. But I am having a hard time obtaining the values that the user entered once they clicked submit. I want to be able to get these values in the backbean.
Here is submit button
<p:commandButton value="Submit" action="#{dynaFormController.submitForm}"
process="dynaForm" update=":mainForm:dynaFormGroup :mainForm:inputValues"
oncomplete="handleComplete(xhr, status, args)"/>
<p:commandButton type="reset" value="Reset" style="margin-left: 5px;"/>
I know the submit calls this function
<h:outputScript id="dynaFormScript" target="body">
/* <![CDATA[ */
function handleComplete(xhr, status, args) {
if(args && args.isValid) {
PF('inputValuesWidget').show();
} else {
PF('inputValuesWidget').hide();
}
}
/* ]]> */
</h:outputScript>
Then in the bean we have:
public String submitForm() {
FacesMessage.Severity sev = FacesContext.getCurrentInstance().getMaximumSeverity();
boolean hasErrors = (sev != null && (FacesMessage.SEVERITY_ERROR.compareTo(sev) >= 0));
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("isValid", !hasErrors);
return null;
}
How would I be able to get either the fields values from the submitted form?
I have 3 dynaforms that I would like to submit them and be able to get the values in the back bean. Can anyone explain? I tried looking up some tutorials but I didn't find any explaining this.
Thanks.
It's the same as plain JSF.
You need a variable in your bean, its getters and setters.
Then, you compare it to the DynaFormControl.
#ManagedBean
#SessionScoped
public class DynaFormController implements Serializable {
private static final long serialVersionUID = 1L;
private DynaFormModel model;
private BookProperty bookProperty;
public String getBookProperty() {
return bookProperty;
}
public void setBookProperty(BookProperty bookProperty) {
this.bookProperty = bookProperty;
}
public String submitForm() {
//your code
List<DynaFormControl> controls = model.getControls();
for (DynaFormControl control : controls) {
if(control.getData() instanceof BookProperty) {
BookProperty bp = (BookProperty) c.getData();
//use the object
}
}
return null;
}
}

am i using correct way of JSF coding?

I'm new in JSF. Can i use this way of coding instead of using EL in JSF view? and correct me if there is something wrong in my coding or should i use better way.
#Named
#RequestScoped
public class RegistrationBacking extends Root {
#EJB
private UserManagerLocal userManager;
public String register(){
Map<String, Object> parameterMap = getRequestMap();
User user = new User();
user.setUserName((String) parameterMap.get("userName"));
user.setPassword((String) parameterMap.get("password"));
user.setEmail((String) parameterMap.get("email"));
try{
userManager.registerUser(user);
} catch(UserExistsException ex) {
Logger.getLogger(RegistrationBacking.class.getName()).log(Level.SEVERE, null, ex);
getContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getBundle().getString("loginExist"), ex.getMessage()));
return null;
} catch(Exception ex) {
Logger.getLogger(RegistrationBacking.class.getName()).log(Level.SEVERE, null, ex);
getContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, getBundle().getString("loginError"), ex.getMessage()));
return null;
}
return "index";
}
}
No. You're basically manually grabbing the submitted values from the request parameter map instead of binding the input values to the model. You're manually filling the model in the controller's action method. You won't be able to perform JSF-managed Conversion and Bean Validation on those inputs.
The right way is the following:
<h:form>
<h:inputText value="#{registrationBacking.user.userName}" />
<h:inputSecret value="#{registrationBacking.user.password}" />
<h:inputText value="#{registrationBacking.user.email}" />
<h:commandButton value="Register" action="#{registrationBacking.register}" />
</h:form>
And then in the backing bean:
private User user;
#PostConstruct
public void init() {
user = new User();
}
public String register {
try {
// ...
}
}
See also:
Passing a JSF2 managed pojo bean into EJB or putting what is required into a transfer object
Creating master-detail pages for entities, how to link them and which bean scope to choose
JSF Service Layer

How to get data from the controller model to the view

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.

JSF request scope with get parameter

i know there are many similar threads but no like mine:
I have a requestscope bean:
#ManagedBean
#RequestScoped
public class Bean implements Serializable{
private String username = ""; //managed by textbox
private String password = ""; //managed by textbox
private String id ="-";
//Load the Parameter as usual:
#PostConstruct
public void fetchParams(){
System.out.println("FETCH PARAMS");
FacesContext facesContext = FacesContext.getCurrentInstance();
String id = facesContext.getExternalContext().getRequestParameterMap().get("id");
if(id == null || id.length() == 0) return;
setId(id);
}
// getters & setters
public void doSomething(){ //executed when clicked on the sumbit-button on the jsf-site
StaticFunctions.doSomething(this);
}
}
The code does following:
it retrieves the get-parameter "id" and saves it into String id (confirmed by string.out....).
But when the method doSomething() is executed and the previously stored "id" is read and returns "-" (like nothing happened).
why is this so?
Your ManagedBean is #RequestScoped and will be destroyed at the end of the request. When doSomething() is executed the user submitted the form and started a new request.
So you should see "FETCH PARAMS" twice in the console because two Beans are created but for the second request id is null.
You can find a detailed explanation about the four JSF-Scopes here.

SessionScoped controller not working

EDIT:
Okay, so I tried setting a few console.writes to check what's happening... It seems my logout script is called upon navigation. But I don't call it anywhere except on my logout button.
Here is my template code:
<div class="navbar">
<div class="navbar-inner">
<ul class="nav">
<li class="active">Home</li>
<li>Races</li>
<li>Horses</li>
<h:panelGroup rendered="#{memberController.logged == true}">
<li>History</li>
<li>Logout</li>
</h:panelGroup>
<h:panelGroup rendered="#{memberController.logged == false}">
<li>Login</li>
<li>Create Account</li>
</h:panelGroup>
</ul>
</div>
</div>
Original message:
I'm creating a website for my school project (Java EE)... It's our first year doing so.
Now as this is evening school and only had a semester learning it, you might see that my way of doing things ain't the best out there :)
So to get started, I'm trying to create a login feature but instead of those hundered lines of security codes, we may use a simple session scoped member object.
So here you have a few of my classes:
Member class:
#Entity
#Table(name = "members")
public class Member implements Serializable {
//+ Getters, setters, HashCode and equals
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private long id;
private double money;
#NotNull(message = "Username cannot be null")
#Size(min = 4, message = "Username should be of minimum 4 characters")
private String userName;
#NotNull(message = "Password cannot be null")
#Size(min = 4, message = "Password should be of minimum 4 characters")
private String password;
#PostPersist
private void initDefault() {
this.money = 500;
}
}
MemberBean class:
#Stateless
public class MemberBean {
#PersistenceContext(unitName="HorseRacingPU")
private EntityManager em;
public Member getMember(long id){
return em.find(Member.class, id);
}
public Member getMember(String username, String password){
TypedQuery<Member> q = em.createQuery("SELECT u FROM Member u WHERE u.userName=?1 AND u.password=?2", Member.class);
q.setParameter(1, username);
q.setParameter(2, password);
return q.getSingleResult();
}
public List<Member> getAllMembers(){
TypedQuery<Member> q = em.createQuery("SELECT u FROM Member u", Member.class);
return q.getResultList();
}
public Member addOrUpdateMember(Member u){
Member original = em.find(Member.class, u.getId());
if(original == null){
em.persist(u);
return u;
}else{
return em.merge(u);
}
}
public Member deleteMember(long id){
Member original = em.find(Member.class, id);
if(original != null){
em.remove(original);
}
return original;
}
}
MemberController class:
#SessionScoped
public class MemberController implements Serializable {
#EJB
private MemberBean bean;
private String username;
private String password;
private Member member;
private boolean logged = false;
// + their getters and setters
public List<Member> getAllMembers() {
return bean.getAllMembers();
}
public String login() {
member = bean.getMember(username, password);
if (member != null) {
logged = true;
return "/races/list.xhtml?faces-redirect=true";
}
return "/users/login.xhtml?faces-redirect=true";
}
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/index.xhtml?faces-redirect=true";
}
public void checkLogin(ComponentSystemEvent e) {
if (!logged) {
FacesContext context = FacesContext.getCurrentInstance();
ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
handler.performNavigation("/users/login.xhtml?faces-redirect=true");
}
}
public Member getMember() {
return member;
}
public void submit() {
bean.addOrUpdateMember(member);
}
}
The main error I'm getting is the following:
INFO: Exception when handling error trying to reset the response.
A more specific detail error can be found here: http://pastebin.com/h5nTNnes
So what happens is that when I login, everything works great. The moment I navigate to another url (after being forwarded to /races/list) I get logged out. The error itself shows when I use the checkLogin():
<f:event type="preRenderView" listener="#{memberController.checkLogin}" />
I'm not sure whether this is related, but when I login without any demo data (or with wrong credentials) I get an evaluation exception and that no entity could be retrieved.
Here more details: http://pastebin.com/Tv9mQ1K9
What could this be? I scratched my head for 3 days now and can't seem to find an issue anywhere.
This,
<li>Logout</li>
is not right.
The onclick attribute should reference a JavaScript handler. E.g. alert('peek-a-boo');. JSF/EL treats it as a plain vanilla string and expects that the logout() method returns some JavaScript code as String which should then be inlined in the HTML result. Imagine that the method actually returned alert('peek-a-boo');, then the final result (as you see in browser by rightclick, View Source) would be this:
<li>Logout</li>
However, in your particular case you're actually performing a logout and returning a string value of /index.xhtml?faces-redirect=true. So the generated HTML ends up being
<li>Logout</li>
Which is invalid JS code. But that's not the major problem: the user is been logged out without clicking the link!
You need a fullworthy JSF command component instead. E.g. <h:commandLink>.
<li><h:form><h:commandLink value="Logout" action="#{memberController.logout()}"/></h:form></li>
The method is this way only invoked when the link is actually clicked, which is exactly what you need.

Resources