Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern
Asked Answered
U

6

61

I'm implementing MVC using JSP and JDBC. I have imported a database class file to my JSP file and I would like to show the data of a DB table. I don't know how I should return the ResultSet from the Java class to the JSP page and embed it in HTML.

How can I achieve this?

Umbilication answered 15/2, 2011 at 11:37 Comment(0)
W
131

In a well designed MVC approach, the JSP file should not contain any line of Java code and the servlet class should not contain any line of JDBC code.

Assuming that you want to show a list of products in a webshop, the following code needs to be created.

  • A Product class representing a real world entity of a product, it should be just a Javabean.

    public class Product {
    
        private Long id; 
        private String name;
        private String description;
        private BigDecimal price;
    
        // Add/generate getters/setters/c'tors/equals/hashcode boilerplate.
    }
    
  • A DAO class which does all the nasty JDBC work and returns a nice List<Product>.

    public class ProductDAO {
    
        private DataSource dataSource;
    
        public ProductDAO(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        public List<Product> list() throws SQLException {
            List<Product> products = new ArrayList<Product>();
    
            try (
                Connection connection = dataSource.getConnection();
                PreparedStatement statement = connection.prepareStatement("SELECT id, name, description, price FROM product");
                ResultSet resultSet = statement.executeQuery();
            ) {
                while (resultSet.next()) {
                    Product product = new Product();
                    product.setId(resultSet.getLong("id"));
                    product.setName(resultSet.getString("name"));
                    product.setDescription(resultSet.getString("description"));
                    product.setPrice(resultSet.getBigDecimal("price"));
                    products.add(product);
                }
            }
    
            return products;
        }
    
    }
    
  • A servlet class which obtains the list and puts it in the request scope.

    @WebServlet("/products")
    public class ProductsServlet extends HttpServlet {
    
        @Resource(name="jdbc/YourDB") // For Tomcat, define as <Resource> in context.xml and declare as <resource-ref> in web.xml.
        private DataSource dataSource;
        private ProductDAO productDAO;
    
        @Override
        public void init() {
            productDAO = new ProductDAO(dataSource);
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            try {
                List<Product> products = productDAO.list();
                request.setAttribute("products", products); // Will be available as ${products} in JSP
                request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);
            } catch (SQLException e) {
                throw new ServletException("Cannot obtain products from DB", e);
            }
        }
    
    }
    
  • Finally a JSP file in /WEB-INF/products.jsp which uses JSTL <c:forEach> to iterate over List<Product> which is made available in EL by ${products}, and uses JSTL <c:out> to escape string properties in order to avoid XSS holes when it concerns user-controlled input.

    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/format" prefix="fmt" %>
    ...
    <table>
        <c:forEach items="${products}" var="product">
            <tr>
                <td>${product.id}</td>
                <td><c:out value="${product.name}" /></td>
                <td><c:out value="${product.description}" /></td>
                <td><fmt:formatNumber value="${product.price}" type="currency" currencyCode="USD" /></td>
            </tr>
        </c:forEach>
    </table>
    

To get it to work, just call the servlet by its URL. Provided that the servlet is annotated @WebServlet("/products") or mapped in web.xml with <url-pattern>/products</url-pattern>, then you can call it by http://example.com/contextname/products

See also:

