Quarkus中存储MultipartFormDataInput文件后重新转发的问题
解决Quarkus中Multipart文件存储后转发的二进制内容输出问题
你遇到的核心问题是:Quarkus的REST框架默认会把byte[]的toString()结果(比如[[B@dbe8688)输出到Multipart响应中,而不是把byte数组作为二进制流写入。以下是几种可行的解决方案:
方案一:改用InputStream作为Multipart Part的类型
将存储的byte[]转换为ByteArrayInputStream,框架会自动读取流内容并输出二进制数据:
- 修改
MyFiles类:
@MultipartForm public class MyFiles { @FormParam("files") @PartType(MediaType.APPLICATION_OCTET_STREAM) public List<InputStream> files; public MyFiles(List<InputStream> files) { this.files = files; } public MyFiles() { files = new ArrayList<>(); } public void add(byte[] fileBytes) { files.add(new ByteArrayInputStream(fileBytes)); } }
- 调整发送文件的方法:
@GET @Produces(MediaType.MULTIPART_FORM_DATA) public MyFiles sendStoredFiles() throws IOException { MyFiles myFiles = new MyFiles(); // 遍历从数据库获取的byte[]列表,逐个转成InputStream添加 for (byte[] fileBytes : getByteArrayFromDataSource()) { myFiles.add(fileBytes); } return myFiles; }
方案二:自定义MessageBodyWriter处理byte[]序列化
如果必须保留byte[]类型,可以自定义消息体写入器,强制框架将byte数组作为二进制流输出:
@Provider @Produces(MediaType.APPLICATION_OCTET_STREAM) public class ByteArrayBodyWriter implements MessageBodyWriter<byte[]> { @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return byte[].class.isAssignableFrom(type); } @Override public void writeTo(byte[] bytes, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { entityStream.write(bytes); } }
将这个类放在Quarkus能扫描到的包下(比如应用根包),框架会自动使用它来处理byte[]类型的Multipart Part,输出正确的二进制内容。
优化建议:保留文件元数据
实际场景中,转发文件时最好保留原始的文件名、Content-Type等元数据,让接收方更易处理。可以创建一个元数据类存储这些信息:
public class FileMetadata { private String filename; private String contentType; private byte[] content; // 构造方法、Getter和Setter public FileMetadata(String filename, String contentType, byte[] content) { this.filename = filename; this.contentType = contentType; this.content = content; } // 省略Getter、Setter }
读取Multipart时获取元数据:
public FileMetadata getFileMetadata(MultipartFormDataInput input) { Map<String, List<InputPart>> uploadForm = input.getFormDataMap(); List<InputPart> inputParts = uploadForm.get("files"); if (inputParts == null || inputParts.isEmpty()) return null; InputPart part = inputParts.get(0); // 解析文件名 String disposition = part.getHeaders().getFirst("Content-Disposition"); String filename = disposition.split("filename=")[1].replace("\"", ""); // 获取Content-Type String contentType = part.getHeaders().getFirst("Content-Type"); try { byte[] content = IOUtils.toByteArray(part.getBody(InputStream.class, null)); return new FileMetadata(filename, contentType, content); } catch (IOException e) { e.printStackTrace(); return null; } }
转发时手动构建规范的Multipart响应:
@GET @Produces(MediaType.MULTIPART_FORM_DATA) public Response sendStoredFiles() throws IOException { List<FileMetadata> fileMetadatas = getFileMetadatasFromDataSource(); FormDataMultiPart multiPart = new FormDataMultiPart(); for (FileMetadata metadata : fileMetadatas) { ByteArrayInputStream inputStream = new ByteArrayInputStream(metadata.getContent()); // 创建带元数据的Part FormDataBodyPart part = new FormDataBodyPart("files", inputStream, MediaType.valueOf(metadata.getContentType())); part.setContentDisposition(FormDataContentDisposition.name("files") .filename(metadata.getFilename()).build()); multiPart.bodyPart(part); } return Response.ok(multiPart).build(); }
内容的提问来源于stack exchange,提问作者user19906023
相关产品推荐
相关产品推荐

