亲宝软件园·资讯

展开

SpringBoot集成FastDFS+Nginx整合基于Token的防盗链的方法

人气:0

为什么要用SpringBoot?

SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。

为什么要用Nginx?

概述

Nginx(engine x)是一个开源的,支持高并发的www服务和代理服务软件。Nginx是俄罗斯人Igor Sysoev开发的,最初被应用到俄罗斯的大型网站(www.rambler.ru)上。后来作者将源代码以类BSD许可证的形式开源出来供全球使用。在功能应用方面,Nginx不仅是一个优秀的Web服务软件,还具有反向代理负载均衡和缓存的功能。在反向代理负载均衡方面类似于LVS负载均衡及HAProxy等你专业代理软件。Nginx部署起来更加方便简单,在缓存服务功能方面,有类似于Squid等专业的缓存服务软件。Nginx可以运行在UNIX、Linux、MS Windows Server、Mac OS X Server、Solaris等操作系统中。

Nginx的重要特性

Nginx所具备的WWW服务特性

Nginx软件主要企业应用

Web服务应用产品性能对比

为什么Nginx比Apache的性能高?

如何正确采用Web服务器?

关于部署,就不在重复了,如果需要请移步《Java高级架构之FastDFS分布式文件集群》:

使用IDEA场景启动器创建工程

创建Maven工程,修改POM.xml文件添加如下依赖:

<dependencies>
  <!-- SpringBoot的自动配置相关依赖 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>1.5.20.RELEASE</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <version>1.5.20.RELEASE</version>
  </dependency>
  <!-- 日志相关的依赖 -->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
    <version>1.5.20.RELEASE</version>
  </dependency>
  <!-- 对象池相关的依赖 -->
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.0</version>
  </dependency>

</dependencies>

创建必要的包

一般情况下,SpringBoot都会提供相应的@EnableXxx注解标注在应用的主启动类上开启某个功能:

// EnableFastdfsClient.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(FastdfsAutoConfiguration.class)
@Documented
public @interface EnableFastdfsClient {
}

下面是相关的自动配置类:

// FastdfsAutoConfiguration.java
@Configuration
@EnableConfigurationProperties(FastdfsProperties.class)
public class FastdfsAutoConfiguration {
  @Autowired
  private FastdfsProperties fastdfsProperties;

  @Bean
  @ConditionalOnMissingBean(FastdfsClientService.class)
  public FastdfsClientService fastdfsClientService() throws Exception {
    return new FastdfsClientService(fastdfsProperties);
  }
}

创建相关的工厂类:

// StorageClientFactory.java
// 用于创建连接对象的工厂类
public class StorageClientFactory implements PooledObjectFactory<StorageClient> {

  @Override
  public PooledObject<StorageClient> makeObject() throws Exception {
    TrackerClient client = new TrackerClient();
    TrackerServer server = client.getConnection();
    return new DefaultPooledObject<>(new StorageClient(server, null));
  }

  @Override
  public void destroyObject(PooledObject<StorageClient> p) throws Exception {
    p.getObject().getTrackerServer().close();
  }

  @Override
  public boolean validateObject(PooledObject<StorageClient> p) {
    return false;
  }

  @Override
  public void activateObject(PooledObject<StorageClient> p) throws Exception {

  }

  @Override
  public void passivateObject(PooledObject<StorageClient> p) throws Exception {

  }
}

Properties类用来映射application.properties或者application.yml配置文件:

// FastdfsProperties.java
@ConfigurationProperties(prefix = "fastdfs")
public class FastdfsProperties {
  // 连接超时时间
  // 网络超时时间
  // 字符集编码
  // 是否使用Token
  // Token加密密钥
  // 跟踪器IP地址,多个使用分号隔开
  // 连接池的连接对象最大个数
  // 连接池的最大空闲对象个数
  // 连接池的最小空闲对象个数
  // Nginx服务器IP,多个使用分号分割
  // 获取连接对象时可忍受的等待时长(毫秒)
  private String connectTimeout = "5";
  private String networkTimeout = "30";
  private String charset = "UTF-8";
  private String httpAntiStealToken = "false";
  private String httpSecretKey = "";
  private String httpTrackerHttpPort = "";
  private String trackerServers = "";
  private String connectionPoolMaxTotal = "18";
  private String connectionPoolMaxIdle = "18";
  private String connectionPoolMinIdle = "2";
  private String nginxServers = "";

  // 需要创建相关的Setter和Getter方法
}

在Service类中封装方法, 下面仅展示3个常用的方法:

// FastdfsClientSerivce.java
public class FastdfsClientService {
  // SpringBoot加载的配置文件
  // 连接池配置项
  // 转换后的配置条目
  // 连接池
  // Nginx服务器地址
  private FastdfsProperties fdfsProp;
  private GenericObjectPoolConfig config;
  private Properties prop;
  private GenericObjectPool<StorageClient> pool;
  private String[] nginxServers;
  private Logger logger;

