Beispiel für Spring Boot-Datei - Ajax und REST

Beispiel für das Hochladen von Spring Boot-Dateien - Ajax und REST

Dieser Artikel zeigt Ihnen, wie Sie Dateien in einer Spring Boot-Webanwendung (REST-Struktur) mithilfe von Ajax-Anforderungen hochladen.

In diesem Artikel verwendete Tools:

  1. Spring Boot 1.4.3.RELEASE

  2. Feder 4.3.5.FREIGABE

  3. Thymeleaf

  4. jQuery (Webjars)

  5. Maven

  6. Embedded Tomcat 8.5.6

  7. Google Chrome Browser (Network Inspect)

1. Projektstruktur

Eine Standard-Maven-Projektstruktur.

spring-boot-file-upload-ajax-directory-1

2. Projektabhängigkeit

Deklariert eine zusätzliche Webjar-Abhängigkeit vonjQueryfür Ajax-Anforderungen in HTML-Form.

pom.xml


    4.0.0

    com.example
    spring-boot-file-upload
    jar
    1.0

    
        org.springframework.boot
        spring-boot-starter-parent
        1.4.3.RELEASE
    

    
        1.8
    

    

        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

        
        
            org.springframework.boot
            spring-boot-devtools
            true
        

        
            org.webjars
            jquery
            2.2.4
        

    

    
        
            
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

3. Datei-Upload

Zur Unterstützung der Ajax-Anforderung und -Antwort wird die einfachste Lösung inResponseEntity zurückgegeben.

3.1 The below example demonstrates three possible ways to upload files:

  1. Upload einzelner Dateien -MultipartFile

  2. Upload mehrerer Dateien -MultipartFile[]

  3. Kartendatei in ein Modell hochladen -@ModelAttribute

RestUploadController.java

package com.example.controller;

import com.example.model.UploadModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestController
public class RestUploadController {

    private final Logger logger = LoggerFactory.getLogger(RestUploadController.class);

    //Save the uploaded file to this folder
    private static String UPLOADED_FOLDER = "F://temp//";

    // 3.1.1 Single file upload
    @PostMapping("/api/upload")
    // If not @RestController, uncomment this
    //@ResponseBody
    public ResponseEntity uploadFile(
            @RequestParam("file") MultipartFile uploadfile) {

        logger.debug("Single file upload!");

        if (uploadfile.isEmpty()) {
            return new ResponseEntity("please select a file!", HttpStatus.OK);
        }

        try {

            saveUploadedFiles(Arrays.asList(uploadfile));

        } catch (IOException e) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity("Successfully uploaded - " +
                uploadfile.getOriginalFilename(), new HttpHeaders(), HttpStatus.OK);

    }

    // 3.1.2 Multiple file upload
    @PostMapping("/api/upload/multi")
    public ResponseEntity uploadFileMulti(
            @RequestParam("extraField") String extraField,
            @RequestParam("files") MultipartFile[] uploadfiles) {

        logger.debug("Multiple file upload!");

        // Get file name
        String uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename())
                .filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , "));

        if (StringUtils.isEmpty(uploadedFileName)) {
            return new ResponseEntity("please select a file!", HttpStatus.OK);
        }

        try {

            saveUploadedFiles(Arrays.asList(uploadfiles));

        } catch (IOException e) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity("Successfully uploaded - "
                + uploadedFileName, HttpStatus.OK);

    }

    // 3.1.3 maps html form to a Model
    @PostMapping("/api/upload/multi/model")
    public ResponseEntity multiUploadFileModel(@ModelAttribute UploadModel model) {

        logger.debug("Multiple file upload! With UploadModel");

        try {

            saveUploadedFiles(Arrays.asList(model.getFiles()));

        } catch (IOException e) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity("Successfully uploaded!", HttpStatus.OK);

    }

    //save file
    private void saveUploadedFiles(List files) throws IOException {

        for (MultipartFile file : files) {

            if (file.isEmpty()) {
                continue; //next pls
            }

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

        }

    }
}

3.2 A simple model for above example 3.1.3 – @ModelAttribute

UploadModel.java

package com.example.model;

import org.springframework.web.multipart.MultipartFile;

public class UploadModel {

    private String extraField;

    private MultipartFile[] files;

    //getters and setters
}

4. Die Ansichten

HTML-Formular für mehrere Datei-Uploads.

upload.html





Spring Boot - Multiple file upload example - AJAX







Ajax Post Result

    

