Thursday, 20 September 2018

Spring MVC Generate Response as XML Example

In this post we’ll see how to generate XML in Spring MVC framework. For marshalling and unmarshalling (converting object from/to XML) JAXB is used in this Spring MVC example.

Technologies used

Following is the list of tools used for the Spring MVC XML generation example.

  • Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  • Java 10
  • Tomcat server V 9.0.10
  • Eclipse Photon 4.8.0 for Java EE development (This Eclipse version supports Java 10)
  • JAXB API 2.3.0

Spring MVC Project structure using Maven

Maven Dependencies

Apart from Spring dependencies JAXB dependencies are also to be added to the pom.xml for generation of XML. From JDK 9, JEE modules are deprecated so you will need to add dependencies in your pom.xml for inclusion of JAXB jars previously these jars were part of JDK itself.

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>javax.activation-api</artifactId>
    <version>1.2.0</version>
</dependency>

Requirement for generating XML in Spring MVC

In order to return XML as response with in your Spring MVC application-

  1. You need to annotate your model bean with JAXB annotations.
  2. @ResponseBody annotation has to be added to the controller's method, with that return is serialized to the response body through an HttpMessageConverter.

Spring MVC generate XML as response – Model classes

There are two classes User class whose objects are returned in the XML form and UserListContainer class which contains the List of objects of type User, this class is needed as we are sending a list of Users. These POJOs are annotated with JAXB annotations for defining the XML structure.

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement
@XmlType(propOrder = {"firstName", "lastName", "email"})
public class User {

 private String firstName;
 private String lastName;
 private String email;

 public User() {
  
 }
 public User(String firstName, String lastName, String email) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.email = email;
 }
 
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="users")
public class UserListContainer {

    private List<User> userList;

    @XmlElement(name = "user")
    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
}

Spring MVC XML as response – Controller class

@Controller
public class UserController {
    @RequestMapping(value = "/getUsers", method = RequestMethod.GET, produces="application/xml")
    @ResponseBody
    public UserListContainer getUsers(Model model) throws Exception{
        List<User> users = getListOfUsers();
        UserListContainer userList = new UserListContainer();
        userList.setUserList(users);
        return userList;
    }
    
    // Dummy method for adding List of Users
    private List<User> getListOfUsers() throws ParseException {
        List<User> users = new ArrayList<User>();
        users.add(new User("Jack", "Reacher", "abc@xyz.com"));
        users.add(new User("Remington", "Steele", "rs@cbd.com"));
        users.add(new User("Jonathan", "Raven", "jr@sn.com"));
        return users;
    }
}

Here in the handler method you can see a new attribute “produces” with value as “application/xml” with in the @RequestMapping annotation to explicitly specify the MIME media types or representations a resource can produce and send back to the client.

@ResponseBody annotation is also used in the handler method to indicate that the returned object has to be serialized to the response body. Note that return is serialized to the response body through an HttpMessageConverter.

Deploying and testing application

Once the application is deployed to Tomcat server it can be accessed using the URL- http://localhost:8080/spring-mvc/getUsers and XML will be returned as response.

Spring MVC XML generation

That's all for this topic Spring MVC Generate Response as XML Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring MVC Excel Generation Example
  2. Difference Between @Controller And @RestController Annotations in Spring
  3. Spring MVC Example With @PathVaribale - Creating Dynamic URL
  4. Spring MVC - Binding List of Objects Example
  5. Spring MVC Form Example With Bean Validation

You may also like -

>>>Go to Spring Tutorial Page

Tuesday, 18 September 2018

Spring MVC Excel Generation Example

In this post we’ll see how to generate an Excel sheet in Spring MVC using the fields from a view page (JSP).

Technologies used

Following is the list of tools used for the Spring MVC PDF generation example.

  • Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  • Java 10
  • Tomcat server V 9.0.10
  • Eclipse Photon 4.8.0 for Java EE development (This Eclipse version supports Java 10)
  • Apache POI 4.0.0 (Required for generating excel)

Spring framework support for Apache POI

Apache POI is an open source library using which you can read and write Excel files from your Java program.

Spring framework provides support for Excel document views using two abstract classes-

  1. AbstractXlsView- You will use AbstractXlsView as superclass for Excel document views in traditional XLS format.
  2. AbstractXlsxView- You will use AbstractXlsxView as superclass for Excel document views in the Office 2007 XLSX format.

Both of these classes are compatible with Apache POI 3.5 and higher.

With in Apache POI also there are two implementations for these two types of sheets-

  1. HSSF- It is the POI Project's pure Java implementation of the Excel '97(-2007) file format.
  2. XSSF- It is the POI Project's pure Java implementation of the Excel 2007 OOXML (.xlsx) file format.

Note that there is a component module that attempts to provide a common high level Java API to both OLE2 and OOXML document formats which is SS for Excel workbooks. So we’ll try to use SS package as much as possible so that one implementation can be replaced by another seamlessly.

Spring MVC Excel generation example using Apache POI

In this Spring MVC Excel generation example we’ll generate a .xls file available for downloading/openeing as an xls format sheet.

Spring MVC Project structure using Maven

Maven Dependencies

Apart from Spring dependencies following dependencies are also to be added to the pom.xml for generating excel and for JSTL tags.

<dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.0.0</version>
</dependency>
<!-- For JSTL tags -->
<dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
</dependency>

Spring MVC PDF generation example flow

The model class used in the example is User with fields firstName, lastName, email and dob. In the example there is a JSP that shows a list of Users and there is a button “View Excel”. In the JSP that list of users is bound to a Model.

When the button is clicked, the request is mapped to the appropriate controller method and from there the logical view name and Model where the list of users is set as attribute is transferred to the view which creates an Excel sheet. To resolve a view to a PDF another view resolver has to be added.

Spring MVC PDF generation example – Model classes

User class is the bean class in this example. For field of type java.util.Date pattern is also specified using the @DateTimeFormat annotation.

import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;

public class User {

 private String firstName;
 private String lastName;
 private String email;
 @DateTimeFormat(pattern = "dd/MM/yyyy")
 private Date dob;
 public User() {
  
 }
 public User(String firstName, String lastName, String email, Date dob) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.email = email;
  this.dob = dob;
 }
 
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
 public Date getDob() {
  return dob;
 }
 public void setDob(Date dob) {
  this.dob = dob;
 }
}
Following class acts a container for the List of User objects.
public class UserListContainer {
    private List<User> users;

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

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

Spring MVC Excel generation – Views

showUsers.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring MVC List of objects display</title>
</head>
<body>
<form:form method="POST" action="viewExcel" modelAttribute="Users">
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
<c:forEach items="${Users.users}" var="user" varStatus="tagStatus">
    <tr>
        <td><form:input path="users[${tagStatus.index}].firstName" value="${user.firstName}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].lastName" value="${user.lastName}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].email" value="${user.email}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].dob"  readonly="true"/></td>
    </tr>
</c:forEach>
</table>
<input type="submit" value="View Excel" />
</form:form>
</body>
</html>

This JSP displays the users in the List by iterating the List and again bind list to the Model. Clicking “View Excel” button generates the PDF using the List bound to the Model.

Spring MVC View for Excel sheet

For generating .xls sheet you need to extend the Abstract class AbstractXlsView and provide implementation for the buildExcelDocument() method to generate excel sheet as per your requirement.

import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.netjs.model.User;
import org.springframework.web.servlet.view.document.AbstractXlsView;

public class ExcelView extends AbstractXlsView {
    private static final String[] header= {"First Name", "Last Name", "Email", "DOB"};
    @Override
    protected void buildExcelDocument(Map<String, Object> model, Workbook workbook,
        HttpServletRequest request, HttpServletResponse response) throws Exception {
        // List of users that will be displayed in the Excel
        List<User> users = (List<User>)model.get("Users");
        int rowNum = 1;
        // Creating sheet with in the workbook
        Sheet sheet = workbook.createSheet("Users");
        /** for header **/
        Font font = workbook.createFont();
        font.setFontName("HELVETICA");
        font.setBold(true);
        CellStyle style = workbook.createCellStyle();
        style.setFont(font);
        Row row = sheet.createRow(0);
        for(int i = 0; i < header.length; i++) {
            Cell cell = row.createCell(i);
            cell.setCellValue(header[i]);
            cell.setCellStyle(style);
        }
        /** header ends **/
        /** Rows in the sheet **/
        CellStyle dateStyle = workbook.createCellStyle();
        // Setting format For the date column
        dateStyle.setDataFormat(workbook.getCreationHelper().createDataFormat()
                 .getFormat("dd/MM/yyyy"));
        for(User user : users) {
            row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(user.getFirstName());
            row.createCell(1).setCellValue(user.getLastName());
            row.createCell(2).setCellValue(user.getEmail());
            Cell cell = row.createCell(3);
            cell.setCellValue(user.getDob());
            cell.setCellStyle(dateStyle);
        }
    }
}

Spring MVC Excel generation – Controller Class

@Controller
public class UserController {
    @RequestMapping(value = "/getUsers", method = RequestMethod.GET)
    public String getUsers(Model model) throws Exception{
        List<User> users = getListOfUsers();
        UserListContainer userList = new UserListContainer();
        userList.setUsers(users);
        model.addAttribute("Users", userList);
        return "showUsers";
    }
    
    @RequestMapping(value = "/viewExcel", method = RequestMethod.POST)
    public ModelAndView viewExcel(@ModelAttribute("Users") UserListContainer userList) throws Exception{        
        List<User> users = userList.getUsers();
        return new ModelAndView("viewExcel", "Users", users);
    }
    
    // Dummy method for adding List of Users
    private List<User> getListOfUsers() throws ParseException {
        List<User> users = new ArrayList<User>();
        Calendar dob = Calendar.getInstance();
        dob.set(1975,6,12);
        users.add(new User("Jack", "Reacher", "abc@xyz.com", dob.getTime()));
        // Using LocalDate from new time&date API 
        LocalDate date = LocalDate.of(2016, Month.APRIL, 28);
        users.add(new User("Remington", "Steele", "rs@cbd.com",
           Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())));
        dob.set(1965,12,6);
        users.add(new User("Jonathan", "Raven", "jr@sn.com", dob.getTime()));
        return users;
    }
}

In the Controller class there are two handler methods. Method getUsers() displays the list of users in a JSP page (showUsers.jsp). In that JSP there is a “View Excel” button, the request created on clicking that button is handled by the handler method viewExcel() which passes the list of users and the logical view name to be resolved to an excel view.

Spring MVC Excel generation – Configuration

The Spring configuration file is as follows.

mvcexample-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
        
     <mvc:annotation-driven />
     <context:component-scan base-package="org.netjs.controller" />
      <bean id="ExcelResolver" class=
        "org.springframework.web.servlet.view.ResourceBundleViewResolver">
         <property name="order" value="1"/>
        <property name="basename" value="excel-view"/>
    </bean>
     <bean id="JSPViewResolver" class=
        "org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="2"/>
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

As you can see two view resolver classes are configured here.

ResourceBundleViewResolver resolves the views from the properties file. ResourceBundleViewResolver is the Implementation of ViewResolver that uses bean definitions in a ResourceBundle, specified by the bundle base name, and for each view it is supposed to resolve, it uses the value of the property [viewname].(class) as the view class and the value of the property [viewname].url as the view url.

Here “basename” property has the value excel-view which means properties file is named excel-view.properties file.

excel-view.properties

viewExcel.(class)=org.netjs.config.ExcelView

Controller class handler method viewExcel() returns logical view name as “viewExcel” which is used to resolve the view class using this properties file.

Another view resolver InternalResourceViewResolver is used to resolve the view name to JSPs.

Here note that both the Resolvers have a property order too which decides the priority. Lower order value means higher priority. Here ResourceBundleViewResolver has order set as 1 which means Spring framework will first try to resolve view using this class.

As a rule InternalResourceViewResolver should always have higher order value because it will always be resolved to view irrespetive of value returned giving no chance to any other Resolver class.

