Spring REST 文档中的文档图像响应
Document Image response in Spring REST Docs
我有一个生成随机图像的 REST 端点。我正在使用 Spring REST 文档,但响应在 http-response.adoc 文件中全是乱码。 Mock MVC 和 REST Docs 是否有一种简单的方法将文件存储在某个地方以便我的 .adoc 文件可以引用它?
不是完美但可行的解决方案:
class ImageSnippet implements Snippet {
private final String filePath;
public ImageSnippet(String filePath) {
this.filePath = filePath;
}
@Override
public void document(Operation operation) throws IOException {
byte[] picture = operation.getResponse().getContent();
Path path = Paths.get(filePath);
Files.deleteIfExists(path);
Files.createDirectories(path.getParent());
Files.createFile(path);
try (FileOutputStream fos = new FileOutputStream(path.toFile())) {
fos.write(picture);
}
}
}
以及MockMvc测试中的用法(图片文件夹路径很重要):
mockMvc.perform(get("/my-profile/barcode")
.accept(MediaType.IMAGE_PNG))
.andExpect(status().isOk())
.andDo(document("my-profile/barcode",
new ImageSnippet("build/asciidoc/html5/images/barcode.png")));
在 .adoc
模板中:
image::barcode.png[]
这是我的 build.gradle
Asciidoctor 配置(imagesdir
很重要):
asciidoctor {
dependsOn test
backends = ['html5']
options doctype: 'book'
attributes = [
'source-highlighter': 'highlightjs',
'imagesdir' : './images',
'toc' : 'left',
'toclevels' : 3,
'numbered' : '',
'icons' : 'font',
'setanchors' : '',
'idprefix' : '',
'idseparator' : '-',
'docinfo1' : '',
'safe-mode-unsafe' : '',
'allow-uri-read' : '',
'snippets' : snippetsDir,
linkattrs : true,
encoding : 'utf-8'
]
inputs.dir snippetsDir
outputDir 'build/asciidoc'
sourceDir 'src/docs/asciidoc'
sources {
include 'index.adoc'
}
}
您可以做的是实现一个自定义代码段来保存生成的响应。您可以使用您收到的操作的 RestDocumentationContext 属性来获取输出目录。
mockMvc.perform(get("/example"))
.andDo(document("some-example", operation -> {
var context = (RestDocumentationContext) operation.getAttributes().get(RestDocumentationContext.class.getName());
var path = Paths.get(context.getOutputDirectory().getAbsolutePath(), operation.getName(), "response-file.png");
Files.createDirectories(path.getParent());
Files.write(path, operation.getResponse().getContent());
}));
然而,这将在您的输出目录中创建一个 .png 文件,如果您在需要嵌入它的源目录中有 Asciidoc,这通常不是很有用。因此,您可以改为创建一个 Asciidoc 文件,其中包含图像标签的自定义 HTML,其源是响应的 base64 表示形式。
mockMvc.perform(get("/example"))
.andDo(document("some-example", operation -> {
var context = (RestDocumentationContext) operation.getAttributes().get(RestDocumentationContext.class.getName());
var path = Paths.get(context.getOutputDirectory().getAbsolutePath(), operation.getName(), "response-file.adoc");
var outputStream = new ByteArrayOutputStream();
outputStream.write("++++\n".getBytes());
outputStream.write("<img src=\"data:image/png;base64,".getBytes());
outputStream.write(Base64.getEncoder().encode(operation.getResponse().getContent()));
outputStream.write("\"/>\n".getBytes());
outputStream.write("++++\n".getBytes());
Files.createDirectories(path.getParent());
Files.write(path, outputStream.toByteArray());
}));
尽管 space 的开销有点大,但如果您使用它,则无需从源中引用构建文件。
如果您不 need/want 显示文档中的图像,另一种方法是:使用 ContentModifyingOperationPreprocessor
将字节替换为一些字符串,使文档的读者清楚响应中会有一些图像字节。
例如:
mockMvc.perform(get("/api/users/{id}/avatar", user.getId().asString())
.with(createCustomerAuth()))
.andExpect(status().isOk())
.andDo(document("get-user-avatar-example",
null,
Preprocessors.preprocessResponse(new ContentModifyingOperationPreprocessor(new ContentModifier() {
@Override
public byte[] modifyContent(byte[] originalContent, MediaType contentType) {
return "<< IMAGE BODY HERE >>".getBytes(StandardCharsets.UTF_8);
}
}))));
这会生成一个 adoc
文件,如下所示:
[source,http,options="nowrap"]
----
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 15
Cache-Control: max-age=3600
<< IMAGE BODY HERE >>
----
我有一个生成随机图像的 REST 端点。我正在使用 Spring REST 文档,但响应在 http-response.adoc 文件中全是乱码。 Mock MVC 和 REST Docs 是否有一种简单的方法将文件存储在某个地方以便我的 .adoc 文件可以引用它?
不是完美但可行的解决方案:
class ImageSnippet implements Snippet {
private final String filePath;
public ImageSnippet(String filePath) {
this.filePath = filePath;
}
@Override
public void document(Operation operation) throws IOException {
byte[] picture = operation.getResponse().getContent();
Path path = Paths.get(filePath);
Files.deleteIfExists(path);
Files.createDirectories(path.getParent());
Files.createFile(path);
try (FileOutputStream fos = new FileOutputStream(path.toFile())) {
fos.write(picture);
}
}
}
以及MockMvc测试中的用法(图片文件夹路径很重要):
mockMvc.perform(get("/my-profile/barcode")
.accept(MediaType.IMAGE_PNG))
.andExpect(status().isOk())
.andDo(document("my-profile/barcode",
new ImageSnippet("build/asciidoc/html5/images/barcode.png")));
在 .adoc
模板中:
image::barcode.png[]
这是我的 build.gradle
Asciidoctor 配置(imagesdir
很重要):
asciidoctor {
dependsOn test
backends = ['html5']
options doctype: 'book'
attributes = [
'source-highlighter': 'highlightjs',
'imagesdir' : './images',
'toc' : 'left',
'toclevels' : 3,
'numbered' : '',
'icons' : 'font',
'setanchors' : '',
'idprefix' : '',
'idseparator' : '-',
'docinfo1' : '',
'safe-mode-unsafe' : '',
'allow-uri-read' : '',
'snippets' : snippetsDir,
linkattrs : true,
encoding : 'utf-8'
]
inputs.dir snippetsDir
outputDir 'build/asciidoc'
sourceDir 'src/docs/asciidoc'
sources {
include 'index.adoc'
}
}
您可以做的是实现一个自定义代码段来保存生成的响应。您可以使用您收到的操作的 RestDocumentationContext 属性来获取输出目录。
mockMvc.perform(get("/example"))
.andDo(document("some-example", operation -> {
var context = (RestDocumentationContext) operation.getAttributes().get(RestDocumentationContext.class.getName());
var path = Paths.get(context.getOutputDirectory().getAbsolutePath(), operation.getName(), "response-file.png");
Files.createDirectories(path.getParent());
Files.write(path, operation.getResponse().getContent());
}));
然而,这将在您的输出目录中创建一个 .png 文件,如果您在需要嵌入它的源目录中有 Asciidoc,这通常不是很有用。因此,您可以改为创建一个 Asciidoc 文件,其中包含图像标签的自定义 HTML,其源是响应的 base64 表示形式。
mockMvc.perform(get("/example"))
.andDo(document("some-example", operation -> {
var context = (RestDocumentationContext) operation.getAttributes().get(RestDocumentationContext.class.getName());
var path = Paths.get(context.getOutputDirectory().getAbsolutePath(), operation.getName(), "response-file.adoc");
var outputStream = new ByteArrayOutputStream();
outputStream.write("++++\n".getBytes());
outputStream.write("<img src=\"data:image/png;base64,".getBytes());
outputStream.write(Base64.getEncoder().encode(operation.getResponse().getContent()));
outputStream.write("\"/>\n".getBytes());
outputStream.write("++++\n".getBytes());
Files.createDirectories(path.getParent());
Files.write(path, outputStream.toByteArray());
}));
尽管 space 的开销有点大,但如果您使用它,则无需从源中引用构建文件。
如果您不 need/want 显示文档中的图像,另一种方法是:使用 ContentModifyingOperationPreprocessor
将字节替换为一些字符串,使文档的读者清楚响应中会有一些图像字节。
例如:
mockMvc.perform(get("/api/users/{id}/avatar", user.getId().asString())
.with(createCustomerAuth()))
.andExpect(status().isOk())
.andDo(document("get-user-avatar-example",
null,
Preprocessors.preprocessResponse(new ContentModifyingOperationPreprocessor(new ContentModifier() {
@Override
public byte[] modifyContent(byte[] originalContent, MediaType contentType) {
return "<< IMAGE BODY HERE >>".getBytes(StandardCharsets.UTF_8);
}
}))));
这会生成一个 adoc
文件,如下所示:
[source,http,options="nowrap"]
----
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 15
Cache-Control: max-age=3600
<< IMAGE BODY HERE >>
----