Categories: springmvc

Spring MVC 4 FileUpload-Download Hibernate+MySQL Example

This post shows uploading files into Database using Spring MVC 4, Hibernate & MySQL Database. Spring MVC File upload database example, download and delete from database using Hibernate+MySQL. Let’s get going.

Main highlights of the posts are:

  • Prepare database side setup [create required tables]
  • Prepare Model Classes, DAO and Service layer [will be used by controller to handle file upload/download/delete operation]
  • Prepate Hibernate configuration
  • Prepare Spring Configuration for File Upload/download and delete.
  • And finally run application to upload files, download files and delete files.

You may prefer to directly jump on the specific sections you are interested in as it’s a long post with complete example.


Following technologies being used:

  • Spring 4.2.0.RELEASE
  • Hibernate 4.3.10.Final
  • MySQL Server 5.6
  • validation-api 1.1.0.Final
  • hibernate-validator 5.1.3.Final
  • Bootstrap v3.3.2
  • Maven 3
  • JDK 1.7
  • Tomcat 8.0.21
  • Eclipse JUNO Service Release 2

Let’s begin.

Project directory structure

Following will be the final project structure:


Step 2: Declare Dependencies in pom.xml

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.websystique.springmvc</groupId>
  <artifactId>Spring4MVCFileUploadDownloadWithHibernate</artifactId>
  <packaging>war</packaging>
  <version>1.0.0</version>
  <name>Spring4MVCFileUploadDownloadWithHibernate Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
  
   <properties>
  <springframework.version>4.2.0.RELEASE</springframework.version>
  <hibernate.version>4.3.10.Final</hibernate.version>
  <mysql.connector.version>5.1.31</mysql.connector.version>
 </properties>

 <dependencies>
  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-tx</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>${springframework.version}</version>
  </dependency>

  <!-- Hibernate -->
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>${hibernate.version}</version>
  </dependency>

  <!-- jsr303 validation -->
  <dependency>
   <groupId>javax.validation</groupId>
   <artifactId>validation-api</artifactId>
   <version>1.1.0.Final</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>5.1.3.Final</version>
  </dependency>

  <!-- MySQL -->
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>${mysql.connector.version}</version>
  </dependency>

  <!-- Servlet+JSP+JSTL -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.1.0</version>
  </dependency>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>javax.servlet.jsp-api</artifactId>
   <version>2.3.1</version>
  </dependency>
  <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
  </dependency>
  
 </dependencies>

 <build>
  <pluginManagement>
   <plugins>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>3.2</version>
     <configuration>
      <source>1.7</source>
      <target>1.7</target>
     </configuration>
    </plugin>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-war-plugin</artifactId>
     <version>2.4</version>
     <configuration>
      <warSourceDirectory>src/main/webapp</warSourceDirectory>
      <warName>Spring4MVCFileUploadDownloadWithHibernate</warName>
      <failOnMissingWebXml>false</failOnMissingWebXml>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>
  <finalName>Spring4MVCFileUploadDownloadWithHibernate</finalName>
 </build>
</project>

Create Schema

We will take a trivial example of User and documents relationship. A User can have several documents, it’s a OneToMany Relationship between User and his Documents.

create table APP_USER (
   id BIGINT NOT NULL AUTO_INCREMENT,
   sso_id VARCHAR(30) NOT NULL,
   first_name VARCHAR(30) NOT NULL,
   last_name  VARCHAR(30) NOT NULL,
   email VARCHAR(30) NOT NULL,
   PRIMARY KEY (id),
   UNIQUE (sso_id)
);
 
 
create table USER_DOCUMENT(
   id BIGINT NOT NULL AUTO_INCREMENT,
   user_id BIGINT NOT NULL,
   name  VARCHAR(100) NOT NULL,
   description VARCHAR(255) ,
   type VARCHAR(100) NOT NULL,
   content longblob NOT NULL,
   PRIMARY KEY (id),
   CONSTRAINT document_user FOREIGN KEY (user_id) REFERENCES APP_USER (id) ON UPDATE CASCADE ON DELETE CASCADE
);

Highlight of above schema is content longblob. We will store the files into binary format in this column.

Create Model Classes

Let’s create Model classes that maps to above mentioned tables.

package com.websystique.springmvc.model;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="USER_DOCUMENT")
public class UserDocument {

 @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Integer id; 
 
 @Column(name="name", length=100, nullable=false)
 private String name;
 
 @Column(name="description", length=255)
 private String description;
 
 @Column(name="type", length=100, nullable=false)
 private String type;
 
 @Lob @Basic(fetch = FetchType.LAZY)
 @Column(name="content", nullable=false)
 private byte[] content;

 @ManyToOne(optional = false)
 @JoinColumn(name = "USER_ID")
 private User user;
 
 
 public Integer getId() {
  return id;
 }

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

 public String getName() {
  return name;
 }

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

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }

 public byte[] getContent() {
  return content;
 }

 public void setContent(byte[] content) {
  this.content = content;
 }

 public User getUser() {
  return user;
 }

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

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  result = prime * result + ((name == null) ? 0 : name.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (!(obj instanceof UserDocument))
   return false;
  UserDocument other = (UserDocument) obj;
  if (id == null) {
   if (other.id != null)
    return false;
  } else if (!id.equals(other.id))
   return false;
  if (name == null) {
   if (other.name != null)
    return false;
  } else if (!name.equals(other.name))
   return false;
  return true;
 }

 @Override
 public String toString() {
  return "UserDocument [id=" + id + ", name=" + name + ", description="
    + description + ", type=" + type + "]";
 }


 
}

Main feature of this Entity class is the content property

@Lob @Basic(fetch = FetchType.LAZY)
 @Column(name="content", nullable=false)
 private byte[] content;

We have chosen a byte[] to store the content of file. @LobSpecifies that a this persistent property should be persisted as a large object to a database-supported large object type which in our case is longblob. @Basic annotation is an optional annotation, serving here as placeholder to instruct hibernate to lazy load the binary content.

Below is the corresponding User class.

package com.websystique.springmvc.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.validator.constraints.NotEmpty;

@Entity
@Table(name="APP_USER")
public class User {

 @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Integer id;

 @NotEmpty
 @Column(name="SSO_ID", unique=true, nullable=false)
 private String ssoId;
 
 @NotEmpty
 @Column(name="FIRST_NAME", nullable=false)
 private String firstName;

 @NotEmpty
 @Column(name="LAST_NAME", nullable=false)
 private String lastName;

 @NotEmpty
 @Column(name="EMAIL", nullable=false)
 private String email;

 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private Set<UserDocument> userDocuments = new HashSet<UserDocument>();
 
 public Integer getId() {
  return id;
 }

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

 public String getSsoId() {
  return ssoId;
 }

 public void setSsoId(String ssoId) {
  this.ssoId = ssoId;
 }

 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 Set<UserDocument> getUserDocuments() {
  return userDocuments;
 }

 public void setUserDocuments(Set<UserDocument> userDocuments) {
  this.userDocuments = userDocuments;
 }


 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((id == null) ? 0 : id.hashCode());
  result = prime * result + ((ssoId == null) ? 0 : ssoId.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (!(obj instanceof User))
   return false;
  User other = (User) obj;
  if (id == null) {
   if (other.id != null)
    return false;
  } else if (!id.equals(other.id))
   return false;
  if (ssoId == null) {
   if (other.ssoId != null)
    return false;
  } else if (!ssoId.equals(other.ssoId))
   return false;
  return true;
 }

 @Override
 public String toString() {
  return "User [id=" + id + ", ssoId=" + ssoId + ", firstName=" + firstName + ", lastName=" + lastName
    + ", email=" + email + "]";
 }

}

Nothing special,just a trivial one-to-many mapping with UserDocument. A User can have several documents.

Create DAO layer

package com.websystique.springmvc.dao;

import java.util.List;

import com.websystique.springmvc.model.UserDocument;

public interface UserDocumentDao {

 List<UserDocument> findAll();
 
 UserDocument findById(int id);
 
 void save(UserDocument document);
 
 List<UserDocument> findAllByUserId(int userId);
 
 void deleteById(int id);
}
package com.websystique.springmvc.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.websystique.springmvc.model.UserDocument;

@Repository("userDocumentDao")
public class UserDocumentDaoImpl extends AbstractDao<Integer, UserDocument> implements UserDocumentDao{

 @SuppressWarnings("unchecked")
 public List<UserDocument> findAll() {
  Criteria crit = createEntityCriteria();
  return (List<UserDocument>)crit.list();
 }

 public void save(UserDocument document) {
  persist(document);
 }

 
 public UserDocument findById(int id) {
  return getByKey(id);
 }

 @SuppressWarnings("unchecked")
 public List<UserDocument> findAllByUserId(int userId){
  Criteria crit = createEntityCriteria();
  Criteria userCriteria = crit.createCriteria("user");
  userCriteria.add(Restrictions.eq("id", userId));
  return (List<UserDocument>)crit.list();
 }

 
 public void deleteById(int id) {
  UserDocument document =  getByKey(id);
  delete(document);
 }

}
package com.websystique.springmvc.dao;

import java.util.List;

import com.websystique.springmvc.model.User;


public interface UserDao {

 User findById(int id);
 
 User findBySSO(String sso);
 
 void save(User user);
 
 void deleteBySSO(String sso);
 
 List<User> findAllUsers();

}

package com.websystique.springmvc.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.websystique.springmvc.model.User;



@Repository("userDao")
public class UserDaoImpl extends AbstractDao<Integer, User> implements UserDao {

 public User findById(int id) {
  User user = getByKey(id);
  return user;
 }

 public User findBySSO(String sso) {
  System.out.println("SSO : "+sso);
  Criteria crit = createEntityCriteria();
  crit.add(Restrictions.eq("ssoId", sso));
  User user = (User)crit.uniqueResult();
  return user;
 }

 @SuppressWarnings("unchecked")
 public List<User> findAllUsers() {
  Criteria criteria = createEntityCriteria().addOrder(Order.asc("firstName"));
  criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);//To avoid duplicates.
  List<User> users = (List<User>) criteria.list();
  
  return users;
 }

 public void save(User user) {
  persist(user);
 }

 public void deleteBySSO(String sso) {
  Criteria crit = createEntityCriteria();
  crit.add(Restrictions.eq("ssoId", sso));
  User user = (User)crit.uniqueResult();
  delete(user);
 }

}

package com.websystique.springmvc.dao;

import java.io.Serializable;

import java.lang.reflect.ParameterizedType;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class AbstractDao<PK extends Serializable, T> {
 
 private final Class<T> persistentClass;
 
 @SuppressWarnings("unchecked")
 public AbstractDao(){
  this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
 }
 
 @Autowired
 private SessionFactory sessionFactory;

 protected Session getSession(){
  return sessionFactory.getCurrentSession();
 }

 @SuppressWarnings("unchecked")
 public T getByKey(PK key) {
  return (T) getSession().get(persistentClass, key);
 }

 public void persist(T entity) {
  getSession().persist(entity);
 }

 public void delete(T entity) {
  getSession().delete(entity);
 }
 
 protected Criteria createEntityCriteria(){
  return getSession().createCriteria(persistentClass);
 }

}

Create Service Layer

package com.websystique.springmvc.service;

import java.util.List;

import com.websystique.springmvc.model.UserDocument;

public interface UserDocumentService {

 UserDocument findById(int id);

 List<UserDocument> findAll();
 
 List<UserDocument> findAllByUserId(int id);
 
 void saveDocument(UserDocument document);
 
 void deleteById(int id);
}

package com.websystique.springmvc.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.websystique.springmvc.dao.UserDocumentDao;
import com.websystique.springmvc.model.UserDocument;

@Service("userDocumentService")
@Transactional
public class UserDocumentServiceImpl implements UserDocumentService{

 @Autowired
 UserDocumentDao dao;

 public UserDocument findById(int id) {
  return dao.findById(id);
 }

 public List<UserDocument> findAll() {
  return dao.findAll();
 }

 public List<UserDocument> findAllByUserId(int userId) {
  return dao.findAllByUserId(userId);
 }
 
 public void saveDocument(UserDocument document){
  dao.save(document);
 }

 public void deleteById(int id){
  dao.deleteById(id);
 }
 
}

package com.websystique.springmvc.service;

import java.util.List;

import com.websystique.springmvc.model.User;


public interface UserService {
 
 User findById(int id);
 
 User findBySSO(String sso);
 
 void saveUser(User user);
 
 void updateUser(User user);
 
 void deleteUserBySSO(String sso);

 List<User> findAllUsers(); 
 
 boolean isUserSSOUnique(Integer id, String sso);

}
package com.websystique.springmvc.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.websystique.springmvc.dao.UserDao;
import com.websystique.springmvc.model.User;


@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{

 @Autowired
 private UserDao dao;

 public User findById(int id) {
  return dao.findById(id);
 }

 public User findBySSO(String sso) {
  User user = dao.findBySSO(sso);
  return user;
 }

 public void saveUser(User user) {
  dao.save(user);
 }

 /*
  * Since the method is running with Transaction, No need to call hibernate update explicitly.
  * Just fetch the entity from db and update it with proper values within transaction.
  * It will be updated in db once transaction ends. 
  */ public void updateUser(User user) {
  User entity = dao.findById(user.getId());
  if(entity!=null){
   entity.setSsoId(user.getSsoId());
   entity.setFirstName(user.getFirstName());
   entity.setLastName(user.getLastName());
   entity.setEmail(user.getEmail());
   entity.setUserDocuments(user.getUserDocuments());
  }
 }

 
 public void deleteUserBySSO(String sso) {
  dao.deleteBySSO(sso);
 }

 public List<User> findAllUsers() {
  return dao.findAllUsers();
 }

 public boolean isUserSSOUnique(Integer id, String sso) {
  User user = findBySSO(sso);
  return ( user == null || ((id != null) && (user.getId() == id)));
 }
 
}

Create Hibernate Configuration Class

package com.websystique.springmvc.configuration;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.websystique.springmvc.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {

    @Autowired
    private Environment environment;

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.websystique.springmvc.model" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }
 
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }
    
    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        return properties;        
    }
    
 @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}

This class uses following application.properties

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/websystique
jdbc.username = myuser
jdbc.password = mypassword
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.show_sql = true
hibernate.format_sql = true

Prepare Configuration for File Upload

Spring provides several possibilities to upload a file. We will use one of possible way, which is Programmatic registration of Servlet 3.0 specific javax.servlet.MultipartConfigElement with SpringMVC DispatcherServlet. This registration provides opportunity to set specific properties like maximum file size, request size, location and threshold after which file will be stored temporarily on disk during upload operation.

Additionally, we need to add StandardServletMultipartResolver Bean to our Spring Configuration. It’s a standard implementation of the MultipartResolver interface, based on the Servlet 3.0 javax.servlet.http.Part API.

package com.websystique.springmvc.configuration;

import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

 @Override
 protected Class<?>[] getRootConfigClasses() {
  return new Class[] { HelloWorldConfiguration.class };
 }
 
 @Override
 protected Class<?>[] getServletConfigClasses() {
  return null;
 }
 
 @Override
 protected String[] getServletMappings() {
  return new String[] { "/" };
 }

    @Override
 protected void customizeRegistration(ServletRegistration.Dynamic registration) {
     registration.setMultipartConfig(getMultipartConfigElement());
 }

    private MultipartConfigElement getMultipartConfigElement(){
  MultipartConfigElement multipartConfigElement = new MultipartConfigElement(LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
  return multipartConfigElement;
 }
    
    /*Set these variables for your project needs*/ 
    
 private static final String LOCATION = "C:/mytemp/";

 private static final long MAX_FILE_SIZE = 1024 * 1024 * 25;//25MB
 
 private static final long MAX_REQUEST_SIZE = 1024 * 1024 * 30;//30MB

 private static final int FILE_SIZE_THRESHOLD = 0;
}

Notice how we have overridden function customizeRegistration in order to register the required MultiPartConfigElement to DispatcherServlet. The next step to activate multipart support is to register a Bean of type StandardServletMultipartResolver as shown below in configuration class.

Remarks
This article is showing only one way of file upload with Spring. You may also like Spring MVC 4 File Upload Example using Commons fileupload and Spring MVC 4 File Upload Example using Servlet 3 MultiPartConfigElement to learn more details and other possibilities to upload a file with Spring.

Create Spring Configuration Class

package com.websystique.springmvc.configuration;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;


@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.websystique.springmvc")
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter{
 
 @Bean(name="multipartResolver")
 public StandardServletMultipartResolver resolver(){
  return new StandardServletMultipartResolver();
 }

 /**
     * Configure ViewResolvers to deliver preferred views.
     */ @Override
 public void configureViewResolvers(ViewResolverRegistry registry) {

  InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
  viewResolver.setViewClass(JstlView.class);
  viewResolver.setPrefix("/WEB-INF/views/");
  viewResolver.setSuffix(".jsp");
  registry.viewResolver(viewResolver);
 }
 
 /**
     * Configure ResourceHandlers to serve static resources like CSS/ Javascript etc...
     */    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
    
    /**
     * Configure MessageSource to lookup any validation/error message in internationalized property files
     */    @Bean
 public MessageSource messageSource() {
     ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
     messageSource.setBasename("messages");
     return messageSource;
 }
    
}

Create Wrapper class for File

Spring provides org.springframework.web.multipart.MultipartFile which is a representation of an uploaded file received in a multipart request. It provides handy methods like getName(), getContentType(), getBytes(), getInputStream() etc.. which make life bit easier while retrieving information about file being uploaded.

Let’s write a wrapper class to further simply it’s usage in our application

package com.websystique.springmvc.model;

import org.springframework.web.multipart.MultipartFile;

public class FileBucket {

 MultipartFile file;
 
 String description;

 public MultipartFile getFile() {
  return file;
 }

 public void setFile(MultipartFile file) {
  this.file = file;
 }

 public String getDescription() {
  return description;
 }

 public void setDescription(String description) {
  this.description = description;
 }

}

Create Spring MVC Controller Class

Following is a trivial controller class. Methods we are interested in are uploadDocument, downloadDocument & deleteDocument. Rest of the methods are simple methods to save/update/delete a user and basic navigation.

package com.websystique.springmvc.controller;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import com.websystique.springmvc.model.FileBucket;
import com.websystique.springmvc.model.User;
import com.websystique.springmvc.model.UserDocument;
import com.websystique.springmvc.service.UserDocumentService;
import com.websystique.springmvc.service.UserService;
import com.websystique.springmvc.util.FileValidator;



@Controller
@RequestMapping("/")
public class AppController {

 @Autowired
 UserService userService;
 
 @Autowired
 UserDocumentService userDocumentService;
 
 @Autowired
 MessageSource messageSource;

 @Autowired
 FileValidator fileValidator;
 
 @InitBinder("fileBucket")
 protected void initBinder(WebDataBinder binder) {
    binder.setValidator(fileValidator);
 }
 
 /**
  * This method will list all existing users.
  */ @RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET)
 public String listUsers(ModelMap model) {

  List<User> users = userService.findAllUsers();
  model.addAttribute("users", users);
  return "userslist";
 }

 /**
  * This method will provide the medium to add a new user.
  */ @RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)
 public String newUser(ModelMap model) {
  User user = new User();
  model.addAttribute("user", user);
  model.addAttribute("edit", false);
  return "registration";
 }

 /**
  * This method will be called on form submission, handling POST request for
  * saving user in database. It also validates the user input
  */ @RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
 public String saveUser(@Valid User user, BindingResult result,
   ModelMap model) {

  if (result.hasErrors()) {
   return "registration";
  }

  /*
   * Preferred way to achieve uniqueness of field [sso] should be implementing custom @Unique annotation 
   * and applying it on field [sso] of Model class [User].
   * 
   * Below mentioned peace of code [if block] is to demonstrate that you can fill custom errors outside the validation
   * framework as well while still using internationalized messages.
   * 
   */  if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
   FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
      result.addError(ssoError);
   return "registration";
  }
  
  userService.saveUser(user);
  
  model.addAttribute("user", user);
  model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
  //return "success";
  return "registrationsuccess";
 }


 /**
  * This method will provide the medium to update an existing user.
  */ @RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.GET)
 public String editUser(@PathVariable String ssoId, ModelMap model) {
  User user = userService.findBySSO(ssoId);
  model.addAttribute("user", user);
  model.addAttribute("edit", true);
  return "registration";
 }
 
 /**
  * This method will be called on form submission, handling POST request for
  * updating user in database. It also validates the user input
  */ @RequestMapping(value = { "/edit-user-{ssoId}" }, method = RequestMethod.POST)
 public String updateUser(@Valid User user, BindingResult result,
   ModelMap model, @PathVariable String ssoId) {

  if (result.hasErrors()) {
   return "registration";
  }

  userService.updateUser(user);

  model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " updated successfully");
  return "registrationsuccess";
 }

 
 /**
  * This method will delete an user by it's SSOID value.
  */ @RequestMapping(value = { "/delete-user-{ssoId}" }, method = RequestMethod.GET)
 public String deleteUser(@PathVariable String ssoId) {
  userService.deleteUserBySSO(ssoId);
  return "redirect:/list";
 }
 

 
 @RequestMapping(value = { "/add-document-{userId}" }, method = RequestMethod.GET)
 public String addDocuments(@PathVariable int userId, ModelMap model) {
  User user = userService.findById(userId);
  model.addAttribute("user", user);

  FileBucket fileModel = new FileBucket();
  model.addAttribute("fileBucket", fileModel);

  List<UserDocument> documents = userDocumentService.findAllByUserId(userId);
  model.addAttribute("documents", documents);
  
  return "managedocuments";
 }
 

 @RequestMapping(value = { "/download-document-{userId}-{docId}" }, method = RequestMethod.GET)
 public String downloadDocument(@PathVariable int userId, @PathVariable int docId, HttpServletResponse response) throws IOException {
  UserDocument document = userDocumentService.findById(docId);
  response.setContentType(document.getType());
        response.setContentLength(document.getContent().length);
        response.setHeader("Content-Disposition","attachment; filename=\"" + document.getName() +"\"");
 
        FileCopyUtils.copy(document.getContent(), response.getOutputStream());
 
   return "redirect:/add-document-"+userId;
 }

 @RequestMapping(value = { "/delete-document-{userId}-{docId}" }, method = RequestMethod.GET)
 public String deleteDocument(@PathVariable int userId, @PathVariable int docId) {
  userDocumentService.deleteById(docId);
  return "redirect:/add-document-"+userId;
 }

 @RequestMapping(value = { "/add-document-{userId}" }, method = RequestMethod.POST)
 public String uploadDocument(@Valid FileBucket fileBucket, BindingResult result, ModelMap model, @PathVariable int userId) throws IOException{
  
  if (result.hasErrors()) {
   System.out.println("validation errors");
   User user = userService.findById(userId);
   model.addAttribute("user", user);

   List<UserDocument> documents = userDocumentService.findAllByUserId(userId);
   model.addAttribute("documents", documents);
   
   return "managedocuments";
  } else {
   
   System.out.println("Fetching file");
   
   User user = userService.findById(userId);
   model.addAttribute("user", user);

   saveDocument(fileBucket, user);

   return "redirect:/add-document-"+userId;
  }
 }
 
 private void saveDocument(FileBucket fileBucket, User user) throws IOException{
  
  UserDocument document = new UserDocument();
  
  MultipartFile multipartFile = fileBucket.getFile();
  
  document.setName(multipartFile.getOriginalFilename());
  document.setDescription(fileBucket.getDescription());
  document.setType(multipartFile.getContentType());
  document.setContent(multipartFile.getBytes());
  document.setUser(user);
  userDocumentService.saveDocument(document);
 }
 
}

Create Validator

Create a simple validator to validate file input.

package com.websystique.springmvc.util;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

import com.websystique.springmvc.model.FileBucket;



@Component
public class FileValidator implements Validator {
  
 public boolean supports(Class<?> clazz) {
  return FileBucket.class.isAssignableFrom(clazz);
 }

 public void validate(Object obj, Errors errors) {
  FileBucket file = (FileBucket) obj;
   
  if(file.getFile()!=null){
   if (file.getFile().getSize() == 0) {
    errors.rejectValue("file", "missing.file");
   }
  }
 }
}

Following is the properties file messages.properties, used for entire application.

NotEmpty.user.firstName=First name can not be blank.
NotEmpty.user.lastName=Last name can not be blank.
NotEmpty.user.email=Email can not be blank.
NotEmpty.user.ssoId=SSO ID can not be blank.
non.unique.ssoId=SSO ID {0} already exist. Please fill in different value.
missing.file= Please select a file.

Create Views

