Springboot actual combat code: [How to return pictures gracefully]
This article will summarize the common methods for returning pictures:
- Streaming return: mainly because the implementation is different, based on response and HttpConvertMessage
- base64 returns
Explanation
The picture can come from many places, it can be a local folder, it can also be a network stream, or a database binary, here for simplicity, local files are used.
@RestController
@RequestMapping("/")
public class ImgController {
private String imgPath = "E:\\meme.png";
private InputStream getImgInputStream() throws FileNotFoundException {
return new FileInputStream(new File(imgPath));
}
rely
The IOUtils used below should be familiar to everyone, from the classic common-io module
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
1. Return based on response
Very basic and simple way:
import org.apache.commons.io.IOUtils;
import org.springframework.http.MediaType;
/**
* 使用response输出图片流
*/
@GetMapping("/img-response")
public void getImage(HttpServletResponse resp) throws IOException {
final InputStream in = getImgInputStream();
resp.setContentType(MediaType.IMAGE_PNG_VALUE);
IOUtils.copy(in, resp.getOutputStream());
}
2. Return byte stream based on producers
2.1 Returning raw byte stream
Let's first see what happens if the byte stream directly returns the picture:
/**
* 试试直接返回字节流,不指定content-type
*/
@GetMapping(value = "/img-byte")
public byte[] getImageByte() throws IOException {
final InputStream in = getImgInputStream();
return IOUtils.toByteArray(in);
}
The result is as follows: garbled, because the content-type is wrong
2.2 Specify content-type to return byte stream
Use producers to specify types: here we specify 2 types and see what happens
@GetMapping(value = "/img-media-type",
produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
public byte[] getImage() throws IOException {
final InputStream in = getImgInputStream();
return IOUtils.toByteArray(in);
}
The picture can be returned normally, but a closer look, the reason in the response header content-type
is image/jpeg
that when we request by default, springboot matches the first type of jpeg, although we are a png picture.
So how do we make it return content-type image/png
?
By reading the source code comments, we know that we
only need to pass the place we want when we request it Accept
. The following is an example of postman:
In fact, this method can also be used on the /img-byte
interface above , and it will not return garbled characters.
At the same time, if we pass an unsupported type, we will get 406
an error:
2.3 Download image files directly
If we want to directly pop up the download box, we can specify the content-type as:application/octet-stream
@GetMapping(value = "/img-file.png",
produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE})
public byte[] getImageFile() throws IOException {
final InputStream in = getImgInputStream();
return IOUtils.toByteArray(in);
}
@GetMapping(value = "/img/{iconId}", produces = {MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_JPEG_VALUE})
public byte[] getImage(@PathVariable String iconId) throws IOException {
final GisIcon icon = iconService.getById(iconId);
if (icon == null) {
throw new IllegalArgumentException("不存在此图片");
}
final FileInputStream fio = new FileInputStream(new File(iconService.getSavePath(icon.getUsername(),
icon.getName(), icon.getId())));
byte[] bytes = new byte[fio.available()];
log.info("读取文件结果:{}", fio.read(bytes, 0, fio.available()));
return bytes;
}
3. base64 picture
import java.util.Base64;
@GetMapping("/img-base64")
public String getBase64Img() throws IOException {
final byte[] bytes = IOUtils.toByteArray(getImgInputStream());
return Base64.getEncoder().encodeToString(bytes);
}
Front-end reception:
function reqListener (base64) {
var body = document.getElementsByTagName("body");
var img = document.createElement("img");
img.src = "data:image/png;base64, "+base64;
body.appendChild(img);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://localhost:8013/img-base64");
oReq.send();