因為項目需要搭建檔案伺服器,研究後,最後選型FastDFS分布式檔案存儲系統。
由于docker鏡像安裝的友善化,是以決定采用docker安裝。
拉取鏡像
docker pull morunchang/fastdfs
檢視鏡像
[[email protected] ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/morunchang/fastdfs latest a729ac95698a 18 months ago 460.1 MB
運作tracker
docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
運作storage
docker run -d --name storage --net=host -e TRACKER_IP=<your tracker server address>:22122 -e GROUP_NAME=<group name> morunchang/fastdfs sh storage.sh
/*
1.使用的網絡模式是–net=host, <your tracker server address> 替換為你機器的Ip即可
2.<group name> 是組名,即storage的組,下面預設用group1
3.如果想要增加新的storage伺服器,再次運作該指令,注意更換 新組名
4. docker ps 檢視容器資訊
[[email protected] ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ccdf6bbeab48 morunchang/fastdfs "sh storage.sh" 5 seconds ago Up 4 seconds storage
a7253c93bce1 morunchang/fastdfs "sh tracker.sh" About a minute ago Up About a minute tracker
*/
修改nginx的配置,不攔截上傳内容
進入storage的容器内部,修改nginx.conf
//1.進入容器内部
docker exec -it storage /bin/bash
// storage 是 docker ps 中的NAMES
// exit 退出
[email protected]:/# cd data
[email protected]:/data# ls
fast_data fastdfs fastdfs-nginx-module libfastcommon nginx nginx-1.9.11.tar.gz
//2.修改nginx配置檔案
[email protected]:/# vi /data/nginx/conf/nginx.conf
//3. 添加修改内容
location /group1/M00 {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_cache http-cache;
proxy_cache_valid 200 304 12h;
proxy_cache_key $uri$is_args$args;
proxy_pass http://fdfs_group1;
expires 30d;
}
//4.退出
[email protected]:/data/nginx/conf# exit
exit
//5. 重新開機storage服務
[[email protected] ~]# docker restart storage
storage
到這裡docker已經安裝完成。
---------------------------------------華麗的分割線-----------------------------------------------
下面是與springMVC項目內建
上傳fastdfs-client-java至nexus私有庫上,
配置項目maven的pom檔案
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27</version>
</dependency>
resources下建立fast_client.conf檔案
并新增以下内容
connect_timeout = 60
#網絡逾時時間
network_timeout = 60
#字元集
charset = UTF-8
#跟蹤伺服器的端口
http.tracker_http_port = 8080
http.anti_steal_token = no
http.secret_key = 123456
#跟蹤伺服器位址 。跟蹤伺服器主要是起到負載均衡的作用
tracker_server = ip:22122
新增工具類FastDFSUtil.java和FileUtil.java
package com.ls.common.web.utils.fastdfs;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class FastDFSUtil {
private final static
Logger logger = LoggerFactory.getLogger(FastDFSUtil.class);
public static Map<String, Object> uploadLocalFile(String filePath) {
Map<String, Object> retMap = new HashMap<String, Object>();
String command = "fdfs_upload_file /etc/fdfs/client.conf " + filePath;
String fileId = "";
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
Process process = Runtime.getRuntime().exec(command);
inputStreamReader = new InputStreamReader(process.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
String line;
if ((line = bufferedReader.readLine()) != null) {
fileId = line;
}
if (fileId.contains("M00")) {
retMap.put("code", "0000");
retMap.put("group", fileId.substring(0, 6));
retMap.put("msg", fileId.substring(7, fileId.length()));
} else {
retMap.put("code", "0001"); //上傳錯誤
retMap.put("msg", fileId); //傳回資訊
}
} catch (Exception e) {
logger.error("IOException:" + e.getMessage());
retMap.put("code", "0002");
retMap.put("msg", e.getMessage());
}finally {
if (inputStreamReader!=null){
try {
inputStreamReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return retMap;
}
public static Map<String, Object> upload(String filePath) {
Map<String, Object> retMap = new HashMap<String, Object>();
File file = new File(filePath);
TrackerServer trackerServer = null;
StorageServer storageServer = null;
if (file.isFile()) {
try {
String tempFileName = file.getName();
byte[] fileBuff = FileUtil.getBytesFromFile(file);
String fileId = "";
//截取字尾
String fileExtName = tempFileName.substring(tempFileName.lastIndexOf(".") + 1);
ConfigAndConnectionServer configAndConnectionServer = new ConfigAndConnectionServer().invoke(1);
StorageClient1 storageClient1 = configAndConnectionServer.getStorageClient1();
storageServer = configAndConnectionServer.getStorageServer();
trackerServer = configAndConnectionServer.getTrackerServer();
NameValuePair[] metaList = new NameValuePair[3];
//原始檔案名稱
metaList[0] = new NameValuePair("fileName", tempFileName);
//檔案字尾
metaList[1] = new NameValuePair("fileExtName", fileExtName);
//檔案大小
metaList[2] = new NameValuePair("fileLength", String.valueOf(file.length()));
//開始上傳檔案
fileId = storageClient1.upload_file1(fileBuff, fileExtName, metaList);
retMap = handleResult(retMap, fileId);
} catch (Exception e) {
e.printStackTrace();
retMap.put("code", "0002");
retMap.put("msg", e.getMessage());
} finally {
colse(storageServer, trackerServer);
}
} else {
retMap.put("code", "0001");
retMap.put("msg", "error:本地檔案不存在!");
}
return retMap;
}
public static Map<String, Object> upload(MultipartFile file) {
Map<String, Object> retMap = new HashMap<String, Object>();
TrackerServer trackerServer = null;
StorageServer storageServer = null;
try {
if (file.isEmpty()) {
retMap.put("code", "0001");
retMap.put("msg", "error:檔案為空!");
} else {
ConfigAndConnectionServer configAndConnectionServer = new ConfigAndConnectionServer().invoke(1);
StorageClient1 storageClient1 = configAndConnectionServer.getStorageClient1();
storageServer = configAndConnectionServer.getStorageServer();
trackerServer = configAndConnectionServer.getTrackerServer();
String tempFileName = file.getOriginalFilename();
//設定元資訊
NameValuePair[] metaList = new NameValuePair[3];
//原始檔案名稱
metaList[0] = new NameValuePair("fileName", tempFileName);
//檔案字尾
byte[] fileBuff = file.getBytes();
String fileId = "";
//截取字尾
String fileExtName = tempFileName.substring(tempFileName.lastIndexOf(".") + 1);
metaList[1] = new NameValuePair("fileExtName", fileExtName);
//檔案大小
metaList[2] = new NameValuePair("fileLength", String.valueOf(file.getSize()));
fileId = storageClient1.upload_file1(fileBuff, fileExtName, metaList);
retMap = handleResult(retMap, fileId);
}
} catch (Exception e) {
e.printStackTrace();
retMap.put("code", "0002");
retMap.put("msg", "error:檔案上傳失敗!");
}finally {
colse(storageServer, trackerServer);
}
return retMap;
}
public static void download(HttpServletResponse response, String group, String filepath, String downname) {
StorageServer storageServer = null;
TrackerServer trackerServer = null;
try {
ConfigAndConnectionServer configAndConnectionServer = new ConfigAndConnectionServer().invoke(0);
StorageClient storageClient = configAndConnectionServer.getStorageClient();
storageServer = configAndConnectionServer.getStorageServer();
trackerServer = configAndConnectionServer.getTrackerServer();
byte[] b = storageClient.download_file(group, filepath);
if (b == null) {
logger.error("Error1 : file not Found!");
response.getWriter().write("Error1 : file not Found!");
} else {
logger.info("下載下傳檔案..");
downname = new String(downname.getBytes("utf-8"), "ISO8859-1");
response.setHeader("Content-Disposition", "attachment;fileName=" + downname);
OutputStream out = response.getOutputStream();
out.write(b);
out.close();
}
} catch (Exception e) {
e.printStackTrace();
try {
response.getWriter().write("Error1 : file not Found!");
} catch (IOException e1) {
e1.printStackTrace();
}
}finally {
colse(storageServer, trackerServer);
}
}
public static Map<String, Object> delete(String group, String filepath) {
Map<String, Object> retMap = new HashMap<String, Object>();
StorageServer storageServer = null;
TrackerServer trackerServer = null;
try {
ConfigAndConnectionServer configAndConnectionServer = new ConfigAndConnectionServer().invoke(0);
StorageClient storageClient = configAndConnectionServer.getStorageClient();
storageServer = configAndConnectionServer.getStorageServer();
trackerServer = configAndConnectionServer.getTrackerServer();
int i = storageClient.delete_file(group, filepath);
if (i == 0) {
retMap.put("code", "0000");
retMap.put("msg", "删除成功!");
} else {
retMap.put("code", "0001");
retMap.put("msg", "檔案不存在!");
}
} catch (Exception e) {
e.printStackTrace();
retMap.put("code", "0002");
retMap.put("msg", "删除失敗!");
} finally {
colse(storageServer, trackerServer);
}
return retMap;
}
private static void colse(StorageServer storageServer, TrackerServer trackerServer) {
if (storageServer != null && trackerServer != null) {
try {
storageServer.close();
trackerServer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static Map<String, Object> handleResult(Map<String, Object> retMap, String fileId) {
if (!fileId.equals("") && fileId != null) {
retMap.put("code", "0000");
retMap.put("group", fileId.substring(0, 6));
retMap.put("msg", fileId.substring(7, fileId.length()));
} else {
retMap.put("code", "0003");
retMap.put("msg", "error:上傳失敗!");
}
return retMap;
}
private static class ConfigAndConnectionServer {
private TrackerServer trackerServer;
private StorageServer storageServer;
private StorageClient storageClient;
private StorageClient1 storageClient1;
public TrackerServer getTrackerServer() {
return trackerServer;
}
public StorageServer getStorageServer() {
return storageServer;
}
public StorageClient getStorageClient() {
return storageClient;
}
public StorageClient1 getStorageClient1() {
return storageClient1;
}
public ConfigAndConnectionServer invoke(int flag) throws IOException, MyException {
ClassPathResource cpr = new ClassPathResource("fdfs_client.conf");
ClientGlobal.init(cpr.getClassLoader().getResource("fdfs_client.conf").getPath());
TrackerClient tracker = new TrackerClient();
trackerServer = tracker.getConnection();
storageServer = null;
if (flag == 0) {
storageClient = new StorageClient(trackerServer, storageServer);
} else {
storageClient1 = new StorageClient1(trackerServer, storageServer);
}
return this;
}
}
}
package com.ls.common.web.utils.fastdfs;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import java.io.*;
import java.util.Date;
/**
* FastDFS工具類
* @author yusheng
* @since 2018-4-28
* @version 1.0
*/
public class FileUtil {
public static void saveImage(CommonsMultipartFile[] files, int i) {
if(!files[i].isEmpty()){
int pre = (int) System.currentTimeMillis();
try {
//拿到輸出流,同時重命名上傳的檔案
FileOutputStream os = new FileOutputStream("f:/img"+"/" + new Date().getTime()+".jpg");
//拿到上傳檔案的輸入流
ByteArrayInputStream in = (ByteArrayInputStream) files[i].getInputStream();
//以寫位元組的方式寫檔案
int b = 0;
while((b=in.read()) != -1){
os.write(b);
}
os.flush();
os.close();
in.close();
int finaltime = (int) System.currentTimeMillis();
System.out.println(finaltime - pre);
} catch (Exception e) {
e.printStackTrace();
System.out.println("上傳出錯");
}
}
}
/**
* 擷取檔案流
* @param f
* @return
*/
public static byte[] getBytesFromFile(File f){
if (f == null) {
return null;
}
try {
FileInputStream stream = new FileInputStream(f);
ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
for (int n;(n = stream.read(b)) != -1;) {
out.write(b, 0, n);
}
stream.close();
out.close();
return out.toByteArray();
} catch (IOException e) {
}
return null;
}
}
編寫測試類
@RequestMapping("/upload")
public String upload(@RequestParam("file") CommonsMultipartFile[] files,
HttpServletRequest request){
for(int i = 0;i<files.length;i++){
Map<String, Object> retMap = FastDFSUtil.upload(files[i]);
String code = (String) retMap.get("code");
String group = (String) retMap.get("group");
String msg = (String) retMap.get("msg");
if ("0000".equals(code)){
logger.info("檔案上傳成功");
//TODO:将上傳檔案的路徑儲存到mysql資料庫
}else {
logger.info("檔案上傳失敗");
}
}
return "/success";
}
傳回msg為檔案存儲路徑,測試後拼接ip端口,浏覽器通路,可以通路則內建成功。