且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Docker 安装 fastdfs,后台实现文件上传

更新时间:2022-04-04 12:43:18

首先安装Docker ,在前篇播客中介绍怎样安装Docker ,可以去看一下,我安装的Docker 是基于Ubuntu安装的,不喜欢的小伙伴可以使用Centos进行安装,下面是我的环境 。
Docker 安装 fastdfs,后台实现文件上传
首先在usr目录下面创建一系列文件,文件顺序在上图中可以看到,当然也可以自己创建。进入该文件,进行创建docker-compose.yml文件该文件是在第一层fastdfs的目录下
Docker 安装 fastdfs,后台实现文件上传
下面开始查看docker-compose.yml 文件
Docker 安装 fastdfs,后台实现文件上传

第一个fastdfs,表示当前容器依赖那个容器,build 表示构建数据卷,Dockerfile 文件,restart 表示服务重启之后,该服务也会重启,container_name 表示,当前容器的名称,volumes: 表示 将数据卷 进行映射,将fastdfs/storage 文件 映射到 自己定义的文件中。下面进入fastdfs 文件,进行查看Dockerfile文件

Docker 安装 fastdfs,后台实现文件上传

需要将这些文件,拷贝到当前目录下,码云地址:https://gitee.com/sgqing/fastdfsPeiZhiWenJian.git

下面开始配置这写文件,其中上图 中的 文件 1 是不存在的, 在运行之后生成的应该是,修改当前的配置文件主要是修改里面的服务的ip地址,修改成你当前虚拟机的地址,并且把url进行修改成指定的文件的地址

client.conf 文件,进行修改下面两处,修改完成之后,保存退出

Docker 安装 fastdfs,后台实现文件上传

config文件,如果使用我提供的话,直接使用接即可,如果不是需要将local 去除掉

Docker 安装 fastdfs,后台实现文件上传

entrypoint.sh 文件,首先 使用 chmod -x entrypoint.sh 将当前文件修改成 可执行文件,也不需要配置

Docker 安装 fastdfs,后台实现文件上传

该文件里面的配置是,在启动的时候,就会启动 fdfs 的 trackerd 和 storaged

mod_fastdfs.conf 文件,也是修改 ip地址 和 path地址

Docker 安装 fastdfs,后台实现文件上传

nginx.conf 文件,如果使用我提供的文件不需要进行修改,如果不是,需要修改下面的配置

Docker 安装 fastdfs,后台实现文件上传

storage.conf 文件,需要修改三个地方,好好找找,不太好找

Docker 安装 fastdfs,后台实现文件上传

tracker.conf 文件, 修改路径

Docker 安装 fastdfs,后台实现文件上传

上面是修改的全部的文件,下面开始配置Dockerfile 文件,下面是配置,版本***是用我提供的,不然会出现错误,下面配置就不进行说明,拷贝过去可直接用

MAINTAINER topsale@vip.qq.com

# 更新数据源
WORKDIR /etc/apt
RUN echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse' > sources.list
RUN echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse' >> sources.list
RUN echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse' >> sources.list
RUN echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse' >> sources.list
RUN apt-get update

# 安装依赖
RUN apt-get install make gcc libpcre3-dev zlib1g-dev --assume-yes

# 复制工具包
ADD fastdfs-5.11.tar.gz /usr/local/src
ADD fastdfs-nginx-module_v1.16.tar.gz /usr/local/src
ADD libfastcommon.tar.gz /usr/local/src
ADD nginx-1.13.6.tar.gz /usr/local/src

# 安装 libfastcommon
WORKDIR /usr/local/src/libfastcommon
RUN ./make.sh && ./make.sh install

# 安装 FastDFS
WORKDIR /usr/local/src/fastdfs-5.11
RUN ./make.sh && ./make.sh install

# 配置 FastDFS 跟踪器
ADD tracker.conf /etc/fdfs
RUN mkdir -p /fastdfs/tracker

# 配置 FastDFS 存储
ADD storage.conf /etc/fdfs
RUN mkdir -p /fastdfs/storage

# 配置 FastDFS 客户端
ADD client.conf /etc/fdfs

# 配置 fastdfs-nginx-module
ADD config /usr/local/src/fastdfs-nginx-module/src

