JavaData & JavaCreating a Java EE Web Application: A Case Study

Creating a Java EE Web Application: A Case Study

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Web development today cannot altogether be separated from the enterprise application context. The components often work together. With the demand of high performance, transactional security, fluid navigation, and eye candy look and feel, designing a web application is really a daunting task. Once a great design is made, the application must be optimized to deal with the reality factors such as poor network bandwidth, surging traffic, browser limitations, and so forth. Each of them play a vital role in the designing process and can completely change design decisions. Changes are better handled at Winitial design phases than being sorry later. The article takes on some aspects of creating a Web application in the JEE framework with an example application.

Design Consideration

There are many best practices to design decisions that we often dearly adhere without considering the alternatives and tradeoff of using one over the other. For example, a B2C application may require focus on handling large traffic with pretty straightforward underlying domain logic. An automated processing system, on the other hand, may require high usability with complex UI and business processing. We cannot be naive and plug in the same pattern into almost every design need.

There are numerous standard design patterns available for Web presentation, such as Page Controller, Front Controller, MVC, MVP, MOVE, Template View, Transform View, Two Step View, Application Controller, and so on. To rate, perhaps Page Controller is the simplest whereas MVC is complex. MVC is the most relied-upon pattern in the enterprise arena. It may not be excellent but lays fine foundation in most cases. Interested readers may visit Martin Fowler’s Catalog of Patterns of Enterprise Application Architecture for detailed information on different types of patterns and their uses in software design.

Page Controller

This pattern has a one-module-per-page interface that acts as a controller for each logical page of the Web site. It states basic Web experience and can be structured with CGI script or Servlet. Perhaps, the first Servlet/JSP application you have written is the simplest example of this pattern.

This pattern is pretty simple, as is obvious. inappropriate for design consideration where complex layers of domain logic needs to be implemented.

Front Controller

This pattern is structured to handle Web site calls in two layers: Web handler and command hierarchy. Web handler pulls information from the post and gets request from the Web server and delegates responsibility to the appropriate command in the hierarchy to carry out the action. Because this pattern emphasizes on the responsibility of Web server mostly, it is easy to port the application from one server to another.

MVC (Model View Controller)

MVC is a widely used pattern, excellent at decoupling presentation concerns from the model. The model contains application-specific content and processing logic, including content objects, access to external data, and all application-specific processing functionality. the view contains UI-specific functionality that enables presentation of content and processing logic required by the end user. the controller maintains the liaison between the model and the view and coordinates flow of data between them. The controller is too much intertwined with the view and there is a very fine-line difference to call it a separate layer.

Because this pattern emphasis on the fact of the model layer, any application that has no real behavior in it in any manner is inappropriate. In the form of layer upon layer, it is quite suitable to implement a complicated design.

A Quick Example

To appreciate further, let’s implement this pattern with the help of a program. The idea is to create a CRUD Web application using techniques of JSF, EJB, and JPA. The database to work upon the following example is:

SQL: creating app_user table (in MySQL)

CREATE TABLE app_user
(
   id INT PRIMARY KEY,
   fname VARCHAR(45),
   name VARCHAR(45),
   dob DATE,
   email VARCHAR(255),
   uname VARCHAR(16),
   pass VARCHAR(32),
   egdate DATETIME,
   security_question VARCHAR(45),
   security_answer VARCHAR(45),
);

The following JPA Entity bean represents the model layer.

Entity

