Files are passed between the front end and back end services in form-data form via POST requests.

By setting the Content-Type of the HTTP request response, the back end passes the data to the front end as a binary stream.

1 Use form-data to send data to the backend

1.1 Definition of back-end Data Receiving Interface

Back-end interface /form-data definition

@Slf4j
@RestController
@RequestMapping(value = "/rest")
public class FileTransmit {
    @PostMapping(value = "/form-data")
    public String formData(HttpServletRequest request,
                           @RequestParam(value = "email", required = false) String email,
                           @RequestParam(value = "file_excel", required = false) MultipartFile multipartFile,
                           UserInfo userInfo) {
        StandardMultipartHttpServletRequest standardMultipartRequest = (StandardMultipartHttpServletRequest) request;
​
        log.info("multipartFile in @RequestParam={}", multipartFile.getOriginalFilename());
        MultiValueMap<String, MultipartFile> multiFileMap = standardMultipartRequest.getMultiFileMap();
        for (String paramKey : multiFileMap.keySet()) {
            List<MultipartFile> multipartFileList = multiFileMap.get(paramKey);
            log.info("MultipartFile key={}, size={}", paramKey, multipartFileList.size());
            for (MultipartFile curMultipartFile : multipartFileList) {
                log.info("MultipartFile key={}, file name={}",
                        paramKey, curMultipartFile.getOriginalFilename());
                log.info("MultipartFile in request equals to file in @RequestParam={}",
                        multipartFile.equals(curMultipartFile));
            }
        }
​
        log.info("email in @RequestParam={}", email);
        log.info("userInfo in RequestParam={}", userInfo);
        Map<String, String[]> paramMap = standardMultipartRequest.getParameterMap();
        for (String paramKey : paramMap.keySet()) {
            log.info("param key={}, size={}, value={}",
                    paramKey, paramMap.get(paramKey).length, paramMap.get(paramKey));
        }
        return "Form Data processed finished!";
    }
}
Copy the code

1.2 Postman Debugging Interface

Set request body to form-data, can pass text data and file data at the same time, file key can contain multiple files (file_excel), key can also duplicate (ID, name, email).

As a result, the @requestParam annotation fetches the data specified in the form-data key, while the HttpServletRequest Request contains all the form-data data.

Since @requestParam modifies email and multipartFile not as arrays or lists, text email takes a concatenated value, while file multipartFile takes the first value. To receive multiple files, change the interface definition to List

MultipartFile.

1.3 Front-end transmission of form-data

Fill in the data on the page with a simple HTML demonstration, and when you click submit, invoke the interface defined in Section 1.1 and pass the data to the back end as form-data.

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Upload FormData</title> </head> <body> <form id="Form1" action="http://localhost:8080/rest/form-data" method="post" enctype="multipart/form-data"> <div style="text-align: left"> ID: <input name="id" type="text" /> <br /> ID: <input name="id" type="text" /> <br /> Name: <input name="name" type="text" /> <br /> Name: <input name="name" type="text" /> <br /> Email: <input name="email" type="text" /> <br /> Email: <input name="email" type="text" /> <br /> File: <input id="1" name="file_excel" type="file" multiple="multiple" /> <br /> File: <input id="2" name="file_img" type="file" /> <br /> <input type="submit" value="submit" /> <input type="reset" value="reset" /> </div> </form> </body> </html>Copy the code

1.4 Back-end transmission of form-data

Shows how the backend directly encapsulates data in form-data format and then invokes the interface defined in Section 1.1 to implement file data transfer between back-end services.

HttpHeaders sets the data type passed by the request to form-data, encapsulates the Requset header and Request Body with HttpEntity, and calls the POST interface with the postForObject method of RestTemplate.

MultiValueMap is used to encapsulate data in form-data format, and FileSystemResource is used for file type data.

public class FileTransmitTest { private RestTemplate restTemplate; private final String URL_ROOT = "http://localhost:8080/rest"; @Before public void init() { restTemplate = new RestTemplate(); } @Test public void FormDataTest() { MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap(); requestBody.add("file_excel", new FileSystemResource(new File("E:\dataJava\data\city_info.xlsx"))); requestBody.add("file_excel", new FileSystemResource(new File("E:\dataJava\data\user_info.xlsx"))); requestBody.add("file_img", new FileSystemResource(new File("E:\dataJava\data\github.png"))); requestBody.add("email", "[email protected]"); requestBody.add("email", "[email protected]"); requestBody.add("id", "123"); requestBody.add("id", "12345"); requestBody.add("name", "zhangsan"); requestBody.add("name", "kuangtu"); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(requestBody, httpHeaders); String response = restTemplate.postForObject(URL_ROOT+"/form-data", requestEntity, String.class); System.out.println(response); }}Copy the code

1.5 Send a file to the back end

Demonstrates that the back end receives a single file and saves it to the specified directory.

The interface definition