There are several views in this application. What we are most interested in is the one with file uploads/downloads. It’s shown below

managedocuments.jsp

&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;%@ taglib prefix=&quot;form&quot; uri=&quot;http://www.springframework.org/tags/form&quot;%&gt;

&lt;html&gt;

&lt;head&gt;
 &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;
 &lt;title&gt;Upload/Download/Delete Documents&lt;/title&gt;
 &lt;link href=&quot;&lt;c:url value='/static/css/bootstrap.css' /&gt;&quot; rel=&quot;stylesheet&quot;&gt;&lt;/link&gt;
 &lt;link href=&quot;&lt;c:url value='/static/css/app.css' /&gt;&quot; rel=&quot;stylesheet&quot;&gt;&lt;/link&gt;
&lt;/head&gt;

&lt;body&gt;
 &lt;div class=&quot;generic-container&quot;&gt;
  &lt;div class=&quot;panel panel-default&quot;&gt;
     &lt;!-- Default panel contents --&gt;
     &lt;div class=&quot;panel-heading&quot;&gt;&lt;span class=&quot;lead&quot;&gt;List of Documents &lt;/span&gt;&lt;/div&gt;
     &lt;div class=&quot;tablecontainer&quot;&gt;
    &lt;table class=&quot;table table-hover&quot;&gt;
        &lt;thead&gt;
           &lt;tr&gt;
             &lt;th&gt;No.&lt;/th&gt;
             &lt;th&gt;File Name&lt;/th&gt;
             &lt;th&gt;Type&lt;/th&gt;
             &lt;th&gt;Description&lt;/th&gt;
             &lt;th width=&quot;100&quot;&gt;&lt;/th&gt;
             &lt;th width=&quot;100&quot;&gt;&lt;/th&gt;
      &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
     &lt;c:forEach items=&quot;${documents}&quot; var=&quot;doc&quot; varStatus=&quot;counter&quot;&gt;
      &lt;tr&gt;
       &lt;td&gt;${counter.index + 1}&lt;/td&gt;
       &lt;td&gt;${doc.name}&lt;/td&gt;
       &lt;td&gt;${doc.type}&lt;/td&gt;
       &lt;td&gt;${doc.description}&lt;/td&gt;
       &lt;td&gt;&lt;a href=&quot;&lt;c:url value='/download-document-${user.id}-${doc.id}' /&gt;&quot; class=&quot;btn btn-success custom-width&quot;&gt;download&lt;/a&gt;&lt;/td&gt;
       &lt;td&gt;&lt;a href=&quot;&lt;c:url value='/delete-document-${user.id}-${doc.id}' /&gt;&quot; class=&quot;btn btn-danger custom-width&quot;&gt;delete&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
     &lt;/c:forEach&gt;
        &lt;/tbody&gt;
       &lt;/table&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&quot;panel panel-default&quot;&gt;
   
   &lt;div class=&quot;panel-heading&quot;&gt;&lt;span class=&quot;lead&quot;&gt;Upload New Document&lt;/span&gt;&lt;/div&gt;
   &lt;div class=&quot;uploadcontainer&quot;&gt;
    &lt;form:form method=&quot;POST&quot; modelAttribute=&quot;fileBucket&quot; enctype=&quot;multipart/form-data&quot; class=&quot;form-horizontal&quot;&gt;
   
     &lt;div class=&quot;row&quot;&gt;
      &lt;div class=&quot;form-group col-md-12&quot;&gt;
       &lt;label class=&quot;col-md-3 control-lable&quot; >enctype="multipart/form-data"</code> and <code>input type="file"</code> for file input. Rest is usual Spring MVC stuff.

Other views in this application are shown below [feel free to skip them].

<code>registration.jsp</code>

&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;
&lt;%@ taglib prefix=&quot;form&quot; uri=&quot;http://www.springframework.org/tags/form&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;

&lt;html&gt;

&lt;head&gt;
 &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;
 &lt;title&gt;User Registration Form&lt;/title&gt;
 &lt;link href=&quot;&lt;c:url value='/static/css/bootstrap.css' /&gt;&quot; rel=&quot;stylesheet&quot;&gt;&lt;/link&gt;
 &lt;link href=&quot;&lt;c:url value='/static/css/app.css' /&gt;&quot; rel=&quot;stylesheet&quot;&gt;&lt;/link&gt;
&lt;/head&gt;

&lt;body&gt;

  &lt;div class=&quot;generic-container&quot;&gt;
 &lt;div class=&quot;well lead&quot;&gt;User Registration Form&lt;/div&gt;
  &lt;form:form method=&quot;POST&quot; modelAttribute=&quot;user&quot; class=&quot;form-horizontal&quot;&gt;
  &lt;form:input type=&quot;hidden&quot; path=&quot;id&quot; id=&quot;id&quot;/&gt;
  
  &lt;div class=&quot;row&quot;&gt;
   &lt;div class=&quot;form-group col-md-12&quot;&gt;
    &lt;label class=&quot;col-md-3 control-lable&quot; >registrationsuccess.jsp</code>

&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;


