Fala Renato, tudo bem ?
Imagino que você vai enviar a requisição para uma app Spring Boot, seja de um navegador, ou de uma app qualquer. Se for isso imagino que teria duas opções. A primeira delas é fazer uma requisição com Content-type multipart (ao invés de application/json) e enviar o json como um simples conteúdo textual de um campo.
Exemplo:
Controller esperando receber um conteudo String (json) e um MultipartFile, pra poder contar com as facilidades do Spring MVC pra esse arquivo, por exemplo, salvar localmente com foto.transferTo(new File(...))
, etc, etc.
@RestController
public class TesteController {
@RequestMapping(method=RequestMethod.POST, value="/send")
public ResponseEntity<String> receiveData(String pessoaJson, MultipartFile foto) {
ObjectMapper mapper = new ObjectMapper();
PessoaDto pessoa = null;
try {
pessoa = mapper.readValue(pessoaJson, PessoaDto.class);
} catch (IOException e) {
return ResponseEntity.badRequest().body("Não foi possível ler o json");
}
System.out.println(pessoa);
System.out.println(foto.getOriginalFilename());
return ResponseEntity.ok("Deu certo!");
}
}
Pagina qualquer com script montando a requisição do tipo multipart e colocando a foto selecionada, mais o conteúdo json a partir de dados preenchidos por um usuário.
<!DOCTYPE html>
...
<script type="text/javascript">
function sendData() {
var pessoa = {
nome: document.querySelector('#nome').value,
idade: document.querySelector('#idade').value
};
var foto = document.querySelector('#imagePicker').files[0];
var formData = new FormData();
formData.append("pessoaJson", JSON.stringify(pessoa));
formData.append("foto", foto);
fetch('http://localhost:8080/send', {
method: 'POST',
body: formData
})
.then(response => {
if(!response.ok)
throw new Error("não foi possível completar cadastro");
return response.text();
})
.then(data => alert(data));
}
</script>
...
<body>
<label for="nome">Nome:</label>
<input type="text" id="nome"/>
<label for="idade">Idade:</label>
<input type="text" id="idade"/>
<label for="imagePicker">Foto:</label>
<input type="file" id="imagePicker" />
<input type="button" onclick="sendData()" value="Enviar" />
</body>
...
O inconveniente dessa abordagem é que você não vai conseguir fazer o Spring montar a partir do json o objeto que representa Pessoa, dado que o content-type da request é diferente. Você vai precisar escrever o código que pega a informação que veio no campo e converter usando alguma lib json (no exemplo a Jackson Json) para o seu objeto. Você pode fazer isso tanto no controller, quanto criar um converter String <-> PessoaDto pra facilitar o código do controller.
Uma questão que gostaria de abrir é: Será que precisa mesmo que seja um json que venha junto com a foto ? Dado que, pra aproveitar o upload precisamos montar um request multipart (através do FormData), porque não montar esse objeto normalmente, campo a campo, como num simples formulário ?
Dessa forma ficaria assim:
<!-- conteudo omitido -->
<script type="text/javascript">
function sendData() {
var formData = new FormData();
formData.append("nome", document.querySelector('#nome').value);
formData.append("idade", document.querySelector('#idade').value);
formData.append("foto", document.querySelector('#imagePicker').files[0]);
fetch('http://localhost:8080/send', {
method: 'POST',
body: formData
})
.then(response => {
if(!response.ok)
throw new Error("não foi possível completar cadastro");
return response.text();
})
.then(data => alert(data));
}
</script>
Controller recebendo direto o conteúdo do formData, sendo possível já fazer o binding pro seu objeto
@RequestMapping(method=RequestMethod.POST, value="/send")
public ResponseEntity<String> receiveData(PessoaDto pessoaDto, MultipartFile foto) {
System.out.println(pessoaDto);
System.out.println(foto.getOriginalFilename());
// salva -> foto.transferTo(new File("caminhoDoArquivo"))
// ou manda para um serviço de storage -> String urlFoto = s3.save(foto.getInputStream())
// monta seu objeto de domínio -> new Pessoa(nome, idade, urlFoto)
// segue a vida -> salva num banco .. etc, etc
return ResponseEntity.ok("Deu certo!");
}
Olha como tudo fica muito mais fácil. Acho que isso pode ajudar.