· 개별 객실 조회 (백엔드)
RoomController.java
// 객실 개별 조회
@GetMapping("/room/{roomId}")
public ResponseEntity<Optional<RoomResponse>> getRoomById(@PathVariable Long roomId) {
// roomService를 통해 roomId에 해당하는 객실 정보를 Optional<Room>으로 가져온다
// Optional<Room>: 해당 ID의 객실이 있을 수도 있고 없을 수도 있다
Optional<Room> theRoom = roomService.getRoomById(roomId);
// 데이터가 없으면 예외 발생
return theRoom.map((room) -> {
RoomResponse roomResponse = getRoomResponse(room);
return ResponseEntity.ok(Optional.of(roomResponse));
}).orElseThrow(() -> new ResourceNotFoundException("해당 객실이 없습니다"));
}
// Room 객체를 RoomResponse로 변환
private RoomResponse getRoomResponse(Room room) {
// 특정 Room의 모든 예약 정보 가져오기
List<BookedRoom> bookings = getaAllBookingsByRoomId(room.getId());
// 각 예약 정보(bookings)를 BookingResponse 객체로 변환
List<BookingResponse> bookingInfo = bookings.stream()
.map(booking -> new BookingResponse(booking.getBookingId(),
booking.getCheckInDate(),
booking.getCheckOutDate(),
booking.getBookingConfirmationCode()))
.toList();
byte[] photoBytes = null;
// Room 객체의 객실 이미지 데이터
Blob photoBlob = room.getPhoto();
if (photoBlob != null) {
try {
// BLOB 데이터 -> byte[](바이트 배열)로 변환
photoBytes = photoBlob.getBytes(1, (int) photoBlob.length());
} catch (SQLException e) {
e.printStackTrace(); // 에러 로그 출력
throw new PhotoRetrievalException("객실 이미지 불러오는 중 오류 발생");
}
}
// Room 정보를 기반으로 RoomResponse 객체 생성 후 반환
return new RoomResponse(room.getId(),
room.getRoomType(),
room.getRoomPrice(),
room.isBooked(),
photoBytes,
bookingInfo);
}
RoomServiceImpl.java
// 객실 개별 조회
@Override
public Optional<Room> getRoomById(Long roomId) {
return Optional.of(roomRepository.findById(roomId).get());
}
· 개별 객실 수정 (백엔드)
RoomController.java
// 객실 개별 수정
@PutMapping("/update/{roomId}")
public ResponseEntity<RoomResponse> updateRoom(@PathVariable Long roomId,
@RequestParam(required = false) String roomType,
@RequestParam(required = false) BigDecimal roomPrice) throws SQLException, IOException {
// roomService를 통해 객실 정보 수정
Room theRoom = roomService.updateRoom(roomId, roomType, roomPrice);
// 수정된 Room 객체를 roomResponse(DTO)로 변환 --> 클라이언트에 전달
RoomResponse roomResponse = getRoomResponse(theRoom);
return ResponseEntity.ok(roomResponse);
}
RoomServiceImpl.java
// 객실 개별 수정
@Override
public Room updateRoom(Long roomId, String roomType, BigDecimal roomPrice) {
Room room = roomRepository.findById(roomId)
.orElseThrow(() -> new ResourceNotFoundException("해당 객실이 없습니다"));
if (roomType != null) {
room.setRoomType(roomType);
}
if (roomPrice != null) {
room.setRoomPrice(roomPrice);
}
return roomRepository.save(room);
}
· 개별 객실 조회/수정 (클라이언트)
ApiFunctions.js
// 객실 개별 조회
export async function getRoomById(roomId) {
try {
const result = await api.get(`/rooms/room/${roomId}`)
return result.data
}
catch(error) {
throw new Error(`개별 객실 정보를 가져오는데 실패했습니다: ${error.message}`)
}
}
// 객실 개별 수정
export async function updateRoom(roomId, roomData) {
const formData = new FormData()
formData.append("roomType", roomData.roomType)
formData.append("roomPrice", roomData.roomPrice)
const response = await api.put(`/rooms/update/${roomId}`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
}
})
return response
}
EditRoom.jsx
// 객실 수정 폼
import { useEffect, useState } from "react";
import { getRoomById, updateRoom } from "../utils/ApiFunctions";
import { Link, useParams } from "react-router-dom";
export default function EditRoom() {
const [room, setRoom] = useState({
roomType: "",
roomPrice: "",
});
const [imagePreview, setImagePreview] = useState("");
const [successMessage, setSuccessMessage] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const { roomId } = useParams();
// 객실 유형 데이터
const roomTypes = [
"Suite room",
"Family room",
"Penthouse",
"Deluxe room",
"Superior room",
];
const handleInputChange = (event) => {
const { name, value } = event.target;
setRoom({
...room,
[name]: value,
});
};
const handleRoomTypeChange = (type) => {
setRoom({
...room,
roomType: type,
});
};
useEffect(() => {
const fetchRoom = async () => {
try {
// 객실 개별 조회
const roomData = await getRoomById(roomId);
setRoom(roomData);
// Base64 이미지 데이터 검증 및 설정
if (roomData.photo) {
// 이미 data:image 접두사가 있는지 확인
const photoData = roomData.photo.startsWith('data:image')
? roomData.photo
// 'data:image/jpeg;base64,' 접두사를 붙이기 --> 브라우저가 Base64로 인코딩된 이미지 표시 용도
: `data:image/jpeg;base64,${roomData.photo}`;
setImagePreview(photoData);
}
} catch (error) {
console.error("Error fetching room:", error);
setErrorMessage("객실 정보를 불러오는데 실패했습니다.");
}
};
fetchRoom();
}, [roomId]);
// 객실 수정 제출
const handleSubmit = async (e) => {
e.preventDefault();
try {
// 객실 수정 api 호출
const response = await updateRoom(roomId, room);
if (response.status === 200) {
setSuccessMessage("객실이 수정되었습니다!");
const updatedRoomData = await getRoomById(roomId);
setRoom(updatedRoomData);
// 이미지 데이터 업데이트
if (updatedRoomData.photo) {
const photoData = updatedRoomData.photo.startsWith('data:image')
? updatedRoomData.photo
: `data:image/jpeg;base64,${updatedRoomData.photo}`;
setImagePreview(photoData);
}
setErrorMessage("");
} else {
setErrorMessage("Error updating room");
}
} catch (error) {
console.error(error);
setErrorMessage(error.message);
}
};
return (
<section className="w-full text-center">
<h2 className="text-3xl font-bold my-6">기존 객실 수정</h2>
{successMessage && (
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 text-green-500 py-2 px-4 rounded shadow-lg text-center">
{successMessage}
</div>
)}
{successMessage && (
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 text-red-500 py-2 px-4 rounded shadow-lg text-center">
{errorMessage}
</div>
)}
<div>
{imagePreview && (
<img
src={imagePreview}
alt="Preview of Room Photo"
className="h-64 object-cover mx-auto my-4 rounded-md"
/>
)}
</div>
<form className="flex flex-col space-y-6" onSubmit={handleSubmit}>
<div>
<label htmlFor="roomType" className="block text-gray-700 font-medium mb-2">
Room Type
</label>
<div className="flex space-x-2 justify-center mx-auto">
{roomTypes.map((type, index) => (
<label
key={index}
className={`px-4 py-2 border rounded-md cursor-pointer ${
room.roomType === type
? "bg-blue-600 text-white"
: "bg-white text-gray-700 border-gray-300"
}`}
onClick={() => handleRoomTypeChange(type)}
>
<input
type="radio"
name="roomType"
value={type}
checked={room.roomType === type}
onChange={() => handleRoomTypeChange(type)}
className="hidden"
/>
{type}
</label>
))}
</div>
</div>
<div>
<label htmlFor="roomPrice" className="block text-gray-700 font-medium mb-2">
Room Price
</label>
<input
className="w-full p-3 border border-gray-300 rounded-md"
required
id="roomPrice"
name="roomPrice"
type="number"
value={room.roomPrice}
onChange={handleInputChange}
/>
</div>
<div className="flex gap-4">
<Link
to="/existing-rooms"
className="w-full py-3 bg-gray-300 text-gray-700 font-semibold rounded-md hover:bg-gray-400 transition text-center"
>
뒤로가기
</Link>
<button
className="w-full py-3 bg-blue-600 text-white font-semibold rounded-md hover:bg-blue-700 transition"
type="submit"
>
객실 수정
</button>
</div>
</form>
</section>
);
}
'Web Project > booking' 카테고리의 다른 글
Select all rooms (Frontend) (2) - 고객용 (0) | 2024.11.23 |
---|---|
Add navbar / footer (0) | 2024.11.23 |
Delete a single room (Frontend) (0) | 2024.11.18 |
Delete a single room (Backend) (0) | 2024.11.17 |
Select all rooms (Frontend) (0) | 2024.11.15 |