1

I have a @SessionScoped ManagedBean that I've injected into a @RequestScoped to access the user stored in the session. My code is working I just want to know if I'm using a good practice, if not can you tell me what's wrong please? Because I'm new to JSF and I don't want to learn some bad coding from the beginning, thank you very much in advance.

My Entity Utilisateur :

    @Entity
    public class Utilisateur {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long      id;
    @NotNull( message = "Veuillez saisir une adresse email" )
    @Pattern( regexp = "([^.@]+)(\\.[^.@]+)*@([^.@]+\\.)+([^.@]+)", message = "Merci de saisir une adresse mail valide" )
    private String    email;
    @Column( name = "mot_de_passe" )
    @NotNull( message = "Veuillez saisir un mot de passe" )
    @Pattern(regexp = ".*(?=.{8,})(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*", message = "Le mot de passe saisi n'est pas assez sécurisé")
    private String motDePasse;
    @NotNull( message = "Veuillez saisir un nom d'utilisateur" )
    @Size( min = 3, message = "Le nom d'utilisateur doit contenir au moins 3 caractères" )
    private String    nom;
    @Column( name = "date_inscription" )
    private Timestamp dateInscription;
//getters .. setters..
    }

My Entity Ferme :

@Entity
public class Ferme {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    @Column( name = "id_ferme" )
    private Long      id_ferme;
    @Column( name = "nom_ferme" )
    private String nom_ferme;
    @ManyToOne
    @JoinColumn( name = "utilisateur_id" )
    private Utilisateur utilisateur;

//getters .. setters..

}

My @Statless DAO :

@Stateless
public class UtilisateurDao {
 @PersistenceContext( unitName = "myBD_PU" )
    private EntityManager       em;

 public List<Ferme> lister( Utilisateur user) throws DAOException {
        try {
            TypedQuery<Ferme> query = em.createQuery( "SELECT u FROM Ferme u WHERE u.utilisateur = :userid", Ferme.class );
            query.setParameter("userid", user);

            return query.getResultList();
        } catch ( Exception e ) {
            throw new DAOException( e );
        }
    }
}

My LoginBean :

    @ManagedBean
    @SessionScoped
    public class LoginBean implements Serializable {

        private static final long serialVersionUID = 1L;

        private String email,mdp;
        private Utilisateur user;
        private boolean LoggedIn;
        @EJB 
        UtilisateurDao utilisateurDao; 

        // getters .. setters



public String authentification() {

    if (utilisateurDao.login(email, mdp) != null) {
        user = utilisateurDao.login(email, mdp);
        LoggedIn = true;
        return "listeFermes.xhtml?faces-redirect=true";
    }
    LoggedIn = false;
    FacesMessage message = new FacesMessage( "E-mail ou Mot de passe incorrecte!" );
    FacesContext.getCurrentInstance().addMessage( null, message );

    return "";
}

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "/login.xhtml?faces-redirect=true";
}
     }

My ListeFermesBean :

    @ManagedBean
    @RequestScoped
    public class ListeFermesBean implements Serializable{

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        @ManagedProperty(value="#{loginBean}")
        private LoginBean loginBean;

        @EJB
        UtilisateurDao utilisateurDao;

        private Utilisateur user;
        private List<Ferme> liste;

public List<Ferme> getListe() {
        liste = new ArrayList<Ferme>();
        user = loginBean.getUser();
        return  liste = utilisateurDao.lister(user);
    }
    }

Login.xhtml :

<!DOCTYPE html>
<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:form id="Login">
         <fieldset>
            <legend>Login</legend>
            <h:outputLabel for="email">Adresse email <span class="requis">*</span></h:outputLabel>
            <h:inputText id="email" value="#{loginBean.email}" size="20" maxlength="60">
            </h:inputText>
            <h:message id="emailMessage" for="email" errorClass="erreur" />
            <br />

            <h:outputLabel for="motdepasse">Mot de passe <span class="requis">*</span></h:outputLabel>
            <h:inputSecret id="motdepasse" value="#{loginBean.mdp}" size="20" maxlength="20">
            </h:inputSecret>
            <h:message id="motDePasseMessage" for="motdepasse" errorClass="erreur" />
            <br />

            <h:messages globalOnly="true" infoClass="erreur" />

            <h:commandButton value="Login" action="#{loginBean.authentification}" styleClass="sansLabel">
            </h:commandButton>
            <br />
            <h:commandButton value="Logout" action="#{loginBean.logout}" styleClass="sansLabel" />
            <br />
            <h:link value="Inscrivez-vous" outcome="inscription" />



          </fieldset>
        </h:form>   
    </h:body>
</html>

And finally the listeFermes.xhtml page which displays the List from listeFermesBean by User id stored in the object User in the session.

<!DOCTYPE html>
<html lang="fr"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:c="http://java.sun.com/jstl/core">
    <h:head>
        <title>SUCCES</title>
    </h:head>
    <h:body>

        <ui:fragment rendered= "#{!loginBean.loggedIn}">
        Not logged !
        </ui:fragment>
        <ui:fragment rendered= "#{loginBean.loggedIn}">
        Welcome : #{loginBean.user.nom} <br />
        E-mail : #{loginBean.user.email} <br />

        <table border="1">
        <tr>
            <td>Nom Ferme</td>
            <td>Nom User</td>
            <td>ID User</td>
        </tr>
        <c:forEach items="#{ listeFermesBean.liste }" var="x">
        <tr>
            <td>#{x.nom_ferme}</td>
            <td>#{x.utilisateur.nom}</td>
            <td>#{x.utilisateur.id}</td>
        </tr>
        </c:forEach>      
        </table>
        </ui:fragment>

    </h:body>
</html>
Dwix
  • 1,139
  • 3
  • 20
  • 45
  • I'd use CDI instead of JSF (`@Named` instead of `@ManagedBean`, `@Inject` instead of `@ManagedProperty` and scopes - it's newer technology) and I would not inject `@EJB` into `@RequestScoped` but I'd create this method in `@SessionScoped` and delegate call to it. With `@Stateless` it is not a problem but it will be if you use `@Stateful`. – Geinmachi Oct 03 '15 at 15:05
  • @Geinmachi Thank you for your advice. So if I did understand, you're saying that I shouldn't inject EJB in both SessionScoped and RequestScoped, but instead I should create all the methods that use the "User" object from the session into the SessionScoped, and then I can call them in the RequestScoped Bean ? – Dwix Oct 03 '15 at 15:30
  • Yes, here is thread about injecting `@Stateful` into `@RequestScoped` so you can have an idea what I was talking about. http://stackoverflow.com/questions/4562941/problem-using-stateful-ejb-in-managedbean-with-requestscope – Geinmachi Oct 03 '15 at 15:40
  • @Geinmachi Ok, thanks a ton for your help! – Dwix Oct 03 '15 at 15:46
  • TL;DR : injecting a wider scoped JSF managed bean into a narrower scoped JSF managed bean is a legal game. The reverse is however, untrue. In other words, injecting a session scoped JSF managed bean into a request scoped JSF managed bean is perfectly legal. – Tiny Oct 03 '15 at 16:53
  • @Tiny Thanks for your help :) – Dwix Oct 04 '15 at 10:49
  • With cdi managed beans this is different. You can do injection both ways. – Kukeltje Oct 06 '15 at 08:01

2 Answers2

2

As said in the comment you should use cdi injection. I believe this is a big no no as well:

public List<Ferme> getListe() {
        liste = new ArrayList<Ferme>();
        user = loginBean.getUser();
        return  liste = utilisateurDao.lister(user);
    }

You should not do any business intensive things in your getters/setters. The reason is those can be called multiple times in the background.

Instead you should call your services in a method that is called AFTER the service has been injected.

@PostConstruct
public void init(){
    listeFerm = utilisateurDao.lister(user);
}
public List<Ferm> getListFerm(){
   return listFerm;
}

You didn't post your auth method(probably on purpose though).

Reguarding your Auth system you said you will deal with this after but still you don't need to go through the DAO with that. You should read about JAAS in the doc which is how to deal with this automatically then you don't need to go through a service and you can authenticate users in the bean. ie: Request.login(username, password) if my memory serves me right. You have to read about the subject though, you should use hash + salt when authenticating users.

