# Version requirements

FizzGate integrated platform v2.1.0 or above (Installation Tutorial (opens new window))

The FizzGate integration platform has supported the forwarding of file upload requests since 1.0. Starting from 2.1.0, the service orchestration function supports form-data upload files to facilitate more complex interface orchestration.

# Example description

Usually the file upload or image service is maintained as an independent service. It only focuses on file upload and maintenance and does not handle specific business logic. It will provide a file upload interface. After the upload is successful, the interface returns the URL (or file ID) of the file for the business party to use. The business party only needs to store the URL of the file. The following takes the scenario of modifying personal information as an example:

  • Users can modify name, age and avatar
  • The back-end service has a public universal file upload interface, which is submitted through multipart/form-data, such as: /post/fileUpload
  • The backend service already has an interface for saving user information, such as: /post/saveProfile, and the input parameters are (userId, name, age, avatarUrl)

In order to realize this function, we usually need to write an interface to update personal information. First, call /post/fileUpload to upload the image. After getting the image URL, we then call the /post/saveProfile interface to save it to the user table.

Let's use this scenario to compile an interface for updating personal information.

# Environment preparation

Create a service to simulate the existing interface, project code: https://gitee.com/fizzgate/fizz-examples/fizz-examples-rest-api.git

FileUploadController.java:

package we.controller;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.Part;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
  *Example
  *
  * @author Francis Dong
  *
  */
@RestController
public class FileUploadController {

/**
*
*File upload
*
* @param exchange
* @return
*/
@PostMapping(value = "/post/fileUpload", consumes = "multipart/form-data")
public Object formData(ServerWebExchange exchange) {
Mono<MultiValueMap<String, Part>> m = exchange.getMultipartData();
return m.flatMap(md -> {
// extract non-file form data
Map<String, Object> params = extractFormData(md);
System.out.println(params);

List<FilePart> list = new ArrayList<>();
for (Entry<String, List<Part>> entry : md.entrySet()) {
List<Part> val = entry.getValue();
if (val != null && val.size() > 0) {
val.stream().forEach(part -> {
if (part instanceof FilePart) {
FilePart fp = (FilePart) part;
list.add(fp);
}
});
}
}

if (list != null && list.size() > 0) {
Flux<FilePart> fileParts = Flux.fromIterable(list);
return fileParts.flatMap(fp -> {
String tmpPath = System.getProperty("user.dir") + "/tmp/";
File tmpFolder = new File(tmpPath);
if (!tmpFolder.exists()) {
tmpFolder.mkdirs();
}
String path = tmpPath + fp.filename();
System.out.println(path);

// Return file path
return fp.transferTo(new File(path)).then(Mono.just("/tmp/" + fp.filename()));
}).collectList().flatMap(urls -> {
Map<String, Object> result = new HashMap<>();
result.put("urls", urls);
return Mono.just(result);
});

} else {
return Mono.just(new HashMap<>());
}
});
}

/**
*Save profile
*
* @param exchange
* @return
*/
@PostMapping(value = "/post/saveProfile", consumes = "application/x-www-form-urlencoded")
public Object saveProfile(ServerWebExchange exchange) {
Mono<MultiValueMap<String, String>> m = exchange.getFormData();
return m.flatMap(md -> {
// save profile info ...
System.out.println(md);

Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("message", 0);
Map<String, Object> user = new HashMap<>();
user.put("userId", md.getFirst("userId"));
user.put("name", md.getFirst("name"));
user.put("age", md.getFirst("age"));
user.put("avatarUrl", md.getFirst("avatarUrl"));
result.put("user", user);
return Mono.just(result);
});
}

public static Map<String, Object> extractFormData(MultiValueMap<String, Part> params) {
HashMap<String, Object> m = new HashMap<>();

if (params == null || params.isEmpty()) {
return m;
}

for (Entry<String, List<Part>> entry : params.entrySet()) {
List<Part> val = entry.getValue();
if (val != null && val.size() > 0) {
if (val.size() > 1) {
List<String> formFieldValues = new ArrayList<>();
val.stream().forEach(part -> {
if (part instanceof FormFieldPart) {
FormFieldPart p = (FormFieldPart) part;
formFieldValues.add(p.value());
} else if (part instanceof FilePart) {
FilePart fp = (FilePart) part;
formFieldValues.add(fp.filename());
}
});
if (formFieldValues.size() > 0) {
m.put(entry.getKey(), formFieldValues);
}
} else {
if (val.get(0) instanceof FormFieldPart) {
FormFieldPart p = (FormFieldPart) val.get(0);
m.put(entry.getKey(), p.value());
} else if (val.get(0) instanceof FilePart) {
FilePart fp = (FilePart) val.get(0);
m.put(entry.getKey(), fp.filename());
}
}
}
}
return m;
}
}

  • Universal file upload interface URL: http://127.0.0.1:8080/post/fileUpload

  • Update user information interface: http://127.0.0.1:8080/post/saveProfile (to demonstrate the form submission method