转载

SpringBoot实现azure blob的文件上传

Azure Blob 存储是 Microsoft 提供的适用于云的对象存储解决方案。 Blob 存储最适合存储巨量的非结构化数据

准备

Azure 订阅

点击 创建免费帐户 ,选择免费开始,使用微软账户注册订阅后即可试用12个月

Azure 存储帐户

点击 创建存储帐户 ,根据教程即可创建一个存储账户,若没有安装azure cli,推荐直接参考【门户网站】一栏

Azure门户凭据

  1. 登录到 Azure 门户 。
  2. 找到自己的存储帐户。
  3. 在存储帐户概述的“设置”部分,选择“访问密钥”。 在这里,可以查看你的帐户访问密钥以及每个密钥的完整连接字符串。
  4. 找到“密钥 1”下面的“连接字符串”值,选择“复制”按钮复制该连接字符串。 下一步需将此连接字符串值添加到某个环境变量。
SpringBoot实现azure blob的文件上传

开发步骤

配置

  • 引入依赖
<!--lombok -->
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
</dependency>

<!--azure storage -->
<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-storage-spring-boot-starter</artifactId>
    <version>0.2.0</version>
</dependency>
复制代码
  • 属性配置
spring:
  servlet:  	
    multipart:	# spring mvc文件上传
      max-request-size: 10MB
      max-file-size: 1MB

azure:
  storage: # azure储存配置
    default-endpoints-protocol: https
    account-name: [account-name]
    account-key: [account-key]
    endpoint-suffix: [endpoint-suffix]
    container-reference: [container-reference]	# 容器名称
    generate-thumbnail: false  # 生成缩略图
复制代码

代码编写

  • 根据属性编写对应参数类
@Data
@Component
public class AzureStorageParam {

    @Value("${azure.storage.default-endpoints-protocol}")
    private String defaultEndpointsProtocol;

    @Value("${azure.storage.account-name}")
    private String accountName;

    @Value("${azure.storage.account-key}")
    private String accountKey;

    @Value("${azure.storage.endpoint-suffix}")
    private String endpointSuffix;

    @Value("${azure.storage.container-reference}")
    private String containerReference;

    /**
     * 拼接连接字符串
     */
    public String getStorageConnectionString() {
        String storageConnectionString =
            String.format("DefaultEndpointsProtocol=%s;AccountName=%s;AccountKey=%s;EndpointSuffix=%s",
                defaultEndpointsProtocol, accountName, accountKey, endpointSuffix);
        return storageConnectionString;
    }
}
复制代码
  • 编写文件上传的返回模型
@Data
@Accessors(chain = true)
public class BlobUpload {
    // 文件名
    private String fileName;

    // 原文件
    private String fileUrl;

    // 缩略图
    private String thumbnailUrl;
}
复制代码
  • 工具类
/**
 * 获取blob container
 * 
 * @param storageConnectionString
 * @param containerReference
 * @return
 */
public static CloudBlobContainer getAzureContainer(String storageConnectionString, String containerReference) {
    CloudStorageAccount storageAccount;
    CloudBlobClient blobClient = null;
    CloudBlobContainer container = null;
    try {
        storageAccount = CloudStorageAccount.parse(storageConnectionString);
        blobClient = storageAccount.createCloudBlobClient();
        container = blobClient.getContainerReference(containerReference);

        container.createIfNotExists(BlobContainerPublicAccessType.CONTAINER, new BlobRequestOptions(),
            new OperationContext());
        return container;
    } catch (Exception e) {
        logger.error("获取azure container异常: [{}]" , e.getMessage());
    }
    return null;
}
复制代码
  • 编写文件上传的业务层接口
public interface IAzureStorageService {

    /**
     * 上传文件(图片)
     * @param type 文件类型
     * @param multipartFiles 文件
     * @return
     */
    BaseResult<Object> uploadFile(String type, MultipartFile[] multipartFiles);
}
复制代码
  • 实现类
@Service
public class AzureStorageServiceImpl implements IAzureStorageService {
    // 设置缩略图的宽高
    private static int thumbnailWidth = 150;
    private static int thumbnailHeight = 100;
    private static String thumbnailPrefix = "mini_";
    private static String originPrefix = "FAQ_";
    private final Logger logger = LoggerFactory.getLogger(AzureStorageServiceImpl.class);

    @Value("{azure.storage.generate-thumbnail}")
    private String generateThumbnail;

    @Autowired
    private AzureStorageParam azureStorageParam;