package org.mano.model.entity;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table(name = "app_user")
@XmlRootElement
@NamedQueries({
   @NamedQuery(name = "User.findAll",
      query = "SELECT u FROM User u"),
   @NamedQuery(name = "User.findByUname",
      query = "SELECT u FROM User u WHERE u.uname = :uname"),
   @NamedQuery(name = "User.findByEmail",
      query = "SELECT u FROM User u WHERE u.email = :email"),
   @NamedQuery(name = "User.findByPass",
      query = "SELECT u FROM User u WHERE u.pass = :pass"),
   @NamedQuery(name = "User.findByRegdate",
      query = "SELECT u FROM User u WHERE u.regdate = :regdate"),
   @NamedQuery(name = "User.findByFname",
      query = "SELECT u FROM User u WHERE u.fname = :fname"),
   @NamedQuery(name = "User.findByLname",
      query = "SELECT u FROM User u WHERE u.lname = :lname"),
   @NamedQuery(name = "User.findById",
      query = "SELECT u FROM User u WHERE u.id = :id"),
   @NamedQuery(name = "User.findByDob",
      query = "SELECT u FROM User u WHERE u.dob = :dob"),
   @NamedQuery(name = "User.findBySecurityQuestion",
      query = "SELECT u FROM User u
      WHERE u.securityQuestion = :securityQuestion"),
   @NamedQuery(name = "User.findBySecurityAnswer",
      query = "SELECT u FROM User u
      WHERE u.securityAnswer = :securityAnswer")})
public class User implements Serializable {

   private static final long serialVersionUID = 1L;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 16)
   @Column(name = "uname")
   private String uname;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 255)
   @Column(name = "email")
   private String email;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 32)
   @Column(name = "pass")
   private String pass;
   @Basic(optional = false)
   @NotNull
   @Column(name = "regdate")
   @Temporal(TemporalType.TIMESTAMP)
   private Date regdate;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 45)
   @Column(name = "fname")
   private String fname;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 45)
   @Column(name = "lname")
   private String lname;
   @Id @GeneratedValue(strategy =
      GenerationType.AUTO)
   @Basic(optional = false)
   @NotNull
   @Column(name = "id")
   private Integer id;
   Basic(optional = false)
   @NotNull
   @Column(name = "dob")
   @Temporal(TemporalType.TIMESTAMP)
   private Date dob;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 45)
   @Column(name = "security_question")
   private String securityQuestion;
   @Basic(optional = false)
   @NotNull
   @Size(min = 1, max = 45)
   @Column(name = "security_answer")
   private String securityAnswer;

   public User() {
   }

   public User(Integer id) {
      this.id = id;
   }

   public User(Integer id,
         String uname,
         String email,
         String pass, Date regdate,
         String fname,
         String lname, Date dob,
         String securityQuestion,
         String securityAnswer) {
      this.id = id;
      this.uname = uname;
      this.email = email;
      this.pass = pass;
      this.regdate = regdate;
      this.fname = fname;
      this.lname = lname;
      this.dob = dob;
      this.securityQuestion = securityQuestion;
      this.securityAnswer = securityAnswer;
   }

   public String getUname() {
      return uname;
   }

   public void setUname(String uname) {
      this.uname = uname;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public String getPass() {
      return pass;
   }

   public void setPass(String pass) {
      this.pass = pass;
   }

   public Date getRegdate() {
      return regdate;
   }

   public void setRegdate(Date regdate) {
       this.regdate = regdate;
   }

   public String getFname() {
      return fname;
   }

   public void setFname(String fname) {
      this.fname = fname;
   }

   public String getLname() {
      return lname;
   }

   public void setLname(String lname) {
      this.lname = lname;
   }

   public Integer getId() {
      return id;
   }

   public void setId(Integer id) {
      this.id = id;
   }

   public Date getDob() {
      return dob;
   }

   public void setDob(Date dob) {
      this.dob = dob;
   }

   public String getSecurityQuestion() {
      return securityQuestion;
   }

   public void setSecurityQuestion(String securityQuestion) {
      this.securityQuestion = securityQuestion;
   }

   public String getSecurityAnswer() {
      return securityAnswer;
   }

   public void setSecurityAnswer(String securityAnswer) {
      this.securityAnswer = securityAnswer;
   }

   @Override
   public int hashCode() {
      int hash = 0;
      hash += (id != null ? id.hashCode() : 0);
      return hash;
   }

   @Override
   public boolean equals(Object object) {
      // TODO: Warning - this method won't work in
      // the case the id fields are not set
      if (!(object instanceof User)) {
         return false;
      }
      User other = (User) object;
      if ((this.id == null && other.id != null) ||
            (this.id != null &&
            !this.id.equals(other.id))) {
         return false;
      }
      return true;
   }

   @Override
   public String toString() {
      return "org.mano.entity.User[ id=" + id + " ]";
   }
}

EJB

The EJB that represents the data access object class is as follows:

package org.mano.model.ejb;

import java.util.List;
import javax.ejb.Remote;
import org.mano.model.entity.User;

