|
@@ -0,0 +1,118 @@
|
|
|
+package cn.gygxzc.cloud.tina.fastdfs.client.controller;
|
|
|
+
|
|
|
+import cn.gygxzc.cloud.tina.fastdfs.client.mata.CommonFileMata;
|
|
|
+import cn.gygxzc.cloud.tina.fastdfs.client.mata.FailedStorePath;
|
|
|
+import com.github.tobato.fastdfs.domain.MataData;
|
|
|
+import com.github.tobato.fastdfs.domain.StorePath;
|
|
|
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
|
|
|
+import io.reactivex.Observable;
|
|
|
+import io.reactivex.Single;
|
|
|
+import io.reactivex.SingleOnSubscribe;
|
|
|
+import io.reactivex.schedulers.Schedulers;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Created by niantuo on 2018/10/27.
|
|
|
+ * 文件上传接口。
|
|
|
+ * 文件上传的接口
|
|
|
+ */
|
|
|
+@RestController
|
|
|
+@RequestMapping("/files/upload")
|
|
|
+public class FdfsUploadController {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private FastFileStorageClient storageClient;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传文件,需要自己附带一些信息
|
|
|
+ *
|
|
|
+ * @param file 文件本身信息
|
|
|
+ * @param fileMata 文件的自定义数据
|
|
|
+ * @return 文件的
|
|
|
+ */
|
|
|
+ @PostMapping
|
|
|
+ public Object upload(@RequestParam("file") MultipartFile file, CommonFileMata fileMata) {
|
|
|
+
|
|
|
+ Set<MataData> mataData = fileMata.mataData(file);
|
|
|
+ String fileExtName = file.getOriginalFilename();
|
|
|
+ try {
|
|
|
+ return storageClient.uploadFile(file.getInputStream(), file.getSize(), fileExtName, mataData);
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException("文件上传失败,请重试。");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 多文件上传。
|
|
|
+ * 暂时这种方式不知道会有什么风险。
|
|
|
+ * 把这个线程挂起来是不是也浪费了一些性能。
|
|
|
+ *
|
|
|
+ * @param files 文件信息
|
|
|
+ * @param fileMata 文件描述
|
|
|
+ * @return 文件的下载路径,不保证,顺序
|
|
|
+ */
|
|
|
+ @PostMapping("/multi")
|
|
|
+ public Object multiUpload(@RequestParam("files") List<MultipartFile> files, CommonFileMata fileMata) {
|
|
|
+
|
|
|
+ final Object mLock = new Object();
|
|
|
+ List<FailedStorePath> failedStorePaths = new ArrayList<>();
|
|
|
+ List<StorePath> storePaths = new ArrayList<>();
|
|
|
+ Observable.fromIterable(files)
|
|
|
+ .flatMapSingle(file -> uploadToFdfs(file, fileMata))
|
|
|
+ .doOnNext(storePath -> {
|
|
|
+ if (storePath instanceof FailedStorePath) {
|
|
|
+ failedStorePaths.add((FailedStorePath) storePath);
|
|
|
+ } else {
|
|
|
+ storePaths.add(storePath);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .toList()
|
|
|
+ .subscribe(results -> {
|
|
|
+ synchronized (mLock) {
|
|
|
+ mLock.notifyAll();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ synchronized (mLock) {
|
|
|
+ try {
|
|
|
+ mLock.wait();
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Map<String, Object> results = new HashMap<>();
|
|
|
+ results.put("paths", storePaths);
|
|
|
+ results.put("error", failedStorePaths);
|
|
|
+ return results;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 多文件上传,有可能只有一两个文件失败,这个时候,需要做一些处理.
|
|
|
+ * 设置文件上传最大的超时时长为两分钟,过长会影响用户体验
|
|
|
+ *
|
|
|
+ * @param file 上传的文件
|
|
|
+ * @param fileMata 文件的描述
|
|
|
+ * @return 文件的地址信息
|
|
|
+ */
|
|
|
+ private Single<StorePath> uploadToFdfs(MultipartFile file, CommonFileMata fileMata) {
|
|
|
+ return Single.create((SingleOnSubscribe<StorePath>) subscriber -> {
|
|
|
+ Set<MataData> mataData = fileMata.mataData(file);
|
|
|
+ String fileExtName = file.getOriginalFilename();
|
|
|
+ StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), fileExtName, mataData);
|
|
|
+ subscriber.onSuccess(storePath);
|
|
|
+ })
|
|
|
+ .timeout(2, TimeUnit.MINUTES)
|
|
|
+ .retry(3)
|
|
|
+ .onErrorReturn(throwable -> new FailedStorePath(file))
|
|
|
+ .subscribeOn(Schedulers.io());
|
|
|
+ }
|
|
|
+
|
|
|
+}
|