Ced
  • 15,847
  • 14
  • 87
  • 146
  • Thank you for your answer, my loginBean is now like this (in the new answer above) I can't add it in this comment. – Dwix Oct 05 '15 at 22:55
  • I've posted again my authentification method ( in my new answer for you above ) if that's what you were talking about. Thanks in advance :) – Dwix Oct 05 '15 at 23:17
  • @dwix Are you planning on storing passwords as plain text ? Because that's how you lose every user passwords. When you post additional code you should just edit your main question. I'm gonna edit my post in reguards to your new code. Then you can accept my answer as it helped you (clicking the v). Also an upvote is welcome for internet points. – Ced Oct 06 '15 at 00:02
  • No I'll deal with the password later, thanks! and I'll vote to let you know if it helped :) – Dwix Oct 06 '15 at 00:08
  • @dwix I'll still edit my post because there are things wrong with your code.1 second – Ced Oct 06 '15 at 00:09
  • And the UtilisateurDao.lister(user) (injected Stateless) in the PostConstruct is not working, so the list is always empty. I think the dao call should stay in the getter method ? – Dwix Oct 06 '15 at 00:14
  • @dwix You should absolutly NOT keep the database call in the getter. It's a big no, no. http://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times – Ced Oct 06 '15 at 00:21
  • @dwix The service in the postconstruct should be called. You have to change the packages of sessionScoped, requestScoped and viewscoped if you didn't already did it. – Ced Oct 06 '15 at 00:24
  • Ok, and yes I did change the packages to (javax.enterprise.context) everything was working till I used the Dao.lister() in the PostConstruct. and I'm waiting for your advice about the code that added below about the delete/add methods in the sessionScoped bean and about re-calling them in the requestScoped bean :) – Dwix Oct 06 '15 at 00:28
  • @dwix si tu veux on peut aller sur le chat, je vois pas quand tu calls addFerme – Ced Oct 06 '15 at 00:34
  • je n'ai pas assez de "reputation" pour utiliser le chat, désolé. Regarde le code que j'ai ajouté dans ma deuxième réponse au sujet ( au dessous ) j'ai la méthode 'addFerme" dans le loginBean et une autre méthode addFerme dans le requsetScoped bean, et cette dérnière ne fait qu'appeler la méthode addFerme du loginBean, quelqu'un m'a dit de faire comme ça mais je ne vois pas vraiment l'utilité, – Dwix Oct 06 '15 at 00:38
  • I'm not sure what you want to do exactly there is not the whole code. My conclusion is that PostConstruct is to load data in your bean. You can access another bean data by Injecting it in another bean then calling the getters. There is missing code here and here I think in the post and I can't redo the whole code for you, I ain't paid. But I think I gave you some things to search like postConstruct and Inject. Do not do any business intensive in the getters /setters though. I hope I helped. I need to sleep. – Ced Oct 06 '15 at 00:41
  • @dwix jvois pas ce que tu veux faire avec addferme ca m'as l'air mauvais. Ca fait quoi en gros addFerme ? C'est appellé quand ? C'est des fermes créés par l'utilisateur ? Ou tu veux créer une ferme a chaque fois qu'un user se connecte ? – Ced Oct 06 '15 at 00:41
  • J'ai une méthode void "creerFerme( Ferme ferme, Utilisateur user )" dans le dao, je l'appelle dans le loginBean, ça crée une ferme pour l'utilisateur connecté par un formulaire, et j'appelle la méthode sur la vue ( action="#{loginBean.addFerme}" ) And I'm not asking you to give me the answer for everything, you can help me as you like and when you like, sorry if I wasn't clear before. – Dwix Oct 06 '15 at 00:48
  • Choisi dans quelle bean tu mets cette method. La mettre dans une bean pour en appeller une autre n'a aucun sens. Cela dit ton utisateur n'est plus le meme que celui que tu as en DB car celui qui est en DB a une ferme de plus (celle que tu ajoutes) alors soit ajoute la a la liste ou reload ton utilisateur si tu veux qu'il soit raffraichit (si c'est important si par exemple tu utilise #{loginbean.user.fermes} qlq part). – Ced Oct 06 '15 at 00:54
  • 1
    D'accord, merci beaucoup pour ton aide! – Dwix Oct 06 '15 at 00:57
  • @dwix Derien. Si tu sais upvotes aussi ca me ferait plaisir. bonne nuit;) – Ced Oct 06 '15 at 01:03
  • Pas assez de réputation pour upvote :s, mais j'ai marqué ta réponse comme "accepté" – Dwix Oct 06 '15 at 01:09