  public FastdfsClientService(FastdfsProperties fdfsProp) throws Exception {
    this.fdfsProp = fdfsProp;
    this.logger = LoggerFactory.getLogger(getClass());
    init();
    create();
    info();
  }

  /**
   * 初始化全局客户端
   */
  private void init() throws Exception {
    this.prop = new Properties();
    this.logger.info("FastDFS: reading config file...");
    this.logger.info("FastDFS: fastdfs.connect_timeout_in_seconds=" + this.fdfsProp.getConnectTimeout());
    this.logger.info("FastDFS: fastdfs.network_timeout_in_seconds=" + this.fdfsProp.getNetworkTimeout());
    this.logger.info("FastDFS: fastdfs.charset=" + this.fdfsProp.getCharset());
    this.logger.info("FastDFS: fastdfs.http_anti_steal_token=" + this.fdfsProp.getHttpAntiStealToken());
    this.logger.info("FastDFS: fastdfs.http_secret_key=" + this.fdfsProp.getHttpSecretKey());
    this.logger.info("FastDFS: fastdfs.http_tracker_http_port=" + this.fdfsProp.getHttpTrackerHttpPort());
    this.logger.info("FastDFS: fastdfs.tracker_servers=" + this.fdfsProp.getTrackerServers());
    this.logger.info("FastDFS: fastdfs.connection_pool_max_total=" + this.fdfsProp.getConnectionPoolMaxTotal());
    this.logger.info("FastDFS: fastdfs.connection_pool_max_idle=" + this.fdfsProp.getConnectionPoolMaxIdle());
    this.logger.info("FastDFS: fastdfs.connection_pool_min_idle=" + this.fdfsProp.getConnectionPoolMinIdle());
    this.logger.info("FastDFS: fastdfs.nginx_servers=" + this.fdfsProp.getNginxServers());

    this.prop.put("fastdfs.connect_timeout_in_seconds", this.fdfsProp.getConnectTimeout());
    this.prop.put("fastdfs.network_timeout_in_seconds", this.fdfsProp.getNetworkTimeout());
    this.prop.put("fastdfs.charset", this.fdfsProp.getCharset());
    this.prop.put("fastdfs.http_anti_steal_token", this.fdfsProp.getHttpAntiStealToken());
    this.prop.put("fastdfs.http_secret_key", this.fdfsProp.getHttpSecretKey());
    this.prop.put("fastdfs.http_tracker_http_port", this.fdfsProp.getHttpTrackerHttpPort());
    this.prop.put("fastdfs.tracker_servers", this.fdfsProp.getTrackerServers());
    ClientGlobal.initByProperties(this.prop);
  }
  /**
   * 显示初始化信息
   */
  private void info() {
    this.logger.info("FastDFS parameter: ConnectionPoolMaxTotal ==> " + this.pool.getMaxTotal());
    this.logger.info("FastDFS parameter: ConnectionPoolMaxIdle ==> " + this.pool.getMaxIdle());
    this.logger.info("FastDFS parameter: ConnectionPoolMinIdle ==> " + this.pool.getMinIdle());
    this.logger.info("FastDFS parameter: NginxServer ==> " + Arrays.toString(this.nginxServers));
    this.logger.info(ClientGlobal.configInfo());
  }

  /**
   * 创建连接池
   */
  private void create() {
    this.config = new GenericObjectPoolConfig();
    this.logger.info("FastDFS Client: Creating connection pool...");
    this.config.setMaxTotal(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxTotal()));
    this.config.setMaxIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxIdle()));
    this.config.setMinIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMinIdle()));
    StorageClientFactory factory = new StorageClientFactory();
    this.pool = new GenericObjectPool<StorageClient>(factory, this.config);
    this.nginxServers = this.fdfsProp.getNginxServers().split(",");
  }

  /**
   * Nginx服务器负载均衡算法
   *
   * @param servers 服务器地址
   * @param address 客户端IP地址
   * @return 可用的服务器地址
   */
  private String getNginxServer(String[] servers, String address) {
    int size = servers.length;
    int i = address.hashCode();
    int index = abs(i % size);
    return servers[index];
  }

  /**
   * 带有防盗链的下载
   *
   * @param fileGroup    文件组名
   * @param remoteFileName 远程文件名称
   * @param clientIpAddress 客户端IP地址
   * @return 完整的URL地址
   */
  public String autoDownloadWithToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception {
    int ts = (int) (System.currentTimeMillis() / 1000);
    String token = ProtoCommon.getToken(remoteFileName, ts, ClientGlobal.getG_secret_key());
    String nginx = this.getNginxServer(this.nginxServers, clientIpAddress);
    return "http://" + nginx + "/" + fileGroup + "/" + remoteFileName + "?token=" + token + "&ts=" + ts;
  }

  /**
   * 上传文件,适合上传图片
   *
   * @param buffer 字节数组
   * @param ext  扩展名
   * @return 文件组名和ID
   */
  public String[] autoUpload(byte[] buffer, String ext) throws Exception {
    String[] upload = this.upload(buffer, ext, null);
    return upload;
  }

  /**
   * 不带防盗链的下载,如果开启防盗链会导致该方法抛出异常
   *
   * @param fileGroup    文件组名
   * @param remoteFileName 远程文件ID
   * @param clientIpAddress 客户端IP地址,根据客户端IP来分配Nginx服务器
   * @return 完整的URL地址
   */
  public String autoDownloadWithoutToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception {
    if (ClientGlobal.getG_anti_steal_token()) {
      this.logger.error("FastDFS Client: You've turned on Token authentication.");
      throw new Exception("You've turned on Token authentication.");
    }
    String nginx = this.getNginxServer(this.nginxServers, clientIpAddress);
    return "http://" + nginx + fileGroup + "/" + remoteFileName;
  }

  // 后面还有好多方法,就不一一展示了
}

