Spring Batch/Azure存储帐户blob资源[container";foo";,blob=';bar';]无法解析为绝对文件路径

Spring Batch/Azure存储帐户blob资源[container";foo";,blob=';bar';]无法解析为绝对文件路径,spring,azure,spring-batch,azure-storage,azure-storage-blobs,Spring,Azure,Spring Batch,Azure Storage,Azure Storage Blobs,我正在尝试使用Spring写入Azure存储 我在Bean中配置资源,而不是从类中自动连接资源 BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connectionString).endpoint(endpoint).buildClient(); 以下是Azure存储容器中的blob名称: String resourceString = "azure-blob://foo/bar.c

我正在尝试使用Spring写入Azure存储

我在Bean中配置资源,而不是从类中自动连接资源

BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connectionString).endpoint(endpoint).buildClient();
以下是Azure存储容器中的blob名称:

String resourceString = "azure-blob://foo/bar.csv"
设置Azure存储模式解析程序:

AzureStorageResourcePatternResolver storageResourcePatternResolver = new AzureStorageResourcePatternResolver(client);
然后获取资源:

Resource resource = storageResourcePatternResolver.getResource(resourceString);
这就是我得到的错误:

java.lang.UnsupportedOperationException: Azure storage account blob resource [container='foo', blob='bar.csv'] cannot be resolved to absolute file path
at com.azure.spring.autoconfigure.storage.resource.BlobStorageResource.getFile(BlobStorageResource.java:83) ~[azure-spring-boot-3.4.0.jar:na]
at org.springframework.batch.item.support.AbstractFileItemWriter.getOutputState(AbstractFileItemWriter.java:367) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.item.support.AbstractFileItemWriter.open(AbstractFileItemWriter.java:308) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.item.support.AbstractFileItemWriter$$FastClassBySpringCGLIB$$f2d35c3.invoke(<generated>) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.5.jar:5.3.5]
at org.springframework.batch.item.file.FlatFileItemWriter$$EnhancerBySpringCGLIB$$5ce6a900.open(<generated>) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:104) ~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:311) ~[spring-batch-core-4.3.2.jar:4.3.2]
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:205) ~[spring-batch-core-4.3.2.jar:4.3.2]
at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:138) [spring-batch-core-4.3.2.jar:4.3.2]
at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:135) [spring-batch-core-4.3.2.jar:4.3.2]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_221]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_221]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_221]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_221]2021-05-25 09:24:36.168  INFO 4916 --- [ taskExecutor-3] o.s.batch.core.step.AbstractStep         : Step: [slaveStep:partition155] executed in 347ms2021-05-25 09:24:36.240 ERROR 4916 --- [ taskExecutor-1] o.s.batch.core.step.AbstractStep         : Encountered an error executing step slaveStep in job job1
java.lang.UnsupportedOperationException:Azure存储帐户blob资源[container='foo',blob='bar.csv']无法解析为绝对文件路径
在com.azure.spring.autoconfigure.storage.resource.BlobStorageResource.getFile(BlobStorageResource.java:83)~[azure-spring-boot-3.4.0.jar:na]
在org.springframework.batch.item.support.AbstractFileItemWriter.getOutputState(AbstractFileItemWriter.java:367)~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
在org.springframework.batch.item.support.AbstractFileItemWriter.open(AbstractFileItemWriter.java:308)~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
在org.springframework.batch.item.support.AbstractFileItemWriter$$FastClassBySpringCGLIB$$f2d35c3.invoke()~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
在org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)~[spring-core-5.3.5.jar:5.3.5]
在org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:163)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.procedue(CglibAopProxy.java:750)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:186)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.procedue(CglibAopProxy.java:750)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)~[spring-aop-5.3.5.jar:5.3.5]
在org.springframework.batch.item.file.FlatFileItemWriter$$EnhancerBySpringCGLIB$$5ce6a900.open()~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
在org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:104)~[spring-batch-infrastructure-4.3.2.jar:4.3.2]
在org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:311)~[spring-batch-core-4.3.2.jar:4.3.2]
在org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:205)~[spring-batch-core-4.3.2.jar:4.3.2]
在org.springframework.batch.core.partition.support.taskExecutionPartitionHandler$1.call(taskExecutionPartitionHandler.java:138)[spring-batch-core-4.3.2.jar:4.3.2]
在org.springframework.batch.core.partition.support.taskExecutionPartitionHandler$1.call(taskExecutionPartitionHandler.java:135)[spring-batch-core-4.3.2.jar:4.3.2]
在java.util.concurrent.FutureTask.run(FutureTask.java:266)[na:1.8.0_221]
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)[na:1.8.0_221]
在java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)[na:1.8.0_221]
在java.lang.Thread.run(Thread.java:748)[na:1.8.0Ý]2021-05-25 09:24:36.168信息4916---[taskExecutor-3]o.s.batch.core.step.AbstractStep:step:[slaveStep:partition155]在347ms2021-05-25 09:24:36.240错误4916---[taskExecutor-1]o.s.batch.core.step.AbstractStep:在作业job1中执行步骤slaveStep时遇到错误