0
@Named
@SessionScoped
public class LoginBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private String email,mdp;
    private Utilisateur user;
    private boolean LoggedIn;
    private List<Ferme> liste;
    private Ferme ferme = new Ferme();
    @Inject
    UtilisateurDao utilisateurDao; 



    public Ferme getFerme() {
        return ferme;
    }
    public void setFerme(Ferme ferme) {
        this.ferme = ferme;
    }
    public void setListe(List<Ferme> liste) {
        this.liste = liste;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getMdp() {
        return mdp;
    }
    public void setMdp(String mdp) {
        this.mdp = mdp;
    }
    public Utilisateur getUser() {
        return user;
    }
    public void setUser(Utilisateur user) {
        this.user = user;
    }
    public boolean isLoggedIn() {
        return LoggedIn;
    }
    public void setLoggedIn(boolean loggedIn) {
        LoggedIn = loggedIn;
    }


    public String authentification() {

        if (utilisateurDao.login(email, mdp) != null) {
            user = utilisateurDao.login(email, mdp);
            LoggedIn = true;
            return "listeFermes.xhtml?faces-redirect=true";
        }
        LoggedIn = false;
        FacesMessage message = new FacesMessage( "Wrong E-mail or Password!" );
        FacesContext.getCurrentInstance().addMessage( null, message );

        return "";
    }



public String logout() {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("You are disconnected!"));
            ExternalContext externalContext = context.getExternalContext();
            externalContext.getFlash().setKeepMessages(true);
            externalContext.invalidateSession();

            return "/login.xhtml?faces-redirect=true";
        }

    public void deleteFerme(int id) {
            utilisateurDao.supprimerFerme(user, id);
        }

        public void addFerme() {
            utilisateurDao.creerFerme(ferme, user);
        }

        public List<Ferme> getListe() {
        return liste;
    }

    @PostConstruct
    public void init(){
        liste = utilisateurDao.lister(user);
    }

// Should I declare my Ferme and then initilize it new Ferme(); in the @PostConstruct too ? or leave it like it is ? // & should I use the CRUD methods that use my "User" object stored in the session, in the @SessionScope bean? and then call the methods in my @RequestScoped bean? like this :

@SessionScope
public class LoginBean {

    ..
    ..
    public void addFerme() {
    utilisateurDao.creerFerme(ferme, user);
}
    }


    //////..... and then in the RequestScoped bean :

@RequestScoped
    ..
    ..
    @Inject
    private LoginBean loginBean;

    public void addFerme() {

            loginBean.addFerme();
        }

// login Method

@Stateless
public class UtilisateurDao {

@PersistenceContext( unitName = "MyBD_PU" )
    private EntityManager       em;

public Utilisateur login(String email, String mdp) throws DAOException {
        Utilisateur user = null;
        Query requete = em.createQuery( JPQL_LOGIN );
        requete.setParameter( PARAM_EMAIL, email ).setParameter(PARAM_PWD, mdp);

        try {
            user = (Utilisateur) requete.getSingleResult();
            if (user!=null) {
                return user;
            }
            return null;
        } catch ( NoResultException e ) {
            return null;
        } catch ( Exception e ) {
             FacesMessage message = new FacesMessage( FacesMessage.SEVERITY_ERROR, e.getMessage(), null );
             FacesContext facesContext = FacesContext.getCurrentInstance();
             facesContext.addMessage( null, message );
        }
        return user;

    }

}
Dwix
  • 1,139
  • 3
  • 20
  • 45