为了在IDEA中使用便捷的配置提示功能,我们需要创建元数据文件(resources/spring-configuration-metadata.json):

{
 "groups": [
  {
   "name": "fastdfs",
   "type": "com.bluemiaomiao.properties.FastdfsProperties",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties"
  }
 ],
 "properties": [
  {
   "name": "connectTimeout",
   "type": "java.lang.String",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties",
   "defaultValue": "5"
  },
  {
   "name": "networkTimeout",
   "type": "java.lang.String",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties",
   "defaultValue": "30"
  },
  {
   "name": "charset",
   "type": "java.lang.String",
   "defaultValue": "UTF-8"
  },
  {
   "name": "httpAntiStealToken",
   "type": "java.lang.String",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties",
   "defaultValue": "false"
  },
  {
   "name": "httpSecretKey",
   "type": "java.lang.String",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties"
  },
  {
   "name": "httpTrackerHttpPort",
   "type": "java.lang.Integer",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties"
  },
  {
   "name": "trackerServers",
   "type": "java.lang.String",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties"
  },
  {
   "name": "connectionPoolMaxTotal",
   "type": "java.lang.Integer",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties",
   "defaultValue": "18"
  },
  {
   "name": "connectionPoolMaxIdle",
   "type": "java.lang.Integer",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties",
   "defaultValue": "18"
  },
  {
   "name": "connectionPoolMinIdle",
   "type": "java.lang.Integer",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties",
   "defaultValue": "2"
  },
  {
   "name": "nginxServers",
   "type": "java.lang.String",
   "sourceType": "com.bluemiaomiao.properties.FastdfsProperties"
  }
 ],
 "hints": [
  {
   "name": "http_anti_steal_token",
   "values": [
    {
     "value": "false"
    },
    {
     "value": "true"
    }
   ]
  }
 ]
}

应用到项目中

创建SpringBoot项目,勾选Web选项,版本选择1.5.20

进入场景启动器的项目目录执行mvn clean install 将其安装到本地

在POM.xml文件中添加依赖:

<dependency>
  <groupId>com.bluemiaomiao</groupId>
  <artifactId>fastdfs-spring-boot-starter</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

记得开启IDEA的自动导入功能

创建配置文件application.properties

fastdfs.nginx-servers=192.168.80.2:8000,192.168.80.3:8000,192.168.80.4:8000
fastdfs.tracker-servers=192.168.80.2:22122,192.168.80.3:22122,192.168.80.4:22122
fastdfs.http-secret-key=2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw
fastdfs.http-anti-steal-token=true
fastdfs.http-tracker-http-port=8080
fastdfs.network-timeout=30
fastdfs.connect-timeout=5
fastdfs.connection-pool-max-idle=18
fastdfs.connection-pool-min-idle=2
fastdfs.connection-pool-max-total=18
fastdfs.charset=UTF-8

或者使用application.yml

fastdfs:
 charset: UTF-8
 connect-timeout: 5
 http-secret-key: 2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw
 network-timeout: 30
 http-anti-steal-token: true
 http-tracker-http-port: 8080
 connection-pool-max-idle: 20
 connection-pool-max-total: 20
 connection-pool-min-idle: 2
 nginx-servers: 192.168.80.2:8000,192.168.80.3:8000,192.168.80.4:8000
 tracker-servers: 192.168.80.2:22122,192.168.80.3:22122,192.168.80.4:22122

创建控制器类测试方法

// controllers.DownloadController.java
@Controller
@RequestMapping(value = "/download")
public class DownloadController {

  @Autowired
  private FastdfsClientService service;

  @ResponseBody
  @RequestMapping(value = "/image")
  public String image() throws Exception {
    // 之前上传过的数据,实际应用场景应该使用SQL数据库来存储
    return service.autoDownloadWithToken("group1", "M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4.tar.gz", "192.168.80.1");
  }
}

项目主页:https://github.com/bluemiaomiao/fastdfs-spring-boot-starter

国内项目主页:https://gitee.com/bluemiaomiao/fastdfs-spring-boot-starter

您可能感兴趣的文章:

加载全部内容

相关教程
猜你喜欢
用户评论