Deploying and testing the application

Once the application is deployed to Tomcat server it can be accessed using the URL- http://localhost:8080/spring-mvc/getUsers

Spring MVC excel generation

Generated Excel for download

On clicking the View Excel button Excel sheet is generated and there is a prompt for saving it.

Generated Excel sheet

Generated excel sheet with user details.

That's all for this topic Spring MVC Excel Generation Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring MVC File Upload (Multipart Request) Example
  2. Spring MVC Example With @PathVaribale - Creating Dynamic URL
  3. Spring MVC Form Example With Bean Validation
  4. Spring Transaction Management JDBC Example Using @Transactional Annotation
  5. JDBCTemplate With ResultSetExtractor Example in Spring

You may also like -

>>>Go to Spring Tutorial Page

Monday, 17 September 2018

Spring MVC PDF Generation Example

In this post we’ll see how to generate a PDF in Spring MVC using the fields from a view page (JSP).

Technologies used

Following is the list of tools used for the Spring MVC PDF generation example.

  • Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  • Java 10
  • Tomcat server V 9.0.10
  • Eclipse Photon 4.8.0 for Java EE development (This Eclipse version supports Java 10)
  • iText 7.1.3
  • OpenPDF 1.2.3

Options for generating PDF in Spring MVC

  1. One of the option for generating PDF is iText. In Spring framework iText support is for a very old version so requires some work on your behalf to get it work with the current versions.
  2. Another option is OpenPDF which is a fork from iText. Spring framework class AbstractPdfView can directly be used to generate PDF using OpenPDF. Spring framework recommends OpenPDF.
    Reference - https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/view/document/AbstractPdfView.html

Spring MVC PDF generation example using iText

First we’ll see how to generate a PDF using iText.

Maven dependencies

Maven is used for managing dependencies in this Spring MVC PDF generation example.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>spring-mvc</groupId>
  <artifactId>spring-mvc</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>Spring MVC</name>
  <description>Spring MVC example</description>
  <properties>
    <spring.version>5.0.8.RELEASE</spring.version>
  </properties>
  <dependencies>
    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-core</artifactId>
       <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.0</version>
        <scope>provided</scope>
    </dependency>
    <!-- For JSTL tags -->
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- For iText -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>kernel</artifactId>
        <version>7.1.3</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
       <artifactId>layout</artifactId>
        <version>7.1.3</version>
    </dependency>
  </dependencies>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
          <release>10</release>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.1</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

In the pom.xml apart from Spring framework dependencies, iText dependencies are also added which adds the following jars.

kernel-7.1.3.jar
io-7.1.3.jar
layout-7.1.3.jar

Spring MVC PDF generation example flow

In the example there is a JSP that shows a list of Users and there is a button “ViewPDF”. In the JSP that list of users is bound to a Model.

When the button is clicked, the request is mapped to the appropriate controller method and from there the logical view name and Model where the list of users is set as attribute is transferred to the view which creates a PDF. To resolve a view to a PDF another view resolver has to be added.

Spring MVC PDF generation – iText related classes

With in Spring framework there is an abstract class AbstractPdfView which acts as a superclass for PDF views. But the AbstractPdfView class works with the original iText 2.1.7 version (with com.lowagie.* package) where as the current version is iText 7.x (with com.itextpdf package).

That requires some work on your behalf to make the Spring MVC work with the current iText version. AbstractPdfView class extends AbstractView class and adds PDF specific functionality. So, you need to do that yourself, creating a class that extends AbstractView and uses the new com.itextpdf package. You can still copy most of the functionality from the AbstractPdfView class, difference is now you are pointing to the com.itextpdf.* classes where as AbstractPdfView class uses the older com.lowagie.* classes. Also code for PDF generation in iText 7.x is a little different from iText 5.x version.

import java.io.ByteArrayOutputStream;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.AbstractView;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;

public abstract class NetJSAbstractViewPDF extends AbstractView {
    
    public NetJSAbstractViewPDF() {
        setContentType("application/pdf");
    }
    
    @Override
    protected boolean generatesDownloadContent() {
        return true;
    }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // IE workaround: write into byte array first.
        ByteArrayOutputStream baos = createTemporaryOutputStream();

        // Apply preferences and build metadata.
        PdfWriter writer = new PdfWriter(baos);
        Document document = new Document(new PdfDocument(writer), PageSize.A4);
    
        buildPdfMetadata(model, document, request);

        // Build PDF document.
        buildPdfDocument(model, document, writer, request, response);
        document.close();

        // Flush to HTTP response.
        writeToResponse(response, baos);
    }
    
    protected void buildPdfMetadata(Map<String, Object> model, Document document, HttpServletRequest request) {
    }
    
    protected abstract void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

Now NetJSAbstractViewPDF is the abstract class which provides the PDF specific functionality and you need to extend this class to implement abstract method buildPdfDocument() as per your PDF document structure requirements.

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.netjs.model.User;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.UnitValue;

public class PDFView extends NetJSAbstractViewPDF {

    @Override
    protected void buildPdfDocument(Map<String, Object> model, Document document, 
      PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // List of users that will be displayed in the PDF
        List<User> users = (List<User>)model.get("Users");
        // Create table with 3 columns of similar length
        Table table = new Table(new float[]{4, 4, 4});
        table.setWidth(UnitValue.createPercentValue(100));
        PdfFont bold = PdfFontFactory.createFont("Times-Bold");
        // adding header
        table.addHeaderCell(new Cell().add(new Paragraph("First Name").setFont(bold)));
        table.addHeaderCell(new Cell().add(new Paragraph("Last Name").setFont(bold)));
        table.addHeaderCell(new Cell().add(new Paragraph("Email").setFont(bold)));
        // adding rows
        for(User user : users) {
            table.addCell(user.getFirstName());
            table.addCell(user.getLastName());
            table.addCell(user.getEmail());
        }
        
        document.add(table);
    }
}

Spring MVC PDF generation – Controller Class

import java.util.ArrayList;
import java.util.List;

