Spring Boot 从控制器的 RequestMapping 返回 PNG
SprintBoot returning a PNG from a Controller's RequestMapping
我一直在互联网上搜索资源,我觉得我几乎找到了答案,但我似乎无法将 BufferedImage
返回到浏览器 window .
该项目生成一个迷宫,然后可以创建一个 BufferedImage
。
这是来自我的控制器的代码。
@RequestMapping(method = RequestMethod.GET, path = "/image", params = {"rows", "columns"})
public ResponseEntity<byte[]> image(@RequestParam(name = "rows") int rows, @RequestParam(name = "columns") int columns) throws IOException, InterruptedException {
try {
BasicCartesianGrid requestedMaze = new BasicCartesianGrid(rows, columns);
requestedMaze.forEach(CellAlgorithms.BINARY_TREE);
BufferedImage bufferedImage = requestedMaze.toDisplayImage();
{ // Dumping to file for debugging <- this works as expected
File outputFile = new File("save.png");
ImageIO.write(bufferedImage, "png", outputFile);
}
ByteArrayOutputStream pngByteStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", pngByteStream);
byte[] pngBytes = pngByteStream.toByteArray();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(pngBytes.length);
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
return new ResponseEntity<>(pngBytes, headers, HttpStatus.OK);
} catch (Exception e) {
// This hasn't occurred yet, but is for just in case
Thread.sleep(1000);
System.err.println(e.getLocalizedMessage());
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<>(e.getLocalizedMessage().getBytes("ASCII"), headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
我已经确定 PNG 生成正确,因为文件存在并且可以在我的 hard-drive 上查看。我的浏览器返回损坏的图像。从我的终端,我可以获得更多信息。
curl "http://localhost:8080/maze/image?rows=10&columns=10"
转储如下(引号是响应的一部分,而省略号表示的数据因请求而异,因为每个迷宫都是随机生成且唯一的):
"iVBORw0KGgoAAAANSUhEUgAAA......"
我用 google 搜索了这个字符串前缀,找到了 this page。这表明该字符串应用作 data-uri,如下所示:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA…" >
我不确定从这里到哪里去。似乎我的图像生成正确,但我在告诉 browser/spring 这些字节应被解释为图像而不仅仅是字符串的响应中必须缺少 header。
更新:
根据我和 Shawn Clark
在回答部分的对话,这是我目前的情况。
@SpringBootApplication
@Log4j
public class SpringMazesApplication {
@Bean
public HttpMessageConverter<BufferedImage> bufferedImageHttpMessageConverter() {
log.debug("Registering BufferedImage converter");
return new BufferedImageHttpMessageConverter();
}
public static void main(String[] args) throws IOException {
SpringApplication.run(SpringMazesApplication.class, args);
}
}
及实际控制人:
@Controller
@RequestMapping(path = "/maze/basic", method = RequestMethod.GET)
@Log4j
public class BasicMazeController {
@RequestMapping(params = {"format", "format=text"}, produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String simpleMazeText(@RequestParam(name = "rows", defaultValue = "10", required = false) int rows,
@RequestParam(name = "columns", defaultValue = "10", required = false) int columns) throws IOException {
BasicCartesianGrid requestedMaze = new BasicCartesianGrid(rows, columns);
requestedMaze.forEach(CellAlgorithms.BINARY_TREE);
return requestedMaze.toDisplayString();
}
@RequestMapping(params = {"format=image"}, produces = MediaType.IMAGE_PNG_VALUE)
@ResponseBody
public BufferedImage simpleMazeImage(@RequestParam(name = "rows", defaultValue = "10", required = false) int rows,
@RequestParam(name = "columns", defaultValue = "10", required = false) int columns) throws IOException {
log.debug("Starting image generation");
BasicCartesianGrid requestedMaze = new BasicCartesianGrid(rows, columns);
requestedMaze.forEach(CellAlgorithms.BINARY_TREE);
BufferedImage bufferedImage = requestedMaze.toDisplayImage();
{ // Dumping to file for debugging <- this works as expected
log.debug("Dumping image to hd");
File outputFile = new File("save.png");
ImageIO.write(bufferedImage, "png", outputFile);
}
log.debug("Returning from image generation");
return bufferedImage;
}
@RequestMapping
@ResponseBody
public ResponseEntity<String> simpleMazeInvalid(@RequestParam(name = "rows", defaultValue = "10", required = false) int rows,
@RequestParam(name = "columns", defaultValue = "10", required = false) int columns,
@RequestParam(name = "format") String format) throws IOException {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<>("Invalid format: " + format, headers, HttpStatus.BAD_REQUEST);
}
}
从我的终端我可以 curl -D - "url"
我可以看到 logging/debugging 和我终端的输出,转换器在应用程序开始时正确注册,我是从 returns 一个 406 Not Acceptable
的实际图像 uri 中得到你所期望的响应。如果我从图像方法中删除 @ResponseBody
,它只是 returns 一个 500
。我可以验证图像是否正确生成,因为它正在按照我的预期写入磁盘。
查看 @RequestMapping
上的 produces
属性。您可能希望将其设置为 image/png
.
这是一个完整的例子:
@RestController
public class ProduceImage {
@GetMapping(path = "/image", produces = "image/png")
public BufferedImage image() throws Exception {
BufferedImage bufferedImage = ImageIO.read(new File("E:\Downloads\skin_201305121633211421.png"));
return bufferedImage;
}
}
我的 BufferedImage 来自我的计算机,但它可以很容易地成为您从 requestedMaze.toDisplayImage()
获得的 BufferedImage,而无需执行所有其他工作。要完成这项工作,您需要在上下文中包含 BufferedImageHttpMessageConverter
。
@Bean
public HttpMessageConverter<BufferedImage> bufferedImageHttpMessageConverter() {
return new BufferedImageHttpMessageConverter();
}
我一直在互联网上搜索资源,我觉得我几乎找到了答案,但我似乎无法将 BufferedImage
返回到浏览器 window .
该项目生成一个迷宫,然后可以创建一个 BufferedImage
。
这是来自我的控制器的代码。
@RequestMapping(method = RequestMethod.GET, path = "/image", params = {"rows", "columns"})
public ResponseEntity<byte[]> image(@RequestParam(name = "rows") int rows, @RequestParam(name = "columns") int columns) throws IOException, InterruptedException {
try {
BasicCartesianGrid requestedMaze = new BasicCartesianGrid(rows, columns);
requestedMaze.forEach(CellAlgorithms.BINARY_TREE);
BufferedImage bufferedImage = requestedMaze.toDisplayImage();
{ // Dumping to file for debugging <- this works as expected
File outputFile = new File("save.png");
ImageIO.write(bufferedImage, "png", outputFile);
}
ByteArrayOutputStream pngByteStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", pngByteStream);
byte[] pngBytes = pngByteStream.toByteArray();
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(pngBytes.length);
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
return new ResponseEntity<>(pngBytes, headers, HttpStatus.OK);
} catch (Exception e) {
// This hasn't occurred yet, but is for just in case
Thread.sleep(1000);
System.err.println(e.getLocalizedMessage());
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<>(e.getLocalizedMessage().getBytes("ASCII"), headers, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
我已经确定 PNG 生成正确,因为文件存在并且可以在我的 hard-drive 上查看。我的浏览器返回损坏的图像。从我的终端,我可以获得更多信息。
curl "http://localhost:8080/maze/image?rows=10&columns=10"
转储如下(引号是响应的一部分,而省略号表示的数据因请求而异,因为每个迷宫都是随机生成且唯一的):
"iVBORw0KGgoAAAANSUhEUgAAA......"
我用 google 搜索了这个字符串前缀,找到了 this page。这表明该字符串应用作 data-uri,如下所示:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA…" >
我不确定从这里到哪里去。似乎我的图像生成正确,但我在告诉 browser/spring 这些字节应被解释为图像而不仅仅是字符串的响应中必须缺少 header。
更新:
根据我和 Shawn Clark
在回答部分的对话,这是我目前的情况。
@SpringBootApplication
@Log4j
public class SpringMazesApplication {
@Bean
public HttpMessageConverter<BufferedImage> bufferedImageHttpMessageConverter() {
log.debug("Registering BufferedImage converter");
return new BufferedImageHttpMessageConverter();
}
public static void main(String[] args) throws IOException {
SpringApplication.run(SpringMazesApplication.class, args);
}
}
及实际控制人:
@Controller
@RequestMapping(path = "/maze/basic", method = RequestMethod.GET)
@Log4j
public class BasicMazeController {
@RequestMapping(params = {"format", "format=text"}, produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String simpleMazeText(@RequestParam(name = "rows", defaultValue = "10", required = false) int rows,
@RequestParam(name = "columns", defaultValue = "10", required = false) int columns) throws IOException {
BasicCartesianGrid requestedMaze = new BasicCartesianGrid(rows, columns);
requestedMaze.forEach(CellAlgorithms.BINARY_TREE);
return requestedMaze.toDisplayString();
}
@RequestMapping(params = {"format=image"}, produces = MediaType.IMAGE_PNG_VALUE)
@ResponseBody
public BufferedImage simpleMazeImage(@RequestParam(name = "rows", defaultValue = "10", required = false) int rows,
@RequestParam(name = "columns", defaultValue = "10", required = false) int columns) throws IOException {
log.debug("Starting image generation");
BasicCartesianGrid requestedMaze = new BasicCartesianGrid(rows, columns);
requestedMaze.forEach(CellAlgorithms.BINARY_TREE);
BufferedImage bufferedImage = requestedMaze.toDisplayImage();
{ // Dumping to file for debugging <- this works as expected
log.debug("Dumping image to hd");
File outputFile = new File("save.png");
ImageIO.write(bufferedImage, "png", outputFile);
}
log.debug("Returning from image generation");
return bufferedImage;
}
@RequestMapping
@ResponseBody
public ResponseEntity<String> simpleMazeInvalid(@RequestParam(name = "rows", defaultValue = "10", required = false) int rows,
@RequestParam(name = "columns", defaultValue = "10", required = false) int columns,
@RequestParam(name = "format") String format) throws IOException {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<>("Invalid format: " + format, headers, HttpStatus.BAD_REQUEST);
}
}
从我的终端我可以 curl -D - "url"
我可以看到 logging/debugging 和我终端的输出,转换器在应用程序开始时正确注册,我是从 returns 一个 406 Not Acceptable
的实际图像 uri 中得到你所期望的响应。如果我从图像方法中删除 @ResponseBody
,它只是 returns 一个 500
。我可以验证图像是否正确生成,因为它正在按照我的预期写入磁盘。
查看 @RequestMapping
上的 produces
属性。您可能希望将其设置为 image/png
.
这是一个完整的例子:
@RestController
public class ProduceImage {
@GetMapping(path = "/image", produces = "image/png")
public BufferedImage image() throws Exception {
BufferedImage bufferedImage = ImageIO.read(new File("E:\Downloads\skin_201305121633211421.png"));
return bufferedImage;
}
}
我的 BufferedImage 来自我的计算机,但它可以很容易地成为您从 requestedMaze.toDisplayImage()
获得的 BufferedImage,而无需执行所有其他工作。要完成这项工作,您需要在上下文中包含 BufferedImageHttpMessageConverter
。
@Bean
public HttpMessageConverter<BufferedImage> bufferedImageHttpMessageConverter() {
return new BufferedImageHttpMessageConverter();
}