# FastDFS 与 Nginx 集成
WORKDIR /usr/local/src/nginx-1.13.6
RUN ./configure --add-module=/usr/local/src/fastdfs-nginx-module/src
RUN make && make install
ADD mod_fastdfs.conf /etc/fdfs

WORKDIR /usr/local/src/fastdfs-5.11/conf
RUN cp http.conf mime.types /etc/fdfs/

# 配置 Nginx
ADD nginx.conf /usr/local/nginx/conf

COPY entrypoint.sh /usr/local/bin/
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

WORKDIR /
EXPOSE 8888
CMD ["/bin/bash"]

完成上面配置之后,即可保存退出,返回到上一级目录,然后使用 docker-compose up -d 后台运行,执行成功,还有一点,咱们在配置文件中配置了nginx,端口是8888

Docker 安装 fastdfs,后台实现文件上传

安装完成之后,开始进入java 端的开发 ,我这里使用的是 idea ,spring boot starter 是 1.5版本

首先引入fastdfs的maven 的依赖

            <dependency>
                <groupId>org.csource</groupId>
                <artifactId>fastdfs-client-java</artifactId>
                <version>1.27-SNAPSHOT</version>
            </dependency>
            <!-- FastDFS End -->

当然,因为fastdfs在仓库中是没有的,需要将当前依赖手动的安装到本地的仓库中,然后重新加载,可能需要多试几次,跟编译器。电脑有关系,我试了很多次,一直加载不进来

首先使用git进行下载:使用下面的git地址,

下载到本地之后,进入下面的目录中,当然不用注意我的.idea 和.git 文件,我的是因为idea加载不进来,然后将当前文件用idea打开之后,使用mvn 的命令 进行安装,install之后,确实是可以了,也可以试一下

Docker 安装 fastdfs,后台实现文件上传

进行入之后,在当前目录打开 cmd 然后使用 mvn clean install 进行安装,当提示安装完成之后们就会在你指定的环境变量中的 MAVEN_HOME 的路径下的maven下的 conf下面的setting.xml 文件中配置的 仓库地址中生成指定的 文件,生成下面文件

Docker 安装 fastdfs,后台实现文件上传

此时再去idea 中进行加载该依赖。

Docker 安装 fastdfs,后台实现文件上传

完成上面的配置之后,下面开始完成代码上传,我用的前端框架是Metronic 框架,但是很多框架都是一样的,在文件上传的组件中都会设置上传文件的name 和action ,大致相同,你可以随便使用,是要上传文件的name 和 action 上传文件的参数的名称一致即可,下面的配置文件网上有很多,下面是我使用的,直接拷贝即可。

import org.springframework.context.annotation.Configuration;

@Configuration
public class FastDFSConfiguration {

