Spring/SpringBoot

[SpringBoot] 호텔예약사이트 - 관리자 객실조회

코딩맛 2024. 3. 25. 23:54
해당 글은 Spring으로 구현한 프로젝트를 SpringBoot로 리팩토링 하는 과정을 담은 글입니다.

 

이번 시간에는 관리자로 로그인하여 객실 정보를 불러오는 작업을 하려고 합니다.

 

1. 테이블 구조

테이블은 room, room_image으로 구성되어 있습니다.

ROOM 테이블
ROOM_IMAGE 테이블

 

객실 정보를 불러올 때 객실 이미지 정보도 같이 불러와서 목록에 노출시켜야 하므로

객실테이블과 객실 이미지 테이블을 조인 시켜줘야 합니다.

 

2. Entity 선언

 

** 객실 테이블, 객실 이미지 테이블 관계 **

- 객실 테이블 : 주 테이블

- 객실 이미지 테이블 : 대상 테이블

 

객실과 객실이미지는 양방향 관계가 되는데 객실이미지 테이블에 외래키 설정이 되어 있다.

이 구조는 외래키에 Null 값이 들어가지 않는다. 객실이미지는 객실이 없으면 존재하지 않는다.

 

1) Room.java (객실엔티티 - 주 테이블)

package com.boot.sonorous.admin.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.ToString;

@Entity
@Data
@ToString(exclude = "roomImage")
@Table(name = "T_ROOM")
public class Room {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ROOM_ID")
    private int Id;

    private String roomName;
    private String roomSize;
    private String bedType;
    private String roomPrice;
    private String roomAmount;
    private String peopleNum;
    private String roomSpec;
    private String insId;
    private String insDate;
    private String modId;
    private String modDate;

    @OneToOne(mappedBy = "room")
    private RoomImage roomImage;
}

 

2) RoomImage.java

@Entity
@Data
@Table(name = "T_ROOM_IMAGE")
public class RoomImage {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ROOM_IMAGE_ID")
    private int Id;

    private String roomImageName;
    private String roomImagePath;

    @OneToOne
    @JoinColumn(name="room_id")
    private Room room;
}

대상테이블에 외래키를 둬야하기 때문에 @JoinColmn을 객실이미지엔티티에 둡니다.

Room 엔티티에 RoomImage 필드에 mappedBy 속성을 통해 연관 관계의 주인이 RoomImage에 있음을 알립니다.

 

3. Controller 선언

@Controller
public class SonorousRoomController {

    @Autowired
    private SonorousRoomService sonorousRoomService;

    @GetMapping("/roomList")
    public String roomList(Model model, HttpSession session, HttpServletResponse response) throws Exception {
        // 1. 세션값이 널이거나
        // 2. 관리자 권한이 아니면 로그인 페이지 이동
        Member loginMember = (Member)session.getAttribute("loginMember");
        if(loginMember == null || !(loginMember.getMAuth().equals("ADMIN"))){
            response.setContentType("text/html; charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.println("<script>alert('접근 권한이 없습니다.');</script>");
            out.flush();
            out.close();
        }
        List<RoomImage> roomList = sonorousRoomService.roomList();
        System.out.print(roomList);
        model.addAttribute("roomList", roomList);

        return "admin/roomList";
    }
}

 

서비스에 객실 정보를 불러오는 roomList() 메서드를 호출, 엔티티 타입이 RoomImage인 List에 담습니다.

 

4. service 선언

@Service
public class SonorousRoomService {
    @Autowired
    SonorousRoomRepository sonorousRoomRepository;

    public List<RoomImage> roomList() {
        return sonorousRoomRepository.findAll();
    }
}

레퍼지토리에 테이블 모든 컬럼을 조회하는 findAll() 메서드를 호출, List<RoomImage>로 반환합니다.

 

5. Repository 선언

@Repository
public interface SonorousRoomRepository extends JpaRepository<RoomImage, Integer> {
}

레퍼지토리 인자에 RoomImage 엔티티와 Id 값의 타입인 Integer를 넣습니다.

controller에서 roomList 이름의 리스트에 담고 admin/roomLIst 경로의 view 호출합니다.

 

6. view 선언

<div id="table">
                <table style="margin:auto; text-align:center;">
                    <caption style="visibility:hidden">카테고리ID, 케테고리명, 사용여부, Description, 등록자 표시하는 테이블</caption>
                    <colgroup>
                        <col width="10%"/>
                        <col width="30%"/>
                        <col width="40%"/>
                        <col width="20%"/>
                    </colgroup>
                    <tr>
                        <th align="center">No</th>
                        <th align="center">이미지</th>
                        <th align="center">객실이름</th>
                        <th align="center">등록일</th>
                    </tr>
                    <tr th:each="room : ${roomList}">
                        <td th:text="${room.room.Id}"></td>
                        <td th:if="${room.roomImageName != null}">
                            <img style="width: 150px;height:100px" th:src="'/upload/' + ${room.roomImagePath} + '/' + ${room.roomImageName}"/></td>
                        <td>
                            <a th:href="'/roomView?Id=' + ${room.room.Id}" th:text="${room.room.roomName}"></a>
                        </td>
                        <td th:text="${room.room.insDate}"></td>
                    </tr>
                </table>
            </div>

 

roomList 리스트에 담긴 값을 room에 하나씩 담고 값을 꺼내옵니다.

room(객실 이미지정보) > room(객실 정보)가 있으므로 객실 id를 가져오려면 room.room.Id로 가져와줍니다.

객실 이미지는 /upload/객실이미지경로/객실이미지이름 경로에 있어

src에 위와 같이 작성하면 이미지를 불러옵니다.

 

객실 목록 페이지 화면

참고블로그

https://wildeveloperetrain.tistory.com/186

 

JPA @OneToOne 일대일 연관 관계 정리 및 LazyLoding 이슈

JPA를 사용하면서도 연관 관계 매핑을 쓰지 않다가 이번 프로젝트에서 연관 관계를 적용하기 시작하며 정리한 내용이며, JPA 연관 관계 매핑 중에서 1:1 연관 관계인 @OneToOne에 대해 정리한 내용입

wildeveloperetrain.tistory.com