日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java servlet 返回图片_SpringMVC返回图片的几种方式

發布時間:2025/4/5 javascript 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java servlet 返回图片_SpringMVC返回图片的几种方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

SpringMVC返回圖片的幾種方式

后端提供服務,通常返回的json串,但是某些場景下可能需要直接返回二進制流,如一個圖片編輯接口,希望直接將圖片流返回給前端,此時可以怎么處理?

I. 返回二進制圖片

主要借助的是 HttpServletResponse這個對象,實現case如下

@RequestMapping(value = {"/img/render"}, method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})

@CrossOrigin(origins = "*")

@ResponseBody

public String execute(HttpServletRequest httpServletRequest,

HttpServletResponse httpServletResponse) {

// img為圖片的二進制流

byte[] img = xxx;

httpServletResponse.setContentType("image/png");

OutputStream os = httpServletResponse.getOutputStream();

os.write(img);

os.flush();

os.close();

return "success";

}

注意事項

注意ContentType定義了圖片類型

將二進制寫入 httpServletResponse#getOutputStream

寫完之后,flush(), close()請務必執行一次

II. 返回圖片的幾種方式封裝

一般來說,一個后端提供的服務接口,往往是返回json數據的居多,前面提到了直接返回圖片的場景,那么常見的返回圖片有哪些方式呢?

返回圖片的http地址

返回base64格式的圖片

直接返回二進制的圖片

其他...(我就見過上面三種,別的還真不知道)

那么我們提供的一個Controller,應該如何同時支持上面這三種使用姿勢呢?

1. bean定義

因為有幾種不同的返回方式,至于該選擇哪一個,當然是由前端來指定了,所以,可以定義一個請求參數的bean對象

@Data

public class BaseRequest {

private static final long serialVersionUID = 1146303518394712013L;

/**

* 輸出圖片方式:

*

* url : http地址 (默認方式)

* base64 : base64編碼

* stream : 直接返回圖片

*

*/

private String outType;

/**

* 返回圖片的類型

* jpg | png | webp | gif

*/

private String mediaType;

public ReturnTypeEnum returnType() {

return ReturnTypeEnum.getEnum(outType);

}

public MediaTypeEnum mediaType() {

return MediaTypeEnum.getEnum(mediaType);

}

}

為了簡化判斷,定義了兩個注解,一個ReturnTypeEnum, 一個 MediaTypeEnum, 當然必要性不是特別大,下面是兩者的定義

public enum ReturnTypeEnum {

URL("url"),

STREAM("stream"),

BASE64("base");

private String type;

ReturnTypeEnum(String type) {

this.type = type;

}

private static Map map;

static {

map = new HashMap<>(3);

for(ReturnTypeEnum e: ReturnTypeEnum.values()) {

map.put(e.type, e);

}

}

public static ReturnTypeEnum getEnum(String type) {

if (type == null) {

return URL;

}

ReturnTypeEnum e = map.get(type.toLowerCase());

return e == null ? URL : e;

}

}

@Data

public enum MediaTypeEnum {

ImageJpg("jpg", "image/jpeg", "FFD8FF"),

ImageGif("gif", "image/gif", "47494638"),

ImagePng("png", "image/png", "89504E47"),

ImageWebp("webp", "image/webp", "52494646"),

private final String ext;

private final String mime;

private final String magic;

MediaTypeEnum(String ext, String mime, String magic) {

this.ext = ext;

this.mime = mime;

this.magic = magic;

}

private static Map map;

static {

map = new HashMap<>(4);

for (MediaTypeEnum e: values()) {

map.put(e.getExt(), e);

}

}

public static MediaTypeEnum getEnum(String type) {

if (type == null) {

return ImageJpg;

}

MediaTypeEnum e = map.get(type.toLowerCase());

return e == null ? ImageJpg : e;

}

}

上面是請求參數封裝的bean,返回當然也有一個對應的bean

@Data

public class BaseResponse {

/**

* 返回圖片的相對路徑

*/

private String path;

/**

* 返回圖片的https格式

*/

private String url;

/**

* base64格式的圖片

*/

private String base;

}

說明:

實際的項目環境中,請求參數和返回肯定不會像上面這么簡單,所以可以通過繼承上面的bean或者自己定義對應的格式來實現

2. 返回的封裝方式

既然目標明確,封裝可算是這個里面最清晰的一個步驟了

protected void buildResponse(BaseRequest request,

BaseResponse response,

byte[] bytes) throws SelfError {

switch (request.returnType()) {

case URL:

upload(bytes, response);

break;

case BASE64:

base64(bytes, response);

break;

case STREAM:

stream(bytes, request);

}

}

private void upload(byte[] bytes, BaseResponse response) throws SelfError {

try {

// 上傳到圖片服務器,根據各自的實際情況進行替換

String path = UploadUtil.upload(bytes);

if (StringUtils.isBlank(path)) { // 上傳失敗

throw new InternalError(null);

}

response.setPath(path);

response.setUrl(CdnUtil.img(path));

} catch (IOException e) { // cdn異常

log.error("upload to cdn error! e:{}", e);

throw new CDNUploadError(e.getMessage());

}

}

// 返回base64

private void base64(byte[] bytes, BaseResponse response) {

String base = Base64.getEncoder().encodeToString(bytes);

response.setBase(base);

}

// 返回二進制圖片

private void stream(byte[] bytes, BaseRequest request) throws SelfError {

try {

MediaTypeEnum mediaType = request.mediaType();

HttpServletResponse servletResponse = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();

servletResponse.setContentType(mediaType.getMime());

OutputStream os = servletResponse.getOutputStream();

os.write(bytes);

os.flush();

os.close();

} catch (Exception e) {

log.error("general return stream img error! req: {}, e:{}", request, e);

if (StringUtils.isNotBlank(e.getMessage())) {

throw new InternalError(e.getMessage());

} else {

throw new InternalError(null);

}

}

}

說明:

請無視上面的幾個自定義異常方式,需要使用時,完全可以干掉這些自定義異常即可;這里簡單說一下,為什么會在實際項目中使用這種自定義異常的方式,主要是有以下幾個優點

配合全局異常捕獲(ControllerAdvie),使用起來非常方便簡單

所有的異常集中處理,方便信息統計和報警 如,在統一的地方進行異常計數,然后超過某個閥值之后,報警給負責人,這樣就不需要在每個出現異常case的地方來主動埋點了

避免錯誤狀態碼的層層傳遞 - 這個主要針對web服務,一般是在返回的json串中,會包含對應的錯誤狀態碼,錯誤信息

- 而異常case是可能出現在任何地方的,為了保持這個異常信息,要么將這些數據層層傳遞到controller;要么就是存在ThreadLocal中;顯然這兩種方式都沒有拋異常的使用方便

有優點當然就有缺點了:

異常方式,額外的性能開銷,所以在自定義異常中,我都覆蓋了下面這個方法,不要完整的堆棧 @Override

public synchronized Throwable fillInStackTrace() {

return this;

}

編碼習慣問題,有些人可能就非常不喜歡這種使用方式

III. 項目相關

只說不練好像沒什么意思,上面的這個設計,完全體現在了我一直維護的開源項目 Quick-Media中,當然實際和上面有一些不同,畢竟與業務相關較大,有興趣的可以參考

BaseAction: com.hust.hui.quickmedia.web.wxapi.WxBaseAction#buildReturn

IV. 其他

聲明

盡信書則不如,已上內容,純屬一家之言,因本人能力一般,見解不全,如有問題,歡迎批評指正

掃描關注,java分享

總結

以上是生活随笔為你收集整理的java servlet 返回图片_SpringMVC返回图片的几种方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。