docker方式安装fastDFS单机版,带java工具,测试用例

本文详细介绍使用FastDFS进行文件上传、下载、删除的操作方法,包括通过Linux客户端上传、Java客户端上传、MultipartFile远程上传等不同场景,并提供完整的FastDFSUtil工具类实现。

参考docker构建文档,记得开放阿里云8088端口,作为访问入口

安装过程参考:https://blog.youkuaiyun.com/alinyua/article/details/82464496


maven坐标

<!--fastdfs操作工具包-->
<dependency>
    <groupId>org.csource</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27-SNAPSHOT</version>
</dependency>

FastDFSUtil.java

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;

/**
 * @author     :yyj.
 * @ Date       :Created in 15:08 2019/9/18
 * @ Description:fastDFSUtil工具类
 * @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>(3);
        /**
         * 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>(3);
        File file = new File(filePath);
        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        if (file.isFile()) {
            try {
                String tempFileName = file.getName();
                byte[] fileBuff = FastDFSFileUtil.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>(3);
        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);
//                System.out.println("fileIIIIIID--?>>>>:"+fileId);
                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>(3);
        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;
        }
    }
}

放入controller中测试上传

/**
     *    临时测试@RequestMapping("/upload")
     * @param files
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping( "/upload.do")
    public String upload(@RequestParam("file") CommonsMultipartFile[] files,
                         HttpServletRequest request){
        System.out.println("》》》》》》》》》》》》》》》》》》》》》》》》》》》》》jinru方法");

        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");
            System.out.println(retMap);
            if ("0000".equals(code)){
                System.out.println("成功");
                logger.info("文件上传成功");
                //TODO:将上传文件的路径保存到mysql数据库
            }else {
                System.out.println("失败");
                logger.info("文件上传失败");
            }


        }
        return "/success";
    }

postman测试用例

 测试结果

访问资源:(xxxx代表服务器ip)

http://xxxx:8088/group1/M00/00/00/rBMAA14SkLaAXI9pAAC4RY_O1qE628.png 

<think>好的,我现在需要解决用户在离线环境下通过Docker安装FastDFS的问题。首先,我得理解用户的需求:他们想要在无法连接互联网的环境安装FastDFS,并且使用Docker来部署。这可能涉及到离线获取Docker镜像、配置FastDFS以及确保容器在离线环境下正常运行。 首先,我需要确认FastDFS是否有官方的Docker镜像。如果有,用户可能需要提前在有网络的环境中下载镜像并导出,然后在离线环境中导入。如果没有官方镜像,可能需要自己构建Dockerfile,这时候也需要处理依赖包的离线安装。 接下来,用户提到的离线环境意味着所有依赖都需要预先下载好。比如,Docker安装包、FastDFS安装包、libfastcommon等依赖库。这些都需要提前在有网络的情况下下载,并传输到目标机器上。 然后,Docker服务的安装部分,用户可能已经安装Docker,但如果没有,需要指导如何离线安装Docker。这通常涉及下载Docker的rpm或deb包,然后通过包管理器安装。不过用户提供的引用[1]中提到的是将Docker注册为系统服务,这可能是在安装Docker之后进行的步骤,所以可能需要先完成Docker的离线安装。 关于FastDFS的配置,用户需要知道如何修改配置文件,比如tracker.conf和storage.conf,设置正确的IP地址和存储路径。同时,可能需要配置防火墙规则,确保端口开放,这在离线环境中尤其重要,因为无法自动获取更新。 另外,用户可能需要测试FastDFS是否安装成功,这包括启动tracker和storage服务,并使用fdfs_test工具上传文件测试。在离线环境中,这些测试步骤可能需要手动完成,无法依赖网络资源。 可能遇到的问题包括:Docker镜像的兼容性问题、依赖库版本不匹配、配置文件路径错误、权限问题等。需要提供常见问题解决方法,比如检查日志、确认配置参数、确保存储目录权限正确。 最后,生成相关问题需要考虑用户可能进一步的需求,比如如何配置多节点、如何进行性能优化、如何处理存储扩展等。这些相关问题需要与FastDFSDocker环境中的使用相关,并且适合离线场景。 总结步骤应该是:准备离线环境所需的Docker镜像和安装包,安装Docker服务,加载FastDFS镜像,配置和启动容器,进行测试验证,并提供问题排查方法。需要确保所有命令和步骤正确,适合离线操作,同时引用提供的参考资料中的Docker服务注册部分。</think>### 离线环境下通过Docker安装FastDFS的步骤 #### 1. 准备离线环境所需的资源 - **下载Docker离线安装包** 在有网络的环境中,从官网下载对应系统的Docker安装包(如`.rpm`或`.deb`文件),并传输到离线服务器。例如: ```bash wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-20.10.9-3.el7.x86_64.rpm ``` - **获取FastDFS Docker镜像** 使用有网络的机器拉取FastDFS镜像并导出为文件: ```bash docker pull season/fastdfs # 假设该镜像可用 docker save -o fastdfs.tar season/fastdfs ``` 将`fastdfs.tar`传输到离线服务器后加载: ```bash docker load -i fastdfs.tar ``` #### 2. 离线安装Docker服务 - **安装Docker** 使用包管理器安装离线包(以CentOS为例): ```bash yum install -y docker-ce-20.10.9-3.el7.x86_64.rpm ``` - **注册Docker为系统服务** 编辑服务配置文件(参考引用[1]): ```bash vim /etc/systemd/system/docker.service ``` 添加以下内容: ```ini [Unit] Description=Docker Application Container Engine After=network.target [Service] ExecStart=/usr/bin/dockerd Restart=always [Install] WantedBy=multi-user.target ``` 启动服务: ```bash systemctl daemon-reload systemctl start docker systemctl enable docker ``` #### 3. 启动FastDFS容器 - **启动Tracker服务** ```bash docker run -d --name tracker \ -v /data/fastdfs/tracker:/var/fdfs \ -p 22122:22122 \ season/fastdfs tracker ``` - **启动Storage服务** ```bash docker run -d --name storage \ -v /data/fastdfs/storage:/var/fdfs \ -p 23000:23000 \ -e TRACKER_SERVER=<离线服务器IP>:22122 \ season/fastdfs storage ``` 替换`<离线服务器IP>`为实际IP。 #### 4. 验证安装 - **进入容器测试上传** ```bash docker exec -it storage bash echo "Hello FastDFS" > test.txt fdfs_test /etc/fdfs/client.conf upload test.txt ``` 若返回文件ID(如`group1/M00/00/00/xxx.txt`),则表明成功[^2]。 #### 5. 常见问题处理 - **镜像兼容性问题**:确保镜像与宿主机内核版本匹配。 - **存储目录权限**:若上传失败,检查`/data/fastdfs`目录权限是否为`755`。 - **防火墙配置**:开放端口`22122`(Tracker)、`23000`(Storage)和`8888`(HTTP访问)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值