&lt;html&gt;
&lt;head&gt;
 &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;
 &lt;title&gt;Registration Confirmation Page&lt;/title&gt;
 &lt;link href=&quot;&lt;c:url value='/static/css/bootstrap.css' /&gt;&quot; rel=&quot;stylesheet&quot;&gt;&lt;/link&gt;
 &lt;link href=&quot;&lt;c:url value='/static/css/app.css' /&gt;&quot; rel=&quot;stylesheet&quot;&gt;&lt;/link&gt;
&lt;/head&gt;
&lt;body&gt;
 &lt;div class=&quot;generic-container&quot;&gt;
  &lt;div class=&quot;alert alert-success lead&quot;&gt;
      ${success}
  &lt;/div&gt;
  
  &lt;span class=&quot;well pull-left&quot;&gt;
   &lt;a href=&quot;&lt;c:url value='/add-document-${user.id}' /&gt;&quot;&gt;Click here to upload/manage your documents&lt;/a&gt; 
  &lt;/span&gt;
  &lt;span class=&quot;well pull-right&quot;&gt;
   Go to &lt;a href=&quot;&lt;c:url value='/list' /&gt;&quot;&gt;Users List&lt;/a&gt;
  &lt;/span&gt;
 &lt;/div&gt;
&lt;/body&gt;

&lt;/html&gt;

userslist.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>

<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Users List</title>
 <link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link>
 <link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link>
</head>

<body>
 <div class="generic-container">
  <div class="panel panel-default">
     <!-- Default panel contents -->
     <div class="panel-heading"><span class="lead">List of Users </span></div>
     <div class="tablecontainer">
    <table class="table table-hover">
        <thead>
           <tr>
             <th>First Name</th>
             <th>Last Name</th>
             <th>Email</th>
             <th>SSO ID</th>
             <th width="100"></th>
             <th width="100"></th>
      </tr>
        </thead>
        <tbody>
     <c:forEach items="${users}" var="user">
      <tr>
       <td>${user.firstName}</td>
       <td>${user.lastName}</td>
       <td>${user.email}</td>
       <td>${user.ssoId}</td>
       <td><a href="<c:url value='/edit-user-${user.ssoId}' />" class="btn btn-success custom-width">edit</a></td>
       <td><a href="<c:url value='/delete-user-${user.ssoId}' />" class="btn btn-danger custom-width">delete</a></td>
      </tr>
     </c:forEach>
        </tbody>
       </table>
      </div>
  </div>
   <div class="well">
    <a href="<c:url value='/newuser' />">Add New User</a>
   </div>
    </div>
</body>
</html>

Error Handling

Important

During file upload process, you may get problem like “Packet for query is too large”.
To overcome this issue, you need to update the ‘max_allowed_packet’ value in your Mysql configuration file.

  • On Windows you may find it in MySQL Server 5.6/my.ini
  • On Linux you may find it in etc/my.cnf

By default, it’s set to 4M. You can set it based on your needs.

max_allowed_packet=256M

Don’t forget to restart MySQL Server after update.

You can check the updated value by executing this query
>show variables like ‘max%’ ;

Build, Deploy & Run Application

Now build the war (either by eclipse as was mentioned in previous tutorials) or via maven command line( mvn clean install). Deploy the war to a Servlet 3.0 container . Since here i am using Tomcat, i will simply put this war file into tomcat webapps folder and click on start.bat inside tomcat/bin directory.

Open browser and browse at http://localhost:8080/Spring4MVCFileUploadDownloadWithHibernate

Add a user.

Fill in details and register. You should see confirmation.

Click on upload/manage link.

Select a file, provide a description.

Click on upload.

Upload more files.

Verify database.

You can see that user_documents table contains 3 rows with content type shown as ‘BLOB’;.

Now click on download buttons of some of above rows. File should be downloaded right away.

Let’s click on delete for few rows. Those user_documents should be deleted from database as well.

Verify database.

Verify validation. Click on Upload without selecting a file. You should see validation error.

Download Source Code


References

