How to post an Image and JSON object with single request to back end Spring Boot - spring-boot

I want to send image and JSON data to my back end in Spring Boot.
This is my method:
#PostMapping
public void uploadFile(#ModelAttribute FileUploadDto fileUploadDto) {
My FileUploadDto model:
public class FileUploadDto {
private MultipartFile file;
private CategoryModel category;
My CategoryModel model:
#Entity
#Table(name = "Category")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class CategoryModel {
#Id
#Column(name = "id")
//#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String category_name;
private String category_description;
private String image_path;
#JsonIgnore
#OneToMany( mappedBy = "category")
private Set<ProductModel> category;
I do not understand where I'm wrong.
My postman request:

Your payload has to be raw and in json form. Something like this would help Spring boot to convert your payload into a object of an example class:
public class Foo{
public String foo;
public String foo1;
//Getters setters
}
And the request handling method:
#PostMapping
public void uploadFile(#RequestBody Foo foo)
It is also recommended to parse the payload into some a temporary class and then convert objects of the temporary class into the Entity class and vice versa. Take a look at: https://struberg.wordpress.com/2012/01/08/jpa-enhancement-done-right/ for more information
Also, if you want to upload file per REST I also recommend you to take a look at the following documentation: https://www.callicoder.com/spring-boot-file-upload-download-rest-api-example/
Best luck.

Related

Spring Framework Responses from POST

What is the standard object design for accepting a POST request from a client, saving the record to the database, and then returning a response back to the client? I'm working with the Spring framework.
Should I be sending back the entity and hiding properties that aren't necessary for the response?
#RestController
public class SomeController {
private final SomeService service;
#PostMapping(value = "/post/new", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SomeEntity> post(#RequestBody final SomeEntity someEntity) {
SomeEntity savedEntity = service.save(someEntity);
return ResponseEntity.ok(savedEntity);
}
}
#Entity
#Table(name = "posts")
public class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "title")
private String title;
#Column(name = "body")
#JsonIgnore
private String body;
#JsonIgnore
#Column(name = "deleted_ind")
private boolean deleted;
#JsonIgnore
#Column(name = "author")
private String author;
#Column(name = "created_at")
private LocalDateTime createdAt;
}
or would I accept some sort of POST request object that I convert to an entity, then re-assemble the entity into a response?
#JsonIgnoreProperties(ignoreUnknown = true)
public class SomePostRequestResource {
private String title;
private String body;
private String createdAt;
}
#RequiredArgsConstructor
#RestController
public class SomeController {
private final SomeService service;
private final SomeResourceAssembler resourceAssembler;
#PostMapping(value = "/post/new", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SomePostRequestResource> post(
#RequestBody final SomePostRequestResource someResource
) {
SomeEntity savedEntity = service.convertToEntityAndSave(someResource);
SomePostRequestResource response = resourceAssembler.toResource(savedEntity);
return ResponseEntity.ok(response);
}
}
But then maybe I only want to send back the createdAt, would I hide the other properties in the SomePostRequestResource, or do I need another object to represent the response, which only has the property I want to send back?
I would also appreciate any book or article suggestions related to desigining objects for use with a RESTful API. I have seen articles concerning how to design and name the endpoints, but not so many concerning how to design the objects on the backend.
I would recommend you create a DTO class for the incoming/outgoing data containing the filed that are set/viewable by the client like:
public class SomeEntityIncomingDto {
private String title;
....
}
public class SomeEntityOutgoingDto {
private Long id;
private String title;
....
}
On the other hand, You won't need to map your persistence entities to DTOs and vice versa manually, you can use a library like ModelMapper or MapStruct that handles the conversion automatically.

Are there #MappedSuperclass in Spring Reactive Data (R2DBC)