@Remote
public interface UserEJBRemote {
   public List<User> getUsers();
   public User getUserById(int id);
   public User addNewUser(User user);
   public User updateUser(User user);
   public void deleteUser(User user);

}

The implementation class for the EJB is:

package org.mano.model.ejb;

import java.util.Date;
import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.mano.model.entity.User;

@Stateless
@LocalBean
public class UserEJB implements
   UserEJBRemote{

   @PersistenceContext(unitName =
      "userauthappPU")
   private EntityManager em;
   @Override
   public List<User> getUsers() {
      TypedQuery<User> query=
         em.createNamedQuery("User.findAll",
         User.class);
      return query.getResultList();
   }

   @Override
   public User getUserById(int id) {
      return em.find(User.class, id);
   }

   @Override
   public User addNewUser(User user) {
      user.setRegdate(new Date());
      em.persist(user);
      return user;
   }

   @Override
   public User updateUser(User user) {
      return em.merge(user);
   }

   @Override
   public void deleteUser(User user) {
      em.remove(em.merge(user));
   }
}

Managed Bean

The managed bean class for the JSF that acts as the controller in the MVC layer is as follows:

package org.mano.controller.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import org.mano.model.ejb.UserEJBRemote;
import org.mano.model.entity.User;

@Named(value = "uc")
@RequestScoped
public class UserManagedBean implements Serializable{

   @EJB
   private UserEJBRemote userEJB;
   private User user = new User();
   private List<User> list = new ArrayList<>();
   private boolean edit;


   public UserManagedBean() {
   }

   @PostConstruct
   public void init(){
      list=userEJB.getUsers();
   }

   public User getUser() {
      return user;
   }

   public void setUser(User user) {
      this.user = user;
   }

   public List<User> getList() {
      return list;
   }

   public void setList(List<User> list) {
      this.list = list;
   }

   public boolean isEdit() {
      return edit;
   }

   public void setEdit(boolean edit) {
      this.edit = edit;
    }


   public void addUser() {
      userEJB.addNewUser(user);
      list=userEJB.getUsers();
   }

   public void editUser(User usr) {
      user=usr;
      edit=true;
   }

   public void deleteUser(User usr) {
      userEJB.deleteUser(usr);
      list.remove(usr);
   }

   public void saveUser(){
      userEJB.updateUser(user);
      edit=false;
   }
}

userList.xhtml