Weeden answered 15/2, 2011 at 12:34 Comment(16)
Very informative tutorial. I wanted to know how this would work for POST request. I tried doing by maintaining one bean through one request. But on JSP i get the error that saying that don't know how to iterate bean.Indication
And yeah when the response is received on the same page, if i try to send request one more time the servlet handling request is not foundIndication
Don't you have to call 'ProductDAO productDAO = new ProductDAO();' in the servlet method first, or where do you initialize this class?Whitening
@Coretek: in a properly designed Java EE application, that's an injected @Stateless EJB like so @EJB private ProductDAO productDAO;, so that transactions are fully transparently managed. But you can in this particular basic JDBC example of course also instantiate it whatever way you like in servlet's init() method if your environment doesn't support EJBs (e.g. Tomcat).Weeden
@Weeden I followed balusc.blogspot.com/2008/07/dao-tutorial-data-layer.html , but where should I instantiate and place the DAOFactory instance so that it can be used all across the applicationHypertrophy
@itsraja: in servlet's init() or in ServletContextListener's contextInitialized().Weeden
@Weeden thanks. In this part DAOFactory.getInstance("javabase.jdbc"); to replace the hard coded value "javabase.jdbc", can I use a property file as you use for reading database credentials or any other practice is there?Hypertrophy
@itsraja: ServletContext#getInitParameter() returns <context-param> values from web.xml.Weeden
@Weeden I missed it, thanks a lot. If you could extend the tutorial for a plain servlet / jsp application, that will be a unique resource. Because similar designs we can find mostly in frameworks with Injection.Hypertrophy
@Weeden If I have a Role property(object) in User and want a method to return only users of a particular role then I have to write the method with UserDAO itself or I will require a RoleDAO for this.Hypertrophy
@Weeden Hello i have been following your posts since is started learning java though am a nwbie its amazing... I have a doubt in the above mvc which you have explained if i want to create another Service layer where i can perform all the business logic with this example how can i do it.... Pls help me with this i ve similar issue in my project.... Any help will be appreciated.. Thanks in advance...Agreeable
I cannot think of. Isn't creating an instance of ProductDAO in the init() method of the associated Servlet or contextInitialized() of ServletContextListener shared across all the requests?Bertrando
@Tiny: that shouldn't harm if it's stateless (i.e. methods do not depend on any instance variables, like as the code demonstrated in the answer). If it's stateful, then the story of course changes. If you've EJB at hands, it's easier to just annotate it @Stateless (or @Stateful) ... and to replace all that JDBC mess by a JPA oneliner, after all (unless you're playing around with decade-old technologies/approaches for pure learning purposes ;) )Weeden
Shouldn't you add code to prevent XSS? The values in product come from a database and it is very likely that those are input by the user. As I learned on SO, security shouldn't be an afterthought. Even when not thinking about security, the use of < and & will give problems. However, my question is: where to implement encoding? At the moment I use ${Encode.forHtml(var)} in the JSP, but I think this is not the best solution, as it is Java code in the JSP. When getting the values from the database is also not the best point, as encoding should be used on output, not when reading a DB.Crawly
My question has already been answered by reading stackoverflow.com/questions/3177733/… (where the last part covers XSS).Crawly
Thank you for the wonderful example. I think in products servlet @Resource("jdbc/MyDatasource") suppose to be @Resource(name="jdbc/MyDatasource")Bioenergetics
P
12

MVC, in a web application context, doesn't consist in using a class from a JSP. It consists in using the following model :

  1. browser sends a request to a web server
  2. the web server is configured so that the request is handled by a servlet or a filter (the controller : Java code, not JSP code)
  3. The servlet/filter usually dispatches the request to a specific class (called an Action, the specific part of the controller), based on configuration/annotations
  4. The action executes the business logic (i.e. fetch the data from the database in your example : the model)
  5. The action forwards the request to a JSP. The role of the JSP is only to generate HTML code (i.e. display your data : the view)

Since the JSP usually uses JSP tags (the JSTL, for example) and the JSP expression language, and since JSP tags and the EL are designed to get information from JavaBeans, you'd better have your data available in the form of JavaBeans or collections of JavaBeans.

The role of the controller (the action class) is thus to fetch the data, to create JavaBean instances containing the data, in a suitable format for the JSP, to put them in request attributes, and then to dispatch to the JSP. The JSP will then iterate through the JavaBean instances and display what they contain.

You should not implement the MVC framework yourself. Use existing ones (Stripes, Struts, etc.)

Patel answered 15/2, 2011 at 11:51 Comment(0)
E
5

I don't know how should I return the ResultSet from the class file to the JSP page

Well, you don't.

The point of MVC is to separate your model ( the M DB info in this case ) from your view ( V a jsp, in this case ) in such a way you can change the view without braking to application.

To do this you might use an intermediate object to represent your data ( usually called DTO - after Data Transfer Object -, don't know how they call it these days ), and other object to fetch it ( usually a DAO ).

So basically you have your JSP file, get the request parameters, and then invoke a method from the DAO. The dao, internally has the means to connect to the db and fetch the data and builds a collections of DTO's which are returned to the JSP for rendering.

Something like this extremely simplified ( and insecure ) code:

Employee.java

class Employee {
   String name;
   int emplid;
}

EmployeeDAO.java

class EmployeeDAO { 
   ... method to connect 
   etc. 
   List<Employee> getAllNamed( String name ) { 
       String query = "SELECT name, emplid FROM employee where name like ?";
       ResultSet rs = preparedStatement.executeQuery etc etc.
       List<Employee> results = ....
       while( rs.hasNext() ) { 
          results.add( new Employee( rs.getString("name"), rs.getInt("emplid")));
       }
       // close resources etc 
       return results;
    }
}

employee.jsp

<%
   request.setAttribute("employees", dao.getAllNamed( request.getParameter("name") );
%>
<table>
<c:forEach items="${employees}" var="employee">
<tr><td>${employee.emplid}</td><td>${employee.name}</td></tr>
</c:forEach>
</table>

I hope this give you a better idea.

Eleanor answered 15/2, 2011 at 12:35 Comment(1)
Using the JSP (View) to gather data from the DAO and set request attributes and process requests is the job of the Controller/Servlet (mvC). The JSP should only use JSTL ${} or whatever to display the data that was delivered to it by the controller. In an MVC application you never perform business logic in the view template. So your example breaks MVC methodology.Multiped
S
0

I have a problem. I don't understand clearly the code. I have a similar problem with my code.

I have created database SQL and filled up. Then I want to implement a MainServlet (code below) that richieve data from database and in a different jsp page, I want to insert that data in section like h1, h2 ecc... I must use the ${} sintax but I don't know how do that.

Briefly, In jsp file (code below, I MUST USE ${} SINTAX) I want to "call" MainServlet and there I want to richieve data from database and view in jsp file.

I hope I have explained correctly, thank you very much!

MainServlet.java

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * Servlet implementation class MainServlet
 */
@WebServlet({ "/MainServlet" })
public class MainServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final String PATH_JSP = "/WEB-INF/";
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public MainServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see Servlet#init(ServletConfig)
     */
    public void init(ServletConfig config) throws ServletException {
        // TODO Auto-generated method stub
    }

    /**
     * @see Servlet#destroy()
     */
    public void destroy() {
        // TODO Auto-generated method stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String doveAndare = request.getParameter("azione");
        if(doveAndare==null)
            doveAndare = "index";
        try {
            String driverString = "com.mysql.cj.jdbc.Driver";
            Class.forName(driverString);
            String connString = "jdbc:mysql://localhost:3306/ldd_jewels?user=root&password=";
            Connection conn = DriverManager.getConnection(connString);
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM JEWEL");
            while (rs.next() == true) {
                System.out.println(rs.getString("Category") + "\t" + rs.getString("Name"));
                
                /* I try that but does not work
                request.setAttribute("name", rs.getString("Name"));
                javax.servlet.RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/widering_male.jsp");
                dispatcher.forward(request, response); */
            }
            stmt.close();
            conn.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
        request.getRequestDispatcher(PATH_JSP+doveAndare+".jsp").forward(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

doublerow.jsp

   <section id="portfolio-details" class="portfolio-details">
        <div class="container">
          <div class="row gy-4">
            <div class="col-lg-8">
              <div class="portfolio-details-slider swiper">
                <div class="swiper-wrapper align-items-center">
                  <div class="swiper-slide">
                    <img src="assets/img/jewels/doublerow_1.jpg" alt="" />
                  </div>

                  <div class="swiper-slide">
                    <img src="assets/img/jewels/doublerow_2.jpg" alt="" />
                  </div>

                  <div class="swiper-slide">
                    <img src="assets/img/jewels/doublerow_3.jpg" alt="" />
                  </div>
                </div>
                <div class="swiper-pagination"></div>
              </div>
            </div>

            <div class="col-lg-4">
              <div class="portfolio-info">
                <h3>Product details</h3>
                <ul>
                  <li><strong>Code</strong>: 1S3D5</li>
                  <li><strong>Category</strong>: Bracelets</li>
                  <li><strong>Name</strong>: Double Row Hinged Bangle</li>
                  <li><strong>Gender</strong>: Female</li>
                  <li><strong>Material</strong>: Yellow gold</li>
                  <li><strong>Size</strong>: 121mm</li>
                  <li><strong>Price</strong>: €5500</li>
                </ul>
              </div>
              <div class="portfolio-description">
                <h2>Description of product</h2>
                <p>
                  The entwined ends of Tiffany Knot’s signature motif symbolize
                  the power of connections between people. Balancing strength
                  and elegance, each Tiffany Knot design is a complex feat of
                  craftsmanship. This bangle is crafted with yellow gold and
                  polished by hand for high shine. Wear on its own or partnered
                  with classic silhouettes for an unexpected pairing.
                </p>
              </div>
            </div>
          </div>
        </div>
      </section>

This is my database: Database I want to insert each jewel in different pages (each jewel have a jsp file)

Skaw answered 22/4, 2022 at 14:44 Comment(0)
T
-1

You can use the <c:forEach > tag

you can find a detailed example in the following link example use

Thermosetting answered 15/2, 2011 at 11:50 Comment(0)
P
-1

I think it will be better for you to contain the data of the table into a collection such as list and return the list from the Java class and reuse this collection in the JSP.

Pulmonary answered 10/5, 2012 at 18:20 Comment(1)
Passing ResultSet (and Statement and Connection) outside the scope of the method where it's been acquired is a bad practice. You would be unable to close it in the right scope and thus you're leaking DB resources. On long term, the application will crash because DB has run out of resources.Weeden

© 2022 - 2024 — McMap. All rights reserved.