5. jQuery - Ajax-Anfrage

jQuery, um das Formular über das Formular#id abzurufen und die mehrteiligen Formulardaten per Ajax-Anforderung zu senden.

resources/static/js/main.js

$(document).ready(function () {

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

        //stop submit the form, we will post it manually.
        event.preventDefault();

        fire_ajax_submit();

    });

});

function fire_ajax_submit() {

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

    var data = new FormData(form);

    data.append("CustomField", "This is some extra data, testing");

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

    $.ajax({
        type: "POST",
        enctype: 'multipart/form-data',
        url: "/api/upload/multi",
        data: data,
        //http://api.jquery.com/jQuery.ajax/
        //https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
        processData: false, //prevent jQuery from automatically transforming the data into a query string
        contentType: false,
        cache: false,
        timeout: 600000,
        success: function (data) {

            $("#result").text(data);
            console.log("SUCCESS : ", data);
            $("#btnSubmit").prop("disabled", false);

        },
        error: function (e) {

            $("#result").text(e.responseText);
            console.log("ERROR : ", e);
            $("#btnSubmit").prop("disabled", false);

        }
    });

}

6. Ausnahmehandler

Um eine Ausnahme von der Ajax-Anforderung zu behandeln, erweitern Sie einfachResponseEntityExceptionHandler und geben SieResponseEntity zurück.

RestGlobalExceptionHandler.java

package com.example.exception;

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;

//http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling
@ControllerAdvice
public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler {

    // Catch file size exceeded exception!
    @ExceptionHandler(MultipartException.class)
    @ResponseBody
    ResponseEntity handleControllerException(HttpServletRequest request, Throwable ex) {

        HttpStatus status = getStatus(request);
        return new ResponseEntity(ex.getMessage(), status);

        // example
        //return new ResponseEntity("success", responseHeaders, HttpStatus.OK);

    }

    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);
    }

}

7. DEMO

Starten Sie Spring Boot mit den standardmäßig eingebetteten Tomcatmvn spring-boot:run.

7.1 Access http://localhost:8080/, select few files and clicks submit to fire the ajax request.

spring-boot-file-upload-ajax-1

7.2 Google Chrome, review the request and response in the “Network Inspect”

spring-boot-file-upload-ajax-2

7.3 Google Chrome, “Request Payload”

spring-boot-file-upload-ajax-3

8. cURL-Test

Weitere Tests mit dem BefehlcURL.

8.1 Test single file upload.

Terminal

$ curl -F file=@"f:\\data.txt" http://localhost:8080/api/upload/
Successfully uploaded - data.txt

8.2 Test multiple file upload.

Terminal

$ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt"  http://localhost:8080/api/upload/multi/
Successfully uploaded - data.txt , data2.txt

8.3 Test multiple file upload, maps to Model.

Terminal

$ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt"  http://localhost:8080/api/upload/multi/model
Successfully uploaded!

8.4 Test a large movie file (100MB), the following error message will be displayed.

Terminal

$ curl -F file=@"F://movies//300//Sample.mkv"  http://localhost:8080/api/upload/
Attachment size exceeds the allowable limit! (10MB)

9. cURL-Test + Benutzerdefiniertes Fehlerobjekt

9.1 Create an object to store the error detail.

CustomError.java

package com.example.exception;

public class CustomError {

    String errCode;
    String errDesc;

    public CustomError(String errCode, String errDesc) {
        this.errCode = errCode;
        this.errDesc = errDesc;
    }

    //getters and setters
}

9.2 Update the global exception handler to support CustomError object.

RestGlobalExceptionHandler.java

package com.example.exception;

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 {

    @ExceptionHandler(MultipartException.class)
    @ResponseBody
    ResponseEntity handleControllerException(HttpServletRequest request, Throwable ex) {

        HttpStatus status = getStatus(request);

        return new ResponseEntity(new CustomError("0x000123",
                "Attachment size exceeds the allowable limit! (10MB)"), status);

        //return new ResponseEntity("Attachment size exceeds the allowable limit! (10MB)", 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);
    }

}

9.3 cURL to upload a large file again.

Terminal

$ curl -F file=@"F://movies//300//Sample.mkv"  http://localhost:8080/api/upload/

{"errCode":"0x000123","errDesc":"Attachment size exceeds the allowable limit! (10MB)"}

Erledigt. Feedback ist willkommen.

10. Quellcode herunterladen

Herunterladen -spring-boot-file-upload-ajax-rest.zip (11 KB)