0
votes

I am very new in Java Spring and have a problem where I can not figure out what am I missing.

For the shake of brevity I will make it short:

  • I have a controller class with two methods for @GetMapping (get info from a patient in database) and @PostMapping (upload a photo from that patient).
  • In both methods, at some point I am calling through "findById" to database and populating a "Patient" model class object.
  • All the attributes of this class are retrieved successfully from Database but there is an attribute of this class (getPhoto()) that gets a null value only in the @PostMapping method.
  • What am I missing? The code is just the same in both methods.

Thanks very much in advance!!

Controller:

@CrossOrigin(origins="http://localhost:4200", maxAge = 3600)
@RestController
@RequestMapping({"/patients"})
public class PatientController {

    @Autowired
    IPatientService patientService;


    @GetMapping("/{id}")
    public ResponseEntity<?> listPatientId(@PathVariable("id") Integer id){

        Optional<Patient> patient=null;
        Map<String, Object> response=new HashMap<>();

        try{
            patient=patientService.findById(id);
        }catch(DataAccessException e){
            response.put("error", e.getMessage().concat(": "+e.getMostSpecificCause().toString()));
            new ResponseEntity<Map<String, Object>>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        System.out.println("Patient with id: "+id+" / "+patient.get().getId()+" which photo is: "+patient.get().getPhoto());

        /*Some other code*/
    }

    @PostMapping("/upload")
    public ResponseEntity<?> upload(@RequestParam("archive")MultipartFile archive, @RequestParam("id") Integer id){

        Optional<Paciente> paciente = Optional.empty();
        Map<String, Object> respuesta= new HashMap<>();

        try{
            patient=patientService.findById(id);
        }catch(DataAccessException e){
            response.put("error", e.getMessage().concat(": "+e.getMostSpecificCause().toString()));
            new ResponseEntity<Map<String, Object>>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        System.out.println("Patient with id: "+id+" / "+patient.get().getId()+" which photo is: "+patient.get().getPhoto());

        /*Some other code*/

    }
}

Patient class:

@Entity
@Table(name = "patients")
public class Patient {
    @Id
    @Column
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String photo;

    (Getters and setters)
}

Repository:

@Repository
public interface PatientRepository extends JpaRepository<Patient, Integer> {

    Iterable<Patient> findByNameContainingOrSurnameContaining(String name, String surname);

}

Service (Interface and Implemantation):

public interface IPatientService {

    public List<Patient> findAll();

    public Optional<Patient> findById(Integer id);

    public Iterable<Patient> findByNameContainingOrSurnameContaining(String term);

 }



@Service
public class PatientServiceImpl implements IPatientService {

    @Autowired
    private PatientRepository patientDao; 


    @Override
    @Transactional(readOnly = true)
    public List<Patient> findAll() {
        return patientDao.findAll();
    }


    @Override
    public Optional<Patient> findById(Integer id) {
        return patienteDao.findById(id);
    }

    public Iterable<Patient> findByNameContainingOrSurnameContaining(String term){
        return patientDao.findByNameContainingOrSurnameContaining(term, term);
    }

    @Override
    public Patient save(Patient patient){
        return patientDao.save(patient);
    }

    @Override
    public void deleteById(Integer id) {
        patientDao.deleteById(id);
    }


}

As stated before, "patient.get().getPhoto()" returns in @GetMapping the actual value stored in the database. But in the method annotated with @PostMapping returns null for that value (Although other attributes seem to work just fine).

This was the backend, but in the frontend I am using Angular, where I call this method in component (I am showing just the parts involved in the uploading photo):

  patient: Patient;


  constructor(private route: ActivatedRoute, private router: Router, private service: ServiceServicee) {
    this.paient = new Patient();
  }


 uploadPhoto() {
    this.service.uploadPhoto(this.selectedPhoto, 
      this.patient.id).subscribe(patient => {
        this.patient = patient;
      });
  }

Service:


  constructor(private http:HttpClient, private router:Router) {
    this.urlPatients='http://localhost:8080/patients';
   }

uploadPhoto(file: File, id):Observable<Patient>{

     let formData= new FormData();
    

     formData.append("archive", file);
     formData.append("id", id);
     
     return this.http.post(`${this.urlPatients}/upload`, formData).pipe(
       map((response:any)=> response.patient as Patient),
       catchError(e=>{
         console.error(e.error.mensaje);
         return throwError(e);
       })
     );

   }

UPDATE: Using Postman and making a POST to http://localhost:8080/patients/upload and sending in the body a jpg file (form-data - "archive") and a id number("id"), I got a success with the inserts and the method it didn't worked previously in the backend (patient.get().getPhoto()) worked perfectly this time. With the same code, so I assume that it is as @BiteBat said and it is a problem of the Frontend and how it is calling the Backend.

1
As a note, you can simply use @PathVariable("id") Patient patient. However, have you debugged your controller and ensured that the value of id is actually what you expect? - chrylis -cautiouslyoptimistic-
You miss 'return' statement in both catch block - rell
Thanks for your responses. Yes, I made sure that the value id is right in both methods... Although return statement is missing in my example, in the actual code I have it present. - Julián Pelayo

1 Answers

1
votes

I simulated the same environment that you created and it works for me as you expect, I leave the code for you to review what your problem. I would think you are incorrectly calling the POST method. Now, I would recommend that you do not save the images in a relational database, because there are alternatives with better performance, such as Google Storage / Local storage or any file storage service.

Structure:

enter image description here

EntryPoint:

package question;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories
public class JulianPelayoApplication {

    public static void main(String[] args) {
        SpringApplication.run(JulianPelayoApplication.class, args);
    }

}

Controller:

package question.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import question.repository.Patient;
import question.repository.PatientsRepository;

@CrossOrigin(origins="http://localhost:4200", maxAge = 3600)
@RestController
@RequestMapping("/patients")
public class PatientController {

    private PatientsRepository patientsRepository;

    @Autowired
    public PatientController(PatientsRepository patientsRepository) {
        this.patientsRepository = patientsRepository;
    }

    @GetMapping("/{id}")
    public ResponseEntity<?> listPatientId(@PathVariable("id") Integer id){

        Optional<Patient> patient=null;
        Map<String, Object> response=new HashMap<>();

        try{
            patient = patientsRepository.findById(id);
        }catch(DataAccessException e){
            response.put("error", e.getMessage().concat(": "+e.getMostSpecificCause().toString()));
            new ResponseEntity<Map<String, Object>>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        System.out.println("Patient with id: "+id+" / "+patient.get().getId()+" which photo is: "+patient.get().getPhoto());

        return ResponseEntity.ok(patient);
    }

    @PostMapping(value="/upload")
    public ResponseEntity<?> upload(@RequestParam("archive") MultipartFile archive, @RequestParam("id") Integer id){

        Optional<Patient> patient = Optional.empty();
        Map<String, Object> response = new HashMap<>();

        try{
            patient = patientsRepository.findById(id);
        }catch(DataAccessException e){
            response.put("error", e.getMessage().concat(": "+e.getMostSpecificCause().toString()));
            new ResponseEntity<Map<String, Object>>(response, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        System.out.println("Patient with id: "+id+" / "+patient.get().getId()+" which photo is: "+patient.get().getPhoto());

        return ResponseEntity.ok(patient);

    }
    
}

Repository:

package question.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PatientsRepository extends CrudRepository<Patient, Integer>{

}

Patient:

@Entity
@Table(name = "patients", schema = "business")
@Getter @Setter
public class Patient {

    @Id
    @Column
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String photo;
    
}

Spring.properties:

spring.datasource.url=jdbc:postgresql://localhost/test
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>question</groupId>
    <artifactId>JulianPelayo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>JulianPelayo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Response:

Get enter image description here

Post enter image description here enter image description here