Пример Upload file c Spring Boot и jQuery Ajax

View more categories:

1- Цель статьи

В данной статье я покажу вам как создать приложение  Spring Boot загрузки файла с  jQuery Ajax. Ниже является предварительный просмотр приложения, который мы выполним:
Оповестить при происхождении ошибки:
Смотреть так же пример загрузки файла с Spring Boot не используя  AJAX:
File Upload + AngularJS:

2- Создать проект Spring Boot

На  Eclipse создать проект  Spring Boot:
pom.xml
<?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.o7planning</groupId>
    <artifactId>SpringBootFileUploadAjax</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>SpringBootFileUploadAjax</name>
    <description>Spring Boot + File Upload + JQuery Ajax</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
SpringBootFileUploadAjaxApplication.java
package org.o7planning.sbfileupload;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootFileUploadAjaxApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootFileUploadAjaxApplication.class, args);
    }
    
}

3- Form, Controller, Exception Handler

Класс  UploadForm представляет данные form HTML.
UploadForm.java
package org.o7planning.sbfileupload.form;

import org.springframework.web.multipart.MultipartFile;

public class UploadForm {

    private String description;

    private MultipartFile[] files;

    public String getDescription() {
        return description;
    }

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

    public MultipartFile[] getFiles() {
        return files;
    }

    public void setFiles(MultipartFile[] files) {
        this.files = files;
    }

}
MainController.java
package org.o7planning.sbfileupload.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MainController {

    @GetMapping("/")
    public String index() {
        return "upload";
    }

}
Класс  MainRESTController определяет  REST API для обработки данных файлов загруженных пользователями. Данный  REST API будет вызван с помощью  jQuery Ajax (Смотрите в  main.js).
MainRESTController.java
package org.o7planning.sbfileupload.restcontroller;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.o7planning.sbfileupload.form.UploadForm;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
public class MainRESTController {

    // Linux: /home/{user}/test
    // Windows: C:/Users/{user}/test
    private static String UPLOAD_DIR = System.getProperty("user.home") + "/test";

    @PostMapping("/rest/uploadMultiFiles")
    public ResponseEntity<?> multiUploadFileModel(@ModelAttribute UploadForm form) {

        System.out.println("Description:" + form.getDescription());

        String result = null;
        try {

            result = this.saveUploadedFiles(form.getFiles());

        }
        // Here Catch IOException only.
        // Other Exceptions catch by RestGlobalExceptionHandler class.
        catch (IOException e) {
            e.printStackTrace();
            return new ResponseEntity<>("Error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity<String>("Uploaded to: <br/>" + result, HttpStatus.OK);

    }

    // Save Files
    private String saveUploadedFiles(MultipartFile[] files) throws IOException {

        // Make sure directory exists!
        File uploadDir = new File(UPLOAD_DIR);
        uploadDir.mkdirs();

        StringBuilder sb = new StringBuilder();

        for (MultipartFile file : files) {

            if (file.isEmpty()) {
                continue;
            }
            String uploadFilePath = UPLOAD_DIR + "/" + file.getOriginalFilename();

            byte[] bytes = file.getBytes();
            Path path = Paths.get(uploadFilePath);
            Files.write(path, bytes);

            sb.append(uploadFilePath).append("<br/>");
        }
        return sb.toString();
    }
}
По умолчанию размер файла, загруженного на сервер, не должен превышать 1MB. И если пользователь загружает много файлов одновременно, то общий размер так же не может превышать 1MB. Но вы можете конфигурировать, чтобы изменить эти данные.
application.properties
spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=5MB

spring.thymeleaf.cache=false
RestGlobalExceptionHandler является кастомизированным классом, расширенный из класса  ResponseEntityExceptionHandler. В данном классе вы можете обрабатывать исключения, исходящие (throw) из методов  REST. Это помогает вам обрабатывать исключения собранные в одном расположении, вместо того чтобы обрабатывать исключения в каждом методе  REST.
RestGlobalExceptionHandler.java
package org.o7planning.sbfileupload.exceptionhandler;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler {

    // Catch max file size Exception.
    @ExceptionHandler(MultipartException.class)
    @ResponseBody
    public ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {

        HttpStatus status = this.getStatus(request);
        return new ResponseEntity<String>("(Message in RestGlobalExceptionHandler *): " + ex.getMessage(), status);
    }

    // Cache Other Exception
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<?> handleControllerRootException(HttpServletRequest request, Throwable ex) {

        HttpStatus status = this.getStatus(request);
        return new ResponseEntity<String>("(Message in RestGlobalExceptionHandler **): " + ex.getMessage(), status);
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }

}

4- Javascript, View

upload.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
   <head>
      <title>Upload Files</title>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <script type="text/javascript" th:src="@{/main.js}"></script>
   </head>
   <body>
      <h1>Spring Boot File Upload with jQuery Ajax</h1>
      <form method="POST" enctype="multipart/form-data" id="fileUploadForm">
         Description: <br/>
         <input type="text" name="description" style="width:350px;"/>
         <br/><br/>                 
         File to upload (1): <input type="file" name="files"/><br />      
         File to upload (2): <input type="file" name="files"/><br />    
         File to upload (3): <input type="file" name="files"/><br />    
         File to upload (4): <input type="file" name="files"/><br />    
         File to upload (5): <input type="file" name="files"/><br />    
         <input type="submit" value="Submit" id="submitButton"/>
      </form>
      <h2>Upload Results:</h2>
      <div style="border:1px solid #ccc;padding: 5px;">
         <span id="result"></span>
      </div>
      
   </body>
</html>
main.js
$(document).ready(function() {

    $("#submitButton").click(function(event) {

        // Stop default form Submit.
        event.preventDefault();

        // Call Ajax Submit.

        ajaxSubmitForm();

    });

});

function ajaxSubmitForm() {

    // Get form
    var form = $('#fileUploadForm')[0];

    var data = new FormData(form);


    $("#submitButton").prop("disabled", true);

    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: "/rest/uploadMultiFiles",
        data: data,

        // prevent jQuery from automatically transforming the data into a query string
        processData: false,
        contentType: false,
        cache: false,
        timeout: 1000000,
        success: function(data, textStatus, jqXHR) {

            $("#result").html(data);
            console.log("SUCCESS : ", data);
            $("#submitButton").prop("disabled", false);
            $('#fileUploadForm')[0].reset();
        },
        error: function(jqXHR, textStatus, errorThrown) {  

            $("#result").html(jqXHR.responseText);
            console.log("ERROR : ", jqXHR.responseText);
            $("#submitButton").prop("disabled", false);

        }
    });

}

View more categories: