JSF-EJB Best Practices

hyperion

Bekanntes Mitglied
Hallo,

ich habe mir eine Beispielanwendung erstellt, die mittels JSF Eingaben vom Benutzer holt und diese in eine Tabelle einträgt. Da ich kein Profi in dem Gebiet bin, wollte ich Euch mal fragen, wie man das am besten macht.

Ich gehe einfach mal kurz den Weg von der Eingabe bis zur Tabelle durch:

Auszug aus dem jsf. Drei einfache Eingabefelder. Die Daten werden in ein outcomeBean gespeichert und wenn man auf den Button drückt, wird die Methode addOutcome aufgerufen.
HTML:
<h:form>
                    <h:panelGrid columns="2">
                        <h:outputLabel for="category">Category:</h:outputLabel>
                        <h:inputText id="category" value="#{outcomeController.outcomeBean.category}"/>
                        <h:outputLabel for="value">Value:</h:outputLabel>
                        <h:inputText id="value" value="#{outcomeController.outcomeBean.value}"/>
                        <h:outputLabel for="description">Description:</h:outputLabel>
                        <h:inputText id="description" value="#{outcomeController.outcomeBean.description}"/>
                    </h:panelGrid>
                    <h:commandButton value="addOutcome" action="#{outcomeController.addOutcome}" />
                </h:form>

outcomeController ist ein CDI-Bean. und hat das outcomeBean als Attribut, welches im Konstruktor erzeugt wird(ob man das so macht?). outcomeEJB welche die eigentliche Logik implementiert wird mit @EJB injected. Die harte Navigation mit Rückgabe "index.xhtml" ist vermutlich nicht so gut.
Java:
@Named
@RequestScoped
public class OutcomeController {
    
    @EJB 
    private OutcomeEJB outcomeEJB;
    private OutcomeBean outcomeBean;
    
    public OutcomeController(){
        outcomeBean = new OutcomeBean();
    }

...
    
    public String addOutcome(){
        outcomeEJB.addOutcome(outcomeBean);
        return "index.xhtml";
    }

outcomeBean ist ein POJO ohne jegliche Annotationen oder sonst was.
Java:
public class OutcomeBean {
    
    private String category;
    private String description;
    private double value;

   //Setter und getter...    
}

Die EJB sieht dann wie folgt aus. Erzeugt eigentlich nur das @Entity-Objekt(Outcome), setzt die Werte und macht den Eintrag.
Java:
@Stateless
public class OutcomeEJB {

    @PersistenceContext
    private EntityManager em;
      
    public boolean addOutcome(OutcomeBean outcomeBean){
         Outcome outcome = new Outcome();
        outcome.setCategory(outcomeBean.getCategory());
        outcome.setDescription(outcomeBean.getDescription());
        outcome.setValue(outcomeBean.getValue()); 
        em.persist(outcome);
          return true;
    }
}

Outcome noch:
Java:
@Entity
@Table(name = "OUTCOME")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Outcome.findAll", query = "SELECT o FROM Outcome o"),
    @NamedQuery(name = "Outcome.findByOutcomeId", query = "SELECT o FROM Outcome o WHERE o.outcomeId = :outcomeId"),
    @NamedQuery(name = "Outcome.findByCategory", query = "SELECT o FROM Outcome o WHERE o.category = :category"),
    @NamedQuery(name = "Outcome.findByValue", query = "SELECT o FROM Outcome o WHERE o.value = :value"),
    @NamedQuery(name = "Outcome.findByDescription", query = "SELECT o FROM Outcome o WHERE o.description = :description")})
public class Outcome implements Serializable {
   private static final long serialVersionUID = 1L;
       
    @Id
    @GeneratedValue
    @Basic(optional = false)
    @NotNull
    @Column(name = "OUTCOME_ID")
    private Integer outcomeId;
    
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "CATEGORY")
    private String category;
    
    // @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
    @Basic(optional = false)
    @NotNull
    @Column(name = "VALUE")
    private double value;
    
    @Size(max = 100)
    @Column(name = "DESCRIPTION")
    private String description;

    //getter und setter...
}

So also wo ich auch nicht so genau weiß, ob das so toll gelöst ist, ist dass Outcome und OutcomeBean nahezu gleich sind. Outcome hat eben noch die JPA Annotationen.

Freue mich über jeden Tipp!

Gruß,
hyperion
 

CptSocket

Aktives Mitglied
Hallo hyperion

Wenn ich die Snippets richtig verstanden habe sieht dein Beispiel etwa folgendermassen aus:
Anhang anzeigen 7166

Ich würde die folgenden Dinge anschauen:
  1. Naming:
    (Siehe Guidelines, Patterns, and code for end-to-end Java applications)
    Die Endung Bean wird normalerweise für SessionBeans verwendet (gemäss dem Link auch für Entity-Beans, da wird teilweise auch die Endung Entity oder ähnlich benützt).
    Transferobjekte (wie das OutcomeBean in deinem Beispiel) würde ich nicht mit Bean, sondern eher mit Dto, Vo, ... kennzeichnen (Siehe auch java - Difference between DTO, VO, POJO, JavaBeans? - Stack Overflow)
  2. Einsatz der Named Queries
    Was ist der Grund für die Named Queries in der Klasse Outcome?
    Alternative wäre Code ala
    Java:
    public List<Outcome> ladeAlleOutcomes() {
        Criteria criteria = getHibernateSession().createCriteria(Outcome.class);
        List<Outcome> outcomes = criteria.list();
        return outcomes;
    }
    Je nach Anforderungen erweitert um Restriktionen oder ähnlich:
    Java:
    criteria.add(Restrictions.eq("category", category));
    Vorteil von diesem Ansatz wäre, dass du kein oder weniger hql in den Klassen hast. (Der Entscheid zu HQL oder Criteria ist eher subjektiv, Criteria geht wahrscheinlich weniger schnell kaputt).
  3. In deinem Beispiel greifst du direkt aus dem Controller (Client) auf die Persistenz zu. Sobald die Applikation grösser wird, würde ich einen Service- und/oder einen Function/Logic-Layer reinziehen. Andernfalls besteht die Gefahr, dass die Applikation rasch unübersichtlich wird.
  4. Aus Sicht des Unittestings würde es sich anbieten, die Mapping-Logik der Methode OutcomeEjb.addOutcome() in einen Mapper auszulagern. Dann könntest du das Mappen der Objekte unabhängig von der Persistenzanbindung testen => bessere Testbarkeit der Applikation.


Freundliche Grüsse
CptSocket
 
Ähnliche Java Themen

Ähnliche Java Themen

Neue Themen


Oben