spring boot集成FastDFS

Posted zeussbook

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot集成FastDFS相关的知识,希望对你有一定的参考价值。

官方文档:https://github.com/happyfish100/fastdfs-client-java

一、首先,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 ####################

# 文件服务器地址
file_server_addr=file.ljzsg.com:80
# 最大连接数 并发量较大的话可加大该连接数
max_storage_connection=8

## fastdfs为前缀的是FastDFS的配置
fastdfs.connect_timeout_in_seconds=10
fastdfs.network_timeout_in_seconds=30

fastdfs.charset=UTF-8

# token 防盗链功能
fastdfs.http_anti_steal_token=true
# 密钥
fastdfs.http_secret_key=FASTDFS1234567890
# TrackerServer port fastdfs.http_tracker_http_port=80 ## 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.tracker_servers=file.ljzsg.com: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上传工具类

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);
        }
    }

    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();
            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;
    }

    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;
    }

    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;
    }

    public static void deleteFile(String groupName, String remoteFileName)
            throws Exception {
        StorageClient storageClient = getTrackerClient();
        int i = storageClient.delete_file(groupName, remoteFileName);
        logger.info("delete file successfully!!!" + i);
    }

    public static StorageServer[] getStoreStorages(String groupName)
            throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getStoreStorages(trackerServer, groupName);
    }

    public static ServerInfo[] getFetchStorages(String groupName,
                                                String remoteFileName) throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
    }

    public static String getTrackerUrl() throws IOException {
        return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/";
    }

    private static StorageClient getTrackerClient() throws IOException {
        TrackerServer trackerServer = getTrackerServer();
        StorageClient storageClient = new StorageClient(trackerServer, null);
        return  storageClient;
    }

    private static TrackerServer getTrackerServer() throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return  trackerServer;
    }
}

五、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
     */
    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

以上是关于spring boot集成FastDFS的主要内容,如果未能解决你的问题,请参考以下文章

spring boot(十八)集成FastDFS文件上传下载

Spring boot集成Go-FastDFS实现图片上传删除等功能

Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了!

spring boot 整合 redis

Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了

Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了!