Spring Boot + thymeleaf implements the file upload and download function, springthymeleaf

Source: Internet
Author: User
Tags stream api

Spring Boot + thymeleaf implements the file upload and download function, springthymeleaf

Recently, my colleague asked me if I had any technical e-books. I opened the small library on my computer, but the email sent to him was too big, and the company banned folder sharing, so I spent half a day writing a small File Upload program and deploying it on my own Linux machine.

Features:1. File Upload 2. file list display and download

The original uploaded part is ugly. After some js Code is optimized, the interface is shown as follows:

 

First, let's give the results. Next we will demonstrate how to implement them step by step.

1. Create a project

First of all, create a spring-boot project. You can choose to initialize a project on the website or use the Spring Initialier function of IDE to create a new project. Here I create a project from IDEA:

 

Next, enter group and artifact, and click next:

 

At this time, this module selection interface appears. Click the web option to check the Web to prove that this is a webapp. Then click Template Engines to select the front-end Template engine. We choose Thymleaf, spring-boot officially recommends this template to replace jsp.

The last step is to wait until the project Initialization is successful.

 

2. pom settings

First, check which dependencies need to be added to the project and paste my pom file directly:

<?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>com.shuqing28</groupId> <artifactId>upload</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>upload</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter</artifactId> </dependency> <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-configuration-processor</artifactId>  <optional>true</optional> </dependency> <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-test</artifactId>  <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.webjars/bootstrap --> <dependency>  <groupId>org.webjars</groupId>  <artifactId>bootstrap</artifactId>  <version>3.3.5</version> </dependency> <!-- https://mvnrepository.com/artifact/org.webjars.bower/jquery --> <dependency>  <groupId>org.webjars.bower</groupId>  <artifactId>jquery</artifactId>  <version>2.2.4</version> </dependency> </dependencies> <build> <plugins>  <plugin>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-maven-plugin</artifactId>  </plugin> </plugins> </build></project>

We can see that spring-boot-starter-thymeleaf contains the webapp, and the last two webjars integrate bootstrap and jquery, and other code is used later.

The last Spring boot maven plugin is added when the system is created. It has the following benefits:

1. It can package all the jar files under classpath and build an executable "U ber-jar" to facilitate user Transfer Service

2. automatically search for the public static void main () method and mark it as an executable class.

3. provides built-in dependency explanation based on the spring-boot version.

3. Upload File Controller

If you only use SpringMVC to upload files, you need to configure a MultipartResolver bean or. configure a <multipart-config> in xml. However, you do not have to do anything with the automatic configuration of spring-boot. Write the controller class directly. Create the controller package in src/main/java and create FileUploadController:

package com.shuqing28.upload.controller;import com.shuqing28.uploadfiles.pojo.Linker;import com.shuqing28.uploadfiles.exceptions.StorageFileNotFoundException;import com.shuqing28.uploadfiles.service.StorageService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.http.HttpHeaders;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import java.io.IOException;import java.util.List;import java.util.stream.Collectors;@Controllerpublic class FileUploadController {  private final StorageService storageService;  @Autowired  public FileUploadController(StorageService storageService) {    this.storageService = storageService;  }  @GetMapping("/")  public String listUploadedFiles(Model model)throws IOException {    List<Linker> linkers = storageService.loadAll().map(        path -> new Linker(MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,            "serveFile", path.getFileName().toString()).build().toString(),            path.getFileName().toString())    ).collect(Collectors.toList());    model.addAttribute("linkers", linkers);    return "uploadForm";  }  @GetMapping("/files/{filename:.+}")  @ResponseBody  public ResponseEntity<Resource> serveFile(@PathVariable String filename) {    Resource file = storageService.loadAsResource(filename);    return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,        "attachment; filename=\"" + file.getFilename() + "\"").body(file);  }  @PostMapping("/")  public String handleFileUpload(@RequestParam("file") MultipartFile file,                  RedirectAttributes redirectAttributes) {    storageService.store(file);    redirectAttributes.addFlashAttribute("message",        "You successfully uploaded " + file.getOriginalFilename() + "!");    return "redirect:/";  }  @ExceptionHandler(StorageFileNotFoundException.class)  public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {    return ResponseEntity.notFound().build();  }}

@ Controller annotation is added to the class definition to prove that this is a Controller. @ GetMapping and @ PostMapping are added before each method to Get and Post requests respectively.

The first is @ GetMapping ("/"), the listUploadedFiles method, as the name suggests, to display the file list. Here we use storageService to traverse all the files in the folder, the link and file name list are merged using the map method, and an array of Linker objects is returned. The Linker object is a simple pojo and only contains the following two parts:

private String fileUrl;private String fileName;

This method includes the use of Stream in Java 8. If you do not understand it, please refer to this article Java 8 features (2) Stream API.

Next@GetMapping("/files/{filename:.+}") The method is serveFile. This method provides the file download function, or the storageservice code will be pasted later. Finally, use ResponseEntity to return the object to the requester as the body.

@PostMapping("/") HandleFileUpload uses the Post request to upload files. The parameter @ RequestParam ("file") is used to extract the file objects in the webpage request, storageService is used to save the objects, and redirection is used to refresh the webpage, and the message of the successful upload is provided.

4. File Processing

Many methods called by the Controller are provided by StorageService. We define an interface that includes the following methods:

package com.shuqing28.uploadfiles.service;import org.springframework.core.io.Resource;import org.springframework.web.multipart.MultipartFile;import java.nio.file.Path;import java.util.stream.Stream;public interface StorageService {  void init();  void store(MultipartFile file);  Stream<Path> loadAll();  Path load(String filename);  Resource loadAsResource(String filename);  void deleteAll();}

Because I only use the local file system to process the persistent download of files, the following implementation classes are available:

package com.shuqing28.uploadfiles.service;import com.shuqing28.uploadfiles.exceptions.StorageException;import com.shuqing28.uploadfiles.exceptions.StorageFileNotFoundException;import com.shuqing28.uploadfiles.config.StorageProperties;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.core.io.UrlResource;import org.springframework.stereotype.Service;import org.springframework.util.FileSystemUtils;import org.springframework.util.StringUtils;import org.springframework.web.multipart.MultipartFile;import java.io.IOException;import java.net.MalformedURLException;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.nio.file.StandardCopyOption;import java.util.stream.Stream;@Servicepublic class FileSystemStorageService implements StorageService {  private final Path rootLocation;  @Autowired  public FileSystemStorageService(StorageProperties properties) {    this.rootLocation = Paths.get(properties.getLocation());  }  @Override  public void init() {    try {      Files.createDirectories(rootLocation);    }    catch (IOException e) {      throw new StorageException("Could not initialize storage", e);    }  }  @Override  public void store(MultipartFile file) {    String filename = StringUtils.cleanPath(file.getOriginalFilename());    try {      if (file.isEmpty()) {        throw new StorageException("Failed to store empty file" + filename);      }      if (filename.contains("..")) {        // This is a security check        throw new StorageException(            "Cannot store file with relative path outside current directory "                + filename);      }      Files.copy(file.getInputStream(), this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING);    } catch (IOException e) {      throw new StorageException("Failed to store file" + filename, e);    }  }  @Override  public Stream<Path> loadAll() {    try {      return Files.walk(this.rootLocation, 1)          .filter(path -> !path.equals(this.rootLocation))          .map(path->this.rootLocation.relativize(path));    }    catch (IOException e) {      throw new StorageException("Failed to read stored files", e);    }  }  @Override  public Path load(String filename) {    return rootLocation.resolve(filename);  }  @Override  public Resource loadAsResource(String filename) {    try {      Path file = load(filename);      Resource resource = new UrlResource(file.toUri());      if (resource.exists() || resource.isReadable()) {        return resource;      }      else {        throw new StorageFileNotFoundException(            "Could not read file: " + filename);      }    }    catch (MalformedURLException e) {      throw new StorageFileNotFoundException("Could not read file: " + filename, e);    }  }  @Override  public void deleteAll() {    FileSystemUtils.deleteRecursively(rootLocation.toFile());  }}

This class also basically uses Java NIO, and uses the Path object to define the default storage Path for the file.

First, let's look at the store method. store accepts a MultipartFile object as a parameter. If you want to pass a binary byte array in a traditional JSP, multipartFile provides many convenient calling methods so that we can obtain the information of the uploaded files:

public interface MultipartFile extends InputStreamSource { String getName(); String getOriginalFilename(); String getContentType(); boolean isEmpty(); long getSize(); byte[] getBytes() throws IOException; InputStream getInputStream() throws IOException; void transferTo(File dest) throws IOException, IllegalStateException;}

The Code uses the copy method of Files to copy the file stream to the Path corresponding to the location. Of course, we can also use the transferTo method to save the file,file.transferTo(this.rootLocation.resolve(filename).toFile());

The loadAll method loads the Path information of all files under this Path. The loadAsResource method is to load the file as a Resource object, then read the Controller code, and finally accept a Resource object as the body and return it to the requester.

5. Front-end Template

Finally, the front-end template is defined. The Code is as follows:

What is important here is the content in the <form> label, <form method = "POST" action = "/" enctype = "multipart/form-data"> enctype must be written as multipart/form-data and uploaded using POST, the original upload control is ugly, so I made a text + input put on the surface, put an invisible upload file input below, you can look at the code by yourself, this article will not be too long.

Here we also put a list to display the file list. Here we get the linkers object provided by the server, and get the two elements fileUrl and fileName in the foreach.

Here, jquery is replaced with Microsoft CDN, and webjars is always not introduced. I don't know why.

Other settings

Set the file size limit in src/main/resources/application. properties.

spring.http.multipart.max-file-size=128MBspring.http.multipart.max-request-size=128MB

In addition, the default file storage path is set in:

package com.shuqing28.uploadfiles.config;import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties("storage")public class StorageProperties {  private String location = "/home/jenkins/upload-files/";  public String getLocation() {    return location;  }  public void setLocation(String location) {    this.location = location;  }}

Note that due to StorageProperties settings, you must add

@ EnableConfigurationProperties annotation @ SpringBootApplication @ EnableConfigurationProperties (StorageProperties. class) public class UploadApplication {public static void main (String [] args) {SpringApplication. run (UploadApplication. class, args );}}

Summary

The above section describes how Spring Boot + thymeleaf can be used to upload and download files. If you have any questions, please leave a message, the editor will reply to you in a timely manner. Thank you very much for your support for the help House website!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.