Reading CSV file from a servlet inside WAR

In this tutorial we read data from a CSV file located in the WEB-INF directory. We use servlets, JSP files, and JSTL library. The web application is deployed on Tomcat. The Opencsv library is used to read CSV data.

CSV (Comma Separated Values) format is a very popular import and export format used in spreadsheets and databases.

In the following web application, we read data from a CSV file inside a WAR file and display the data in a web page. The countries with population larger than a hundred million are marked.

NetBeans project structure
Figure: NetBeans project structure

The figure shows the project structure in NetBeans.

Excerpt from pom.xml
<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>com.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>3.8</version>
    </dependency> 
    
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    
</dependencies>

The project uses the following dependencies: javaee-web-api, opencsv, and jstl.

countries.csv
Country, Population
Slovakia,5429000
Norway,5271000
Croatia,4225000
Russia,143439000
Mexico,122273000
Vietnam,95261000
Sweden,9967000
Iceland,337600
Israel,8622000
Hungary,9830000
Germany,82175700
Japan,126650000

This is the countries.csv file. It is located in the src/main/resources directory. After building the application, the file is copied to the WAR's WEB-INF/classes directory.

context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ReadCountriesCsvJstlEx"/>

This is Tomcat's context.xml file. It contains the name of the web application.

Country.java
package com.zetcode.bean;

public class Country {

    private String name;
    private int population;

    public Country() {
    }

    public Country(String name, int population) {

        this.name = name;
        this.population = population;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }
}

This is a Country bean that has two attributes: name and population.

CountryService.java
package com.zetcode.service;

import com.opencsv.CSVReader;
import com.zetcode.bean.Country;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class CountryService {

    public static ArrayList<Country> getListOfCountries() throws IOException {

        ArrayList<Country> countries = new ArrayList();

        InputStream is = CountryService.class.getClassLoader().getResourceAsStream("countries.csv");

        try (CSVReader reader = new CSVReader(new InputStreamReader(is))) {
            
            String[] nextLine;
            reader.readNext();

            while ((nextLine = reader.readNext()) != null) {

                Country newCountry = new Country(nextLine[0],
                        Integer.valueOf(nextLine[1]));
                countries.add(newCountry);
            }
        }

        return countries;
    }
}

The CountryService reads data from the CSV file.

InputStream is = CountryService.class.getClassLoader().getResourceAsStream("countries.csv");

We get the InputStream to the countries.csv file with the getResourceAsStream() method.

try (CSVReader reader = new CSVReader(new InputStreamReader(is))) {

CSVReader is a class to read CSV files.

reader.readNext();

We skip the first row which contains header columns.

while ((nextLine = reader.readNext()) != null) {

    Country newCountry = new Country(nextLine[0],
            Integer.valueOf(nextLine[1]));
    countries.add(newCountry);
}

We go through the file line by line and create a Country object from each row. We add the created objects to the list.

ReadCountries.java
package com.zetcode.web;

import com.zetcode.bean.Country;
import com.zetcode.service.CountryService;
import java.io.IOException;
import java.util.ArrayList;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ReadCountries", urlPatterns = {"/ReadCountries"})
public class ReadCountries extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        response.setContentType("text/html;charset=UTF-8");

        ArrayList<Country> countries = CountryService.getListOfCountries();
        request.setAttribute("countries", countries);

        RequestDispatcher dispatcher = request.getRequestDispatcher("listCountries.jsp");
        dispatcher.forward(request, response);

    }
}

In the ReadCountries servlet, we call the getListOfCountries() service method and set the returned list of countries to the request object as an attribute. The processing is transferred to the listCountries.jsp.

listCountries.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Countries</title>
    <style>
        .marked { color: chocolate }
    </style>
</head>
<body>
<table>

    <thead>
        <tr>
            <th>Country</th>
            <th>Population</th>
        </tr>
    </thead>

    <tbody>

        <c:forEach items="${countries}" var="count">

            <c:if test="${count.population > 100000000}">
                <tr class="marked">
                    <td>
                        <c:out value="${count.name}"/>
                    </td>
                    <td>
                        <fmt:formatNumber type="number" value="${count.population}" />
                    </td>                   
                </tr>
            </c:if>
            <c:if test="${count.population < 100000000}">
                <tr>
                    <td>
                        <c:out value="${count.name}"/>
                    </td>
                    <td>
                        <fmt:formatNumber type="number" value="${count.population}" />
                    </td>                   
                </tr>
            </c:if>
        </c:forEach>

    </tbody>
    </table>
</body>
</html>

In the listCountries.jsp file, we display the data in an HTML table.

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

We use two JSTL tag libraries: the core and the formatting library.

<c:forEach items="${countries}" var="count">

With the <c:forEach> tag we iterate over the countries object.

<c:if test="${count.population > 100000000}">
    <tr class="marked">
        <td>
            <c:out value="${count.name}"/>
        </td>
        <td>
            <fmt:formatNumber type="number" value="${count.population}" />
        </td>                   
    </tr>
</c:if>

If the country's population is larger than one hundred million, we use the marked class for the row; it displyas the row in a different colour. The test is performed with the JSTL's <c:if> tag. The <fmt:formatNumber> tag is used to format the value.

index.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>List countries</title>
    </head>
    <body>
        <a href="ReadCountries">List countries</a>
    </body>
</html>

The index.jsp contains a link that calls the ReadCountries servlet. The servlet reads the data from a CSV file and returns the data in a view back to the browser.

Countries
Figure: Countries

In the above screenshot we see the list of countries available in the CSV file inside the application's WAR. Countries with population over one hundred million are displayed in a different colour.

In this tutorial, we have shown how to read CSV data located inside the WAR file.

You might also be interested in the following related tutorials: Java tutorial, Java validation tutorial, and Opencsv tutorial.