Search code examples
springspring-bootspring-mvcspring-data-jpathymeleaf

How to show data from table that is mapped with another table in Many To One relationship full stack using Spring boot (backend) and Thymeleaf (front)


This is full-stack project based on Spring Boot (backend) and Thymeleaf (frontend). I have this page (table) on my website which shows all hotels in my Hotel Management System App:

enter image description here

When I click on Details it shows new page for particular hotel:

enter image description here

When I click on View Rooms it should show the list of the rooms available for that particular Hotel. I wonder how can I do that? So far, I was only available to list all the rooms (not related to particular hotel) but I want to list the rooms for the particular hotel only.

class Room is mapped with class Hotel by @ManyToOne relationship, which means that several rooms can be listed in one hotel (I will show souce code bellow). When I want to create new room, there is an option to choose to which hotel that particular room belongs:

enter image description here

Here is the code of classes Room and Hotel :

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
@Table(
        name = "room"
)
public class Room {

    @Id
    @SequenceGenerator(
            name = "room_sequence",
            sequenceName = "room_sequence",
            allocationSize = 1
    )
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "room_sequence"
    )
    private Long roomId;
    @Column(
            name = "name",
            nullable = false
    )
    private String name;
    @Column(
            name = "price"
    )
    private Integer price;

    @ManyToOne
    @JoinColumn(
            name = "hotel_id",
            referencedColumnName = "hotelId"
    )
    private Hotel hotel;
}
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Builder
@Table(
        name = "hotel"
)
public class Hotel {

    @Id
    @SequenceGenerator(
            name = "hotel_sequence",
            sequenceName = "hotel_sequence",
            allocationSize = 1
    )
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "hotel_sequence"
    )
    private Long hotelId;
    @Column(
            name = "name",
            nullable = false
    )
    private String name;
    @Column(
            name = "star",
            nullable = false
    )
    private Integer star;
    @Column(
            name = "location",
            nullable = false
    )
    private String location;

    @JsonIgnore
    @OneToMany(mappedBy = "hotel")
    @ToString.Exclude
    private Set<Room> rooms;
}

And here is the whole RoomController with methods to: create new room, update existing room, delete room, show "create new room" form, show "update existing room" form etc.:

@Controller
@RequestMapping("/hms/rooms")
public class RoomController {

    private final RoomServiceImpl roomService;
    private final HotelServiceImpl hotelService;

    @Autowired
    public RoomController(RoomServiceImpl roomService, HotelServiceImpl hotelService) {
        this.roomService = roomService;
        this.hotelService = hotelService;
    }

    @GetMapping
    public String listRooms(Model model) {
        model.addAttribute("rooms", roomService.getAllRooms());
        return "rooms";
    }


    @GetMapping("/new")
    public String addRoomForm(Model model) {
        Room room = new Room();
        List<Hotel> listHotels = hotelService.getAllHotels();

        model.addAttribute("room", room);
        model.addAttribute("listHotels", listHotels);
        return "room_create";
    }

    @PostMapping
    public String addNewRoom(@ModelAttribute("room") Room room) {
        roomService.addNewRoom(room);
        return "redirect:/hms/rooms";
    }

    @GetMapping("/edit/{roomId}")
    public String updateRoomForm(@PathVariable Long roomId, Model model) {
        List<Hotel> listHotels = hotelService.getAllHotels();

        model.addAttribute("room", roomService.findRoomById(roomId));
        model.addAttribute("listHotels", listHotels);
        return "room_edit";
    }

    @PostMapping("/{roomId}")
    public String updateRoom(@PathVariable Long roomId, @ModelAttribute("room") Room room) {
        // get room from database by id
        Room existingRoom = roomService.findRoomById(roomId);
        existingRoom.setRoomId(roomId);
        existingRoom.setName(room.getName());
        existingRoom.setPrice(room.getPrice());
        existingRoom.setHotel(room.getHotel());

        // save updated room object
        roomService.updateRoom(existingRoom);
        return "redirect:/hms/rooms";
    }

    // handler method to handle delete room request
    @GetMapping("/{roomId}")
    public String deleteRoom(@PathVariable Long roomId) {
        roomService.deleteRoomById(roomId);
        return "redirect:/hms/rooms";
    }

    @GetMapping("/details/{roomId}")
    public String viewRoom(@PathVariable Long roomId, Model model) {
        model.addAttribute("room", roomService.findRoomById(roomId));
        return "room_view";
    }
}

Also, here is the thymeleaf logic code which is used to get list of hotels on "create new room form":

<div class="form-group">
    <label> Hotel </label>
    <select th:field="*{hotel}" class="form-control" required>
        <th:block th:each="hotel : ${listHotels}">
            <option th:text="${hotel.name}" th:value="${hotel.hotelId}"/>
        </th:block>
    </select>
</div>

Solution

  • You could easily achieve at your repository level as well as in your thymleaf too, please have a look at code below

    <span th:each="room : ${hotel.getRooms()}">
    

    I hope it helps!