import org.netjs.model.User;
import org.netjs.model.UserListContainer;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UserController {
    @RequestMapping(value = "/getUsers", method = RequestMethod.GET)
    public String getUsers(Model model) throws Exception{
        List<User> users = getListOfUsers();
        UserListContainer userList = new UserListContainer();
        userList.setUsers(users);
        model.addAttribute("Users", userList);
        return "showUsers";
    }
    
    @RequestMapping(value = "/viewPDF", method = RequestMethod.POST)
    public ModelAndView viewPDF(@ModelAttribute("Users") UserListContainer userList) throws Exception{
        List<User> users = userList.getUsers();
        return new ModelAndView("viewPDF", "Users", users);
    }
    
    // Dummy method for adding List of Users
    private List<User> getListOfUsers() {
        List<User> users = new ArrayList<User>();
        users.add(new User("Jack", "Reacher", "abc@xyz.com"));
        users.add(new User("Remington", "Steele", "rs@cbd.com"));
        users.add(new User("Jonathan", "Raven", "jr@sn.com"));
        return users;
    }
}

In the Controller class there are two handler methods. Method getUsers() displays the list of users in a JSP page (showUsers.jsp). In that JSP there is a “View PDF” button, the request created on clicking that button is handled by the handler method viewPDF() which passes the list of users and the logical view name to be resolved to a PDF view.

Spring MVC PDF generation – Views

showUsers.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring MVC List of objects display</title>
</head>
<body>
<form:form method="POST" action="viewPDF" modelAttribute="Users">
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
<c:forEach items="${Users.users}" var="user" varStatus="tagStatus">
    <tr>
        <td><form:input path="users[${tagStatus.index}].firstName" value="${user.firstName}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].lastName" value="${user.lastName}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].email" value="${user.email}" readonly="true"/></td>
    </tr>
</c:forEach>
</table>
<input type="submit" value="View PDF" />
</form:form>
</body>
</html>

This JSP displays the users in the List by iterating the List and again bind list to the Model. Clicking “View PDF” button generates the PDF using the List bound to the Model.

We have already seen the PDF view class PDFView.java.

Spring MVC PDF generation – Model Classes

List will have objects of the User class.

public class User {

 private String firstName;
 private String lastName;
 private String email;
 public User() {
  
 }
 public User(String firstName, String lastName, String email) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.email = email;
 }
 
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}

Following class acts a container for the List of User objects.

public class UserListContainer {
    private List<User> users;

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

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

Spring MVC PDF generation – Configuration

The Spring configuration file is as follows.

mvcexample-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
        
     <mvc:annotation-driven />
     <context:component-scan base-package="org.netjs.controller" />
      <bean id="PDFResolver" class=
        "org.springframework.web.servlet.view.ResourceBundleViewResolver">
         <property name="order" value="1"/>
        <property name="basename" value="pdf-view"/>
    </bean>
     <bean id="JSPViewResolver" class=
        "org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="2"/>
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

As you can see two view resolver classes are configured here.

ResourceBundleViewResolver resolves the views from the properties file. ResourceBundleViewResolver is the Implementation of ViewResolver that uses bean definitions in a ResourceBundle, specified by the bundle base name, and for each view it is supposed to resolve, it uses the value of the property [viewname].(class) as the view class and the value of the property [viewname].url as the view url.
Here “basename” property has the value pdf-view which means properties file is named pdf-view.properties file.

pdf-view.properties

viewPDF.(class)=org.netjs.config.PDFView

Controller class handler method viewPDF returns logical view name as “viewPDF” which is used to resolve the view class using this properties file.

Another view resolver InternalResourceViewResolver is used to resolve the view name to JSPs.

Here note that both the Resolvers have a property order too which decides the priority. Lower order value means higher priority. Here ResourceBundleViewResolver has order set as 1 which means Spring framework will first try to resolve view using this class.

As a rule InternalResourceViewResolver should always have higher order value because it will always be resolved to view irrespetive of value returned giving no chance to any other Resolver class.

Spring MVC PDF generation using OpenPDF

If you are using OpenPDF to generate PDF in your Spring MVC application then you need to make following changes.

Maven dependency

For OpenPDF you need to add following dependency in your pom.xml

<dependency>
        <groupId>com.github.librepdf</groupId>
        <artifactId>openpdf</artifactId>
        <version>1.2.3</version>
</dependency>

PDF view class

When using OpenPDF you can directly subclass AbstractPdfView as OpenPDF uses com.lowagie.* classes, no need to create your own Abstract class by extending AbstractView class.

import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.netjs.model.User;
import org.springframework.web.servlet.view.document.AbstractPdfView;
import com.lowagie.text.Document;
import com.lowagie.text.Font;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;

public class OpenPDFView extends AbstractPdfView{

    @Override
    protected void buildPdfDocument(Map<String, Object> model, Document document, 
       PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("buildPdfDocument in OpenPDFView");
        // List of users that will be displayed in the PDF
        List<User> users = (List<User>)model.get("Users");
        Font font = new Font(Font.HELVETICA, 18, Font.BOLDITALIC);

        PdfPTable table = new PdfPTable(3);
        table.setWidthPercentage(100.0f);
        table.setWidths(new float[] {4.0f, 4.0f, 4.0f});
        PdfPCell cell = new PdfPCell();
        cell.setPhrase(new Phrase("First Name", font));
        table.addCell(cell);
        cell.setPhrase(new Phrase("Last Name", font));
        table.addCell(cell);
        cell.setPhrase(new Phrase("Email", font));
        table.addCell(cell);
        // adding rows
        for(User user : users) {
            table.addCell(user.getFirstName());
            table.addCell(user.getLastName());
            table.addCell(user.getEmail());
        }
        // adding table to document
        document.add(table);
    }
}

Properties class change

In properties class referred by ResourceBundleViewResolver, now the view class should be this new PDF view class.

pdf-view.properties

viewPDF.(class)=org.netjs.config.OpenPDFView

Deploying and testing the application

Once the application is deployed to Tomcat server it can be accessed using the URL- http://localhost:8080/spring-mvc/getUsers

Spring MVC PDF generation

Generated PDF

On clicking the View PDF button PDF is generated. Screen shot shows how it looks like in Chrome browser.

Spring MVC pdf generation

That's all for this topic Spring MVC PDF Generation Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring MVC File Download Example
  2. Spring MVC Redirect Example
  3. Spring MVC Exception Handling Example Using @ExceptionHandler And @ControllerAdvice
  4. Spring MVC Example With @PathVaribale - Creating Dynamic URL
  5. Spring Transaction Management JDBC Example Using @Transactional Annotation

You may also like -

>>>Go to Spring Tutorial Page

Friday, 14 September 2018

Spring MVC - Binding List of Objects Example

In this post we’ll see how to bind a list of objects in Spring MVC so that the objects in that List can be displayed in the view part.

Technologies used

Following is the list of tools used for the Spring MVC form example with bean validation.