I have a super Entity class like this:
#Getter
#Setter
#NoArgsConstructor
public class GenericEntity {
#Id
private Long id;
#JsonIgnore
#CreatedBy
private Long createdBy;
#JsonIgnore
#CreatedDate
private Long createdDate;
#JsonIgnore
#LastModifiedBy
private Long updatedBy;
#JsonIgnore
#LastModifiedDate
private Long updatedDate;
#JsonIgnore
#Version
private Integer version = 0;
}
and a Role class extends from GenericEntity like this:
#Getter
#Setter
#NoArgsConstructor
public class Role extends GenericEntity {
private String name;
private String desc;
private Integer sort;
}
And after that I have interface RoleRepo like this:
#Repository
public interface RoleRepo extends ReactiveCrudRepository<Role, Long>;
In Router function, I have 2 handler methods
private Mono<ServerResponse> findAllHandler(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON)
.body(roleRepo.findAll(), Role.class);
}
private Mono<ServerResponse> saveOrUpdateHandler(ServerRequest request) {
return ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(request.bodyToMono(Role.class).flatMap(role -> {
return roleRepo.save(role);
}), Role.class);
}
The method findAllHandler works fine, but the saveOrUpdateHandler throw exception like this:
java.lang.IllegalStateException: Required identifier property not found for class org.sky.entity.system.Role!
at org.springframework.data.mapping.PersistentEntity.getRequiredIdProperty(PersistentEntity.java:105) ~[spring-data-commons-2.2.0.M2.jar:2.2.0.M2]
at org.springframework.data.r2dbc.function.convert.MappingR2dbcConverter.lambda$populateIdIfNecessary$0(MappingR2dbcConverter.java:85) ~[spring-data-r2dbc-1.0.0.M1.jar:1.0.0.M1]
But when I move
#Id
private Long id;
from GenericEntity class to Role class, the two methods work fine.
Are there any Annations #MappedSuperclass/JPA in Spring Reactive Data like that
I wish the id field in GenericEntity for all extends class
Thanks for your help
Sorry, my English so bad
I had a similar problem and after some search, I didn't find an answer to your question, so I test it by writing code and the answer is spring data R2DBC doesn't need #Mappedsuperclass. it aggregates Role class properties with Generic class properties and then inserts all into the role table without the need to use any annotation.

SPRING REST controller - return image AND json values

I have built a rest web service, using SPRING and Hibernate.
I have 2 entities : Image and user, linked with a oneToOne annotation.
When I try to return the user details AND the image corresponding to this user, I get this error :
"org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation"
When I do it separately It works fine, but when I do it in one route, I get this error.
Here is my controller :
#CrossOrigin(
origins = "*",
methods = {RequestMethod.POST, RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.DELETE},
allowedHeaders = "*")
#RestController
#RequestMapping(path = "/user")
public class UserController {
#Autowired
UserRepository userRepository;
#Autowired
ImageRepository imageRepsository;
doesn't work--> #RequestMapping(value="/{userId}/getUserAndImage",method=RequestMethod.GET,produces = MediaType.IMAGE_JPEG_VALUE )
public Optional<User> getUserAndImage(#PathVariable Long userId) {
return userRepository.findById(userId);
}
works fine--> #RequestMapping(value="/{userId}/image", method=RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public byte[] getUserImage(#PathVariable Long userId) {
byte[] image = (imageRepsository.findImageWithUserId(userId)).getImage();
return image;
}
Here are entities :
User entity :
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#NotNull
#Size(max=100)
#Column
private String nom;
#NotNull
#Size(max=250)
#Column
private String prenom;
#OneToOne(fetch=FetchType.EAGER,
cascade = CascadeType.PERSIST)
private Image image;
//getters and setters
}
Image entity :
#Entity
#Table(name="images")
public class Image {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="image")
#Lob
private byte[] image;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name="user_id")
private User user;
//getters and setters
}
in the annotation, produce set as MediaType.IMAGE_JPEG_VALUE, then your code return response as User object. As result it throw that exception because spring expect your code to return JPEG type file only.
What can i suggest here,use produces = MediaType.APPLICATION_JSON_VALUE, and convert your image from byte[] to base64 string then return response as json object

Ignoring Nested properties in Jackson OnDemand