    @Override
    public BaseResult<Object> uploadFile(String type, MultipartFile[] multipartFiles) {
        // 校验图片
        if (hasInvalidPic(multipartFiles)) {
            return BaseResult.error("包含非法图片格式");
        }

        List<BlobUpload> blobUploadEntities = new ArrayList<>();

        // 获取blob容器
        CloudBlobContainer container = AzureStorageUtil.getAzureContainer(
            azureStorageParam.getStorageConnectionString(), azureStorageParam.getContainerReference());
        if (container == null) {
            logger.error("获取azure container异常");
            return BaseResult.error("获取容器失败");
        }
        try {
            for (MultipartFile tempMultipartFile : multipartFiles) {
                try {
                    // 将 blob 上传到容器
                    String contentType = tempMultipartFile.getContentType().toLowerCase();
                    if (!contentType.equals("image/jpg") && !contentType.equals("image/jpeg")
                        && !contentType.equals("image/png")) {
                        return BaseResult.error("not pic");
                    }
                    // 时间+随机数+文件扩展名
                    String picType = contentType.split("/")[1];
                    String timeStamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
                    int number = (int)((Math.random() * 9) * 1000);
                    String referenceName = originPrefix + timeStamp + number + "." + picType;
                    CloudBlockBlob blob = container.getBlockBlobReference(referenceName);
                    blob.getProperties().setContentType(tempMultipartFile.getContentType());
                    blob.upload(tempMultipartFile.getInputStream(), tempMultipartFile.getSize());

                    // 返回图片URL
                    BlobUpload blobUploadEntity = new BlobUpload();
                    blobUploadEntity.setFileName(tempMultipartFile.getOriginalFilename())
                        .setFileUrl(blob.getUri().toString());

                    // 生成缩略图
                    if ("true".equalsIgnoreCase(generateThumbnail)) {
                        BufferedImage img =
                            new BufferedImage(thumbnailWidth, thumbnailHeight, BufferedImage.TYPE_INT_RGB);
                        BufferedImage read = ImageIO.read(tempMultipartFile.getInputStream());
                        img.createGraphics().drawImage(
                            read.getScaledInstance(thumbnailWidth, thumbnailHeight, Image.SCALE_SMOOTH), 0, 0, null);
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        ImageIO.write(img, "jpg", baos);
                        InputStream bais = new ByteArrayInputStream(baos.toByteArray());

                        String blobThumbnail = originPrefix + thumbnailPrefix + timeStamp + number + ".jpg";
                        CloudBlockBlob thumbnailBlob = container.getBlockBlobReference(blobThumbnail);
                        thumbnailBlob.getProperties().setContentType("image/jpeg");
                        thumbnailBlob.upload(bais, baos.toByteArray().length);

                        blobUploadEntity.setFileUrl(blob.getUri().toString())
                            .setThumbnailUrl(thumbnailBlob.getUri().toString());

                        // 关闭流
                        baos.close();
                        bais.close();
                    }
                    blobUploadEntities.add(blobUploadEntity);
                } catch (Exception e) {
                    logger.error("上传[{}]时出现异常:[{}]", tempMultipartFile.getOriginalFilename(), e.getMessage());
                    return BaseResult.error("上传出现异常,请稍后再试");
                }
            }
            return BaseResult.success(blobUploadEntities);
        } catch (Exception e) {
            logger.error("上传文件出现异常: [{}]", e.getMessage());
        }
        return BaseResult.error("上传出现异常,请稍后再试");
    }

    /**
     * 判断批量文件中是否都为图片
     */
    private boolean hasInvalidPic(MultipartFile[] multipartFiles) {
        List<String> picTypeList = Arrays.asList("image/jpg", "image/jpeg", "image/png");
        return Arrays.stream(multipartFiles).anyMatch(i -> !picTypeList.contains(i.getContentType().toLowerCase()));
    }
}
复制代码
  • mvc控制器
@RestController
public class UploadController {
    private static final Logger logger = LoggerFactory.getLogger(UploadController.class);

    @Autowired
    AzureStorageServiceImpl azureStorageService;

    /**
     * 文件上传(图片)
     * 
     * @param multipartFiles
     * @return
     */
    @PostMapping("/upload")
    public BaseResult<Object> upload(@RequestPart("file") MultipartFile[] multipartFiles) {
        logger.info("开始文件上传...");
        if (multipartFiles == null || multipartFiles.length == 0) {
            return BaseResult.error("上传失败,请选择文件");
        }

        return azureStorageService.uploadFile("PICTURE", multipartFiles);
    }
}
复制代码

实列测试

使用postman测试

【请求体】-【form-data】-【key=file】,然后从本地选择若干图片

SpringBoot实现azure blob的文件上传
  • 复制图片url即可查看图片
SpringBoot实现azure blob的文件上传
  • 查看blob容器,即可以看到最新上传的文件
SpringBoot实现azure blob的文件上传

使用表单提交测试

为方便测试,直接使用thymeleaf模板进行页面上传

  • 引入依赖
<!-- thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
复制代码
  • 简易页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多文件上传</title>
</head>
<body>
<form method="post" action="/upload" enctype="multipart/form-data">
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
复制代码
  • 控制器添加跳转请求
@Controller
public class UploadController {
    private static final Logger logger = LoggerFactory.getLogger(UploadController.class);

    @Autowired
    AzureStorageServiceImpl azureStorageService;

    /**
     * 文件上传,跳转使用
     */
    @GetMapping("/upload")
    public String upload() {
        return "upload";
    }

    /**
     * 文件上传(图片)
     */
    @PostMapping("/upload")
    @ResponseBody
    public BaseResult<Object> upload(@RequestPart("file") MultipartFile[] multipartFiles) {
        logger.info("开始文件上传...");
        if (multipartFiles == null || multipartFiles.length == 0) {
            return BaseResult.error("上传失败,请选择文件");
        }

        return azureStorageService.uploadFile("PICTURE", multipartFiles);
    }
}
复制代码
  • 浏览器访问http://localhost:8082/upload,选择图片上传
SpringBoot实现azure blob的文件上传
  • 上传成功
SpringBoot实现azure blob的文件上传
原文  https://juejin.im/post/5e104b69f265da5d4727b6b8
正文到此结束
Loading...