当前位置:   article > 正文

文件服务器FastDFS

文件服务器

FastDFS可用于分布式系统环境中自行搭建文件服务器,可以达到服务器资源动静分离,请求分流的效果。本篇简单概述下其使用方法。

准备工作:

  1. 搭建springboot脚手架并成功运行,可参考历史分享springboot+mybatis

  2. 启动FastDFS服务(tracker, storage及nginx)(搭建配置FastDFS服务,后续会在运维章节另行讲述)

1. maven添加FastDFS client依赖

<dependency>    <groupId>com.github.tobato</groupId>    <artifactId>fastdfs-client</artifactId>    <version>1.26.7</version></dependency>

2.FastDFS配置

2.1 yml

fdfs:  # 文件下载拉取地址  web-server-url: https://img.xxx.com  so-timeout: 3000  connect-timeout: 1200  thumb-image: # 缩略图    width: 60    height: 60  tracker-list: 192.168.2.9:22122  pool:    jmx-enabled: false #禁止JMX重复注册,影响springboot JMX监控

2.2 FastDFS client config

import com.github.tobato.fastdfs.FdfsClientConfig;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Import;@Import({FdfsClientConfig.class})@SpringBootApplicationpublic class FdfsApplication {    public static void main(String[] args) {        SpringApplication.run(FdfsApplication.class, args);    }}

3.FastDFS使用

3.1 fdfs util

