spring boot整合FastDFS maven倉庫有jar包還是報錯怎麼辦?
一、首先,maven工程新增依賴
<!--fastdfs--> <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27-RELEASE</version> </dependency>
如果報錯請參考maven倉庫有jar包還是報錯怎麼辦?
二、resources目錄下新增fdfs_client.conf檔案
前面使用nginx支援http方式訪問檔案,但所有人都能直接訪問這個檔案伺服器了,所以做一下許可權控制。
從來都是我能借用別人的圖片,而別人借用我的圖片不好意思不行!
FastDFS的許可權控制是在服務端開啟token驗證,客戶端根據檔名、當前unix時間戳、祕鑰獲取token,在地址中帶上token引數即可通過http方式訪問檔案。
#################### FastDFS-Client Start ####################
#預設值為30s
connect_timeout = 10
#預設值為30s
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
# token 防盜鏈功能
http.anti_steal_token = true
http.secret_key = FastDFS1234567890
tracker_server = 192.168.1.118:22122
#tracker_server = 192.168.0.119:22122
## Tracker Server, if more than one, separate with ","
# fastdfs.tracker_servers=10.0.11.201:22122,10.0.11.202:22122,10.0.11.203:22122
#fastdfs.tracker_servers=${tracker_server_addr}:22122
#################### FastDFS-Client End ####################
對應檔案伺服器上/etc/fdfs下的http.conf
修改http.conf # vim /etc/fdfs/http.conf 設定為true表示開啟token驗證 http.anti_steal.check_token=true 設定token失效的時間單位為秒(s) http.anti_steal.token_ttl=1800 金鑰,跟客戶端配置檔案的fastdfs.http_secret_key保持一致 http.anti_steal.secret_key=FASTDFS1234567890 如果token檢查失敗,返回的頁面 http.anti_steal.token_check_fail=/ljzsg/fastdfs/page/403.html
記得重啟服務
三、客戶端生成token
訪問檔案需要帶上生成的token以及unix時間戳,所以返回的token是token和時間戳的拼接。
之後,將token拼接在地址後即可訪問:file.ljzsg.com/group1/M00/00/00/wKgzgFnkaXqAIfXyAAEoRmXZPp878.jpeg?token=078d370098b03e9020b82c829c205e1f&ts=1508141521
/** * 獲取訪問伺服器的token,拼接到地址後面 * * @param filepath 檔案路徑 group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg * @param httpSecretKey 金鑰 * @return 返回token,如: token=078d370098b03e9020b82c829c205e1f&ts=1508141521 */ public static String getToken(String filepath, String httpSecretKey){ // unix seconds int ts = (int) Instant.now().getEpochSecond(); // token String token = "null"; try { token = ProtoCommon.getToken(getFilename(filepath), ts, httpSecretKey); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (MyException e) { e.printStackTrace(); } StringBuilder sb = new StringBuilder(); sb.append("token=").append(token); sb.append("&ts=").append(ts); return sb.toString(); }
注意事項
如果生成的token驗證無法通過,請進行如下兩項檢查:
A. 確認呼叫token生成函式(ProtoCommon.getToken),傳遞的檔案ID中沒有包含group name。傳遞的檔案ID格式形如:M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
B. 確認伺服器時間基本是一致的,注意伺服器時間不能相差太多,不要相差到分鐘級別。
對比下發現,如果系統檔案隱私性較高,可以直接通過fastdfs-client提供的API去訪問即可,不用再配置Nginx走http訪問。配置Nginx的主要目的是為了快速訪問伺服器的檔案(如圖片),如果還要加許可權驗證,則需要客戶端生成token,其實已經沒有多大意義。關鍵是,這裡我沒找到FastDFS如何對部分資源加token驗證,部分開放。有知道的還請留言。
四、封裝FastDFS上傳工具類
import org.csource.common.NameValuePair; import org.csource.fastdfs.*; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * @Auther: lanhaifeng * @Date: 2019/4/25 0025 09:11 * @Description:檔案上傳工具類 */ public class FastDFSClient { private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class); static { try { String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();; ClientGlobal.init(filePath); } catch (Exception e) { logger.error("FastDFS Client Init Fail!",e); } } /** * 檔案上傳 * @param file 自定義檔案上傳類 * @return */ public static String[] upload(FastDFSFile file) { logger.info("File Name: " + file.getName() + "File Length:" + file.getContent().length); NameValuePair[] meta_list = new NameValuePair[1]; meta_list[0] = new NameValuePair("author", file.getAuthor()); long startTime = System.currentTimeMillis(); String[] uploadResults = null; StorageClient storageClient=null; try { storageClient = getTrackerClient(); //upload_file()三個引數:@param fileContent ①:檔案的內容,位元組陣列 ②:副檔名 ③檔案擴充套件資訊 陣列 uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list); } catch (IOException e) { logger.error("IO Exception when uploadind the file:" + file.getName(), e); } catch (Exception e) { logger.error("Non IO Exception when uploadind the file:" + file.getName(), e); } logger.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms"); if (uploadResults == null && storageClient!=null) { logger.error("upload file fail, error code:" + storageClient.getErrorCode()); } String groupName = uploadResults[0]; String remoteFileName = uploadResults[1]; logger.info("upload file successfully!!!" + "group_name:" + groupName + ", remoteFileName:" + " " + remoteFileName); return uploadResults; } /** * 查詢檔案資訊 * @param groupName * @param remoteFileName * @return */ public static FileInfo getFile(String groupName, String remoteFileName) { try { StorageClient storageClient = getTrackerClient(); return storageClient.get_file_info(groupName, remoteFileName); } catch (IOException e) { logger.error("IO Exception: Get File from Fast DFS failed", e); } catch (Exception e) { logger.error("Non IO Exception: Get File from Fast DFS failed", e); } return null; } /** * 下載檔案 * @param groupName 檔案路徑 * @param remoteFileName 輸出流 中包含要輸出到磁碟的路徑 * @return */ public static InputStream downFile(String groupName, String remoteFileName) { try { StorageClient storageClient = getTrackerClient(); byte[] fileByte = storageClient.download_file(groupName, remoteFileName); InputStream ins = new ByteArrayInputStream(fileByte); return ins; } catch (IOException e) { logger.error("IO Exception: Get File from Fast DFS failed", e); } catch (Exception e) { logger.error("Non IO Exception: Get File from Fast DFS failed", e); } return null; } /** * 刪除檔案 * ==0表示成功 * @param groupName 組名 如:group1 * @param remoteFileName 不帶組名的路徑名稱 如:M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg * @throws Exception */ public static int deleteFile(String groupName, String remoteFileName) throws Exception { StorageClient storageClient = getTrackerClient(); return storageClient.delete_file(groupName, remoteFileName); } /** * 獲取storage * @param groupName 組名 * @return * @throws IOException */ public static StorageServer[] getStoreStorages(String groupName) throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerClient.getStoreStorages(trackerServer, groupName); } /** * * @param groupName * @param remoteFileName * @return * @throws IOException */ public static ServerInfo[] getFetchStorages(String groupName,String remoteFileName) throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName); } /** * 獲取reacker地址 * @return * @throws IOException */ public static String getTrackerUrl() throws IOException { return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/"; } /** * 獲取tracker連線 * @return * @throws IOException */ private static StorageClient getTrackerClient() throws IOException { TrackerServer trackerServer = getTrackerServer(); StorageClient storageClient = new StorageClient(trackerServer, null); return storageClient; } /** * 獲取tracker服務 * @return * @throws IOException */ private static TrackerServer getTrackerServer() throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerServer; } }
FastDFSFile
/** * @Auther: lanhaifeng * @Date: 2019/4/25 0025 09:15 * @Description:檔案資訊類 */ public class FastDFSFile { private String name;//檔名 private byte[] content; //檔案的內容,位元組陣列 private String ext; //副檔名,不包含(.) private String md5; //加密 private String author; public FastDFSFile() { } public FastDFSFile(String name, byte[] content, String ext) { this.name = name; this.content = content; this.ext = ext; } public String getName() { return name; } public void setName(String name) { this.name = name; } public byte[] getContent() { return content; } public void setContent(byte[] content) { this.content = content; } public String getExt() { return ext; } public void setExt(String ext) { this.ext = ext; } public String getMd5() { return md5; } public void setMd5(String md5) { this.md5 = md5; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
五、controller呼叫
@Controller public class UploadController { private static Logger logger = LoggerFactory.getLogger(UploadController.class); @GetMapping("/") public String index() { return "upload"; }
@PostMapping("/upload") public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { if (file.isEmpty()) { redirectAttributes.addFlashAttribute("message", "Please select a file to upload"); return "redirect:uploadStatus"; } try { // Get the file and save it somewhere String path=saveFile(file); redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + file.getOriginalFilename() + "'"); redirectAttributes.addFlashAttribute("path", "file path url '" + path + "'"); } catch (Exception e) { logger.error("upload file failed",e); } return "redirect:/uploadStatus"; } @GetMapping("/uploadStatus") public String uploadStatus() { return "uploadStatus"; } /** * @param multipartFile * @return * @throws IOException 這個方法後面可以自己封裝一個util,這裡只是測試 */ public String saveFile(MultipartFile multipartFile) throws IOException { String[] fileAbsolutePath={}; String fileName=multipartFile.getOriginalFilename(); String ext = fileName.substring(fileName.lastIndexOf(".") + 1); byte[] file_buff = null; InputStream inputStream=multipartFile.getInputStream(); if(inputStream!=null){ int len1 = inputStream.available(); file_buff = new byte[len1]; inputStream.read(file_buff); } inputStream.close(); FastDFSFile file = new FastDFSFile(fileName, file_buff, ext); try { fileAbsolutePath = FastDFSClient.upload(file); //upload to fastdfs } catch (Exception e) { logger.error("upload file Exception!",e); } if (fileAbsolutePath==null) { logger.error("upload file failed,please upload again!"); } String path=FastDFSClient.getTrackerUrl()+fileAbsolutePath[0]+ "/"+fileAbsolutePath[1]; return path; } }
參考:https://www.cnblogs.com/Leo_wl/p/7705158.html
https://blog.csdn.net/qq_26641781/article/details/80913482
一、首先,maven工程新增依賴
<!--fastdfs--> <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27-RELEASE</version> </dependency>
如果報錯請參考maven倉庫有jar包還是報錯怎麼辦?
二、resources目錄下新增fdfs_client.conf檔案
前面使用nginx支援http方式訪問檔案,但所有人都能直接訪問這個檔案伺服器了,所以做一下許可權控制。
從來都是我能借用別人的圖片,而別人借用我的圖片不好意思不行!
FastDFS的許可權控制是在服務端開啟token驗證,客戶端根據檔名、當前unix時間戳、祕鑰獲取token,在地址中帶上token引數即可通過http方式訪問檔案。
#################### FastDFS-Client Start ####################
#預設值為30s
connect_timeout = 10
#預設值為30s
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
# token 防盜鏈功能
http.anti_steal_token = true
http.secret_key = FastDFS1234567890
tracker_server = 192.168.1.118:22122
#tracker_server = 192.168.0.119:22122
## Tracker Server, if more than one, separate with ","
# fastdfs.tracker_servers=10.0.11.201:22122,10.0.11.202:22122,10.0.11.203:22122
#fastdfs.tracker_servers=${tracker_server_addr}:22122
#################### FastDFS-Client End ####################
對應檔案伺服器上/etc/fdfs下的http.conf
修改http.conf # vim /etc/fdfs/http.conf 設定為true表示開啟token驗證 http.anti_steal.check_token=true 設定token失效的時間單位為秒(s) http.anti_steal.token_ttl=1800 金鑰,跟客戶端配置檔案的fastdfs.http_secret_key保持一致 http.anti_steal.secret_key=FASTDFS1234567890 如果token檢查失敗,返回的頁面 http.anti_steal.token_check_fail=/ljzsg/fastdfs/page/403.html
記得重啟服務
三、客戶端生成token
訪問檔案需要帶上生成的token以及unix時間戳,所以返回的token是token和時間戳的拼接。
之後,將token拼接在地址後即可訪問:file.ljzsg.com/group1/M00/00/00/wKgzgFnkaXqAIfXyAAEoRmXZPp878.jpeg?token=078d370098b03e9020b82c829c205e1f&ts=1508141521
/** * 獲取訪問伺服器的token,拼接到地址後面 * * @param filepath 檔案路徑 group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg * @param httpSecretKey 金鑰 * @return 返回token,如: token=078d370098b03e9020b82c829c205e1f&ts=1508141521 */ public static String getToken(String filepath, String httpSecretKey){ // unix seconds int ts = (int) Instant.now().getEpochSecond(); // token String token = "null"; try { token = ProtoCommon.getToken(getFilename(filepath), ts, httpSecretKey); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (MyException e) { e.printStackTrace(); } StringBuilder sb = new StringBuilder(); sb.append("token=").append(token); sb.append("&ts=").append(ts); return sb.toString(); }
注意事項
如果生成的token驗證無法通過,請進行如下兩項檢查:
A. 確認呼叫token生成函式(ProtoCommon.getToken),傳遞的檔案ID中沒有包含group name。傳遞的檔案ID格式形如:M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
B. 確認伺服器時間基本是一致的,注意伺服器時間不能相差太多,不要相差到分鐘級別。
對比下發現,如果系統檔案隱私性較高,可以直接通過fastdfs-client提供的API去訪問即可,不用再配置Nginx走http訪問。配置Nginx的主要目的是為了快速訪問伺服器的檔案(如圖片),如果還要加許可權驗證,則需要客戶端生成token,其實已經沒有多大意義。關鍵是,這裡我沒找到FastDFS如何對部分資源加token驗證,部分開放。有知道的還請留言。
四、封裝FastDFS上傳工具類
import org.csource.common.NameValuePair; import org.csource.fastdfs.*; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * @Auther: lanhaifeng * @Date: 2019/4/25 0025 09:11 * @Description:檔案上傳工具類 */ public class FastDFSClient { private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class); static { try { String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();; ClientGlobal.init(filePath); } catch (Exception e) { logger.error("FastDFS Client Init Fail!",e); } } /** * 檔案上傳 * @param file 自定義檔案上傳類 * @return */ public static String[] upload(FastDFSFile file) { logger.info("File Name: " + file.getName() + "File Length:" + file.getContent().length); NameValuePair[] meta_list = new NameValuePair[1]; meta_list[0] = new NameValuePair("author", file.getAuthor()); long startTime = System.currentTimeMillis(); String[] uploadResults = null; StorageClient storageClient=null; try { storageClient = getTrackerClient(); //upload_file()三個引數:@param fileContent ①:檔案的內容,位元組陣列 ②:副檔名 ③檔案擴充套件資訊 陣列 uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list); } catch (IOException e) { logger.error("IO Exception when uploadind the file:" + file.getName(), e); } catch (Exception e) { logger.error("Non IO Exception when uploadind the file:" + file.getName(), e); } logger.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms"); if (uploadResults == null && storageClient!=null) { logger.error("upload file fail, error code:" + storageClient.getErrorCode()); } String groupName = uploadResults[0]; String remoteFileName = uploadResults[1]; logger.info("upload file successfully!!!" + "group_name:" + groupName + ", remoteFileName:" + " " + remoteFileName); return uploadResults; } /** * 查詢檔案資訊 * @param groupName * @param remoteFileName * @return */ public static FileInfo getFile(String groupName, String remoteFileName) { try { StorageClient storageClient = getTrackerClient(); return storageClient.get_file_info(groupName, remoteFileName); } catch (IOException e) { logger.error("IO Exception: Get File from Fast DFS failed", e); } catch (Exception e) { logger.error("Non IO Exception: Get File from Fast DFS failed", e); } return null; } /** * 下載檔案 * @param groupName 檔案路徑 * @param remoteFileName 輸出流 中包含要輸出到磁碟的路徑 * @return */ public static InputStream downFile(String groupName, String remoteFileName) { try { StorageClient storageClient = getTrackerClient(); byte[] fileByte = storageClient.download_file(groupName, remoteFileName); InputStream ins = new ByteArrayInputStream(fileByte); return ins; } catch (IOException e) { logger.error("IO Exception: Get File from Fast DFS failed", e); } catch (Exception e) { logger.error("Non IO Exception: Get File from Fast DFS failed", e); } return null; } /** * 刪除檔案 * ==0表示成功 * @param groupName 組名 如:group1 * @param remoteFileName 不帶組名的路徑名稱 如:M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg * @throws Exception */ public static int deleteFile(String groupName, String remoteFileName) throws Exception { StorageClient storageClient = getTrackerClient(); return storageClient.delete_file(groupName, remoteFileName); } /** * 獲取storage * @param groupName 組名 * @return * @throws IOException */ public static StorageServer[] getStoreStorages(String groupName) throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerClient.getStoreStorages(trackerServer, groupName); } /** * * @param groupName * @param remoteFileName * @return * @throws IOException */ public static ServerInfo[] getFetchStorages(String groupName,String remoteFileName) throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName); } /** * 獲取reacker地址 * @return * @throws IOException */ public static String getTrackerUrl() throws IOException { return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/"; } /** * 獲取tracker連線 * @return * @throws IOException */ private static StorageClient getTrackerClient() throws IOException { TrackerServer trackerServer = getTrackerServer(); StorageClient storageClient = new StorageClient(trackerServer, null); return storageClient; } /** * 獲取tracker服務 * @return * @throws IOException */ private static TrackerServer getTrackerServer() throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerServer; } }
FastDFSFile
/** * @Auther: lanhaifeng * @Date: 2019/4/25 0025 09:15 * @Description:檔案資訊類 */ public class FastDFSFile { private String name;//檔名 private byte[] content; //檔案的內容,位元組陣列 private String ext; //副檔名,不包含(.) private String md5; //加密 private String author; public FastDFSFile() { } public FastDFSFile(String name, byte[] content, String ext) { this.name = name; this.content = content; this.ext = ext; } public String getName() { return name; } public void setName(String name) { this.name = name; } public byte[] getContent() { return content; } public void setContent(byte[] content) { this.content = content; } public String getExt() { return ext; } public void setExt(String ext) { this.ext = ext; } public String getMd5() { return md5; } public void setMd5(String md5) { this.md5 = md5; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
五、controller呼叫
@Controller public class UploadController { private static Logger logger = LoggerFactory.getLogger(UploadController.class); @GetMapping("/") public String index() { return "upload"; }
@PostMapping("/upload") public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { if (file.isEmpty()) { redirectAttributes.addFlashAttribute("message", "Please select a file to upload"); return "redirect:uploadStatus"; } try { // Get the file and save it somewhere String path=saveFile(file); redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + file.getOriginalFilename() + "'"); redirectAttributes.addFlashAttribute("path", "file path url '" + path + "'"); } catch (Exception e) { logger.error("upload file failed",e); } return "redirect:/uploadStatus"; } @GetMapping("/uploadStatus") public String uploadStatus() { return "uploadStatus"; } /** * @param multipartFile * @return * @throws IOException 這個方法後面可以自己封裝一個util,這裡只是測試 */ public String saveFile(MultipartFile multipartFile) throws IOException { String[] fileAbsolutePath={}; String fileName=multipartFile.getOriginalFilename(); String ext = fileName.substring(fileName.lastIndexOf(".") + 1); byte[] file_buff = null; InputStream inputStream=multipartFile.getInputStream(); if(inputStream!=null){ int len1 = inputStream.available(); file_buff = new byte[len1]; inputStream.read(file_buff); } inputStream.close(); FastDFSFile file = new FastDFSFile(fileName, file_buff, ext); try { fileAbsolutePath = FastDFSClient.upload(file); //upload to fastdfs } catch (Exception e) { logger.error("upload file Exception!",e); } if (fileAbsolutePath==null) { logger.error("upload file failed,please upload again!"); } String path=FastDFSClient.getTrackerUrl()+fileAbsolutePath[0]+ "/"+fileAbsolutePath[1]; return path; } }
參考:https://www.cnblogs.com/Leo_wl/p/7705158.html
https://blog.csdn.net/qq_26641781/article/details/80913482