非常感谢您的帮助。

搜索位置应以
azure blob://
azure文件://
开头。你评论中的“斑点”是不正确的

azure-blob://foo/bar.csv
表示“foo”容器中的“bar.csv”blob。请检查您的存储,确保blob存在

例如,我的blob URL是
https://pamelastorage123.blob.core.windows.net/pamelac/test.txt
,所以
azure-blob://pamelac/test.txt
是正确的

StorageExampleApplication.java:

@SpringBootApplication
public class StorageExampleApplication {

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

    public static void testRescource(){
        String searchLocation = "azure-blob://<container-name>/<blob-name>";
        String connectionString = "<Connection string>";
        String endpoint = "https://<account-name>.blob.core.windows.net";

        BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connectionString).endpoint(endpoint).buildClient();
        AzureStorageResourcePatternResolver storageResourcePatternResolver = new AzureStorageResourcePatternResolver(client);

        Resource resource = storageResourcePatternResolver.getResource(searchLocation);
        System.out.println(resource.getFilename());
    }

}
azure.storage.account-name=[storage-account-name]
azure.storage.account-key=[storage-account-access-key]
azure.storage.blob-endpoint=[storage-blob-endpoint-URL]
结果:

@SpringBootApplication
public class StorageExampleApplication {

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

    public static void testRescource(){
        String searchLocation = "azure-blob://<container-name>/<blob-name>";
        String connectionString = "<Connection string>";
        String endpoint = "https://<account-name>.blob.core.windows.net";

        BlobServiceClient client = new BlobServiceClientBuilder().connectionString(connectionString).endpoint(endpoint).buildClient();
        AzureStorageResourcePatternResolver storageResourcePatternResolver = new AzureStorageResourcePatternResolver(client);

        Resource resource = storageResourcePatternResolver.getResource(searchLocation);
        System.out.println(resource.getFilename());
    }

}
azure.storage.account-name=[storage-account-name]
azure.storage.account-key=[storage-account-access-key]
azure.storage.blob-endpoint=[storage-blob-endpoint-URL]

设计用于处理表示可写文件的任何资源。以下是Javadoc的摘录:

The location of the output file is defined by a Resource and must represent
a writable file.

此编写器的初始化过程通过调用
resource\getFile
检查传递的资源是否为可写文件。在您的情况下,您正在使用的
资源
实现,即
BlobStorageResource
为该操作抛出
java.lang.UnsupportedOperationException
,从而导致您的错误。您需要提供一个
资源
实现,该实现表示
FlatFileItemWriter所期望的文件

Ok。我将resourceString从azure blob更改为blob。现在我得到的java.lang.IllegalArgumentException资源未在以下位置找到:blob://foo/bar.csv 。这很有帮助,因此它清除了连接到容器/文件的正确方式。我想我的头衔太开放了,不能只剩下春天了。我编辑了Spring Batch。嗨,@msuzuki。有更新吗?问题解决了吗?嗨,Pamela,基于@Mahmoud Ben Hassine的响应,我为Azure Blob的FileWriterItem设置了实现,错误得到了错误。现在我收到另一个错误,抱怨输出流被关闭。我在中打开了另一个问题。Thx马哈茂德!让我来介绍一下如何为Azure Blob实现FlatFileItem。我在GCP上发现了类似的东西。。。所以我会用它作为指导。我会报告进展的。嗨,Mahmo