import com.github.tobato.fastdfs.domain.fdfs.StorePath;import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException;import com.github.tobato.fastdfs.exception.FdfsUploadImageException;import com.github.tobato.fastdfs.service.FastFileStorageClient;import lombok.extern.slf4j.Slf4j;import net.coobird.thumbnailator.Thumbnails;import org.apache.commons.io.FilenameUtils;import org.apache.commons.io.IOUtils;import org.apache.commons.lang3.StringUtils;import org.springframework.web.multipart.MultipartFile;import javax.imageio.ImageIO;import java.awt.*;import java.awt.image.BufferedImage;import java.io.*;import java.util.Arrays;import java.util.List;import java.util.UUID;/** * @author Bruce * @date 2021/3/12 */@Slf4jpublic final class FdfsUtil {
  1. private static final List<String> IMAGE_TYPE =
  2.   Arrays.asList("jpg", "jpeg", "png", "bmp", "tif", "gif", "webp");
private static final List<String> VIDEO_TYPE = Arrays.asList("mp4", "avi"); private static final String IMG_LINUX_LOCATION = "/usr/local/data/img"; /** * 前端 文件上传 * @param fastFileStorageClient * @param file * @param imageServer * @param needThumbnail * @param needSize * @return * @throws IOException */
  1. public static UploadFile upload(FastFileStorageClient fastFileStorageClient,
  2.   MultipartFile file, String imageServer,
  3.   Byte needThumbnail, Byte needSize)
  4.   throws IOException {
  1. UploadFile uploadFile = new UploadFile(
  2.   file.getOriginalFilename(), file.getSize(), file.getContentType());
  1. uploadFile(fastFileStorageClient, file.getInputStream(),
  2.   uploadFile, imageServer, needThumbnail, needSize);
return uploadFile; } /** * 后端 文件上传 * @param fastFileStorageClient * @param file * @param imageServer * @param needThumbnail * @param needSize * @return */
  1. public static UploadFile upload(FastFileStorageClient fastFileStorageClient,
  2.   File file, String imageServer,
  3.   Byte needThumbnail, Byte needSize) {
try (InputStream is = new FileInputStream(file)) {
  1. UploadFile uploadFile = new UploadFile(
  2.   file.getName(), file.length(), null);
  1. uploadFile(fastFileStorageClient, is, uploadFile,
  2.   imageServer, needThumbnail, needSize);
return uploadFile; } catch (Exception e){ throw new CommonException("上传文件失败", e); } } /** * 上传文件,处理图片 * @param fastFileStorageClient * @param inputStream * @param uploadFile * @param imageServer * @param needThumbnail * @param needSize * @throws IOException */
  1. private static void uploadFile(FastFileStorageClient fastFileStorageClient,
  2.   InputStream inputStream, UploadFile uploadFile,
  3.   String imageServer, Byte needThumbnail,
  4.   Byte needSize) throws IOException {
  1. log.info("文件上传 originalFileName={}, fileSize={}",
  2.   uploadFile.getOriginalFilename(), uploadFile.getFileSize());
// 获取文件后缀
  1. String fileExtName = FilenameUtils.getExtension(
  2.   uploadFile.getOriginalFilename()).toLowerCase();
// 限制图片文件上传大小 if(isSupportType(fileExtName)){ validateUploadImage(uploadFile, fileExtName); } // 缓存文件流 byte[] fileStream = IOUtils.toByteArray(inputStream); // 上传原图或文件
  1. uploadOrigFile(fastFileStorageClient, uploadFile,
  2.   imageServer, fileStream, fileExtName);
// 上传图片缩略图 if(isSupportType(fileExtName)){
  1. uploadImageThumbnails(fastFileStorageClient, uploadFile,
  2.   imageServer, fileStream, fileExtName, needThumbnail, needSize);
} log.info("上传文件地址={}", uploadFile.getFullFilename()); } /** * 限制图片文件上传大小 * @param uploadFile * @param fileExtName */
  1. private static void validateUploadImage(UploadFile uploadFile,
  2.   String fileExtName){
// gif文件,大小校验,超过4兆,不上传 if("gif".equals(fileExtName)){ if(uploadFile.getFileSize() > 4 * 1024 * 1024){ throw new CommonException("GIF动图大小不能超过4M"); } } else if(VIDEO_TYPE.contains(fileExtName)){ if(uploadFile.getFileSize() > 40 * 1024 * 1024){ throw new CommonException("视频大小不能超过40M"); } } else{ // 普通图片文件不能超过10M if(uploadFile.getFileSize() > 10 * 1024 * 1024){ throw new CommonException("上传单张图片不能超过10M"); } } } /** * 上传原文件 * @param fastFileStorageClient * @param uploadFile * @param imageServer * @param fileStream * @param fileExtName */
  1. private static void uploadOrigFile(FastFileStorageClient fastFileStorageClient,
  2.   UploadFile uploadFile, String imageServer,
byte[] fileStream, String fileExtName){ try (ByteArrayInputStream is = new ByteArrayInputStream(fileStream)) {
  1. StorePath originalStorePath = fastFileStorageClient.uploadFile(
  2.   is, uploadFile.getFileSize(), fileExtName, null);
  1. uploadFile.setFullFilename(imageServer.concat("/").concat(
  2.   originalStorePath.getFullPath()));
} catch (IOException e) { log.error("upload Image error", e.getCause()); throw new FdfsUploadImageException("upload Image error", e.getCause()); } } /** * 上传图片缩略图 * @param fastFileStorageClient * @param uploadFile * @param imageServer * @param fileStream * @param fileExtName * @param needThumbnail * @param needSize * @throws IOException */
  1. private static void uploadImageThumbnails(
  2.   FastFileStorageClient fastFileStorageClient,
  3.   UploadFile uploadFile, String imageServer,
  4.   byte[] fileStream, String fileExtName,
  5.   Byte needThumbnail, Byte needSize)
  6.   throws IOException {
// 默认图片缩略图取原图 uploadFile.setThumbnail(uploadFile.getFullFilename()); // 缩略图也需要计算图片尺寸大小 if(Constant.YES.equals(needSize) || Constant.YES.equals(needThumbnail)){ // 获取图片尺寸
  1. BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(
  2.   fileStream));
if(bufferedImage != null){ uploadFile.setWidth(bufferedImage.getWidth()); uploadFile.setHeight(bufferedImage.getHeight()); // 压缩处理 if(Constant.YES.equals(needThumbnail)){ InputStream is = null; try { ByteArrayOutputStream out = new ByteArrayOutputStream();
  1. float outputQuality = getOutputQuality(
  2.   uploadFile.getFileSize());
if(!"jpg".equals(fileExtName)){ // 先转成jpg
  1. String newPicPath = IMG_LINUX_LOCATION + File.separator
  2.   + UUID.randomUUID().toString() + ".jpg";
  1. Thumbnails.of(new ByteArrayInputStream(fileStream))
  2.   .scale(1f).toFile(newPicPath);
// 原比例不变,大小压缩
  1. Thumbnails.of(newPicPath).scale(1f)
  2.   .outputQuality(outputQuality).toOutputStream(out);
// 删除jpg图片 new File(newPicPath).delete(); } else {
  1. Thumbnails.of(new ByteArrayInputStream(fileStream))
  2. .scale(1f).outputQuality(outputQuality)
  3.   .toOutputStream(out);
} is = new ByteArrayInputStream(out.toByteArray()); // 上传缩略图
  1. StorePath thumbnailStorePath = fastFileStorageClient
  2.   .uploadFile(is, is.available(), fileExtName, null);
  1. uploadFile.setThumbnail(imageServer.concat("/")
  2.   .concat(thumbnailStorePath.getFullPath()));
log.info("上传缩略图地址={}", uploadFile.getThumbnail()); } catch (IOException e) { log.error("upload ThumbImage error", e.getCause());
  1. throw new FdfsUploadImageException(
  2.   "upload ThumbImage error",e.getCause());
} finally { IOUtils.closeQuietly(is); } } } } } /** * 设置压缩比例 * @param fileSize * @return */ private static float getOutputQuality(long fileSize){ if (fileSize < 64 * 1024) { return 1f; } else if (fileSize < 256 * 1024) { return 0.4f; } else if (fileSize < 2 * 1024 * 1024) { return 0.2f; } return 0.1f; } /** * 判断文件格式是否支持 * @param fileExtName * @return */ private static boolean isSupportType(String fileExtName) { return IMAGE_TYPE.contains(fileExtName) || VIDEO_TYPE.contains(fileExtName); } /** * 删除文件 * @param fileUrl 文件访问地址 * @param fastFileStorageClient */
  1. public static void deleteFile(FastFileStorageClient fastFileStorageClient,
  2.   String fileUrl) {
if (StringUtils.isEmpty(fileUrl)) { return; } try { StorePath storePath = StorePath.parseFromUrl(fileUrl);
  1. fastFileStorageClient.deleteFile(
  2.   storePath.getGroup(), storePath.getPath());
} catch (FdfsUnsupportStorePathException e) { log.warn("异常信息:", e); }    }}