    @Bean
    public StorageFactory storageFactory(){
        return new StorageFactory();
    }
}
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class FastDFSStorageService implements StorageService, InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(FastDFSStorageService.class);

    private TrackerClient trackerClient;

    @Value("${storage.fastdfs.tracker_server}")
    private String trackerServer;

    @Override
    public String upload(byte[] data, String extName) {
        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        StorageClient1 storageClient1 = null;
        try {
            NameValuePair[] meta_list = null; // new NameValuePair[0];

            trackerServer = trackerClient.getConnection();
            if (trackerServer == null) {
                logger.error("getConnection return null");
            }
            storageServer = trackerClient.getStoreStorage(trackerServer);
            storageClient1 = new StorageClient1(trackerServer, storageServer);
            String fileid = storageClient1.upload_file1(data, extName, meta_list);
            logger.debug("uploaded file <{}>", fileid);
            return fileid;
        } catch (Exception ex) {
            logger.error("Upload fail", ex);
            return null;
        } finally {
            if (storageServer != null) {
                try {
                    storageServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (trackerServer != null) {
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            storageClient1 = null;
        }
    }

    @Override
    public int delete(String fileId) {
//        System.out.println("deleting ....");
        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        StorageClient1 storageClient1 = null;
        int index = fileId.indexOf('/');
        String groupName = fileId.substring(0, index);
        try {
            trackerServer = trackerClient.getConnection();
            if (trackerServer == null) {
                logger.error("getConnection return null");
            }
            storageServer = trackerClient.getStoreStorage(trackerServer, groupName);
            storageClient1 = new StorageClient1(trackerServer, storageServer);
            int result = storageClient1.delete_file1(fileId);
            return result;
        } catch (Exception ex) {
            logger.error("Delete fail", ex);
            return 1;
        } finally {
            if (storageServer != null) {
                try {
                    storageServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (trackerServer != null) {
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            storageClient1 = null;
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        File confFile = File.createTempFile("fastdfs", ".conf");
        PrintWriter confWriter = new PrintWriter(new FileWriter(confFile));
        confWriter.println("tracker_server=" + trackerServer);
        confWriter.close();
        ClientGlobal.init(confFile.getAbsolutePath());
        confFile.delete();
        TrackerGroup trackerGroup = ClientGlobal.g_tracker_group;
        trackerClient = new TrackerClient(trackerGroup);

        logger.info("Init FastDFS with tracker_server : {}", trackerServer);
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;

import java.util.HashMap;
import java.util.Map;

public class StorageFactory implements FactoryBean<StorageService> {
    @Autowired
    private AutowireCapableBeanFactory acbf;

    /**
     * 存储服务的类型,目前仅支持fastdfs
     */
    @Value("${storage.type}")
    private String type;

    private Map<String, Class<? extends StorageService>> classMap;

    public StorageFactory() {
        classMap = new HashMap<>();
        classMap.put("fastdfs", FastDFSStorageService.class);
    }

    @Override
    public StorageService getObject() throws Exception {
        Class<? extends StorageService> clazz = classMap.get(type);
        if (clazz == null) {
            throw new RuntimeException("Unsupported storage type [" + type + "], valid are " + classMap.keySet());
        }

        StorageService bean = clazz.newInstance();
        acbf.autowireBean(bean);
        acbf.initializeBean(bean, bean.getClass().getSimpleName());
        return bean;
    }

    @Override
    public Class<?> getObjectType() {
        return StorageService.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
    /**
     * 上传文件
     *
     * @param data    文件的二进制内容
     * @param extName 扩展名
     * @return 上传成功后返回生成的文件id;失败,返回null
     */
    public String upload(byte[] data, String extName);

    /**
     * 删除文件
     *
     * @param fileId 被删除的文件id
     * @return 删除成功后返回0,失败后返回错误代码
     */
    public int delete(String fileId);
}
import com.ooqui.gaming.service.web.admin.gamingserverwebadmin.config.fastdfs.StorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import utils.MapperUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Controller
public class UploadController {
    @Value("${fastdfs.base.url}")
    private String FASTDFS_BASE_URL;

    @Autowired
    private StorageService storageService;

    @ResponseBody
    @RequestMapping("upload")
    public String upload(MultipartFile uploadFile, MultipartFile wangEditorH5File) {
        if (uploadFile != null) {
            String oName = uploadFile.getOriginalFilename();
            String extName = oName.substring(oName.indexOf(".") + 1);
            HashMap<String, Object> map = new HashMap<>();

            try {
                String uploadUrl = storageService.upload(uploadFile.getBytes(), extName);
                map.put("success", "上传成功");
                map.put("url", FASTDFS_BASE_URL + uploadUrl);
            } catch (IOException e) {
                map.put("error", 1);
                map.put("message", "上传失败");
            }

            return MapperUtils.mapToJson(map);
        } else if (wangEditorH5File != null) {
            String oName = wangEditorH5File.getOriginalFilename();
            String extName = oName.substring(oName.indexOf(".") + 1);

            Map<String, Object> map = Maps.newHashMap();

            try {
                String uploadUrl = storageService.upload(wangEditorH5File.getBytes(), extName);
                String url = FASTDFS_BASE_URL + uploadUrl;

                // 上传成功
                map.put("errno", 0);
                map.put("data", new String[]{url});
            } catch (IOException e) {
                // 上传失败
                map.put("errno", 1);
                map.put("message", "服务端错误");
            }

            return MapperUtils.mapToJson(map);
        }

        return "";
    }
}

上面是用到的java 文件,这些文件都是官网提供好的,我也是直接拷贝过来使用的,html的代码我就不展示了,你只要只一个可用的前端框架,在框架中会有action 和 name 属性的配置,我这边的action的路径是 /upload,上传文件的名称是 uploadFile

你只要将这两个参数进行传递即可完成文件上传,当然,在文件上传成功之后,会返回你上传文件的路径,路径是你上传服务器的地址加上fastdfs的文件地址,你可以拿着改地址直接保存到数据库,或者访问即可

有问题可以在下方留言。