一般文件上傳或圖片服務都是一個獨立的服務來維護,它只專一於文件的上傳和維護,不處理具體的業務邏輯。它會提供一個文件上傳接口,上傳成功後接口返回文件的URL(或文件ID)供業務方使用,業務方只須要存儲文件的URL;下面以修改我的信息場景爲例說明:html
爲了實現這個功能在往常咱們需求編寫一個更新我的信息接口,先調用/post/fileUpload上傳圖片,拿到圖片URL後再調用/post/saveProfile接口保存到用戶表。前端
下面以這個場景來編排一個更新我的信息的接口java
建立一個服務來模擬已有的接口,項目代碼:github.com/wehotel/fiz…react
FileUploadController.java:git
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;
}
}
複製代碼
通用文件上傳接口URL: http://127.0.0.1:8080/post/fileUploadgithub
更新用戶信息接口: http://127.0.0.1:8080/post/saveProfile (爲了演示form表單的提交方式,接口限制只能使用x-www-form-urlencoded提交方式)web
菜單位置:服務編輯->接口列表,點擊新增spring
在配置輸入tab能夠定義接口的入參和請求頭等信息,若是不定義網關不會對接收到的參數作任何校驗。後端
由於要前後調用兩個接口,需求新增2個步驟. 在步驟1裏調用圖片上傳接口,在步驟2裏調用保存用戶信息接口。api
步驟一:
點擊新增HTTP服務,把上傳文件服務和保存用戶信息的服務添加到系統。
選擇剛添加的服務fizz-examples-rest-api,填寫上傳文件接口路徑/post/fileUpload,請求體裏選form-data,引用用戶輸入的圖片參數。
步驟二:
添加步驟二,選fizz-examples-rest-api服務,填寫保存用戶信息接口路徑/post/saveProfile,引用步驟一上傳文件接口的返回結果和用戶輸入的姓名和年齡數據。
配置要返回給前端的響應報文,這裏直接引用步驟二的結果
配置完接口後,點擊測試
發佈接口後訪問URL: http://[網關IP]:8600/proxy/func-test/user/updateProfile
Fizz網關v2.1.0或以上版本 (安裝教程(opens new window))
Fizz網關從1.0開始已支持文件上傳請求的轉發,從2.1.0開始在服務編排功能對form-data上傳文件進行了支持,以便進行更復雜的接口編排。