分布式文件存储

一.跨域解决方案CORS
1.1什么是跨域:
当前浏览器的地址栏上的路径与浏览器内部Ajax 发出的请求不一致(域名或者端口号或者协议有任何一个不同即视为请求不一致),就是跨域.
如果跨域调用会出现如下错误:
No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin

‘http://localhost:9100’ is therefore not allowed access. The response had HTTP status code 400.

前后端分离一定会产生跨域问题,解决跨域问题可以采用CORS方案.
1.2什么是CORS
CORS是一个W3C标准,全称"跨域资源共享".CORS需要浏览器和服务器同时支持,目前,所有的浏览器都支持该功能,IE浏览器不能低于IE10.它允许浏览器向跨源服务器发出XMLHTTPRequest请求,从而克服了AJAX
只能同源使用的限制.整个CROS通信过程,都是浏览器自动完成,不需要用户参与,对于开发者来说,CORS通信与同源的AJAX没有差别,代码完全一样,浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉,因此,实现CORS通信的关键是服务器,只要实现了CORS接口,就可以跨源通信.
请求的过程如下:
首先浏览器向服务器发出跨域请求,然后服务器给浏览器允许跨域的响应,然后浏览器发出请求,服务器给出响应.
在这里插入图片描述具体如何实现? springMVC的版本在4.2或者以上的,可以Controller类上使用注解@CrossOrign实现跨域.
二.分布式文件存储
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储,文件同步,文件访问,等.
FastDFS为互联网量身定制,充分考虑了冗余备份,负载均衡,线性扩容等机制,并注重高可用,高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传,下载等服务.
FastDFS架构包括Tracker server和Storage Server 客户端请求Tracker sercer 进行文件上传,下载,通过Tracker server调度最终由Storage server完成文件上传和下载.
Tracker server 进行文件上传,下载,通过Tracker server 调度最终由Storage server完成文件上传和下载.
Tracker server负责负载均衡和调度,通过Tracker server 在文件上传时可以根据一些策略找到Stroage server提供文件上传服务,可以将tracker称为追踪服务器或调度服务器,Storger server作用是文件存储,客户端上传的文件最终都存储在Storage server中 ,Storage server没有实现自己的文件系统而是利用操作的文件系统来管理文件.可以将Stroage称为存储服务器.

在这里插入图片描述
上传流程:
在这里插入图片描述客户端上传文件后存储服务器将文件id返回给客户端,此文件id用于以后访问该文件的索引信息,文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名
在这里插入图片描述组名:文件上传后所在的Storage组名称,在文件上传成功后,有storage服务器返回,需要客户端自行保存.
虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应.如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推.
数据两级目录:storage服务器在每个虚拟磁盘路径下创建的两级目录,用来存储数据文件.
文件名:与文件上传时不同,是由存储服务器根据特点信息生成,文件名包含:源存储服务器ip地址,文件创建时间戳,文件大小,随机数和文件拓展名等信息.
FastDFS搭建:
在Docker中搭建FastDFS:
首先拉取镜像:docker pull morunchang/fastdfs
运行tracker:docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
运行storage:
docker run -d --name storage --net=host -e TRACKER_IP=:22122 -e GROUP_NAME= morunchang/fastdfs sh storage.sh

使用的网络模式是:-net=host,< your tracker server address > 替换为你机器的ip即可
< group name>是组名 ,即stroage的组
如果想要增加新的stroage服务器,再次运行该命令,但是要注意更换新的组名
修改nginx的配置
进入storage的容器内部,修改nginx.conf配置文件
dockers exec -it storage /bin/bash
进入后
vi /data/nginx/conf/nginx.conf
添加以下内容:
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 u r i uri uriis_args$args;
proxy_pass http://fdfs_group1;
expires 30d;
}
退出容器:exit
重启容器: docker restart storage
文件存储微服务:
首先构建工程:
引入依赖:

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>

在resource文件夹下创建fdfs_client.conf的配置文件
添加以下内容:
connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 8080
tracker_server = 192.168.200.128:22122

connect_timeout:连接超时时间,单位为秒。

network_timeout:通信超时时间,单位为秒。发送或接收数据时。假设在超时时间后还不能发送或接收数据,则本次网络通信失败

charset: 字符集

http.tracker_http_port :.tracker的http端口

tracker_server: tracker服务器IP和端口设置

创建application.yml配置文件:
添加以下内容:

spring:
  servlet:
    multipart:
      max-file-size: 10MB  #单个文件大小
      max-request-size: 10MB #设置总上传文件大小
  application:
    name: file  #微服务的应用名称
