前言
最近在實現小圖片上傳的過程中剛開始我使用base64字符串做為後台接口參數傳遞給後台並解析保存也沒問題,但是發現第2次及之後就報下面的錯:
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
然後問了AI給的回覆如下:
這個問題通常是由於 Spring Boot 默認的 DataBuffer 限制導致的,默認限制為 256 KB。當你傳遞大於這個大小的 Base64 字符串時,就會出現 DataBufferLimitException。
那沒辦法,所以我只能退一步使用上傳File來實現了,以為自己可以減少工作量,唉,乖乖實現吧!
但是有個問題就是我不僅要上傳文件,還要攜帶參數,之前沒有這樣的需求,如何做呢?
操作
問了AI,下面是實現前端代碼,如下所示:
antd代碼:
const props2 = {
// 不顯示上傳文件列表
showUploadList: false,
// name: 'file',
accept: "image/png, image/jpeg",
multiple: false,
maxCount: 1,
beforeUpload: async (file) => {
console.log('file=>', file)
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('二維碼上傳文件不能大於2MB!');
}
setDlg({
type: 'saveAndRead',
title: '保存到我的文件',
show: true,
// 使用marked把markdown格式轉換成html格式供ckeditor富文本編輯器使用
data: {
name: '',
file: file
},
onSuccess: async (d) => {
console.log('success d=', d)
if (d?.text){
message.success("解析成功")
setParsingQrcode2(d.text)
}else{
message.error("解析失敗")
}
}
})
return false;
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
},
};
<Dragger {...props2}>
<div className={'flex w-full flex-col'}>
<p className="ant-upload-drag-icon">
<UploadOutlined/>
</p>
<p className="ant-upload-text">單擊或將文件拖動到此區域以上傳</p>
<p className="ant-upload-text">(提示:先上傳到我的文件再解析)</p>
</div>
</Dragger>
請求接口代碼:
try {
const formData = new FormData();
formData.append('file', params.file);
formData.append('categoryId', params.categoryId);
formData.append('fileName', params.fileName);
const res = await axios.post(`/space/crud/file/addFileForQrcodeAndRead`, formData);
return res.data
} catch (error) {
return thunkAPI.rejectWithValue({errorMsg: error.message});
}
後台實現:
@PostMapping("/crud/file/addFileForQrcodeAndRead")
public Mono<ResponseEntity<?>> addFileForQrcodeAndRead(@RequestPart("file") Mono<FilePart> file,
@RequestPart("categoryId") String cid,
@RequestPart("fileName") String filename) throws IOException {
LoginUser loginUser = UserContext.getUser();
if (loginUser == null) {
return Mono.just(ResponseEntity.ok(HttpStatus.UNAUTHORIZED));
}
if (!StringUtils.hasLength(cid) || !StringUtils.hasLength(filename)) {
return Mono.just(ResponseEntity.ok(new ResultInfo<>(ResultStatus.DATA_EMPTY)));
}
return file.flatMap(fp -> {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
return fp.content().collectList().flatMap(dataBuffers -> {
try {
dataBuffers.forEach(buffer -> {
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
baos.write(bytes, 0, bytes.length);
});
byte[] bytes = baos.toByteArray();
Long size = (long) bytes.length;
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
BufferedImage bufferedImage = ImageIO.read(inputStream);
BufferedImage bufferedImage2 = addBorder(bufferedImage, 20);
LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage2);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result = new MultiFormatReader().decode(bitmap);
// 注意:重置指針,方便第2次讀取,否則下面獲取不到inputStream
inputStream.reset();
// 是否能檢測到數據,不能檢測數據就添加不成功
if (StringUtils.hasLength(result.getText())) {
}
// 如何二維碼解析出來了,但是添加和上傳圖片失敗,那也返回解析結果
return Mono.just(ResponseEntity.ok(new ResultSuccess<>(result)));
} catch (Exception ex) {
log.info("uploadFileAndRead ex={}", ex.getMessage());
return Mono.just(ResponseEntity.ok(new ResultInfo<>(ResultStatus.Exception)));
}
});
});
這樣就完成了上傳文件並且攜帶參數了。
總結
1、Base64做為參數傳遞到後台會導致參數大小超過限制,因此使用File上傳。
2、後台接收的時候要統一使用RequestPart,剛開始我使用了下面的代碼就出問題了(AI給的代碼):
public ResponseEntity<?> uploadFileAndRead(
@RequestPart("upload") MultipartFile file,
@RequestParam("additionalParam1") String param1,
@RequestParam("additionalParam2") String param2)
3、文件流inputStream讀取之後再次使用就會拿不到,解決辦法:
inputStream.reset();
AI的回答是這樣的:
ByteArrayInputStream 的數據流被讀取一次後,無法再次讀取,因為 ByteArrayInputStream 的內部指針已經到達了流的末尾。
要解決這個問題,可以在讀取流數據後重置 ByteArrayInputStream,或者在需要重新使用時重新創建 ByteArrayInputStream。