  1. Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  2. Java 10
  3. JSTL 1.2
  4. Tomcat server V 9.0.10
  5. Eclipse Photon 4.8.0 for Java EE development (This Eclipse version supports Java 10)

Spring MVC Project structure using Maven

Maven Dependencies

JSTL tags are also used in this Spring MVC example for binding list of objects so you need to add the following Maven dependency for JSTL apart from Spring dependencies.

<dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
</dependency>

It adds the following jar-

jstl-1.2.jar

Spring MVC binding List example – Required XML Configuration

Since JSTL tags are used in JSP so you need your view to resolve to JstlView, for that you need to add viewClass property in the bean definition for InternalResourceViewResolver in your DispatcherServlet configuration.

<bean class=
        "org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

Spring MVC binding List example – Model classes

List will have objects of the User class.
public class User {

 private String firstName;
 private String lastName;
 private String email;
 public User() {
  
 }
 public User(String firstName, String lastName, String email) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.email = email;
 }
 
 public String getFirstName() {
  return firstName;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
}

Following class acts a container for the List of User objects.

public class UserListContainer {
    private List<User> users;

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

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

Spring MVC binding List example – Controller class

@Controller
public class UserController {
    @RequestMapping(value = "/getUsers", method = RequestMethod.GET)
    public String getUsers(Model model) throws Exception{
        List<User> users = getListOfUsers();
        UserListContainer userList = new UserListContainer();
        userList.setUsers(users);
        model.addAttribute("Users", userList);
        return "showUsers";
    }
    
    // Dummy method for adding List of Users
    private List<User> getListOfUsers() {
        List<User> users = new ArrayList<User>();
        users.add(new User("Jack", "Reacher", "abc@xyz.com"));
        users.add(new User("Remington", "Steele", "rs@cbd.com"));
        users.add(new User("Jonathan", "Raven", "jr@sn.com"));
        return users;
    }
    
}

In the controller class there is a handler method getUsers() where a list of users is created and set to the UserListContainer which in turn is added as an attribute to the Model. Logical view name returned from the method is showUsers which resolves to a JSP at the location WEB-INF\jsp\showUsers.jsp.

Spring MVC binding List example – Views

If you just want to iterate the list and show the object fields then you can use the given JSP.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring MVC List of objects display</title>
</head>
<body>
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
<c:forEach items="${Users.users}" var="user" varStatus="tagStatus">
    <tr>
        <td>${user.firstName}</td>
        <td>${user.lastName}</td>
        <td>${user.email}</td>
    </tr>
</c:forEach>
</table>
</body>
</html>

If you want to iterate the list, show the object fields and want to bind the List of objects again to modelAttribute then you can use the following JSP.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring MVC List of objects display</title>
</head>
<body>
<form:form method="POST" action="saveUsers" modelAttribute="Users">
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
<c:forEach items="${Users.users}" var="user" varStatus="tagStatus">
    <tr>
        <td><form:input path="users[${tagStatus.index}].firstName" value="${user.firstName}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].lastName" value="${user.lastName}" readonly="true"/></td>
        <td><form:input path="users[${tagStatus.index}].email" value="${user.email}" readonly="true"/></td>
    </tr>
</c:forEach>
</table>
<input type="submit" value="Save" />
</form:form>
</body>
</html>

In this JSP Spring form tags are used for Spring MVC form fields and for looping the List JSTL tag is used. For these tag libraries following lines are added in the JSP.

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

To verify that the List of users is added to the Model and can be accessed in the handler method you can add the following method in the Controller class.

@RequestMapping(value = "/generatePDF", method = RequestMethod.POST)
public void generatePDF(@ModelAttribute("Users") UserListContainer userList) throws Exception{
    List<User> users = userList.getUsers();
    for(User user : users) {
        System.out.println("First Name- " + user.getFirstName());
    }
}

Once the application is deployed it can be accessed using the URL - http://localhost:8080/spring-mvc/getUsers

Just showing the object fields

Binding list of objects

Showing the object fields and binding to Model

Binding list of objects Spring MVC

That's all for this topic Spring MVC - Binding List of Objects Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring MVC File Download Example
  2. Spring MVC Exception Handling Example Using @ExceptionHandler And @ControllerAdvice
  3. Difference Between @Controller And @RestController Annotations in Spring
  4. Spring MVC Dot (.) Truncation Problem With @PathVariable Annotation
  5. Insert\Update Using JDBCTemplate in Spring Framework

You may also like -

>>>Go to Spring Tutorial Page

Wednesday, 12 September 2018

Spring MVC Dot (.) Truncation Problem With @PathVariable Annotation

In your Spring Web MVC application if you are using @PathVariable annotation along with @RequestMapping annotation to retrieve the parameter from the request path, then you may come across one problem- If the passed parameter has a value with a dot in it (i.e. xxx.xx) then the portion after the last dot (.), including dot, gets truncated when the value is assigned to the variable annotated with @PathVariable annotation.

For example – If you have a handler method in your controller like below.

@RequestMapping(value = "/ip/{address}")
public void processIP(@PathVariable("address") String address) {
 ..
 ..
}

Then the URI /ip/345.67.56.45 will assign 345.67.56 to the variable address.
URI /ip/198.201.231 will assign 198.201 to the variable address.

So, you can see that the value starting from the last dot is always truncated while assigning to the variable annotated with @PathVariable annotation.

Solution to the @PathVariable truncation probelm

Solution for this truncation problem is to include a regex (.+) in the @RequestMapping URI. Here regex (.+) means- match one or more of the token given with (+). That way you are explicitly asking Spring framework to match all the tokens (. in this case) and don’t leave any.

Thus the handler method should be written as following to avoid the dot (.) truncation problem.

@RequestMapping(value = "/ip/{address:.+}")
public void processIP(@PathVariable("address") String address) {
 ..
 ..
}

That's all for this topic Spring MVC Dot (.) Truncation Problem With @PathVariable Annotation. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring Web MVC Tutorial
  2. Spring MVC Example With @RequestParam Annotation
  3. Spring MVC Exception Handling Example Using @ExceptionHandler And @ControllerAdvice
  4. Spring MVC File Upload (Multipart Request) Example
  5. Spring Transaction Management JDBC Example Using @Transactional Annotation

You may also like -

>>>Go to Spring Tutorial Page

Tuesday, 11 September 2018

Spring MVC File Download Example

In this post we’ll see a Spring MVC application to download a file (image, pdf, zip etc.) from web server.

Options in Spring MVC for file download

