docker安装fastDFS文件存储,并与springMVC集成

因为项目需要搭建文件服务器,研究后,最后选型FastDFS分布式文件存储系统。

由于docker镜像安装的方便化,所以决定采用docker安装。

 

拉取镜像

    docker pull morunchang/fastdfs

查看镜像

[root@iZh3cshm0xz7wjZ ~]# 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 查看容器信息 
[root@iZh3cshm0xz7wjZ ~]# 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 退出

root@iZh3cshm0xz7wjZ:/# cd data
root@iZh3cshm0xz7wjZ:/data# ls
fast_data  fastdfs  fastdfs-nginx-module  libfastcommon  nginx  nginx-1.9.11.tar.gz

//2.修改nginx配置文件
root@iZh3cshm0xz7wjZ:/# 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.退出
root@iZh3cshm0xz7wjZ:/data/nginx/conf# exit
exit

//5. 重启storage服务
[root@iZh3cshm0xz7wjZ ~]# 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;

/**
* FastDFS工具类
* @author yusheng
* @since 2018-4-28
* @version 1.0
*/
public class FastDFSUtil {

private final static


Logger logger = LoggerFactory.getLogger(FastDFSUtil.class);


/**
*上传服务器本地文件-通过Linux客户端,调用客户端命令上传
* @param filePath 文件绝对路径
* @return Map<String,Object> code-返回代码, group-文件组, msg-文件路径/错误信息
*/
public static Map<String, Object> uploadLocalFile(String filePath) {
Map<String, Object> retMap = new HashMap<String, Object>();
/**
* 1.上传文件的命令
*/
String command = "fdfs_upload_file /etc/fdfs/client.conf " + filePath;
/**
* 2.定义文件的返回信息
*/
String fileId = "";
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
/**
* 3.通过调用api, 执行linux命令上传文件
*/
Process process = Runtime.getRuntime().exec(command);
/**
* 4.读取上传后返回的信息
*/
inputStreamReader = new InputStreamReader(process.getInputStream());
bufferedReader = new BufferedReader(inputStreamReader);
String line;
if ((line = bufferedReader.readLine()) != null) {
fileId = line;
}
/**
* 5.如果fileId包含M00,说明文件已经上传成功。否则文件上传失败
*/
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;
}


/**
* Description: 直接通过fdfs java客户端上传到服务器-读取本地文件上传
*
* @param filePath 本地文件绝对路径
* @return Map<String,Object> code-返回代码, group-文件组, msg-文件路径/错误信息
*/
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();

/**
* 4.设置文件的相关属性。调用客户端的upload_file1的方法上传文件
*/
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 {
/**
* 5.关闭跟踪服务器的连接
*/
colse(storageServer, trackerServer);
}
} else {
retMap.put("code", "0001");
retMap.put("msg", "error:本地文件不存在!");
}
return retMap;
}


/**
* Description:远程选择上传文件-通过MultipartFile
*
* @param file 文件流
* @return Map<String,Object> code-返回代码, group-文件组, msg-文件路径/错误信息
*/
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()));
/**
* 4.调用客户端呢的upload_file1的方法开始上传文件
*/
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 {
/**
* 5.关闭跟踪服务器的连接
*/
colse(storageServer, trackerServer);
}
return retMap;
}


/**
* 下载文件
*
* @param response
* @param filepath 数据库存的文件路径
* @param downname 下载后的名称
* filepath M00/开头的文件路径
* group 文件所在的组 如:group0
* @throws IOException
*/
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();

/**
*4.调用客户端的下载download_file的方法
*/
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 {
/**
* 5.关闭跟踪服务器的连接
*/
colse(storageServer, trackerServer);
}
}

/**
* 删除文件
*
* @param group 文件分组, filepath 已M00/ 开头的文件路径
* @return Map<String,Object> code-返回代码, msg-错误信息
*/
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();
/**
* 4.调用客户端的delete_file方法删除文件
*/
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 {
/**
* 5.关闭跟踪服务器的连接
*/
colse(storageServer, trackerServer);
}

return retMap;

}

/**
* 关闭服务器
*
* @param storageServer
* @param trackerServer
*/
private static void colse(StorageServer storageServer, TrackerServer trackerServer) {
if (storageServer != null && trackerServer != null) {
try {
storageServer.close();
trackerServer.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

/**
* 处理上传到文件服务器之后,返回来的结果
*
* @param retMap
* @param fileId
* @return
*/
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;
}

/**
* FastDFS客户端配置
*/
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 {
/**
* 1.读取fastDFS客户端配置文件
*/
ClassPathResource cpr = new ClassPathResource("fdfs_client.conf");
/**
* 2.配置文件的初始化信息
*/
ClientGlobal.init(cpr.getClassLoader().getResource("fdfs_client.conf").getPath());
TrackerClient tracker = new TrackerClient();
/**
* 3.建立连接
*/
trackerServer = tracker.getConnection();
storageServer = null;
/**
* 如果flag=0时候,构造StorageClient对象否则构造StorageClient1
*/
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端口,浏览器访问,可以访问则集成成功。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斑马工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值