es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo subir un JSON que incluye un archivo de imagen a una API Rest de Spring Boot.

Actualmente estoy utilizando la API fetch para enviar un objeto JSON a una API REST creada con Spring Boot. Estoy utilizando formData para leer los datos del formulario y almacenarlos en un objeto JSON:

const data = new FormData(form);
const formJson = Object.fromEntries(data.entries());
let responsePromise = await fetch(
    "http://localhost:8080/api/v1/student?id=" + studentId, {
      method: 'PUT',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(formJson)
    });

El backend de Spring Boot espera un JSON que corresponda a la clase de entidad “Student”, que finalmente se almacenará en mi base de datos:

@PutMapping
public ResponseEntity<student> updateStudent(@RequestBody Student student, @RequestParam Long id) {
    Student currentDatabaseEntry = studentService.getStudent(id);
    currentDatabaseEntry.setFirstName(student.getFirstName());

    ...

    return new ResponseEntity<>(currentDatabaseEntry , HttpStatus.FOUND);
}

Esto funciona bien.

Ahora, he agregado una variable a la entidad “Student” que es de tipo “byte[]” y se supone que almacena una imagen del estudiante. Entonces, quiero agregar una entrada a mi objeto JSON con la clave “image” y el valor siendo un archivo multiparte (el valor de un campo de entrada de tipo “file”).

Según lo que he leído en Internet, parece que cuando quiero subir un archivo no debo subir un JSON, sino el objeto formData. Sin embargo, no logro entender cómo manejar esta solicitud en mi backend. ¿No espera Spring Boot que el parámetro “@RequestBody” de la solicitud PUT sea un JSON que se parezca a mi entidad “Student”?

De todos modos, ¿alguien sabe cómo lograr esto?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para agregar un archivo a tu objeto FormData, puedes utilizar el método append():

    const data = new FormData(form);
    const formJson = Object.fromEntries(data.entries());
    const imageFile = document.getElementById('image').files[0]; // obtener el objeto File del campo de entrada
    data.append('image', imageFile); // agregar el archivo al objeto FormData
    let responsePromise = await fetch(
            "http://localhost:8080/api/v1/student?id=" + studentId, {
              method: 'PUT',
              body: data
            });
    

    En el lado de Spring Boot, puedes utilizar la anotación @RequestParam para obtener el archivo de la solicitud multipart:

    @PutMapping
    public ResponseEntity<student> updateStudent(@RequestParam("image") MultipartFile imageFile,
                                                   @RequestParam("student") String studentJson,
                                                   @RequestParam("id") Long id) {
        ObjectMapper objectMapper = new ObjectMapper();
        Student student;
        try {
            student = objectMapper.readValue(studentJson, Student.class);
        } catch (IOException e) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }
        Student currentDatabaseEntry = studentService.getStudent(id);
    
        currentDatabaseEntry.setFirstName(student.getFirstName());
    
        ...
    
        if (!imageFile.isEmpty()) {
            byte[] imageBytes;
            try {
                imageBytes = imageFile.getBytes();
            } catch (IOException e) {
                return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
            }
            currentDatabaseEntry.setImage(imageBytes);
        }
    
        studentService.saveStudent(currentDatabaseEntry);
    
        return new ResponseEntity<>(currentDatabaseEntry, HttpStatus.OK);
    }
    

    En el código de ejemplo anterior, el objeto Student se pasa como un parámetro de cadena separado (en formato JSON) y el archivo de imagen se pasa como un parámetro MultipartFile separado con un nombre personalizado (image). Esto te permite manejar tanto datos JSON como archivos en la misma solicitud.

Comments are closed.