  • In your Spring MVC application for file download you can use HttpServletResponse to write the downloaded file to the output stream of the servlet response. If you are using this option then you need to do the following.
    1. Pass HttpServletResponse as a parameter to your controller handler method and the method's return type is void.
    2. Find MIME type of the content of downloaded file and set it to the response's content type. If you are not able to detect the mime type set it to application/octet-stream. Mime type can be any of these- application/pdf, application/xml, image/png, image/jpeg etc.
    3. In response set a Content-Disposition header- response.setHeader(“Content-Disposition”, “attachment; filename=” + fileName); Where fileName is the name of the file to be downloaded.
    4. Copy the file bytes to the OutputStream of response.
  • You can return the file from the controller handler method as a FileSystemResource wrapped with in ResponseEntity i.e. ResponseEntity<FileSystemResource>. If you are using this option then you need to do the following.
    1. Return type of the controller handler method is ResponseEntity<FileSystemResource>.
    2. Find MIME type of the content of downloaded file and set it to the response's header. If you are not able to detect the mime type set it to application/octet-stream. Mime type can be any of these- application/pdf, application/xml, image/png, image/jpeg etc.
    3. In response set a Content-Disposition header- response.setHeader(“Content-Disposition”, “attachment; filename=” + fileName); Where fileName is the name of the file to be downloaded.
    4. Set the response status code as OK.
    5. Set the content of the file as response entity body.

Spring MVC file download example – Technologies used

Following is the list of tools used for the Spring MVC file download example.

  1. Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  2. Java 10
  3. Tomcat server V 9.0.10
  4. Eclipse Photon 4.8.0 for Java EE development.

Spring MVC file download example project structure using Maven

Spring MVC file download example – View

In the JSP there are two links for downloading two files.

download.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<body>
    <a href='<s:url value="/downloadFileUsingResponse/Rules.pdf"></s:url>'>Download Rules.pdf</a><br/>
    <a href='<s:url value="/downloadFileUsingEntity/Test.png"></s:url>'>Download Test.png</a>
</body>
</body>
</html>

As you can see Spring tags library is used here for creating the URL. For that you need to add the following line in your JSP.

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>

After the application is deployed the JSP page can be accessed using the URL- http://localhost:8080/spring-mvc/download

Here spring-mvc is the name of the Spring MVC application.

Spring MVC file download

Spring MVC file download example – Controller Class

@Controller
public class DownloadController {
    @RequestMapping(value = "/download", method = RequestMethod.GET)
    public String showDownload(Model model) {    
        return "download";
    }
    
