前言
最近在实现小图片上传的过程中刚开始我使用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。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。