3.2 前端上传文件API

import com.github.tobato.fastdfs.service.FastFileStorageClient;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.FilenameUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.multipart.MultipartFile;import java.util.ArrayList;import java.util.List;@Slf4j@RestController@RequestMapping("/fdfs")@Api(tags = "文件上传")public class FdfsController {    @Value("${fdfs.web-server-url}")    private String imageServer;    @Autowired    private FastFileStorageClient fastFileStorageClient;
  1. @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
  2.   produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "文件上传", httpMethod = "POST") public String upload(@RequestParam("file") MultipartFile file, @RequestParam(value = "needSize", defaultValue = "0") Byte needSize, @RequestParam(value = "needThumbnail", defaultValue = "0") Byte needThumbnail) { try {            long start = System.currentTimeMillis(); // 获取文件后缀
  1. String fileExtName = FilenameUtils.getExtension(
  2.   file.getOriginalFilename()).toUpperCase();
  1.             UploadFile uploadFile = FdfsUtil.upload(
  2.   fastFileStorageClient, file, imageServer, needThumbnail, needSize);
long end = System.currentTimeMillis(); log.info("文件上传耗时:{} 耗秒", (end - start));             return JSON.toJSONString(uploadFile); } catch (Exception e) {            log.error("上传文件异常:", e); } log.warn(String.format("文件 %s 上传失败", file.getOriginalFilename())); return "上传文件异常"; }}

3.3 服务端上传文件

  @Value("${fdfs.web-server-url}")  private String imageServer;  @Autowired  private FastFileStorageClient fastFileStorageClient;
  File file = new File("xxxx");
  1.   UploadFile uploadFile = FdfsUtil.upload(
  2. fastFileStorageClient, file, imageServer, nullnull);
  String fileUrl = uploadFile.getFullFilename();  file.deleteOnExit();  return fileUrl;

4.FastDFS工作过程

  

client 连接请求FastDFS,需借助Nginx做http请求代理转发​。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/745111?site=
推荐阅读
相关标签
  

闽ICP备14008679号