The view layer is represented in JSF.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 
      xmlns_h="http://xmlns.jcp.org/jsf/html"
      xmlns_f="http://xmlns.jcp.org/jsf/core">
   <h:head>
      <title>User list</title>

      <link href="style.css" rel="stylesheet" type="text/css"/>
   </h:head>
   <h:body>
      <h:panelGroup rendered="#{!uc.edit}">
         <h3 style="text-align: center;">Add New User</h3>
         <h:form class="form-style-1">
            <h:panelGrid columns="2">
               <h:outputLabel value="First Name : "/>
               <h:inputText value="#{uc.user.fname}"/>
               <h:outputLabel value="Last Name :"/>
               <h:inputText value="#{uc.user.lname}"/>
               <h:outputLabel value="Birth Date : "/>
               <h:inputText value="#{uc.user.dob}">
                  <f:convertDateTime pattern="yyyy-MM-dd"/>
               </h:inputText>
               <h:outputLabel value="Email : "/>
               <h:inputText value="#{uc.user.email}">
                  <f:validateRegex
                     pattern="^[_A-Za-z0-9-+]+(.[_A-Za-z0-9-]+)*
                        @[A-Za-z0-9-]+(.[A-Za-z0-9]+)*
                        (.[A-Za-z]{2,})$" />
               </h:inputText>
               <h:outputLabel value="User Name : "/>
               <h:inputText value="#{uc.user.uname}"/>
               <h:outputLabel value="Password : "/>
               <h:inputSecret value="#{uc.user.pass}"/>
               <h:outputLabel value="Security Question : "/>
               <h:inputText value="#{uc.user.securityQuestion}"/>
               <h:outputLabel value="Answer : "/>
               <h:inputText value="#{uc.user.securityAnswer}"/>
               <h:outputLabel value=""/>
               <h:commandButton value="Add"
                  action="#{uc.addUser()}"/>
            </h:panelGrid>

         </h:form>
      </h:panelGroup>

      <h:panelGroup rendered="#{uc.edit}">
         <h3 style="text-align: center;">Edit User :
            #{uc.user.id}</h3>
         <h:form class="form-style-1">
            <h:panelGrid columns="2">
               <h:outputLabel value="First Name : "/>
               <h:inputText value="#{uc.user.fname}"/>
               <h:outputLabel value="Last Name :"/>
               <h:inputText value="#{uc.user.lname}"/>
               <h:outputLabel value="Birth Date : "/>
               <h:inputText value="#{uc.user.dob}">
                  <f:convertDateTime pattern="yyyy-MM-dd"/>
               </h:inputText>
               <h:outputLabel value="Email : "/>
               <h:inputText value="#{uc.user.email}">
                  <f:validateRegex
                     pattern="^[_A-Za-z0-9-+]+
                        (.[_A-Za-z0-9-]+)*
                        @[A-Za-z0-9-]+(.[A-Za-z0-9]+)*
                        (.[A-Za-z]{2,})$" />
               </h:inputText>
               <h:outputLabel value="User Name : "/>
               <h:inputText value="#{uc.user.uname}"/>
               <h:outputLabel value="Password : "/>
               <h:inputSecret value="#{uc.user.pass}"/>
               <h:outputLabel value="Security Question : "/>
               <h:inputText value="#{uc.user.securityQuestion}"/>
               <h:outputLabel value="Answer : "/>
               <h:inputText value="#{uc.user.securityAnswer}"/>
               <h:outputLabel value=""/>
               <h:commandButton value="Save"
                  action="#{uc.saveUser()}"/>
            </h:panelGrid>

         </h:form>
      </h:panelGroup>

      <h:form rendered="#{not empty uc.list}">
         <h:dataTable class="table-style-1"
               value="#{uc.list}" var="usr">
            <h:column>
               <f:facet name="header">
                  <h:outputText value="ID"/>
               </f:facet>
               <h:outputText value="#{usr.id}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="First Name"/>
               </f:facet>
               <h:outputText value="#{usr.fname}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="Last Name"/>
               </f:facet>
               <h:outputText value="#{usr.lname}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="Birth Date"/>
               </f:facet>
               <h:outputText value="#{usr.dob}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="Registration Date"/>
               </f:facet>
               <h:outputText value="#{usr.regdate}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="User Name"/>
               </f:facet>
               <h:outputText value="#{usr.uname}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="Password"/>
               </f:facet>
               <h:outputText value="#{usr.pass}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="Security Question"/>
               </f:facet>
               <h:outputText value="#{usr.securityQuestion}"/>
            </h:column>
            <h:column>
               <f:facet name="header">
                  <h:outputText value="Security Answer"/>
               </f:facet>
               <h:outputText value="#{usr.securityAnswer}"/>
            </h:column>
            <h:column&gt
               <h:commandLink value="edit"
                  action="#{uc.editUser(usr)}" /> |
               <h:commandLink value="delete"
                  action="#{uc.deleteUser(usr)}" />
            </h:column>
         </h:dataTable>
      </h:form>

      <h:panelGroup rendered="#{empty uc.list}">
         <h3 style="text-align: center;">Empty Table.
            Add New User.</h3>
      </h:panelGroup>

   </h:body>
</html>

style.css

The Style Sheet for the JSF is as follows.

body {
   font: 13px "Lucida Sans Unicode",
      "Lucida Grande", sans-serif;
   color: #4f6b72;
   background: #E6EAE9
}

a {
   font: 13px "Lucida Sans Unicode",
      "Lucida Grande", sans-serif;
   color: #c75f3e;
}

