以往開發的時候都是使用的Apache服務器進行文件上傳,後面改用了Ftp,現在開始接觸FastDFS了,感覺還是FastDFS要高級一點,畢竟是分佈式文件系統,從性能和穩定性上都有很高的保證。
搭建docker版本的FastDFS可以參考前面的文章
https://blog.csdn.net/monkeyblog/article/details/106121070
簡介
FastDFS 是一個開源的高性能分佈式文件系統(DFS)。 它的主要功能包括:文件存儲,文件同步和文件訪問,以及高容量和負載平衡。主要解決了海量數據存儲問題,特別適合以中小文件(建議範圍:4KB < file_size <500MB)爲載體的在線服務。
FastDFS 系統有三個角色:跟蹤服務器(Tracker Server)、存儲服務器(Storage Server)和客戶端(Client)。
Tracker Server:跟蹤服務器,主要做調度工作,起到均衡的作用;負責管理所有的 storage server和 group,每個 storage 在啓動後會連接 Tracker,告知自己所屬 group 等信息,並保持週期性心跳。
Storage Server:存儲服務器,主要提供容量和備份服務;以 group 爲單位,每個 group 內可以有多臺 storage server,數據互爲備份。
Client:客戶端,上傳下載數據的服務器,也就是我們自己的項目所部署在的服務器。
話不多說了,直接上代碼了。我的框架是springboot 。
application.yml
fdfs:
#回顯時的服務器地址,端口是fdfs默認的8888,這裏我沒有進行修改哦,注意哦~
file-host: http://172.16.24.203:8888/
tracker-list:
- 172.16.24.203:22122 #這裏是上傳的服務器地址,配置的是22122端口
so-timeout: 5000
pool:
max-total: 200
max-total-per-key: 50
max-wait-millis: 5000
Java代碼
controller
package com.github.edu.modular.edu.controller;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.github.edu.core.base.controller.BaseController;
import com.github.edu.modular.edu.model.Attachment;
import com.github.edu.modular.edu.service.IAttachmentService;
import com.github.edu.modular.edu.util.ExceptionUtil;
import com.github.edu.modular.edu.util.FileUtil;
import com.github.edu.modular.edu.util.MultipartFileUtil;
import com.github.edu.modular.edu.util.R;
import com.luhuiguo.fastdfs.service.FastFileStorageClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.*;
/**
* attachment控制器
*
* @author Monkey
* @Date 2020-04-19 13:20:14
*/
@RestController
@RequestMapping("/attachment")
@Api(value = "Attachment-controller", description = "附件(完成)")
public class AttachmentController extends BaseController {
@Autowired
private IAttachmentService attachmentService;
@Autowired
private FastFileStorageClient fastFileStorageClient;
/**
* 下載,只支持小文件,適合播放類接口
* @param response
* @param filecode
* @throws Exception
*/
@GetMapping("/play/download/filecode/{filecode}")
@ApiOperation(value = "下載附件(完成)", notes = "下載附件(完成)")
public void downloadAttachment(HttpServletResponse response, @PathVariable String filecode) throws Exception{
Attachment attachment = attachmentService.selectOne(new EntityWrapper<Attachment>()
.eq("attachment_file_code", filecode)
);
if(Objects.isNull(attachment)){
throw new Exception("不是有效的文件地址");
}
String attachmentUrl = attachment.getAttachmentUrl();
String group = attachmentUrl.substring(0, attachmentUrl.indexOf("/"));
String path = attachmentUrl.substring(attachmentUrl.indexOf("/") + 1);
//通過直接下載(大文件會導致超時)
FileUtil.downloadFile(response, attachment.getAttachmentName(), fastFileStorageClient.downloadFile(group, path));
}
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
@ResponseBody
@ApiOperation(value = "上傳工單附件(完成)", notes = "上傳工單附件(完成)")
public Object uploadFile( @ApiParam("工單附件") MultipartFile file,
@ApiParam(value = "附件類型:1.工單 2.題目")@RequestParam(value = "attachmentType", defaultValue = "2", required = false)String attachmentType){
R r = new R();
try {
if (file != null) {
List<Attachment> attachments = new ArrayList<>();
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
File file1 = MultipartFileUtil.multipartFileToFile(file);
Attachment attachment = attachmentService.fileSave(file1, uuid);
attachment.setAttachmentType(attachmentType);
attachments.add(attachment);
//刪除臨時文件
MultipartFileUtil.delteTempFile(file1);
attachmentService.insertBatch(attachments);
Map map = new HashMap<>();
map.put("attachmentCode", uuid);
r.setData(map);
} else {
r = new R(null,"附件不能爲空!", R.FAIL);
}
} catch (Exception e) {
r = ExceptionUtil.getException(e);
}
return r;
}
}
service
package com.github.edu.modular.edu.service.impl;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.github.edu.modular.edu.model.Attachment;
import com.github.edu.modular.edu.service.IAttachmentService;
import com.luhuiguo.fastdfs.domain.StorePath;
import com.luhuiguo.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.util.UUID;
/**
* attachmentService
*
* @author Monkey
* @Date 2020-04-19 13:20:14
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class AttachmentServiceImpl extends ServiceImpl<BaseMapper<Attachment>,Attachment> implements IAttachmentService {
@Autowired
private FastFileStorageClient fastFileStorageClient;
@Override
public Attachment fileSave(File f, String code) throws Exception {
String fileCode = UUID.randomUUID().toString();
String newFilename = fileCode + "." + FilenameUtils.getExtension(f.getName());
StorePath storePath = fastFileStorageClient.uploadFile(FileUtils.readFileToByteArray(f), newFilename);
Attachment attachment1 = new Attachment();
attachment1.setAttachmentUrl(storePath.getFullPath());
attachment1.setAttachmentCode(code);
attachment1.setAttachmentFileCode(fileCode.replaceAll("-", ""));
attachment1.setAttachmentDownloadUrl(("attachment/play/download/filecode/" + fileCode).replaceAll("-", ""));
attachment1.setAttachmentName(f.getName());
attachment1.setAttachmentType("1");
return attachment1;
}
}
util
package com.github.edu.modular.edu.util; /**
* Created by TongGuoBo on 2019/6/19.
*/
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @ClassName MultipartFileToFile
* @Description MultipartFile轉fie
* @Author Monkey
* @Date 2019/6/19 13:48
**/
public class MultipartFileUtil {
/**
* MultipartFile 轉 File
*
* @param file
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) throws Exception {
File toFile = null;
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
}
return toFile;
}
//獲取流文件
private static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 刪除本地臨時文件
* @param file
*/
public static void delteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
del.delete();
}
}
}
package com.github.edu.modular.edu.util;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
public class FileUtil {
/**
* 下載公共配置
* @param response
* @param fileName
* @throws Exception
*/
public static void downloadSetting(HttpServletResponse response, String fileName) throws Exception{
// 配置文件下載
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
// 下載文件能正常顯示中文
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
}
/**
* 下載文件
* @param response
* @param fileName
* 文件名
* @param data
* 下載數據
* @throws Exception
*/
public static void downloadFile(HttpServletResponse response, String fileName, byte[] data) throws Exception{
downloadSetting(response,fileName);
//實現下載
OutputStream os = response.getOutputStream();
os.write(data);
os.flush();
}
}
db
CREATE TABLE `attachment` (
`attachment_id` int(11) NOT NULL AUTO_INCREMENT,
`attachment_task_id` int(11) DEFAULT NULL COMMENT '問題分類id',
`attachment_code` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '附件code',
`attachment_file_code` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '文件編號',
`attachment_url` varchar(256) COLLATE utf8_bin DEFAULT NULL COMMENT '請求地址',
`attachment_name` varchar(256) COLLATE utf8_bin DEFAULT NULL COMMENT '附件名字',
`attachment_type` varchar(2) COLLATE utf8_bin DEFAULT '1' COMMENT '附件類型:1.工單 2.題目',
`attachment_download_url` varchar(256) COLLATE utf8_bin DEFAULT NULL COMMENT '下載地址',
`attachment_create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`attachment_update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '修改時間',
`attachment_create_by` int(11) DEFAULT NULL COMMENT '創建人',
`attachment_update_by` int(11) DEFAULT NULL COMMENT '修改人',
PRIMARY KEY (`attachment_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='附件';
swagger
通過code碼查詢到下載地址,即是接口地址