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;
}
You didn't include the implementation of cloudStorageService.uploadImage(?,?) in the code you pasted here.
Cloudinary's Java implementation requires you pass in the multipart file in bytes. I do not know if you have that since your upload method isn't here.
Maybe refer to the simple implementation here
PS: You can clone the repo to see the implementation of the upload method in the CloudinaryServiceImpl.
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.
spring boot mongodb audit gives duplicate collection error. I'm trying to create dateCreate and dateUpdate fields when I insert and update a collection but when updated it gives the error:
org.springframework.dao.DuplicateKeyException: Write operation error
on server user.domain.com:27017. Write error: WriteError{code=11000,
message='E11000 duplicate key error collection: springboot.category
index: id dup key: { _id: "21" }', details={}}.
the execution is duplicating the key, below is my structure
My class AuditingConfig.java:
Configuration
#EnableMongoAuditing
public class AuditingConfig {
#Bean
public AuditorAware<String> myAuditorProvider() {
return new AuditorAwareImpl();
}
}
My class AuditMetadata.java:
#Setter
#Getter
public class AuditMetadata {
#CreatedDate
private LocalDateTime createdDate;
#LastModifiedDate
private LocalDateTime lastModifiedDate;
#Version
private Long version;
// #CreatedBy
// private String createdByUser;
// #LastModifiedBy
// private String modifiedByUser;
//...getters and setters omitted
}
My class AuditorAwareImpl.java:
public class AuditorAwareImpl implements AuditorAware<String> {
#Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Admin");
}
}
My class entity CategoryMongo.java:
Getter
#Setter
#NoArgsConstructor
#Document(collection = "category")
public class CategoryMongo extends AuditMetadata{
#Id
#JsonProperty("category_id")
private String category_id;
#JsonProperty("id_colletion")
private String emberId;
public String getEmberId() {
return category_id;
}
#JsonProperty("category_name")
private String name;
#JsonProperty("category_active")
private ProductEnum active = ProductEnum.ativo;
#JsonProperty("category_slug")
private String slug;
// #JsonProperty("category_updateAt")
// #LastModifiedDate
// private Date updateAt;
// #JsonProperty("category_createdAt")
// #CreatedDate
// private Date createdAt;
}
My method save:
CategoryMongo catm = new CategoryMongo();
catm.setName(category.getName());
catm.setSlug(category.getSlug());
catm.setActive(category.getActive());
catm.setCategory_id(category.getCategory_id().toString());
catm.setEmberId(category.getCategory_id().toString());
categoryRepositoryMongo.save(catm);
SOLVED
I solved the error I use in the document an interface follows the updated classes:
class AuditMetadata.java:
#Setter
#Getter
public class AuditMetadata {
#CreatedDate
private LocalDateTime createdDate;
#LastModifiedDate
private LocalDateTime lastModifiedDate;
#Version
private Long version;
protected boolean persisted;
// #CreatedBy
// private String createdByUser;
// #LastModifiedBy
// private String modifiedByUser;
//...getters and setters omitted
}
class Document CategoryMongo.java:
#Getter
#Setter
#NoArgsConstructor
#Document(collection = "category")
public class CategoryMongo extends AuditMetadata implements Persistable<String>{
#Id
#JsonProperty("category_id")
private String category_id;
#JsonProperty("id_colletion")
private String emberId;
public String getEmberId() {
return category_id;
}
#JsonProperty("category_name")
private String name;
#JsonProperty("category_active")
private ProductEnum active = ProductEnum.ativo;
#JsonProperty("category_slug")
private String slug;
#Override
#Nullable
public String getId() {
return category_id;
}
#Override
public boolean isNew() {
return !persisted;
}
// #JsonProperty("category_updateAt")
// #LastModifiedDate
// private Date updateAt;
// #JsonProperty("category_createdAt")
// #CreatedDate
// private Date createdAt;
}
save method:
CategoryMongo catm = new CategoryMongo();
catm.setName(category.getName());
catm.setSlug(category.getSlug());
catm.setActive(category.getActive());
catm.setCategory_id(category.getCategory_id().toString());
catm.setPersisted(true);
categoryRepositoryMongo.save(catm);
But something happens that I didn't want to happen: the #CreatedDate field disappears when I update it and only #LastModifiedDate appears in the result. if anyone knows how to solve this post here
I have a spring-boot application.
I have entity:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Document(COLLECTION_NAME)
public class PersonEntity {
public static final String COLLECTION_NAME = "person_info";
private static final String PERSON_NAME = "person_name";
#Id
private PersonId id;
#Field(name = PERSON_NAME)
private String personName;
#Indexed(name = "ttl_index", expireAfterSeconds=20)
private LocalDateTime date;
}
I have a repository interface:
public interface PersonRepository {
void saveWithTtl(PersonEntity entity);
}
The repository implementation:
#Slf4j
#Repository
public class PersonRepositoryImpl implements PersonRepository {
private final int expireAfterSeconds;
private final ReactiveMongoTemplate mongoTemplate;
public PersonRepositoryImpl(#Value("${ttl.index}") int expireAfterSeconds,
ReactiveMongoTemplate mongoTemplate) {
this.expireAfterSeconds = expireAfterSeconds;
this.mongoTemplate = mongoTemplate;
}
#Override
public void saveWithTtl(PersonEntity entity) {
mongoTemplate.indexOps(PersonEntity.class)
.ensureIndex(new Index().on(PersonEntity.CREATED_AT, ASC)
.expire(expireAfterSeconds)).subscribe(result -> log.info("Ttl index has been created: {}", result));
mongoTemplate.save(entity).subscribe(result -> log.info("Entity has been saved: {}", result));
}
}
And, finally, I have test that does not work:
#DataMongoTest
#Testcontainers
public class PersonRepositoryIT {
#Autowired
private ReactiveMongoTemplate mongoTemplate;
#Autowired
private PersonRepository repository;
#Container
private static MongoDbContainer mongoDbContainer = new MongoDbContainer();
#AfterEach
void cleanUp() {
repository.deleteAll();
}
#DynamicPropertySource
static void registerMongoProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", mongoDbContainer::getReplicaSetUrl);
}
#Test
public void shouldCreateAndDeleteRecordsAfterDelay_whenSaveWithTtl_givenDefinedTll() {
//given
PersonEntity givenEntity = PersonEntity.builder().createdAt(LocalDateTime.now())
.personName("Joe")
.id(PERSON_ID).build();
//when
repository.saveWithTtl(givenEntity);
//then
StepVerifier.create(mongoTemplate.estimatedCount(PersonEntity.COLLECTION_NAME))
.expectNext(1L)
.verifyComplete();
}
}
On expectNext it fails coz it returns 0 and not 1.
mongoTemplate.estimatedCount returns 0
When I test the repository from Postman (repo is calling inside service), it creates the document in MongoDB wil ttl index, as expected.
In test fonfig I have set the ${ttl.index} to 20.
What am I doing wrong?
I don't know if it is to late, but I had the same problem today.
I Found your question looking for an answer for my problem hahahaha.
This snipped worked for me:
#Container
public static MongoDBContainer container = new MongoDBContainer(DockerImageName.parse("mongo:6"));
#DynamicPropertySource
static void mongoDbProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", container::getReplicaSetUrl);
}
#Bean
public ReactiveMongoTemplate reactiveMongoTemplate() throws Exception {
container.start();
ConnectionString connectionString = new ConnectionString(container.getReplicaSetUrl());
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
MongoClient mongoClient = MongoClients.create(mongoClientSettings);
return new ReactiveMongoTemplate(mongoClient,"test");
}
Apparently ReactiveMongoTemplate is not being injected by default, then I created my own Bean an it worked
I am getting these error while integrating the spring-boot with JPA repository
here is the code
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/api")
public class EmpController {
#Autowired
private CrudRepo crud;
#Autowired
private AddrCrudRepo addr;
#Autowired
private EntityManager entity;
//#Autowired
//private ModelMapper mapper;
private static int count = 0;
#Bean
public ModelMapper model() {
return new ModelMapper();
}
//#Autowired
// public EmpController(ModelMapper mapper) {
// this.mapper = mapper;
// }
#RequestMapping(path = "/post-addr", method = RequestMethod.POST)
public List<AddressModel> postAddr(#Valid #RequestBody List<AddressRequest> addr1){
// crud.findById(id)
//AddressModel list = new AddressModel();
EmployeeModel emp = new EmployeeModel();
System.out.println("CALLING THE MAPPER "+addr1);
List<AddressModel> addr_list = ObjectMapperUtils.mapAll(addr1, AddressModel.class);
System.out.println("CALLED THE MAPPER "+addr_list);
addr_list.forEach((a) -> {
crud.findById(a.getEmpId()).ifPresent((b) -> {
System.out.println(this.count++);
a.setEmp_id(b);
b.getAddress().add(a);
});
});
// AddressModel addr_list = model().map(addr1, AddressModel.class);
//
// crud.findById(addr1.getEmp_id()).ifPresent((b) -> {
// addr_list.setEmp_id(b);
//
// });`enter code here`
System.out.println(addr_list.size());
List<AddressModel> addr3 = addr.saveAll(addr_list);
System.out.println(addr3);
return addr_list;
}
getting an error in the postAddr method as when it returns the List<AddressModel> and here is the AddressModel
#Entity
#Table(name="Emp_Address")
public class AddressModel implements Serializable{
#Column(name="address_id")
#Id
private Integer address_id;
#Column(name="city")
private String city;
#Column(name="states")
private String states;
#Transient
private Integer empId;
#ManyToOne
#JoinColumn(name="emp_id")
private EmployeeModel emp_id;
public AddressModel() {
}
//getter and setter
and EmployeeModel
#Entity
#Table(name="Employee")
public class EmployeeModel implements Serializable{
#Column(name="Emp_id")
#Id
private Integer emp_id;
#Column(name="Emp_Name")
private String emp_name;
#OneToMany(mappedBy="emp_id")
private Collection<AddressModel> address = new ArrayList<>();
public EmployeeModel() {
}
//getter and setters
so while saveAll is done properly but when the postAddr method returns the List it throws the StackOverflow
This StackOverflow error is coming because generated toString methods of both classes are circularly dependent on each other.
EmployeeModel tries to print AddressModel but again AddressModel tries to print EmployeeModel and hence the error.
Try removing AddressModel from toString method of EmployeeModel class or reverse, remove EmployeeModel from toString method of AddressModel class.
If the createdBy references to a document with unique indexes, it fails throwing dup key error.
AbstractDocument.java
public abstract class AbstractDocument implements Auditable<User, String> {
#Version
private Long version;
#Id
private String id;
private User createdBy;
private DateTime createdDate;
private User lastModifiedBy;
private DateTime lastModifiedDate;
}
User.java
#Document(collection = "users")
public class User extends AbstractDocument {
private String name;
private String surname;
#Indexed(unique = true)
private String username;
}
Book.java
#Document(collection = "books")
public Book extends AbstractDocument {
private String title;
}
Now, I have a script (Spring Batch) which initializes the db with some books. The script defines the auditor this way:
#Configuration
#EnableMongoAuditing
public class MongoConfig {
#Bean
public AuditorAware<User> auditorProvider() {
return new AuditorAware<User>() {
#Override
public User getCurrentAuditor() {
User auditor = new User();
auditor.setUsername("init-batch");
auditor.setName("Data initializer");
auditor.setSurname("Data initializer");
return auditor;
}
};
}
}
The script in somewhere does (for each book I need to persist) bookRepository.save(book)
The first book is persisted, but the second one throws:
nested exception is com.mongodb.DuplicateKeyException: Write failed with error code 11000 and error message 'E11000 duplicate key error index: mydb.books.$createdBy.username dup key: { : "init-batch" }'
Why? The unique index is for users collection, why is it checked for audit references?