.form-style-1 {
   margin:10px auto;
   max-width: 400px;
   padding: 20px 12px 10px 20px;
   font: 13px "Lucida Sans Unicode",
      "Lucida Grande", sans-serif;
}
.form-style-1 li {
   padding: 0;
   display: block;
   list-style: none;
   margin: 10px 0 0 0;
}
.form-style-1 label{
   margin:0 0 3px 0;
   padding:0px;
   display:block;
   font-weight: bold;
}
.form-style-1 input[type=text],
.form-style-1 input[type=date],
.form-style-1 input[type=datetime],
.form-style-1 input[type=number],
.form-style-1 input[type=search],
.form-style-1 input[type=time],
.form-style-1 input[type=url],
.form-style-1 input[type=email],
textarea,
select{
   box-sizing: border-box;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   border:1px solid #BEBEBE;
   padding: 7px;
   margin:0px;
   -webkit-transition: all 0.30s ease-in-out;
   -moz-transition: all 0.30s ease-in-out;
   -ms-transition: all 0.30s ease-in-out;
   -o-transition: all 0.30s ease-in-out;
   outline: none;
}
.form-style-1 input[type=text]:focus,
.form-style-1 input[type=date]:focus,
.form-style-1 input[type=datetime]:focus,
.form-style-1 input[type=number]:focus,
.form-style-1 input[type=search]:focus,
.form-style-1 input[type=time]:focus,
.form-style-1 input[type=url]:focus,
.form-style-1 input[type=email]:focus,
.form-style-1 textarea:focus,
.form-style-1 select:focus{
   -moz-box-shadow: 0 0 8px #88D5E9;
   -webkit-box-shadow: 0 0 8px #88D5E9;
   box-shadow: 0 0 8px #88D5E9;
   border: 1px solid #88D5E9;
}
.form-style-1 .field-divided{
   width: 49%;
}

.form-style-1 .field-long{
   width: 100%;
}
.form-style-1 .field-select{
   width: 100%;
}
.form-style-1 .field-textarea{
   height: 100px;
}
.form-style-1 input[type=submit], .form-style-1 input[type=button]{
   background: #4B99AD;
   padding: 8px 15px 8px 15px;
   border: none;
   color: #fff;
}
.form-style-1 input[type=submit]:hover, .form-style-1 input[type=button]:hover{
   background: #4691A4;
   box-shadow:none;
   -moz-box-shadow:none;
   -webkit-box-shadow:none;
}
.form-style-1 .required{
   color:red;
}

.table-style-1 table {
   color: #333;
   font: 13px "Lucida Sans Unicode", "Lucida Grande", sans-serif;
   width: 100%;
   border-collapse: collapse; border-spacing: 15pt;
}

.table-style-1 td, th {border: 0 none; height: 30px;}

.table-style-1 th {
   background: #4691A4;
   color: #FFF; font-weight: bold;
   height: 40px;
   padding-left: 10px;
   padding-right: 10px;
}

.table-style-1 td { background: #FAFAFA; text-align: center; }
.table-style-1 tr:nth-child(even) td { background: #EEE; }
.table-style-1 tr:nth-child(odd) td { background: #FDFDFD; }
.table-style-1 tr td:first-child, tr th:first-child {
   background: none;
   font-style: italic;
   font-weight: bold;
   font-size: 14px;
   text-align: right;
   padding-right: 10px;
   width: 80px;
}

/* Add border-radius to specific cells! */
.table-style-1 tr:first-child th:nth-child(2) {
   border-radius: 0px 0 0 0;
}

.table-style-1 tr:first-child th:last-child {
   border-radius: 0 0px 0 0;
}

.table-style-1 input[type=submit], .form-style-1 input[type=button]{
   padding: 8px 15px 8px 15px;
   border: none;
   color: #fff;
}
.table-style-1 input[type=submit]:hover, .form-style-1 input[type=button]:hover{
   box-shadow:none;
   -moz-box-shadow:none;
   -webkit-box-shadow:none;
}
Note: The intention of the program is to implement a quick example, hence not much attention given to the optimization. A hint, the JSF can use templates to bring about clarity. Also, validation required for the input data has been overlooked. The code works as shown in the output shown in Figure 1. With a little effort, this example can be an interesting exercise to implement CRUD using JSF, EJB, and JPA.

Output

JEEWeb
Figure 1: Output of the preceding code

Conclusion

Creating a Web application in the JEE framework is not that difficult, but the challenge lies in optimizing performance in view of changing needs. JSF, EJB, and JPA make an excellent combo in easing the complexities of implementing Web application considerably. The precedingprogram is an interesting way to present CRUD functionalities in an application.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories