紺碧のBLOBファイルのアップロードを実現SpringBoot

Azureブロブストレージは、マイクロソフトが提供するクラウドベースのオブジェクト・ストレージ・ソリューションに適しています。最も大規模な非構造化データを格納するためのBLOBストレージ

レディ

Azureのサブスクリプション

クリックして無料アカウントを作成するために、後でのための最大のMicrosoftアカウントのログインを使用して開始するには12ヶ月執行猶予に、自由選択

Azureストレージアカウント

クリックしてストレージアカウントを作成紺碧CLIをインストールしていない場合は、に従ってストレージアカウントを作成するには、チュートリアルを、列に直接参照をお勧めします[ポータル]

Azureのポータル資格

  1. ログオンAzureのポータル
  2. 自分のストレージアカウントを検索します。
  3. ストレージアカウントで概説したように、「設定」セクションには、「アクセスキー」を選択します。ここでは、アカウントのアクセスキーと各キーの完全な接続文字列を表示することができます。
  4. 「キー1」「接続文字列」の値以下に見つかり、接続文字列をコピーするには、「コピー」ボタンを選択します。次のステップは、環境変数に、この文字列値を接続するために必要。

開発段階

コンフィギュレーション

  • 依存性の導入
<!--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);
    }
}
复制代码

コラム本当のテスト

郵便配達のテストを使用します

【ボディ】要求 - フォームデータ[] - []キー=ファイル、およびローカルの複数の画像を選択します

  • ビューの画像に画像のURLをコピーします

  • 最近アップロードされたファイルを見ることができるビューブロブコンテナ、

テストを提出する形式を使用します

テストの便宜上、ページのために直接使用するテンプレートは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 /アップロード、アップロードする画像を選択

  • 成功したアップロード


参考記事:

Azureブロブストレージドキュメント

春ブーツ戦闘Azureストレージにアップロードされたファイル

おすすめ

転載: juejin.im/post/5e104b69f265da5d4727b6b8