I am working on a spring boot application with Hibernate as ORM and Jackson as JSON serialiser .
I have three model objects and CRUD operations for all three models.
Class Student{
private Teacher teacher; // Teacher of the student — to be fetched eagerly
+Getter/Setter
}
class Teacher {
private List<Subject> subject; // List of subjects associated to that user— to be fetched eagerly
+Getter/Setter
}
class Subject {
private long subjectId
//Other subject properties
+ Getter/Setter
}
Whenever I trigger a get request for student info I get the teacher info which is correct where as I also receive Subject info as well which is unnecessary for me. In the same time when I request for Teacher info, I need Subject info should be associated to that for sure. If I use #JsonBackReference for subject I am losing it all the time. I am not sure how to achieve this.
Thanks in advance for your help!!
You can also annotate like this
Class Student{
#JsonIgnoreProperties("subject")
private Teacher teacher; // Teacher of the student — to be fetched eagerly
}
You can use JSON Views
From the spring blog:
public class View {
interface Summary {}
}
public class User {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private String firstname;
#JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
public class Message {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private LocalDate created;
#JsonView(View.Summary.class)
private String title;
#JsonView(View.Summary.class)
private User author;
private List<User> recipients;
private String body;
}
and in the controller
#RestController
public class MessageController {
#Autowired
private MessageService messageService;
#JsonView(View.Summary.class)
#RequestMapping("/")
public List<Message> getAllMessages() {
return messageService.getAll();
}
#RequestMapping("/{id}")
public Message getMessage(#PathVariable Long id) {
return messageService.get(id);
}
}
PS: No link to http://fasterxml.com/ as it's currently down.

retrieving data from database as json in spring boot

I have a MySQL database and I want to retrieve some data as json.
And I have an entity Offre wich has #OneToMany relation with the AssociationCandidatOffre entity.
and I have an api which calles this method in my repository :
offreRepository.findAll();
Offre entity :
#Entity
public class Offre implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CODE_OFFRE")
private Long codeOffre;
private String titre;
#OneToMany(mappedBy = "offre")
private Collection<AssociationCandidatOffre> associationCandidatOffres;
public Collection<AssociationCandidatOffre> getAssociationCandidatOffres() {
return associationCandidatOffres;
}
public void setAssociationCandidatOffres(Collection<AssociationCandidatOffre> associationCandidatOffres) {
this.associationCandidatOffres = associationCandidatOffres;
}
//... getters/setters
}
AssociationCandidatOffre entity :
#Entity
public class AssociationCandidatOffre implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long idAssociation;
private String lettreMotivation;
private String tarifJournalier;
private Date dateDisponibilite;
#ManyToOne
private Candidat candidat;
#ManyToOne
private Offre offre;
#JsonIgnore
#XmlTransient
public Candidat getCandidat() {
return candidat;
}
#JsonSetter
public void setCandidat(Candidat candidat) {
this.candidat = candidat;
}
#JsonIgnore
#XmlTransient
public Offre getOffre() {
return offre;
}
#JsonSetter
public void setOffre(Offre offre) {
this.offre = offre;
}
//... getters/setters
}
the problem is when I call the api /offres to return me a json object I get this error message instead :
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.***.Rekrute.entities.Offre["associationCandidatOffres"]);
nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not extract ResultSet (through reference chain: java.util.ArrayList[0]->com.***.Rekrute.entities.Offre["associationCandidatOffres"])
when I use #JsonIgnore in the getAssocationCandidatOffres I dont get any errors but I want that association in the json result as well.
Normally, this shouldn't generate any error since I have #JsonIgnore in the other side of the relation which is getOffre().
how can I solve this problem ?
You can't convert a bidirectional relation of an enitity to JSON.
You get an endless loop.
JSON-Parser starts with the entity Offer and reads the associated AssociationCandidatOffre via getAssociationCandidatOffres(). For every AssociationCandidatOffre the JSON-Parser read getOffre() and starts again. The parser don't know when he must end.

Resources