JSF Controller, Service and DAO

31,052

Solution 1

Is this the correct way of doing things?

Apart from performing business logic the inefficient way in a managed bean getter method, and using a too broad managed bean scope, it looks okay. If you move the service call from the getter method to a @PostConstruct method and use either @RequestScoped or @ViewScoped instead of @SessionScoped, it will look better.

See also:


Is my terminology right?

It's okay. As long as you're consistent with it and the code is readable in a sensible way. Only your way of naming classes and variables is somewhat awkward (illogical and/or duplication). For instance, I personally would use users instead of userList, and use var="user" instead of var="u", and use id and name instead of userId and userName. Also, a "UserListService" sounds like it can only deal with lists of users instead of users in general. I'd rather use "UserService" so you can also use it for creating, updating and deleting users.

See also:


The "service" feels more like a DAO?

It isn't exactly a DAO. Basically, JPA is the real DAO here. Previously, when JPA didn't exist, everyone homegrew DAO interfaces so that the service methods can keep using them even when the underlying implementation ("plain old" JDBC, or "good old" Hibernate, etc) changes. The real task of a service method is transparently managing transactions. This isn't the responsibility of the DAO.

See also:


And the controller feels like it's doing some of the job of the service.

I can imagine that it does that in this relatively simple setup. However, the controller is in fact part of the frontend not the backend. The service is part of the backend which should be designed in such way that it's reusable across all different frontends, such as JSF, JAX-RS, "plain" JSP+Servlet, even Swing, etc. Moreover, the frontend-specific controller (also called "backing bean" or "presenter") allows you to deal in a frontend-specific way with success and/or exceptional outcomes, such as in JSF's case displaying a faces message in case of an exception thrown from a service.

See also:


All in all, the correct approach would be like below:

<h:dataTable value="#{userBacking.users}" var="user">
    <h:column>#{user.id}</h:column>
    <h:column>#{user.name}</h:column>
</h:dataTable>
@Named
@RequestScoped // Use @ViewScoped once you bring in ajax (e.g. CRUD)
public class UserBacking {

    private List<User> users;

    @EJB
    private UserService userService;

    @PostConstruct
    public void init() {
        users = userService.listAll();
    }

    public List<User> getUsers() {
        return users;
    }

}
@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public List<User> listAll() {
        return em.createQuery("SELECT u FROM User u", User.class).getResultList();
    }

}

You can find here a real world kickoff project here utilizing the canonical Java EE / JSF / CDI / EJB / JPA practices: Java EE kickoff app.

See also:

Solution 2

It is a DAO, well actually a repository but don't worry about that difference too much, as it is accessing the database using the persistence context.

You should create a Service class, that wraps that method and is where the transactions are invoked.

Sometimes the service classes feel unnecessary, but when you have a service method that calls many DAO methods, their use is more warranted.

I normally end up just creating the service, even if it does feel unnecessary, to ensure the patterns stay the same and the DAO is never injected directly.

This adds an extra layer of abstraction making future refactoring more flexible.

Share:
31,052
PDStat
Author by

PDStat

Updated on July 16, 2022

Comments

  • PDStat
    PDStat almost 2 years

    I'm trying to get used to how JSF works with regards to accessing data (coming from a spring background)

    I'm creating a simple example that maintains a list of users, I have something like

    <h:dataTable value="#{userListController.userList}" var="u">
        <h:column>#{u.userId}</h:column>
        <h:column>#{u.userName}</h:column>
    </h:dataTable>
    

    Then the "controller" has something like

    @Named(value = "userListController")
    @SessionScoped
    public class UserListController {
        @EJB
        private UserListService userListService;
    
        private List<User> userList;
    
        public List<User> getUserList() {
            userList = userListService.getUsers();
            return userList;
        }
    }
    

    And the "service" (although it seems more like a DAO) has

    public class UserListService {
    
        @PersistenceContext
        private EntityManager em;
    
        public List<User> getUsers() {
            Query query = em.createQuery("SELECT u from User as u");
            return query.getResultList();
        }
    }
    

    Is this the correct way of doing things? Is my terminology right? The "service" feels more like a DAO? And the controller feels like it's doing some of the job of the service.

  • PDStat
    PDStat almost 9 years
    thanks, I'll probably just add that extra layer then. From a JSF perspective does what I'm doing look like the correct way to go?
  • NimChimpsky
    NimChimpsky almost 9 years
    Looks fine, does it have to be session scoped - using sessions makes clustering somewhat more complex (but also commonly used). Not used jsf myself, I prefer anglular, vanilla html, and a rest api.
  • PDStat
    PDStat almost 9 years
    I'll be adding in some result pages saying things like 'user x added' or 'user x removed' so I assume so, not really sure yet just playing.
  • Tiny
    Tiny almost 9 years
    "JPA is the real DAO here" gives my brain a deep impact to understand this statement. :) Is it anything that provides an abstraction to some kind of persistence mechanism like a DB and allows retrieval and persistence of domain objects to and from the DB without exposing the internal details of the underlying DB is said to be a DAO? This is somewhat confusing as compared to older questions/answers/blogs/tutorials/articles somewhere else.
  • BalusC
    BalusC almost 9 years
    @Tiny: perhaps this answer is helpful to understand the original intent behind DAO pattern: stackoverflow.com/questions/7070467/dao-and-jdbc-relation
  • LyK
    LyK over 8 years
    @BalusC Why is Session Scope too broad? By using the view scope the list will have to be build every time the user loads the page, right? Isn't that "bad"? Or is it that we just prefer that, more than keeping the bean alive for the whole session and consuming memory?
  • BalusC
    BalusC over 8 years
    @LyK: click "How to choose the right bean scope?" for explanation.
  • LyK
    LyK over 8 years
    @BalusC Yes, I have read that. But I initially thought that in this case session scope would be more appropriate. I guess we prefer to query the db again rather than keeping the results in memory for the whole session. Ty!
  • BalusC
    BalusC over 8 years
    @LyK: You shouldn't cache DB results in all sessions in the frontend. You should cache them in a single place in the backend. JPA offers 2nd level cache possibility. Additional advantage, it knows precisely when to invalidate a cached entity.
  • developer10
    developer10 over 7 years
    @BalusC I'm having issues trying to implement this wiring in my own example. @PostConstruct public void init() method is giving me error: WELD-000049: Unable to invoke public void com.example.jsf.GradBacking.init() on com.example.jsf.GradBacking@8dbd4b Also, is there any difference between using javax.faces.bean.RequestScoped and javax.enterprise.context.RequestScoped Does anything about this issue comes to your mind? Thank you!
  • BalusC
    BalusC over 7 years
    @developer10: That method just threw an exception. When getting an exception, always look at bottommost root cause in stack trace for the root cause the problem. All causes there above are just consequences of each other.
  • developer10
    developer10 over 7 years
    @BalusC Thank you, will take a look at the stack now. Btw, there's another part of the Q regarding the two types of RequestScoped annotation - does the choice thereof matter in this case? And finally -- I forgot to mention that when the init() method is in place, none of my EL expressions are evaluated in the JSF (it this due to the exception being thrown??) (I have a dummy field to test), and if I comment it out, then they are evaluated.
  • Serg Shapoval
    Serg Shapoval about 7 years
    You saved my life! thanx