server:
  port: 9007
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true

max-file-size是单个文件大小,max-request-size是设置总上传的数据大小

创建启动类:

@SpringBootApplication
@EnableEurekaClient
public class FileApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileApplication.class);
    }
}

文件信息封装:
文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的md5值、文件的作者等相关属性,我们可以创建一个对象封装这些属性,代码如下:

 public class FastDFSFile {
      //文件名字
      private String name;
      //文件内容
      private byte[] content;
      //文件扩展名
      private String ext;
      //文件MD5摘要值
      private String md5;
      //文件创建作者
      private String author;

      public FastDFSFile(String name, byte[] content, String ext, String height,
                         String width, String author) {
          super();
          this.name = name;
          this.content = content;
          this.ext = ext;
          this.author = author;
      }

      public FastDFSFile(String name, byte[] content, String ext) {
          super();
          this.name = name;
          this.content = content;
          this.ext = ext;
      }

      // getter and setter ...
  }

文件操作:
创建FastDFSClient类,放在com.itheima.file.util下在该类中实现FastDFS信息获取以及文件的相关操作

package com.changgou.file.utils;

import com.changgou.file.pojo.FastDFSFile;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 文件上传的工具类
 */
public class FastDFSClient {

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

    private static TrackerClient trackerClient = null;

    private static StorageClient1 storageClient1 = null;

    private static TrackerServer trackerServer = null;

    private static StorageServer storageServer = null;

    //静态代码块   为了上传文件  初始化加载文件的上传配置文件  (文件中包含  上传文件的地址 连接时间 读取时间 编码集 等
    static {
        try {
            String absolutePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
            ClientGlobal.init(absolutePath);

            trackerClient = new TrackerClient();
            trackerServer = trackerClient.getConnection();
            storageClient1 = new StorageClient1(trackerServer, storageServer);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ClientGlobal is fail:{}",e.getMessage());
        }

    }

    /**
     * 上传文件
     *
     * @param file
     * @return 文件的路径
     */
    public static String uploadFile(FastDFSFile file){
        System.out.println("上传文件");
        NameValuePair[] nameValuePairs = new NameValuePair[1];
        nameValuePairs[0] = new NameValuePair(file.getAuthor());
        try {
            return storageClient1.upload_file1(file.getContent(),file.getExt(),nameValuePairs);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("upload file is fail: {} ",e.getMessage());
        }
        return null;

    }

    /**
     * 下载文件
     * @param path
     * @return  文件对象
     */
    public static InputStream downFile(String path){

        try {
            byte[] bytes = storageClient1.download_file1(path);
            return new ByteArrayInputStream(bytes);
        } catch (Exception e){
            e.getStackTrace();
            logger.error("download file is fail : {}" ,e.getMessage());
        }


        return null;
    }


    /**
     *  删除文件
     * @param path
     *
     */
    public static void deleteFile(String path){

        try {
            storageClient1.delete_file1(path);
        } catch (Exception e)  {
            e.printStackTrace();
            logger.error("delete file is fail : {}",e.getMessage());
        }
    }
    /***
     * 获取Tracker服务地址
     * @return
     * @throws IOException
     */
    public static String getTrackerUrl() throws IOException {
        return "http://"+trackerServer.getInetSocketAddress().getHostString()+":"+ClientGlobal.getG_tracker_http_port()+"/";
    }
    
}

文件上传:

package com.changgou.file.controller;

import com.changgou.entity.Result;
import com.changgou.entity.StatusCode;
import com.changgou.file.pojo.FastDFSFile;
import com.changgou.file.util.FastDFSClient;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

/**
 * 文件管理
 */
@RestController
@RequestMapping("/file")
@CrossOrigin
public class FileController {

    //打印日志
    private Logger logger = LoggerFactory.getLogger(FileController.class);

    /**
     * 上传文件
     * @param file
     * @return 返回对象
     */
    @PostMapping("/uploadFile")
    public Result uploadFile(MultipartFile file){

        //1:创建文件对象
        try {
            FastDFSFile fastDFSFile = new
                    FastDFSFile(file.getOriginalFilename(),file.getBytes(), FilenameUtils.getExtension(file.getOriginalFilename()));
            //2:上传文件
            String path = FastDFSClient.uploadFile(fastDFSFile);
            //3:获取文件的访问路径
            return new Result(true, StatusCode.OK,"上传成功",FastDFSClient.getTrackerUrl() + path);

        } catch (IOException e) {
            e.printStackTrace();

        }

        return null;
    }


}

注意:文件上传,先传到控制器,然后才由控制器传入到FastDFS

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值