View Comments

  • hello
    the community please someone could help me I look for this application
    with rest spring boot, jpa, mysql and angular 4 but here are two months am
    blocked:

    @RestController

    @CrossOrigin("*")
    public class DocumentRestService {

    @Autowired
    private UserDocumentService userDocumentService;
    private UserService userService;

    public DocumentRestService(UserDocumentService userDocumentService,
    UserService userService

    )
    {
    this.userDocumentService = userDocumentService;
    this.userService = userService;

    }

    @InitBinder("fileBucket")
    // protected void initBinder(WebDataBinder binder) {
    // binder.setValidator(fileValidator);
    // }

    @RequestMapping(value = { "/delete-document-{Id}" }, method = RequestMethod.GET)
    public void deleteById(@PathVariable int id) {
    userDocumentService.deleteById(id);
    }

    @RequestMapping(value = { "/add-document-{userId}" }, method = RequestMethod.GET)
    public void addDocuments(@PathVariable int userId ,MultipartFile file,String description) {

    User user = userService.findById(userId);

    FileBucket fileModel = new FileBucket();
    fileModel.setDescription(description);
    fileModel.setFile(file);
    fileModel.set(user);
    List documents = userDocumentService.findAllByUserId(userId);
    fileModel.set((User) documents);

    }

    @RequestMapping(value = { "/download-document-{docId}" }, method = RequestMethod.GET)
    public void downloadDocument(@PathVariable int docId, HttpServletResponse response) throws IOException {
    UserDocument document = userDocumentService.findById(docId);
    response.setContentType(document.getType());
    response.setContentLength(document.getContent().length);
    response.setHeader("Content-Disposition","attachment; filename="" + document.getName() +""");

    FileCopyUtils.copy(document.getContent(), response.getOutputStream());

    }

    @RequestMapping(value = { "/add-document-{userId}" }, method = RequestMethod.POST)
    public void uploadDocument(@Valid FileBucket fileBucket, BindingResult result, @PathVariable int userId) throws IOException{

    if (result.hasErrors()) {
    System.out.println("validation errors");
    User user = userService.findById(userId);
    List documents = userDocumentService.findAllByUserId(userId);
    } else {
    System.out.println("Fetching file");
    User user = userService.findById(userId);
    saveDocument(fileBucket, user);
    }
    }

    private void saveDocument(FileBucket fileBucket, User user) throws IOException{

    UserDocument document = new UserDocument();

    MultipartFile multipartFile = fileBucket.getFile();

    document.setName(multipartFile.getOriginalFilename());
    document.setDescription(fileBucket.getDescription());
    document.setType(multipartFile.getContentType());
    document.setContent(multipartFile.getBytes());
    document.setUser(user);

    userDocumentService.saveDocument(document);
    }

    }

  • Hello , thank you for this tutorial , when i click on Upload button , I get this error :
    SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/SpringMVCHibernateWithSpringSecurityExample] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
    java.lang.NullPointerException
    at com.websystique.springmvc.controller.AppController.saveDocument(AppController.java:253)
    at com.websystique.springmvc.controller.AppController.uploadDocument(AppController.java:241)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)

    Any help please ???

    • Hi, You are getting a NullPointerException in saveDocument, it could be that Filebucket was not properly populated. I would suggest put a breakpoint [in uploadDocument method] and investigate . It is possible that we have some bug here which need to be fixed.

  • Hello, amazing tutorial, thanks.
    I am trying to add a search document functionality?
    How can I do this?
    Thanks in advance.

    • Hello, sorry for quite late reply. For search you could for example preload the filenames from server on UI load, then use javascript [type-ahead] to search and on selection, send a new request to server to download it.

  • Hello Websystique. this is an amazing tutorial. But I get a 404 eror like chandan. I have a proper tomcat conf as I ran a hello world spring app successfully. What could I be possibly missing. Thanks

    • Hi Ashish, that would be strange as this example is time tested. Check if you have the '/' at the end of URL?

  • This is great! But do you know where can I see the location of the file I have uploaded? I am guessing it should be at the temporary location?
    Thank you :)

    • I think I got it now, I got a question which is a bit silly for those who are not aware of how it was stored.. I just learned how this blob thingy in the database works.. :)

  • Hello Websystique, your posts are awesome.I get to learn a lot from here.You are really doing a great job.
    I am using this example for practice and trying yo integrate atmosphere js with it.Following is the link of example I am trying to integrate.
    https://github.com/GregaVrbancic/spring-atmosphere-chat-example
    But while doing so,I am getting following error:

    java.lang.IllegalStateException: MeteorServlet not defined in web.xml
    at org.atmosphere.cpr.Meteor.build(Meteor.java:170)
    at org.atmosphere.cpr.Meteor.build(Meteor.java:151)
    at org.atmosphere.cpr.Meteor.build(Meteor.java:137)
    at org.atmosphere.cpr.Meteor.build(Meteor.java:124)
    at com.websystique.springmvc.resolver.AtmosphereResolver.resolveArgument(AtmosphereResolver.java:22)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:99)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:859)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

    Can you please help me out.You can also refer this question I have asked on stackoverflow:
    http://stackoverflow.com/questions/40292382/how-to-integrate-atmosphere-configuration-in-springs-java-based-configuration-u

    Thanks,
    Omi

    • Hi Omi,
      Nevere heard of Atmosphere stuff before. Anyway, it seems to be a missing configuration. i found this, might help you.

  • hey guys, can you help me with the definition of max request size and max threshold size, what does these actually mean?

    • Hi Abhilash, maxRequestSize is the maximum size allowed for the whole request[means files+other stuff in request]. fileSizeThreshold is the size threshold after which files will
      be written to disk.

Share
Published by

Recent Posts

Spring Boot + AngularJS + Spring Data + JPA CRUD App Example

In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…

7 years ago

Spring Boot Rest API Example

Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…

7 years ago

Spring Boot WAR deployment example

Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…

7 years ago

Spring Boot Introduction + hello world example

Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…

7 years ago

Secure Spring REST API using OAuth2

Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…

8 years ago

AngularJS+Spring Security using Basic Authentication

This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…

8 years ago