    @RequestMapping(value = "/downloadFileUsingResponse/{fileName:.+}")
    public void downloadFileAsResponse(HttpServletRequest request, 
        HttpServletResponse response, @PathVariable("fileName") String fileName) {
        try {
            // getting the path to file 
            String dir = request.getServletContext().getRealPath("/WEB-INF/resources/");            
            Path file = Paths.get(dir, fileName);
            if(!Files.exists(file)){
                String errorMessage = "File you are trying to download does 
                  not exist on the server.";            
                OutputStream outputStream = response.getOutputStream();
                outputStream.write(errorMessage.getBytes(Charset.forName("UTF-8")));
                outputStream.close();
                return;
            }
            // getting mimetype from context
            String mimeType= request.getServletContext().getMimeType(
              file.getFileName().toString());
            if(mimeType == null){
                // Not able to detect mimetype taking default
                mimeType = "application/octet-stream";
            }
            response.setContentType(mimeType);
            response.addHeader("Content-Disposition", "attachment; filename="+fileName);        
            Files.copy(file, response.getOutputStream());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    @RequestMapping(value = "/downloadFileUsingEntity/{fileName:.+}")
    public ResponseEntity<FileSystemResource> downloadFileAsEntity(
            HttpServletRequest request, @PathVariable("fileName") String fileName) {
        
            String dir = request.getServletContext().getRealPath("/WEB-INF/resources/");
            
            Path file = Paths.get(dir, fileName);
            FileSystemResource fileResource = new FileSystemResource(file.toFile());
            if(!Files.exists(file)){                     
                return ResponseEntity.notFound().build();
            }
            // getting mimetype from context
            String mimeType= request.getServletContext().getMimeType(
                file.getFileName().toString());
            if(mimeType==null){
                // Not able to detect mimetype taking default
                mimeType = "application/octet-stream";
            }
            return ResponseEntity.ok()
            .header("Content-Disposition", "attachment; filename="+fileName)
            .contentType(MediaType.valueOf(mimeType)).body(fileResource);
    }
}
  • There are two methods in the controller class for handling download requests. First method downloadFileAsResponse() uses the HttpServletResponse to write the downloaded file to the output stream of the servlet response.
    Second method downloadFileAsEntity() uses the option where FileSystemResource is wrapped with in ResponseEntity and that is returned from the method.
  • File name is passed as a parameter with in the request path and @PathVariable annotation is used to retrieve the parameter from the request path.
  • In case you are wondering why path given along with @RequestMapping has a regular expression .+ in it, please refer this post- Spring MVC Dot (.) Truncation Problem With @PathVariable Annotation
  • Path where files are kept is WEB-INF/resources, in the controller methods file is read from that location. You can change it to some other location, read it through a property file or give an absolute path as per your requirement.
  • In the methods, mime type is detected from the file name. Mime type “application/octet-stream” is used as default.

That's all for this topic Spring MVC File Download Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring Web MVC Tutorial
  2. Spring MVC Example With @RequestParam Annotation
  3. Connection Pooling Using C3P0 Spring Example
  4. Spring Transaction Management JDBC Example Using @Transactional Annotation
  5. How to Read Properties File in Spring Framework

You may also like -

>>>Go to Spring Tutorial Page

Thursday, 6 September 2018

Spring MVC File Upload (Multipart Request) Example

In this post we’ll see a Spring MVC file upload example for single and multiple files.

Following is the list of tools used for the Spring MVC file upload example.

  1. Spring 5.0.8 Release (Spring core, spring web, spring webmvc).
  2. Java 10
  3. commons-fileupload 1.3.3 (If using Apache Commons file upload)
  4. Tomcat server V 9.0.10
  5. Eclipse Photon 4.8.0 for Java EE development (This Eclipse version supports Java 10)

Multipart support in Spring

Spring framework provides an interface MultipartResolver residing in org.springframework.web.multipart package for parsing multipart requests including file uploads.

Spring framework provides support for two implementations of MultipartResolver-

  • Implementation based on Apache Commons FileUpload
  • Implementation based on Servlet 3.0 support for multipart request parsing.

In this post we’ll see Spring file upload example using both of these implementations and with both Spring XML configuration and Java configuration.

Spring MVC Project structure for file upload using Maven

Spring file upload (multipart request) using Servlet 3.0 support

In my opinion using Servlet 3.0 support for file upload is the better option as you don’t need any additional dependencies to use it, existing servlet container (if it supports servlet 3.0 or higher) will suffice.

Spring Servlet 3.0 support for file upload – Required XML Configuration

To use Servlet 3.0 multipart support you need to add a bean of type StandardServletMultipartResolver in your DispatcherServlet configuration.

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"></bean>

StandardServletMultipartResolver bean has no properties to set, if you want to set some constraints on your file upload like maximum file upload size or temporary location then you need to add a "<multipart-config>" section in web.xml

  <servlet>
    <servlet-name>mvcexample</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <multipart-config>
          <!-- 2 MB max file upload size -->
          <max-file-size>2097152</max-file-size>
      </multipart-config>
  </servlet>

Spring Servlet 3.0 support for file upload – Required Java Configuration

If you prefer Spring Java config rather than XML configuration then you need to declare StandardServletMultipartResolver as a bean and need to set a MultipartConfigElement on the Servlet registration for setting configurations like maximum size or storage location.

For Spring MVC with Java config generally AbstractAnnotationConfigDispatcherServletInitializer is used to register DispatcherServlet and it is done automatically. In that case customizeRegistration() method is used to set a MultipartConfigElement on the Servlet registration.

Here is the full class -

import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpringMVCConfigInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
    
    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        registration.setMultipartConfig(new MultipartConfigElement("", 2097152, 4193304, 2097152));    
    }
}
Here note the method customizeRegistration which uses instance of MultipartConfigElement, description of which is as follows.
public MultipartConfigElement(String location,
                              long maxFileSize,
                              long maxRequestSize,
                              int fileSizeThreshold)
  • location- the directory location where files will be stored.
  • maxFileSize- the maximum size allowed for uploaded files.
  • maxRequestSize- the maximum size allowed formultipart/form-data requests.
  • fileSizeThreshold- the size threshold after which files will be written to disk.

Declaring StandardServletMultipartResolver as a bean – Java config

@Configuration
@EnableWebMvc
@ComponentScan(basePackages="org.netjs.controller")
public class WebConfig implements WebMvcConfigurer {
 
 @Bean
 public ViewResolver viewResolver() {
  InternalResourceViewResolver resolver = new InternalResourceViewResolver();
  resolver.setPrefix("/WEB-INF/jsp/");
  resolver.setSuffix(".jsp");
  return resolver;
 }
 
 public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
  configurer.enable();
 }
 
