I’m working on a spring boot ecommerce app that requires cloudinary to persist image and get using the url.
However, all effort to get this done has been proved abortive. The code is not throwing any error but its not persisting in the cloudinary page and the database. And the response is null.
This is a response for example. Meanwhile i expect a link in the form of String
{
"productName": "Track suit",
"price": 300,
"productDescription": "XXL",
"productImage1": "",
"productImage2": "",
"productImage3": ""
}
This is my code
ENTITY
@Entity
public class Product {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String id;
@Column
private String productName;
@Column
private double price;
@Column
private String productDescription;
@Column(nullable = false)
private String productImage1;
@Column(nullable = true)
private String productImage2;
@Column(nullable = true)
private String productImage3;
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
@ManyToOne
@JoinColumn(name = "admin_id")
private Admin admin;
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
@ManyToOne
@JoinColumn(name = "users_entity_id")
private UsersEntity usersEntity;
}
REQUEST DTO
@Data
public class UploadProductRequestDto {
private String productName;
private double price;
private String productDescription;
private MultipartFile productImage1;
private MultipartFile productImage2;
private MultipartFile productImage3;
}
RESPONSE DTO
@Data
public class UploadProductResponseDto {
private String productName;
private double price;
private String productDescription;
private String productImage1;
private String productImage2;
private String productImage3;
}
REPOSITORY
public interface ProductRepository extends JpaRepository<Product,String> {
Optional<Product> findByProductName(String productName);
}
SERVICE
public interface ProductService {
UploadProductResponseDto uploadProducts(UploadProductRequestDto uploadProductRequestDto, String categoryName) throws AuthorizationException, GeneralServiceException, ImageUploadException;
}
SERVICEIMPL
@Slf4j
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
CloudStorageService cloudStorageService;
@Autowired
AdminRepository adminRepository;
@Autowired
CategoryRepository categoryRepository;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
ModelMapper modelMapper;
@Autowired
UserPrincipalService userPrincipalService;
@Autowired
UserRepository userRepository;
@Autowired
ProductRepository productRepository;
@Override
public UploadProductResponseDto uploadProducts(UploadProductRequestDto uploadProductRequestDto, StringcategoryName) throws AuthorizationException, GeneralServiceException, ImageUploadException {
Optional<Category> checkCategory = categoryRepository.findByCategoryName(categoryName);
if (checkCategory.isEmpty()){
throw new AuthorizationException(CATEGORY_NOT_RECOGNIZED);
}
Product product = new Product();
product=mapAdminRequestDtoToProduct(uploadProductRequestDto,product);
productRepository.save(product);
UploadProductResponseDto adminUploadProductResponseDto = packageAdminProductUploadResponseDTO(product);
return adminUploadProductResponseDto;
}
private UploadProductResponseDto packageAdminProductUploadResponseDTO(Product product){
UploadProductResponseDto uploadProductResponseDto=new UploadProductResponseDto();
modelMapper.map(product,uploadProductResponseDto);
return uploadProductResponseDto;
}
private Product mapAdminRequestDtoToProduct(UploadProductRequestDto uploadProductRequestDto,Product product) throws ImageUploadException {
modelMapper.map(uploadProductRequestDto,product);
product=uploadProductImagesToCloudinaryAndSaveUrl(uploadProductRequestDto,product);
product.setId("Product "+ IdGenerator.generateId());
return product;
}
private Product uploadProductImagesToCloudinaryAndSaveUrl(UploadProductRequestDto uploadProductRequestDto,Product product) throws ImageUploadException {
product.setProductImage1(imageUrlFromCloudinary(uploadProductRequestDto.getProductImage1()));
product.setProductImage2(imageUrlFromCloudinary(uploadProductRequestDto.getProductImage2()));
product.setProductImage3(imageUrlFromCloudinary(uploadProductRequestDto.getProductImage3()));
return product;
}
private String imageUrlFromCloudinary(MultipartFile image) throws ImageUploadException {
String imageUrl="";
if(image!=null && !image.isEmpty()){
Map<Object,Object> params=new HashMap<>();
params.put("public_id","E&L/"+extractFileName(image.getName()));
params.put("overwrite",true);
try{
Map<?,?> uploadResult = cloudStorageService.uploadImage(image,params);
imageUrl= String.valueOf(uploadResult.get("url"));
}catch (IOException e){
e.printStackTrace();
throw new ImageUploadException("Error uploading images,vehicle upload failed");
}
}
return imageUrl;
}
private String extractFileName(String fileName){
return fileName.split("\.")[0];
}
}
Controller
@Slf4j
@RestController
@RequestMapping(ApiRoutes.ENMASSE)
public class ProductController {
@Autowired
ProductService productService;
@PostMapping("/upload-product/categoryName")
public ResponseEntity<?> UploadProduct(@ModelAttribute UploadProductRequestDto UploadProductRequestDto,@RequestParam String categoryName){
try{
return new ResponseEntity<>
(productService.uploadProducts(UploadProductRequestDto,categoryName), HttpStatus.OK);
}catch (Exception exception){
return new ResponseEntity<>(exception.getMessage(),HttpStatus.BAD_REQUEST);
}
}
}
CLOUD
cloudConfig
@Component
@Data
public class CloudinaryConfig {
@Value("${CLOUD_NAME}")
private String cloudName;
@Value("${API_KEY}")
private String apikey;
@Value("${API_SECRET}")
private String secretKey;
}
CloudConfiguration
@Component
public class CloudinaryConfiguration {
@Autowired
CloudinaryConfig cloudinaryConfig;
@Bean
public Cloudinary getCloudinaryConfig(){
return new Cloudinary(ObjectUtils.asMap("cloud_name",cloudinaryConfig.getCloudName(),
"api_key",cloudinaryConfig.getApikey(),"api_secret",cloudinaryConfig.getSecretKey()));
}
}
CloudinaryStorageServiceImpl
@Service
public class CloudinaryStorageServiceImpl implements CloudStorageService{
@Autowired
Cloudinary cloudinary;
@Override
public Map<?, ?> uploadImage(File file, Map<?, ?> imageProperties) throws IOException {
return cloudinary.uploader().upload(file,imageProperties);
}
@Override
public Map<?, ?> uploadImage(MultipartFile multipartFile, Map<?, ?> imageProperties) throws IOException {
return cloudinary.uploader().upload(multipartFile.getBytes(),imageProperties);
}
}
CloudStorageService
public interface CloudStorageService {
Map<?,?> uploadImage(File file, Map<?,?> imageProperties) throws IOException;
Map<?,?> uploadImage(MultipartFile multipartFile, Map<?, ?> imageProperties) throws IOException;
}
2
Answers
It happens that there is nothing wrong with my code. The issue is that it has to be coupled with the frontend so the image tag can render it. Thank you.
Maybe refer to the simple implementation here
PS: You can clone the repo to see the implementation of the upload method in the CloudinaryServiceImpl.