我们正在使用react.js MFE和Spring Boot微服务开发微服务应用程序
我有一个反应表单,其中有几个要填写的字段和要上传的 6 个文件,我将其发布到 Spring Boot Rest 控制器。
这是我们用来提交表单的 React 提交函数
const handleSubmit = (e) => {
e.preventDefault();
setErrorMessage(null);
setErrorMessageForiEMessaggi(null);
if (selectedFori.length == 0 || selectedMaterie.length == 0) {
setErrorMessageForiEMessaggi(
"Bisogna selezionare almeno un foro e una materia"
);
} else {
const data = new FormData();
//aggiungo i valori delle select
const formDataAggiornato = {
...formData,
ordine: selectedOrdine,
regioneSedeStudio: selectedRegioneSedeStudio,
provinciaSedeStudio: selectedProvinciaSedeStudio,
comuneSedeStudio: selectedComuneSedeStudio,
materia1: selectedMaterie.length >= 1 ? selectedMaterie[0] : null,
materia2: selectedMaterie.length >= 2 ? selectedMaterie[1] : null,
materia3: selectedMaterie.length == 3 ? selectedMaterie[2] : null,
foro1: selectedFori.length >= 1 ? selectedFori[0] : null,
foro2: selectedFori.length >= 2 ? selectedFori[1] : null,
foro3: selectedFori.length == 3 ? selectedFori[2] : null,
};
for (const [key, file] of Object.entries(prevFiles)) {
if (file) {
const newFileName = file?.name
? `${key}_${file.name}`
: `${key}_${file}`;
console.log("nome file", newFileName);
const renamedFile = new File([file], newFileName, {
type: file.type,
});
data.append(`files`, renamedFile);
}
}
data.append(`files`, prevFiles);
data.append("avvocato", JSON.stringify(formDataAggiornato));
const requestOptions = {
headers: { Authorization: `Bearer ${token}` },
method: "POST",
body: data,
};
// Effettua la richiesta POST utilizzando fetch
fetch(url + API_PATH, requestOptions).then((response) => {
if (response.ok) {
console.log(response);
//chiudo modale
toggleModal(!isOpen);
//svuoto domanda
setDomanda(null);
//ricarico lista domande
reloadListaDomande();
//stampo messaggio successo in TableDomanda
setSuccessMessageTable(
domanda?.id
? "Modifica avvenuta con successo!"
: "Elemento creato correttamente"
);
setErrorMessage(null);
setErrorMessageForiEMessaggi(null);
return response.json();
} else {
setErrorMessage(
"Errore durante il salvataggio dei dati, ricaricare la pagina"
);
console.log(response);
}
});
}
};
这是保存数据和文件的其余控制器
@Operation(summary = "salva l'avvocato", tags = {"Avvocati"})
@PreAuthorize("hasRole('userfo')")
@PostMapping(value = "", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
@ApiResponse(responseCode = "201")
public ResponseEntity<AvvocatoDto> salvaAvvocato(@RequestPart("avvocato") @Valid AvvocatoDto dto, @RequestPart(value = "files", required = false) List<MultipartFile> files) throws IOException, ForbiddenOpException {
提交表单时返回以下错误
2024-07-15 13:06:33.692 ERROR 1 --- [nio-8081-exec-5] c.c.a.exception.ExceptionsHandler : GENERIC ERROR : Content type 'application/octet-stream' not supported
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:211) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:140) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122) ~[spring-web-5.3.27.jar!/:5.3.27]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179) ~[spring-web-5.3.27.jar!/:5.3.27]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146) ~[spring-web-5.3.27.jar!/:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.27.jar!/:5.3.27]
我哪里做错了?
首先,在客户端,当您使用文件获取发布表单数据时,将设置
Content-Type
,如 multipart/form-data; boundary=----....
在 spring 端,您的请求将通过
resolveArgument
中的方法 org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver
解决,并且无法在第一个参数处将文本转换为 AvvocatoDto
。
解析器在尝试获取第一个参数的内容类型并设置为
null
(您在错误日志中看到)时收到 "application/octet-stream"
,之后没有转换器可以从 application/octet-stream
转换为 AvvocatoDto
类。更多详情请参阅AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters
您可以创建模型类来保存所有字段和文件,请参阅这篇文章
将第一个参数更改为字符串
@RequestPart("avvocato") String avvocatoStr
并手动反序列化和验证它。
希望有帮助。