I am working on a Spring Boot application for a real estate listing. I have implemented functionality to upload images when adding or editing listings. The image upload works when adding a new listing, but it doesn’t work when editing an existing listing.
When editing a listing, the application logs “No new image provided or image is empty,” even though I am providing a new image.
package com.marvi.realestatelisting.Controller;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.marvi.realestatelisting.DTO.ListingDTO;
import com.marvi.realestatelisting.DTO.ImageDTO;
import com.marvi.realestatelisting.Entity.Image;
import com.marvi.realestatelisting.Entity.Listing;
import com.marvi.realestatelisting.Service.ListingService;
@RestController
@RequestMapping("/listing")
public class ListingController {
@Autowired
private ListingService service;
private static final String UPLOAD_DIR = "/Users/macUser/uploads/";
private static final Logger log = LoggerFactory.getLogger(ListingController.class);
@PostMapping("/add")
public ListingDTO addListing(
@RequestParam("title") String title,
@RequestParam("address") String address,
@RequestParam("price") double price,
@RequestParam("bedrooms") int bedrooms,
@RequestParam("bathroom") int bathroom,
@RequestParam("year") String year,
@RequestParam("image") MultipartFile image) throws IOException {
Listing listing = new Listing();
listing.setTitle(title);
listing.setAddress(address);
listing.setPrice(price);
listing.setBedrooms(bedrooms);
listing.setBathroom(bathroom);
listing.setYearBuilt(year);
listing.setSold(false);
if (image != null && !image.isEmpty()) {
String imagePath = saveImage(image);
Image img = new Image();
img.setFileName(image.getOriginalFilename());
img.setFilePath(imagePath);
img.setListing(listing);
listing.setImages(List.of(img));
}
Listing savedListing = service.addListing(listing);
return convertToDTO(savedListing);
}
@PutMapping("/edit/{id}")
public ResponseEntity<ListingDTO> editListing(
@PathVariable Long id,
@RequestParam("title") String title,
@RequestParam("address") String address,
@RequestParam("price") double price,
@RequestParam("bedrooms") int bedrooms,
@RequestParam("bathroom") int bathroom,
@RequestParam("year") String year,
@RequestParam("sold") boolean sold,
@RequestParam(value = "image", required = false) MultipartFile image) throws IOException {
Listing listing = service.findListingById(id);
if (listing == null) {
return ResponseEntity.notFound().build();
}
listing.setTitle(title);
listing.setAddress(address);
listing.setPrice(price);
listing.setBedrooms(bedrooms);
listing.setBathroom(bathroom);
listing.setYearBuilt(year);
listing.setSold(sold);
log.info("Received image: {}", image != null ? image.getOriginalFilename() : "No new image");
if (image != null && !image.isEmpty()) {
String imagePath = saveImage(image);
Image img = new Image();
img.setFileName(image.getOriginalFilename());
img.setFilePath(imagePath);
img.setListing(listing);
if (listing.getImages() == null) {
log.info("Images list is null, initializing new ArrayList");
listing.setImages(new ArrayList<>());
} else {
log.info("Images list is not null, clearing existing images");
listing.getImages().clear();
}
listing.getImages().add(img);
log.info("Added new image to listing");
}
Listing updatedListing = service.editListings(id, listing);
return ResponseEntity.ok(convertToDTO(updatedListing));
}
private String saveImage(MultipartFile image) throws IOException {
Path uploadPath = Paths.get(UPLOAD_DIR);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
byte[] bytes = image.getBytes();
Path path = Paths.get(UPLOAD_DIR + image.getOriginalFilename());
Files.write(path, bytes);
log.info("saved image to {}", path.toString());
return path.toString();
}
private ListingDTO convertToDTO(Listing listing) {
ListingDTO listingDTO = new ListingDTO();
listingDTO.setId(listing.getId());
listingDTO.setTitle(listing.getTitle());
listingDTO.setAddress(listing.getAddress());
listingDTO.setPrice(listing.getPrice());
listingDTO.setBedrooms(listing.getBedrooms());
listingDTO.setBathroom(listing.getBathroom());
listingDTO.setYearBuilt(listing.getYearBuilt());
listingDTO.setSold(listing.isSold());
List<ImageDTO> imageDTOs = new ArrayList<>();
for (Image img : listing.getImages()) {
ImageDTO imageDTO = new ImageDTO();
imageDTO.setId(img.getId());
imageDTO.setFileName(img.getFileName());
imageDTO.setFilePath(img.getFilePath());
imageDTO.setListingId(listing.getId());
imageDTOs.add(imageDTO);
}
listingDTO.setImages(imageDTOs);
return listingDTO;
}
}
and also:
package com.marvi.realestatelisting.Entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Data;
@Data
@Entity
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fileName;
private String filePath;
@ManyToOne
@JoinColumn(name = "listing_id")
@JsonBackReference
private Listing listing;
public Image() {
}
public Image(Long id, String fileName, String filePath, Listing listing) {
this.id = id;
this.fileName = fileName;
this.filePath = filePath;
this.listing = listing;
}
}
2024-07-31T22:40:07.218-04:00 WARN 59059 --- [realestatelisting] [nio-8080-exec-2] c.m.r.Controller.ListingController : No new image provided or image is empty
Hibernate: select i1_0.listing_id,i1_0.id,i1_0.file_name,i1_0.file_path from image i1_0 where i1_0.listing_id=?
2024-07-31T22:40:07.242-04:00 INFO 59059 --- [realestatelisting] [nio-8080-exec-2] c.m.r.Controller.ListingController : Listing with id 12 updated successfully
Expected Behavior
The image should be uploaded and associated with the listing when editing a listing.
Actual Behavior
The application logs “No new image provided or image is empty” even when an image is provided.