@ResponseBody @PostMapping(value = "/receive/single") public String receiveSingle(MultipartFile multipartFile) throws IOException { if (multipartFile == null) { return "received file is null!" ; } the info (" file the content-type = {} ", multipartFile. GetContentType ()); Log.info (" file size ={}", multipartfile.getsize ()); Log.info (" filename ={}", multipartfile.getName ()); The log. The info (" file original name = {} ", multipartFile. GetOriginalFilename ()); / / save the received File to the local File destFile = new File (at "E: \ \" + multipartFile getOriginalFilename ()); multipartFile.transferTo(destFile); return "Form Data processed finished!" ; }Copy the code

Interface call

Because the @requestParam annotation is not used in the interface definition, the variable multipartFile cannot be initialized if the key of the form-data parameter is not multipartFile. Only when the key of form-data is set to multipartFile, it can be initialized normally.

If the interface is defined as

public String receiveSingle(@RequestParam(value = "file") MultipartFile multipartFile) throws IOException
Copy the code

The key of form-data must be set to file to initialize multipartFile. Therefore, it is recommended that the value in @requestParam be the same as the variable name, and that the variable name be used for the key encapsulating the parameter when the interface calls.

1.6 summarize

  • In order toform-dataData transfer to the back endrequest headerIn thecontent-type="multipart/form-data".
  • form-dataYou can pass both text and files to the back end.
  • For the file typeform-dataData, back-end interface toMultiPartFileType to receive and can passMultiPartFilethetransferToSave the file locally.
  • For text typeform-dataData, which can be received by defined classes or by primitive type variables.
  • SpringProject back-end interfaceHttpServletRequest requestAll of themform-dataThe data.

2 The back-end end transfers files to the front-end end

Here, as an example, the backend transmits pictures to the front-end, including the following three methods:

  • The back end saves the image on the file storage server and returns the URL of the image to the front end. The front end sets SRC = URL of the IMG tag. This way should be the mainstream, but do not want to make a storage server, did not use this way.
  • The back end returns the base64 encoding of the picture to the front end in the form of a string, and the front end then parses it into a picture display. This way although there is a large picture may be truncated Ken, but it is convenient to choose this way.
  • The back end returns the binary stream of images as a byte array to the front end, which then parses it into a picture display. Returning binary streams is not only useful for images, but also for audio and video.

2.1 Base64 encoded transmission

Back-end interface definition

@crossorigin // Allow cross-domain access @getMapping (value = "/get-img-code") public String getImageBase64(String imageName) throws IOException { log.info("request param={}", imageName); String imgRootPath = "E:\dataJava\data\"; File imgFile = new File(imgRootPath + imageName + ".png"); InputStream inStream =new FileInputStream(imgFile); byte[] imgBytes = new byte[(int) imgFile.length()]; // Create an array of appropriate file sizes instream.read (imgBytes); // Read the contents of the file into the b[] array instream.close (); log.info("image size={}", imgBytes.length); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encodeBuffer(imgBytes); }Copy the code

2.2 Binary stream Transmission

Back-end interface definition

@crossorigin // Allow cross-domain access @getMapping (value = "/get-img-byte") public void getImageByte(HttpServletRequest Request, HttpServletResponse response, String imageName) throws IOException { String imgRootPath = "E:\dataJava\data\"; File imgFile = new File(imgRootPath + imageName + ".png"); InputStream inStream =new FileInputStream(imgFile); byte imgBytes[] = new byte[(int) imgFile.length()]; // Create an array of appropriate file sizes instream.read (imgBytes); // Read the contents of the file into the b[] array instream.close (); response.setContentType("application/octet-stream; charSet=UTF-8"); response.setContentLength(imgBytes.length); try (InputStream inputStream = new ByteArrayInputStream(imgBytes); OutputStream outputStream = response.getOutputStream()) { IOUtils.copy(inputStream, outputStream); outputStream.flush(); }catch (IOException e) { log.error("{}", e.getMessage()); }}Copy the code

2.3 HTML receive and display

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script SRC = "https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" > < / script > < / head > < body > < div id = "main" style = "width: 100%; " > <div id="left" style="width:50%; float:left;" <p>< p>< p>< img id="base64_img" </p> <p>< p>< img id="base64_img" </p> src="" alt="" width="" height=""> </div> <div id="right" style="width:50%; float:left;" > <p>byte image</p> <img id="byte_img" src="http://localhost:8080/rest/get-img-byte? imageName=github" alt="" width="70%" height="70%"> </div> </div> <script> function getImgBase64() { $.ajax({ url : "http://localhost:8080/rest/get-img-code? ImageName =github", type: 'GET', contentType: false, Function (result) {console.log("reponse result:", result); var src = 'data:image/png; base64,' + result; $("#base64_img").attr('src', src); $("#base64_img").css("width", "70%"); $("#base64_img").css("height", "70%"); }, error : function(result) { console.log("reponse result:", result); alert("Post Faile!" ); }}); } </script> </body> </html>Copy the code

Operation effect:

Add: HTTP Headers

HTTP headers allow clients and servers to pass additional information through request and response. A request header consists of a name (case insensitive) followed by a colon (:) followed by a specific value (without a newline character).

Depending on the context, the header can be divided into:

  • General Headers: A header that applies to both request and response messages, but has nothing to do with the data being transferred in the final message body.
  • Request Headers: A header that contains more information about the resource to be fetched or about the client itself.
  • Response Headers: A header that contains supplementary information about the Response, such as its location or the server itself (name and version, etc.).
  • Entity Headers: Contains more information about the Entity body, such as the content-Length degree of the body or its MIME type.

In the Request headers

  • Accept: Indicates that the browser tells the server the type of data that the browser can Accept.
  • Accept-encoding: Indicates the Encoding method that the browser tells the server that the browser can receive the data.
  • Accept-language: indicates the data Language that the browser tells the server that the browser can receive. It is usually used for internationalization.
  • Content-type: indicates the file Type of the POST and PUT request body.

In the Reponse headers

  • Content-type: indicates the data Type returned by the interface.
  • Content-length: The Length of the body returned in octets (8-bit bytes)

References:

HTTP Headers

List of HTTP header fields