0

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());
        }
}
Jumpman
  • 145
  • 1
  • 2
  • 11
  • You should not set all individual fields in the session, you should create an object and put that in the session... – Kukeltje Apr 18 '18 at 09:01
  • @Kukeltje So you mean I should create a Customer object with the firstname, lastname, email, password, etc. and then do I place this object in the managed bean? So what attributes should be in the bean? Is it just the email and password? – Jumpman Apr 18 '18 at 09:50
  • Yes that is correct. See https://stackoverflow.com/questions/30639785/jsf-controller-service-and-dao/ and all referenced questions in there. Oh and learn about JPA... This: `con = DataConnect.getConnection(); ps = con.prepareStatement("SELECT * FROM customer WHERE email = ? AND password = ?"); ps.setString(1, email); ps.setString(2, password);` is very, very 1999.... – Kukeltje Apr 18 '18 at 10:14
  • We talk about JSF here, the idea is to have the model on the backend and have a roundtrip for each action - so no need to store anything in the session, but rely on the backing bean content. – Alexander Rühl Apr 18 '18 at 10:18

1 Answers1

0

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

Alexander Rühl
  • 6,769
  • 9
  • 53
  • 96
  • The problem with trying to set the variables after I submit is that I am not sure how to get the same instance of the bean as when the user inputs the email/password. So once the user inputs their credentials, an instance of the managed bean is created, yes? I have a DAO that queries the database (I've added the code in my post) but how do I access the same instance of the bean in the DAO so I can set the firstname, lastname, etc.? That's the main part I am confused about. – Jumpman Apr 18 '18 at 08:47
  • Your DAO query is part of your model which holds all the fields. When you return from your validate method, you don't return boolean and not the result set from the database, instead use JPA here and query for an object, e.g. Customer). Then you store the new object or individual fields from it in the model. By linking them via EL expressions to your view (e.g. #custBean.firstname}, it will be displayed after returning from the button click and display the new view or update the old. Since you used SessionScoped for your custBean, you still have the same instance and the data will be there. – Alexander Rühl Apr 18 '18 at 10:16
  • When you say "store the new object or individual fields from it in the model" do you mean store the Customer object as a managed bean? So the JPA queries for 1 record representing 1 customer so then the Customer object returned can be used to initialize the rest of the attributes of the already existing CustomerManagedBean? Do you think you can provide some sample code as to how this can be accomplished? – Jumpman Apr 18 '18 at 21:12
  • @Jumpman: I think you just need to have some basics clarified: A managed bean ist just a plain old Java object and represents the business logic of your web page. It can hold any members and provide them via getters and setters like every other Java class. So, when you query an object from the database, e.g. Customer, just store it in a member private Customer myCustomer; provide getter/setter. If you don't need the wohle Customer in your logic, you may as well store only certain fields, e.g. private String name; Up to here, it's nothing JSF-specific, just plain Java object oriented.... – Alexander Rühl Apr 19 '18 at 06:25
  • ...Now you can connect your view with the member fields via EL expressions in input/output elements, e.g. #{custBean.myCustomer.name}, which uses your getters/setters under the hood, display the current content of the member and sets newly input data. By specifying a scope, which survives several requests (like your SessionScope), you are guaranteed to get the same instance each time your request/response goes back and forth. – Alexander Rühl Apr 19 '18 at 06:29
  • @Jumpman: You will find tons of examples, doing CRUD like operations with JSF. Your keywords will be JSF 2 (not use any old 1.x stuff), CDI (use CDI managed components, not JSF managed), JPA (use entities and entity manager, no direct JDBC). – Alexander Rühl Apr 19 '18 at 06:35
  • So I've been reading up on how to use JPA. There weren't many good tutorials on it but I was able to implement something using JPA. So I'm using Netbeans and I used it to generate a Entity Class from Database, which gives me a Customer.java entity. Then I create a Session Bean from Entity Class, which gives me an AbstractFacade.java and a CustomerFacade.java used to interact with the DB. Then I had to create a CustomerController, which has CustomerManagedBean injected, which functions to add customers, validates, etc. Is this more or less the proper way to do it? I will updated my post above. – Jumpman Apr 23 '18 at 00:54
  • https://stackoverflow.com/questions/30639785/jsf-controller-service-and-dao – Kukeltje Apr 23 '18 at 05:28
  • @Jumpman: the example listed by Kukeltje is a good reference (as every post by user BalusC). Don't overcomplicate things, it's ok to separate view logic and business logic in 2 classes, but no need for extra facades or abstract classes. And no need to store single members if you operate on the whole customer anyway - just query for Customer (by named query or entity load) in the business class and store it with one setter as private Customer myCust; in your view controller class and finally reference it in the view with 2-step references like #{custBean.myCust.name} – Alexander Rühl Apr 23 '18 at 07:59