right now I am working on a java project with Spring, but I got really confused about something. In my domain I have the following three entities.
Museum, MuseumReview and Visitor.
A visitor can review multiple museums but can only review a museum once.
A museum can be reviewed by multiple visitors.
The classes:
@Entity @Table(name = "museums") public class Museum { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id;@Column(name = "name", nullable = false, unique = true)private String name;@Column(name = "location", nullable = false)private String location;@Column(name = "date_established", nullable = false)private LocalDate dateEstablished;@Column(name = "status", nullable = false)@Enumerated(EnumType.STRING)private MuseumStatus status;@OneToMany(mappedBy = "museum")private List<MuseumReview> reviews;@OneToMany(mappedBy = "museum", fetch = FetchType.EAGER)private List<Fossil> fossils;// Getters and Setters} // class Museum@Entity @Table(name = "museum_review", uniqueConstraints = {@UniqueConstraint(columnNames = {"museum_id", "visitor_id"})}) public class MuseumReview { @Id@GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id;@ManyToOne(optional = false)@JoinColumn(name = "museum_id")@OnDelete(action = OnDeleteAction.CASCADE)private Museum museum;@ManyToOne(optional = false)@JoinColumn(name = "visitor_id")@OnDelete(action = OnDeleteAction.CASCADE)private Visitor visitor;@Column(name = "review_date", nullable = false)private LocalDate reviewDate;@Column(name = "star_rating")private int starRating;@Column(name = "content")private String content;// Getters and Setters} // class MuseumReview@Entity@Table(name = "visitors") public class Visitor {@Id@GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id;@Column(name = "name", nullable = false)private String name;@Column(name = "email")private String email;@Column(name = "password")private String password;@Column(name = "role", nullable = false)@Enumerated(EnumType.STRING)private Role role;@OneToMany(mappedBy = "visitor")private List<MuseumReview> reviews;public Visitor() {}public Visitor(int id, String name, String email, String password) { this.id = id; this.name = name; this.email = email; this.password = password; this.role = Role.VISITOR;}// Getters and setters} // class VisitorThe Role enum:
public enum Role {VISITOR,ADMIN} // enum RoleCurrently I have an Rest controller for Museum as follows:
@RestController@RequestMapping("/api/museums")public class MuseumApiController { private final MuseumService museumService;private final ModelMapper modelMapper;public MuseumApiController(MuseumService museumService, ModelMapper modelMapper) { this.museumService = museumService; this.modelMapper = modelMapper;}@GetMapping("/{id}")public ResponseEntity<MuseumDto> getMuseum(@PathVariable("id") int id) { final Museum museum = museumService.getById(id); return ResponseEntity.ok(modelMapper.map(museum, MuseumDto.class));}@GetMappingpublic ResponseEntity<List<MuseumDto>> getAllMuseums() { final List<Museum> museums = museumService.getAllWithReviewers(); if (museums.isEmpty()) { return new ResponseEntity<>(HttpStatus.NO_CONTENT); } else { return ResponseEntity.ok(museums.stream().map(museum -> modelMapper.map(museum, MuseumDto.class)).toList()); }}@GetMapping("/search")public ResponseEntity<List<MuseumDto>> searchMuseums(@RequestParam("searchTerm") String searchTerm) { final List<Museum> museums = museumService.search(searchTerm); return ResponseEntity.ok(museums.stream().map(museum -> modelMapper.map(museum, MuseumDto.class)).toList());}@GetMapping("/{id}/reviewers")public ResponseEntity<List<VisitorDto>> getMuseumReviewers(@PathVariable("id") int id) { final List<Visitor> reviewedVisitors = museumService.getReviewedVisitors(id); final List<VisitorDto> reviewedVisitorDtos = reviewedVisitors .stream() .map(visitor -> modelMapper.map(visitor, VisitorDto.class)) .toList(); return ResponseEntity.ok(reviewedVisitorDtos);}@DeleteMapping("/{id}")@PreAuthorize("hasRole('ROLE_ADMIN')")public ResponseEntity<Void> deleteMuseum(@PathVariable("id") int id) { museumService.delete(id); return ResponseEntity.noContent().build();}@PostMapping@PreAuthorize("hasRole('ROLE_ADMIN')")public ResponseEntity<MuseumDto> addMuseum(@RequestBody @Valid AddMuseumDto addMuseumDto) { final Museum addedMuseum = museumService.add(addMuseumDto.name(), addMuseumDto.location(), addMuseumDto.dateEstablished()); return ResponseEntity.status(HttpStatus.CREATED).body(modelMapper.map(addedMuseum, MuseumDto.class));}@PatchMapping("/{id}")@PreAuthorize("hasRole('ROLE_ADMIN')")public ResponseEntity<MuseumDto> patchMuseum( @PathVariable("id") int id, @RequestBody @Valid PatchMuseumDto patchMuseumDto) { final Museum patchedMuseum = museumService.patch( id, patchMuseumDto.name(), patchMuseumDto.location(), patchMuseumDto.dateEstablished(), patchMuseumDto.status() ); return ResponseEntity.ok(modelMapper.map(patchedMuseum, MuseumDto.class));}} // class MuseumApiControllerHowever I also want the visitors to be able to add, remove and update their museum review written for a specific museum. How could I achieve this? I want to be able to specify the star rating and the review content when creating the reviews.
I currently have the following dto which I want to use:
public class ReviewDto {@Min(1)@Max(5)private Integer starRating;@Size(min = 3, max = 300)private String content;// Getters and Setters} // class ReviewDtoShould I use a separate MuseumReviewApiController and a MuseumReviewService for this and if so what should my methods in the MuseumReviewService class look like to achieve this? Would be very happy if anyone could help me on this.
I tried to handle things in the MuseumApiController, but things got really confusing for me and basically I got stuck.