一個成功人士的背后,必定曾經做出過勇敢而又孤獨的決定。
放棄不難,但堅持很酷~
最近在項目上完成了附件上傳和下載功能,是用的 fastdfs 來實現的。好記性不如爛筆頭,今天把關鍵代碼記錄下來,方便以后復用。
<!--fastdfs-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-fastdfs</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2)在 application.yml 中添加 fastdfs 相關配置:
fdfsIp: http://fastdfs:8880/
fastdfs:
connecttimeout-in-seconds: 5
network-timeout-in-seconds: 10
charset: UTF-8
# token 防盜鏈功能
http-anti-steal-token: false
# 密鑰
http-secret-key: FastDFS1234567890
# TrackerServer port
http-tracker-http-port: 8888
# 測試環境
tracker-server-list:
- fastdfs:22122
示例代碼:
上述方法就是將圖片的 base64 碼進行轉換并上傳到了 fastdfs 上。以下是可復制粘貼的源碼:
import org.springframework.fasfdfs.exception.FdfsException;
import org.springframework.fasfdfs.server.FastDFSClient;
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
@Value("${fdfsIp}")
private String fdfsIp;
@Autowired
private FastDFSClient fastDFSClient;
/**
* 保存用戶信息
*
* @param userDto DTO 對象
* @return success/fail
*/
@Override
@Transactional(rollbackFor=Exception.class)
public Boolean saveUser(UserDTO userDto) {
// 圖片base64轉換為圖片url
String imgBase64=userDto.getAvatar;
if (!StrUtil.isBlank(imgBase64)) {
String imageUri=;
try {
imageUri=fdfsIp + fastDFSClient.uploadFileWithBase64(imgBase64, ".jpg");
} catch (FdfsException e) {
log.error("圖片上傳fastdfs異常", e);
}
if (StrUtil.isBlank(imageUri)) {
log.info("圖片轉換失敗!");
return false;
}
userDto.setAvatar(imageUri);
}
// ...
}
}
關于像 word、pdf 這樣的文件上傳到 fastdfs,我是通過 fastdfs-client-java 這個 jar 包來實現:
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27-SNAPSHOT</version>
</dependency>
#jar中使用時需要將此文件名修改為fastdfs_client.conf 。
#也可以在jar被調用方resource下加入fastdfs_client.conf 內容如下
connect_timeout=60
network_timeout=120
charset=UTF-8
http.tracker_http_port=8888
http.anti_steal_token=no
http.secret_key=FastDFS1234567890
tracker_server=fastdfs:22122
@Data
public class FastDFSFile implements Serializable {
private static final long serialVersionUID=2637755431406080379L;
/**
* 文件二進制
*/
private byte content;
/**
* 文件名稱
*/
private String name;
/**
* 文件長度
*/
private Long size;
public FastDFSFile(byte[] content, String name, Long size){
this.content=content;
this.name=name;
this.size=size;
}
}
fastdfs 工具類相關(包含初始化 fatdfs 連接,上傳、下載、刪除文件):
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import java.io.IOException;
import java.io.Serializable;
/**
* @author liuyzh
* @description fastdfs上傳文件,參考鏈接:https://blog.wuwii.com/fsds-java.html
* @date 2020-03-03
*/
@Slf4j
public class FastDFSUtils implements Serializable {
private static final long serialVersionUID=-4462272673174266738L;
private static TrackerClient trackerClient;
private static TrackerServer trackerServer;
private static StorageClient1 storageClient1;
static {
try {
//clientGloble讀配置文件
ClientGlobal.init("fastdfs_client.conf");
//trackerclient
trackerClient=new TrackerClient;
trackerServer=trackerClient.getConnection;
//storageclient
storageClient1=new StorageClient1(trackerServer, );
} catch (Exception e) {
e.printStackTrace;
}
}
/**
* fastDFS文件上傳
*
* @param file 上傳的文件 FastDFSFile
* @return String 返回文件的絕對路徑
*/
public static String uploadFile(FastDFSFile file) {
String path=;
try {
//文件擴展名
String ext=FilenameUtils.getExtension(file.getName);
//mata list是表文件的描述
NameValuePair mata_list=new NameValuePair[3];
mata_list[0]=new NameValuePair("fileName", file.getName);
mata_list[1]=new NameValuePair("fileExt", ext);
mata_list[2]=new NameValuePair("fileSize", String.valueOf(file.getSize));
path=storageClient1.upload_file1(file.getContent, ext, mata_list);
} catch (Exception e) {
e.printStackTrace;
}
return path;
}
/**
* fastDFS文件下載
*
* @param groupName 組名
* @param remoteFileName 文件名
* @param specFileName 真實文件名
* @return ResponseEntity<byte >
*/
public static ResponseEntity<byte> downloadFile(String groupName, String remoteFileName, String specFileName) {
byte content=;
HttpHeaders headers=new HttpHeaders;
try {
content=storageClient1.download_file(groupName, remoteFileName);
headers.setContentDispositionFormData("attachment", new String(specFileName.getBytes("UTF-8"), "iso-8859-1"));
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
} catch (Exception e) {
e.printStackTrace;
}
return new ResponseEntity<byte>(content, headers, HttpStatus.CREATED);
}
/**
* 刪除fastdfs文件
* @param storagePath 文件的全部路徑 如:group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return -1失敗,0成功
* @throws IOException
* @throws Exception
*/
public static Boolean deleteFile(String storagePath) {
int result=-1;
try {
result=storageClient1.delete_file1(storagePath);
} catch (IOException | MyException e) {
log.error("fastdfs刪除文件異常:", e);
}
if (result==-1) {
return false;
} else {
return true;
}
}
/**
* 根據fastDFS返回的path得到文件的組名
* @param path fastDFS返回的path
* @return
*/
public static String getGroupFormFilePath(String path){
return path.split("/")[0];
}
/**
* 根據fastDFS返回的path得到文件名
* @param path fastDFS返回的path
* @return
*/
public static String getFileNameFormFilePath(String path) {
return path.substring(path.indexOf("/")+1);
}
}
@Override
@SneakyThrows
public R uploadFile(MultipartFile file) {
JSONObject jsonObject=new JSONObject;
try {
Long fileSize=file.getSize;
// 檢查文件大小,不能超過5M
if (fileSize >=5 * 1024 * 1024) {
return R.failed("附件大小不允許超過5M");
}
String attachmentName=file.getOriginalFilename;
FastDFSFile fastDFSFile=new FastDFSFile(file.getBytes, file.getOriginalFilename, file.getSize);
String attachmentPath=FastDFSUtils.uploadFile(fastDFSFile);
jsonObject.put("attachmentPath", attachmentPath);
jsonObject.put("attachmentName", attachmentName);
jsonObject.put("attachmentSize", OtherUtil.getFileSizeUnit(fileSize));
return R.ok(jsonObject);
} catch (IOException e) {
log.info("上傳附件異常:", e);
}
return R.failed("附件上傳異常");
}
方式一:
/**
* 案件所屬附件下載
* 接口 demo:http://192.168.166.189:7700/case/download?path=group1/M00/03/CF/wKinzF5d-EOAWPuEAAGjUNtaNqM02.docx
*
* @param path fastdfs返回的路徑
* @return
*/
@RequestMapping(value="/download")
public ResponseEntity<byte> download(String path) {
// 根據附件url獲取附件名稱
AttachmentInfo attachmentInfo=attachmentInfoService.getAttachmentInfoByUrl(path);
// 下載后的文件名稱
String specFileName=attachmentInfo.getFileName;
String filename=FastDFSUtils.getFileNameFormFilePath(path);
String group=FastDFSUtils.getGroupFormFilePath(path);
return FastDFSUtils.downloadFile(group, filename, specFileName);
}
這樣就可以實現瀏覽器下載了。不過還可以用 nginx 的方式來完成文件的下載:
方式二:
在 nginx 的 fastdfs 相關 server 配置里面添加:
if ($arg_attname ~* .(doc|docx|txt|pdf|zip|rar|xls|xlsx|png|jpeg|jpg)$) {
add_header Content-Disposition "attachment;filename=$arg_attname";
}
如下圖所示:
重啟 nginx 后,這樣就可以通過訪問 url 來進行文件下載了。
比如:http://fastdfs:8880/group1/M00/03/CF/wKinzF5d-EOAWPuEAAGjUNtaNqM02.docx?attname=測試.docx
。
/**
* @param storagePath 文件的全部路徑 如:group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return -1失敗,0成功
* @throws IOException
* @throws Exception
*/
public static Boolean deleteFile(String storagePath) {
int result=-1;
try {
result=storageClient1.delete_file1(storagePath);
} catch (IOException | MyException e) {
log.error("fastdfs刪除文件異常:", e);
}
if (result==-1) {
return false;
} else {
return true;
}
}
關于 fastdfs 的文件上傳、下載、刪除的示例代碼上面都已經介紹清楚了,如果有小伙伴遇到了 fastdfs jar 包的依賴問題,也不要慌,我已經踩過坑了,出坑記錄:實操:Could not autowire No beans of 'FastDFS Client' type found 的解決方法 ,可以看這篇。
好了各位,以上就是這篇文章的全部內容了,能看到這里的人呀,都是人才。
白嫖不好,創作不易。也感謝各位的支持和認可,給予我最大的創作動力吧,我們下篇文章見!
如果本篇博客有任何錯誤,請批評指教,不勝感激 !
? Ambari 2.7.3.0 安裝部署 hadoop 3.1.0.0 集群視頻完整版
? 【實戰】使用 Kettle 工具將 mysql 數據增量導入到 MongoDB 中
? 都快2020年了,ambari自定義服務集成,你還沒掌握嗎?文末有福利
? HBase原理(一):架構理解
? HBase二次開發之搭建HBase調試環境,如何遠程debug HBase源代碼
? Kafka消費者 之 指定位移消費
? Kylin配置Spark并構建Cube(修訂版)
? 看完您如果還不明白 Kerberos 原理,算我輸!
歡迎大家留言討論
朕已閱
Flask中,文件上傳通常涉及創建一個表單,用戶可以通過這個表單上傳文件。然后,后端代碼會處理接收到的文件。以下是實現文件上傳功能的步驟:
創建HTML表單 - 使用標簽創建一個表單,設置enctype="multipart/form-data"屬性以支持文件上傳。
File Upload
創建Flask路由 - 定義一個處理文件上傳的路由。
from flask import Flask, request, redirect, url_for, send_from_directory
app=Flask(__name__)
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method=='POST':
file=request.files['file']
if file and '.jpg' in file.filename:
# 保存上傳的文件
filename='uploads/' + file.filename
file.save(filename)
# 重定向到文件上傳后的頁面
return redirect(url_for('success', filename=filename))
return '''
'''
@app.route('/success/')
def success(filename):
# 返回上傳成功的頁面,顯示文件名和下載鏈接
return f'File uploaded successfully: Download {filename}'
@app.route('/download_file/')
def download_file(filename):
return send_from_directory(app.root_path + '/uploads', filename)
if __name__=="__main__":
app.run()
處理上傳的文件 - 在Flask視圖函數中,通過request.files字典訪問上傳的文件。
保存上傳的文件 - 將上傳的文件保存到服務器的指定目錄中。
重定向或返回上傳結果 - 一旦文件被保存,可以重定向用戶到一個新頁面,顯示上傳成功的信息,或者直接在原頁面顯示上傳結果。
提供下載鏈接 - 為了讓用戶能夠下載上傳的文件,可以創建一個路由來提供文件的下載服務。在示例中,使用了send_from_directory函數來實現。
確保服務器上的目標目錄對于Web服務是可寫的,并且處理上傳的代碼要考慮安全性,比如檢查文件類型、大小,防止上傳惡意文件。此外,對于生產環境,應該使用更高級的文件上傳處理方案,比如文件存儲在外部服務上,以及設置適當的權限和安全措施。
于網頁的上傳組件比較常用的webuploader ,jQuery File Upload等,切圖網在做前端項目切圖的時候,不乏有一些后臺或者前臺需要用到上傳組件的,雖然做前端開發不需要實現上傳到服務器的功能,但是前臺的功能還是需要做出來的,特別簡單的可以jquery手寫 基本能夠用了,而復雜的時候就需要上一些插件,而選擇插件的時候也比較講究,插件盡可能要靈活 參數夠多 或者一些擴展方法多, 可以滿足不同的復雜情況,而jQuery File Upload則是相比之下比較不錯的一款。
jQuery File Upload 是一個Jquery文件上傳組件,支持多文件上傳、取消、刪除,上傳前縮略圖預覽、列表顯示圖片大小,支持上傳進度條顯示;支持各種動態語言開發的服務器端。
官網鏈接:https://github.com/blueimp/jQuery-File-Upload/wiki
特點:拖放支持;上傳進度條;圖像預覽;可定制和可擴展的;兼容任何服務器端應用平臺(PHP, Python, Ruby on Rails, Java, Node.js, Go etc.)。
演示地址 https://blueimp.github.io/jQuery-File-Upload/
使用方法:
1. 需要加載的js文件:
jquey-1.8.3.min.js
jquery-ui-widget.js
jquery.iframe-transport.js
jquery.fileupload.js
2. html代碼:
3. js代碼:
3.1 顯示上傳進度條:
3.2 需要一個<div>容器用來顯示進:
4. API
4.1 Initialization:
在上傳按鈕上調用fileupload()方法;
示例:
$('#fileupload').fileupload();
4.2 Options :
1: url:請求發送的目標url
Type: string
Example: ‘/path/to/upload/handler.json’
2.Type: 文件上傳HTTP請求方式,可以選擇“POST”,“PUT”或者”PATCH”,
默認”POST”
Type: string
Example: ‘PUT’
3. dataType:希望從服務器返回的數據類型,默認”json”
Type: string
Example: ‘json’
4. autoUpload:默認情況下,只要用戶點擊了開始按鈕被添加至組件的文件會立即上傳。將autoUpload值設為true可以自動上傳。
Type: boolean
Default: true
5. acceptFileTypes:允許上傳的的文件類型
Example: /(\.|\/)(gif|jpe?g|png|xlsx)$/i
6. maxFileSize: 最大上傳文件大小
Example: 999000 (999KB) //單位:B
7. minFileSize:最小上傳文件大小
Example: 100000 (100KB) //單位:B
8.previewMaxWidth : 圖片預覽區域最大寬度
Example: 100 //單位:px
4.3 Callback Options:
使用方法一:函數屬性
實例:
使用方法二:綁定事件監聽函數
實例:
每個事件名稱都添加前綴:”fileupload”;
注意推薦使用第二種方法。
常用的回調函數:
1. add: 當文件被添加到上傳組件時被觸發
或者$(‘#fileupload’).on(‘fileuploadadd’, function (e, data) {/* … */});
2. processalways: 當一個單獨的文件處理隊列結束(完成或失敗時)觸發
3. progressall: 全局上傳處理事件的回調函數
Example:
4. fail : 上傳請求失敗時觸發的回調函數,如果服務器返回一個帶有error屬性的json響應這個函數將不會被觸發。
5. done : 上傳請求成功時觸發的回調函數,如果服務器返回一個帶有error屬性的json響應這個函數也會被觸發。
6. always : 上傳請求結束時(成功,錯誤或者中止)都會被觸發。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。