 @Bean
 public MultipartResolver multipartResolver() {
  return new StandardServletMultipartResolver();
 }
}

Spring file upload (multipart request) using Commons FileUpload

Another option for parsing multipart request in Spring framework is using Commons FileUpload.

Maven dependency

To use Commons FileUpload you need to have commons-fileupload as a dependency on your classpath. If you are using Maven that can be added in pom.xml as follows-
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
That adds the following jars-
commons-fileupload-1.3.3.jar
commons-io-2.2.jar

Using Commons FileUpload for file upload – Required Spring XML Configuration

To use Apache Commons FileUpload for multipart support you need to configure a bean of type CommonsMultipartResolver with the name multipartResolver in your DispatcherServlet configuration.

<bean id="multipartResolver"   class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="2097152" />
</bean>

CommonsMultipartResolver provides "maxUploadSize", "maxInMemorySize" and "defaultEncoding" settings as bean properties itself so need to add properties in web.xml as in the case with StandardServletMultipartResolver.

Using Commons FileUpload for file upload – Required Java Configuration

If you prefer Spring Java config then you can configure CommonsMultipartResolver as bean in the following way.

@Bean
public MultipartResolver multipartResolver() throws IOException {
 CommonsMultipartResolver cmr = new CommonsMultipartResolver();
 cmr.setMaxUploadSize(2097152);
 return cmr;
}

Spring MVC file upload example– Views

JSP that is used for uploading a single file.

uploadFile.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <form action="uploadFile" method="post" enctype="multipart/form-data">
        <table>
         <tr>
             <td>
                 <label>Select a file to upload:</label>
                 <input type="file" name="file">
             </td>
         </tr>
         <tr>
             <td><input type="submit" value="Upload File"></td>
         </tr>
     </table>
    </form>
</body>
</html>

In the JSP, enctype="multipart/form-data" attribute is used with the form tag to specify that it is a multipart request.

JSP that is used for uploading multiple files.

uploadMultipleFiles.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spring File Upload</title>
</head>
<body>
    <form action="uploadMultiFile" method="POST" enctype="multipart/form-data">
        <table>
         <tr>
             <td>
                 <label>Select a file to upload:</label>
                 <input type="file" name="files">
             </td>
         </tr>
         <tr>
             <td>
                 <label>Select a file to upload:</label>
                 <input type="file" name="files">
             </td>
         </tr>
                  <tr>
             <td>
                 <label>Select a file to upload:</label>
                 <input type="file" name="files">
             </td>
         </tr>
         <tr>
             <td><input type="submit" value="Upload"></td>
         </tr>
     </table>
    </form>
</body>
</html>

Here note that the same name “files” is used in all the input fields. That is required so that request is sent as an array of files.

Another JSP shows the upload status by showing a message set in the controller for success or failure of the upload. Also shows some metadata about the uploaded file like name, size and content type.

uploadStatus.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<table>
    <tr>
        <td>Upload status: ${message}</td>
    </tr>
    <tr>
        <td>File Name: ${file.getOriginalFilename()}</td>
    </tr>
    <tr>
        <td>File Size: ${file.getSize()}</td>
    </tr>
    <tr>
        <td>File Type: ${file.getContentType()}</td>
    </tr>
</table>
</body>
</html> 

Spring MVC file upload – Controller class

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class FileUploadController {
    @RequestMapping(value = "/uploadMulti", method = RequestMethod.GET)
    public String startMultiUpload(Model model) {    
        return "uploadMultipleFiles";
    }
    
    @RequestMapping(value = "/upload", method = RequestMethod.GET)
    public String startUpload(Model model) {    
        return "uploadFile";
    }
    
    // Handler Method for file upload
    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
        String msg= "";
        if(!file.isEmpty()) {
            BufferedOutputStream bos =null;
            try {
                byte[] fileBytes = file.getBytes();
                // location to save the file
                String fileName = "G:\\Test\\"+file.getOriginalFilename();
                bos = new BufferedOutputStream(new FileOutputStream(new File(fileName)));
                bos.write(fileBytes);
                msg = "Upload successful for " + file.getName();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally {
                if(bos != null) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }else {
            msg = "Upload failed for " + file.getName() + " as file is empty";
        }
        model.addAttribute("message", msg);
        model.addAttribute("file", file);
        return "uploadStatus";
    }
    
    // Handler Method for multiple file uploads
    @PostMapping(value = "/uploadMultiFile")
    @ResponseBody
    public String uploadMultipleFiles(@RequestParam("files") MultipartFile[] files, Model model) {
        String msg= "";
        int emptyCount = 0;
        for(MultipartFile file : files) {
            if(!file.isEmpty()) {
                BufferedOutputStream bos =null;
                try {
                    byte[] fileBytes = file.getBytes();
                    // location to save the file
                    String fileName = "G:\\Test\\"+file.getOriginalFilename();
                    bos = new BufferedOutputStream(new FileOutputStream(new File(fileName)));
                    bos.write(fileBytes);
                    msg = msg + "Upload successful for " + file.getOriginalFilename() + "<br />";
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }finally {
                    if(bos != null) {
                        try {
                            bos.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }else {
                emptyCount++;
                
            }
        }
        // Equal means no file is selected for upload
        if(files.length == emptyCount) {
            msg = "Upload failed as no file is selected";
        }
        return msg;
    }
}

In the controller class, uploadFile() method is used for handling single file upload request which has a parameter of type MultipartFile. In the logic for saving the uploaded file at a location, file path is hardcoded, you may change it to get the path from a property file or with respect to server path.

uploadMultipleFiles() method is used for handling multiple file uploads in the Spring Controller class. In the method note that MultipartFile[] parameter is an array now for holding multiple files. Method uses the new Annotation @PostMapping (from Spring 4.3) which is the shortcut for @RequestMapping(method = RequestMethod.POST).

Also uses the annotation @ResponseBody that indicates a method return value should be bound to the web response body. That way string can be returned as a response not as a logical view name to be resolved to JSP.

MultipartFile has a transferTo() method that can also be used for storing the uploaded file at the given location.

 // Handler Method for file upload
 @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
 public String uploadFile(@RequestParam("file") MultipartFile file, Model model) {
  String msg= "";
  if(!file.isEmpty()) {
   
   try {
    String fileName = "G:\\Test\\"+file.getOriginalFilename();
    // for storing uploaded file
    file.transferTo(new File(fileName));
    msg = "Upload successful for " + file.getName();
   } catch (IllegalStateException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }else {
   msg = "Upload failed for " + file.getName() + " as file is empty";
  }
  model.addAttribute("message", msg);
  model.addAttribute("file", file);
  return "uploadStatus";
 }

Spring MVC file upload example - Screens

Upload page with one PDF file selected for uploading.

Spring MVC file upload

Showing the status of the upload.

Spring MVC file upload status

If upload is not successful.

Spring MVC file upload error

Upload page for multiple uploads with two files selected for uploading.

Spring MVC multiple files upload

Showing the status of the upload.

Spring MVC multiple files upload

That's all for this topic Spring MVC File Upload (Multipart Request) Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Spring MVC Form Example With Bean Validation
  2. Spring MVC Exception Handling Example Using @ExceptionHandler And @ControllerAdvice
  3. Difference Between @Controller And @RestController Annotations in Spring
  4. Spring Batch Processing Using JDBCTemplate batchUpdate() Method
  5. Insert\Update Using NamedParameterJDBCTemplate in Spring Framework

You may also like -

>>>Go to Spring Tutorial Page