A REST web service, file uploads & Spring Boot
In this article I will introduce a document archive application with a REST interface created with Spring Boot. You will find out how to handle file uploads by a REST web service. The web front end is created with AngularJS. The application is on GitHub. The impatient of you can follow this link to the repository: rest-document-archive to see the source code.
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications. All configuration is done by annotations. You don’t need a single XML configuration file.
Build and run
To build an run the application open a terminal and type:
~$ git clone https://github.com/murygin/rest-document-archive.git ~$ cd rest-document-archive ~$ mvn package ~$ java -jar target/rest-document-archive-0.1.0.jar
You can now point a browser to http://localhost:8080/ to open the web front end.
REST API
- Add a document/archive/upload?file={file}&person={person}&date={date} POST
- file: A file posted in a multipart request
- person: The name of the uploading person
- date: The date of the document
- Find documents/archive/documents?person={person}&date={date} GET
- person: The name of the uploading person
- date: The date of the document
- Get a document/archive/document/{id} GET
- id: The UUID of a document
Main classes
The document archive consists of a REST service controller, a service and a data access object. In addition there is Java client for the REST service and a web front end.
REST Service Controller
Executes incoming request and defines URL to service method mappings. All remote call are delegated to the archive service.
Service
- Interface: org.murygin.archive.service.IArchiveService
- Implementation: org.murygin.archive.service.ArchiveService
A service to save, find and get documents from an archive.
Data access object
- Interface: org.murygin.archive.dao.IDocumentDao
- Implementation: org.murygin.archive.dao.FileSystemDocumentDao
Data access object to insert, find and load documents. FileSystemDocumentDao saves documents in the file system. No database in involved. For each document a folder is created. The folder contains the document and a properties files with the meta data of the document. Each document in the archive has a Universally Unique Identifier (UUID). The name of the documents folder is the UUID of the document.
Client
A client for the document archive which is using the REST service.
Web client
A web client made with AngularJS.
Implementation details
Here are some implementation details:
Application class
Starting point to run and configure a Spring Boot application is an Application class in the root package of your application.
org.murygin.archive.Application:
@Configuration @ComponentScan @EnableAutoConfiguration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Automatic Spring configuration is done by annotations @Configuration, @ComponentScan and @EnableAutoConfiguration. All classes in the same package or in any sub-packages are configured and added to Springs application context. The main() method uses Spring Boot’s SpringApplication.run() method to launch the application. No external application server is needed to run the web service. Spring boot starts an embedded servlet container.
REST Service Controller
The REST Service Controller ArchiveController.java handles incoming HTTP request and delegates execution to the Java service. The most interesting method is handleFileUpload because it receives the uploaded file. You don’t have to worry about how to convert a multipart file request param to a Java object. Spring does this job for you. All you have to do is defining a parameter of type org.springframework.web.multipart.MultipartFile and mapping it to the request by annotation org.springframework.web.bind.annotation.RequestParam (Line 3).
org.murygin.archive.rest.ArchiveController:
@RequestMapping(value = "/upload", method = RequestMethod.POST) public @ResponseBody DocumentMetadata handleFileUpload( @RequestParam(value="file", required=true) MultipartFile file , @RequestParam(value="person", required=true) String person, @RequestParam(value="date", required=true) @DateTimeFormat(pattern="yyyy-MM-dd") Date date) { try { Document document = new Document(file.getBytes(), file.getOriginalFilename(), date, person ); getArchiveService().save(document); return document.getMetadata(); } catch (Exception e) { // .. exception handling } }
In Line 5 you can see how to convert a String parameter to a Java date by defining a pattern with annotation org.springframework.format.annotation.DateTimeFormat.
File upload AngularJS
I will not describe how to handle a multipart/form-data file upload with AngularJS in this article. I recommend to read this article to learn more about it. You will find my implementation in the files: src/main/resources/static/app.js and index.html
Maven
The Spring Boot Maven plugin simplifies the Maven configuration by a built-in dependency resolver that sets the version number to match Spring Boot dependencies. That’s why Maven configuration is relatively simple in this project
<?xml version="1.0" encoding="UTF-8"?> <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>org.murygin</groupId> <artifactId>rest-document-archive</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.1.6.RELEASE</version> </parent> <properties> <start-class>org.murygin.archive.Application</start-class> </properties> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <repositories> <repository> <id>spring-releases</id> <name>Spring Releases</name> <url>http://repo.spring.io/libs-release</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-releases</id> <name>Spring Releases</name> <url>http://repo.spring.io/libs-release</url> </pluginRepository> </pluginRepositories> </project>
I wanted to try this code but when i type localhost:8080/index.html , i have the view and when i try to upload the file ,it’snot uploaded, i try to see what the problem using developpement tools of chrome it gives me this error :POST http://localhost:8080/archive/upload 400 (Bad Request). Can you help me please
Do you see a stacktrace in your terminal?
do you mean in the console noo there’s no error , just when i click on upload it gives me the error that i mentioned
Very Helpful. Any steps to import the project into Eclipse and run the application on tomcat ?
took me a while, but the 400 error is because the date format is required as YYYY-MM-DD
any steps to import project into eclipse and run on tomcat???