zoukankan      html  css  js  c++  java
  • 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 ####################
    #默认值为30s
    connect_timeout = 10
    #默认值为30s
    network_timeout = 30
    charset = UTF-8
    http.tracker_http_port = 80
    # token 防盗链功能
    http.anti_steal_token = true
    http.secret_key = FastDFS1234567890
    tracker_server = 192.168.1.118:22122
    #tracker_server = 192.168.0.119:22122
    ## 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-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上传工具类

    import org.csource.common.NameValuePair;
    import org.csource.fastdfs.*;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.io.ClassPathResource;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * @Auther: lanhaifeng
     * @Date: 2019/4/25 0025 09:11
     * @Description:文件上传工具类
     */
    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);
            }
        }
    
    
        /**
         * 文件上传
         * @param file 自定义文件上传类
         * @return
         */
        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();
                //upload_file()三个参数:@param fileContent ①:文件的内容,字节数组 ②:文件扩展名 ③文件扩展信息 数组
                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;
        }
    
        /**
         * 查询文件信息
         * @param groupName
         * @param remoteFileName
         * @return
         */
        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;
        }
    
        /**
         * 下载文件
         * @param groupName 文件路径
         * @param remoteFileName 输出流 中包含要输出到磁盘的路径
         * @return
         */
        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;
        }
    
        /**
         * 删除文件
         * ==0表示成功
         * @param groupName 组名 如:group1
         * @param remoteFileName 不带组名的路径名称 如:M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
         * @throws Exception
         */
        public static int deleteFile(String groupName, String remoteFileName)
                throws Exception {
            StorageClient storageClient = getTrackerClient();
            return storageClient.delete_file(groupName, remoteFileName);
        }
    
        /**
         * 获取storage
         * @param groupName 组名
         * @return
         * @throws IOException
         */
        public static StorageServer[] getStoreStorages(String groupName) throws IOException {
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getConnection();
            return trackerClient.getStoreStorages(trackerServer, groupName);
        }
    
        /**
         *
         * @param groupName
         * @param remoteFileName
         * @return
         * @throws IOException
         */
        public static ServerInfo[] getFetchStorages(String groupName,String remoteFileName) throws IOException {
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getConnection();
            return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
        }
    
        /**
         * 获取reacker地址
         * @return
         * @throws IOException
         */
        public static String getTrackerUrl() throws IOException {
            return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/";
        }
    
        /**
         * 获取tracker连接
         * @return
         * @throws IOException
         */
        private static StorageClient getTrackerClient() throws IOException {
            TrackerServer trackerServer = getTrackerServer();
            StorageClient storageClient = new StorageClient(trackerServer, null);
            return  storageClient;
        }
    
        /**
         * 获取tracker服务
         * @return
         * @throws IOException
         */
        private static TrackerServer getTrackerServer() throws IOException {
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getConnection();
            return  trackerServer;
        }
    }

    FastDFSFile
    /**
     * @Auther: lanhaifeng
     * @Date: 2019/4/25 0025 09:15
     * @Description:文件信息类
     */
    public class FastDFSFile {
    
        private String name;//文件名
        private byte[] content; //文件的内容,字节数组
        private String ext; //文件扩展名,不包含(.)
        private String md5; //加密
        private String author;
    
        public FastDFSFile() {
        }
    
        public FastDFSFile(String name, byte[] content, String ext) {
            this.name = name;
            this.content = content;
            this.ext = ext;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public byte[] getContent() {
            return content;
        }
    
        public void setContent(byte[] content) {
            this.content = content;
        }
    
        public String getExt() {
            return ext;
        }
    
        public void setExt(String ext) {
            this.ext = ext;
        }
    
        public String getMd5() {
            return md5;
        }
    
        public void setMd5(String md5) {
            this.md5 = md5;
        }
    
        public String getAuthor() {
            return author;
        }
    
        public void setAuthor(String author) {
            this.author = author;
        }
    }
     

    五、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 这个方法后面可以自己封装一个util,这里只是测试 */ 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

    当然带了token验证每次访问就得带上token,哎屁事真多哎!

  • 相关阅读:
    Node.js理解
    PayPal为什么从Java迁移到Node.js
    移动开发技巧总结
    Flex性能调优相关的一些总结
    Flex组件的生命周期
    Adobe Flash Builder 4.7 新功能详解
    【Django】Cookie
    【Django】路由系统
    【Django】视图系统
    【Django】ORM操作#2
  • 原文地址:https://www.cnblogs.com/zeussbook/p/10764086.html
Copyright © 2011-2022 走看看