In normal service scenarios, a file upload server must be set up as a public service. Generally, only a single file is uploaded. However, in actual business scenarios, it is found that a single file upload cannot meet some business requirements. Therefore, we need to solve how to write an interface for uploading multiple files at the same time and return the address of the downloadable file.

Without further ado, instead of building a Spring Boot project from scratch, if you don’t know, please go directly to the official website for examples.

The following is an example of the above picture, which is relatively simple and only for reference:

1 Back-end interface logic for uploading images

UploadController.java

package com.zz.controllers.fileUpload;

import com.zz.Application;
import com.zz.model.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Configuration;
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.*;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.UUID;

import static com.zz.config.ConfigConstants.getFileDir;

@RestController
@Configuration
public class UploadController {
    
    private static final Logger log = LoggerFactory.getLogger(Application.class);
    
    @Value("${server.port}")
    private String port;
    
  	// Obtain the current IP address
    public String getIp(a) {
        InetAddress localhost = null;
        try {
            localhost = Inet4Address.getLocalHost();
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return localhost.getHostAddress();
    }
    
    @PostMapping(value = "/upload", consumes = {"multipart/form-data"})
    public Response upload(@RequestParam("file") MultipartFile[] files, Response response) {
        log.info("Upload multiple files");
        StringBuilder builder = new StringBuilder();
        // file address
        String fileAddress ="http://"+ getIp()+ ":" + port + File.separator;
    
        ArrayList<String> imgUrls = new ArrayList<String>();
        try {
            for (int i = 0; i < files.length; i++) {
                // old file name
                String fileName = files[i].getOriginalFilename();
                // new filename
                String generateFileName = UUID.randomUUID().toString().replaceAll("-"."") + fileName.substring(fileName.lastIndexOf("."));
                // store filename
                String distFileAddress = fileAddress + generateFileName;
                builder.append(distFileAddress+",");
                imgUrls.add(distFileAddress);
                // generate file to disk
                files[i].transferTo(newFile(getFileDir() + generateFileName)); }}catch (Exception e) {
            e.printStackTrace();
        }
        response.setMsg("success");
        log.info(builder.toString());
        response.setData(imgUrls);
        returnresponse; }}Copy the code

com.zz.model.Response

package com.zz.model;


public class Response {

    private int code;
    private String msg;
    private Object data;
    
    public Object getData(a) {
        return data;
    }
    
    public void setData(Object data) {
        this.data = data;
    }
    
    public int getCode(a) {
        return code;
    }
    
    public void setCode(int code) {
        this.code = code;
    }
    
    public String getMsg(a) {
        return msg;
    }
    
    public void setMsg(String msg) {
        this.msg = msg; }}Copy the code

Instead of receiving a single file, we directly accept multiple file objects and then iterate to generate each corresponding address.

Among them:

GetFileDir sets the location to store the image, which I choose to store somewhere else outside the project

com.zz.config.ConfigConstants.getFileDir

package com.zz.config;

public class ConfigConstants {
    
    public static String fileDir;
    
    public static String getFileDir() {
        fileDir = "/Users/wz/projects/blog/uploadFile/";
        returnfileDir; }}Copy the code

After we have generated the files to the specified folder, how can we configure access to the static file image resources outside the project and download them under the current server?

This is done using the Spring Boot configuration file application.yml, but there are other methods such as WebMvcConfigurer that I won’t go into here.

application.yml

pring:
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

  profiles:
    active: dev

  Static resource configuration
  mvc:
    static-path-pattern: / * *
  resources:
    static-locations: file:/Users/wz/projects/blog/uploadFile/,classpath:/static/,classpath:/resources/,classpath:/file/,classpath:/templates/

server:
  use-forward-headers: true
  tomcat:
    remote-ip-header: X-Real-IP
    protocol-header: X-Forwarded-Proto

# custom
my:
  tokenURL: "55555"
  authURL: "88888"


Copy the code

And then we’re in the result that we’re generating http://192.168.31.77:8080/a7ef32e3922b46aea256a93dd53de288.png, this address can be substantial to over the document file: / Users/wz/uploadFile/projects/blog /, this is roughly a simple file server configuration, of course, far less than this, and compression and other functions, I will talk about later.

The back-end logic is clear;

How does the front end send multiple file objects simultaneously to the back end?

2 How can I upload multiple front-end files

html

<input type="file" multiple class="el-upload" accept="image/*" name="file">
Copy the code

js

//upload
var uploadBtn = document.querySelector('.el-upload');

uploadBtn.onchange = function (e) {
    let files = this.files;
    console.log(this.files);

    const xhr = new XMLHttpRequest();
    xhr.open("post"."/upload".true);
    // xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.onreadystatechange = function () {
        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
            console.log(JSON.parse(this.responseText));
            const {data} = JSON.parse(this.responseText);
            if(! data)return;
            const imageList = data.slice(0);
            let imageStr = ' ';
            imageList.forEach(img= >{
                imageStr += `<img src="${img}"/ > `;
            });
            document.getElementById("result").innerHTML = imageStr; }};const formData = new FormData();

    // Multiple files are uploaded simultaneously
    if(files && files.length){
        for (let i=0; i<files.length; i++) { formData.append("file", files[i])
        }
    }

    console.log(formData);

    xhr.send(formData);
};
Copy the code

The front end sends POST requests through FormData.

Different from the previous single formData.append(); Here we can append multiple binary streams of files with the same name at the same time;

The result is normal, and when we deploy to the server, this can be used as a Web server for everyone to use.

End of chapter!