[프로젝트] 이벤트 예약하기 1

박연주·2022년 7월 20일
0

B반 2팀의 Event-Cafe-Cloud(EC2)

  • 카페의 사장님은 HOST로 가입 후 자신의 카페를 사이트에 등록하여 이벤트 예약을 받을 수 있다.
  • 일반 사용자는 NORMAL로 가입 후 이벤트를 위한 카페를 선정하여 예약할 수 있다.

전체 구조

# com.eventcafecloud
event
 ㄴ controller
 	ㄴ EventApiController
    ㄴ EventController
 ㄴ domain
 	ㄴ type
    	ㄴ EventCategory
    ㄴ Event
    ㄴ EventImage
 ㄴ dto
 	ㄴ EventCreateRequestDto
    ㄴ EventListResponseDto
    ㄴ EventReadResponseDto
    ㄴ EventResponseForProfileDto
    ㄴ EventUpdateRequestDto
    ㄴ EventUpdateResponseDto
 ㄴ repository
 	ㄴEventRepository
 ㄴ service
 	ㄴ EventService
 
 
 # resources
 	ㄴ static
    	ㄴ css
        	ㄴ event.css
            ㄴ eventCreate.css
            ㄴ eventDetail.css
        ㄴ js
        	ㄴ event
            	ㄴ eventCreate.js
                ㄴ eventCreate-datepicker.js
                ㄴ eventList.js
 	ㄴ templates
    	ㄴ event
        	ㄴ fragments
            	ㄴ event-create-form.html
                ㄴ event-detail.html
                ㄴ event-update-modal.html
            ㄴ eventCreateForm.html
            ㄴ eventDetail.html
            ㄴ eventList.html

DB 설계

Event domain

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
@DynamicUpdate
public class Event extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "event_number")
    private Long id;

    @Column(nullable = false)
    private String eventName;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private EventCategory eventCategory;

    @Column(nullable = false)
    private String eventStartDate;

    @Column(nullable = false)
    private String eventEndDate;

    @Column(nullable = false, columnDefinition = "TEXT")
    private String eventInfo;

    @Column(nullable = false)
    private Integer eventPrice;

    @Column(nullable = false)
    private Boolean eventCancelAvail;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_number")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cafe_number")
    private Cafe cafe;

    @OneToMany(mappedBy = "event", cascade = CascadeType.ALL)   // mappedBy, cascade
    private List<EventImage> eventImages = new ArrayList<>();

    public Event(EventCreateRequestDto requestDto) {
        this.eventName = requestDto.getEventName();
        this.eventCategory = requestDto.getEventCategory();
        this.eventStartDate = requestDto.getEventStartDate();
        this.eventEndDate = requestDto.getEventEndDate();
        this.eventInfo = requestDto.getEventInfo();
        this.eventPrice = Integer.valueOf(requestDto.getEventPrice());
        this.eventCancelAvail = true;
    }

메소드와 연관관계 추가

# 메소드
	public void updateEvent(EventUpdateRequestDto requestDto) {
        this.eventName = requestDto.getEventName();
        this.eventInfo = requestDto.getEventInfo();
    }

    public String getDate() {
        SimpleDateFormat today = new SimpleDateFormat("yyyy-MM-dd");
        return today.format(new Date());
    }

    
# 연관 관계 편의 메소드
    public void addUser(User user) {
        this.user = user;
        user.getEvents().add(this);
    }

    public void addCafe(Cafe cafe) {
        this.cafe = cafe;
        cafe.getEvents().add(this);
    }

    public void addEventImage(EventImage eventImage) {
        eventImages.add(eventImage);
        eventImage.addEvent(this);
    }



Event 예약하기

Event Create & Save

1. create 요청이 들어오면 (@PostMapping)
2. EventCreateRequestDto에 필요정보들을 담아서 
3. DB에 저장

EventCreateRequestDto

@Data
public class EventCreateRequestDto {
    
    private String eventName;
    private EventCategory eventCategory;
    private String eventStartDate;
    private String eventEndDate;
    private String eventInfo;
    private String eventPrice;
    private List<MultipartFile> files;
    private Long cafeNumber;
}


EventController

@Controller
@RequiredArgsConstructor
public class EventController {

    private final EventService eventService;
    private final CafeService cafeService;

    // 이벤트 예약 폼
    @GetMapping("/events/registration")    // 해당 Api 로 연결
    public String createEventForm(User loginUser, Model model, @RequestParam Long cafeId) throws ParseException {

        if (loginUser != null) {
            model.addAttribute("userNick", loginUser.getUserNickname());
            model.addAttribute("userId", loginUser.getId());
            model.addAttribute("cafeId", cafeId);     // user가 있을 경우 카페정보와 유저정보를 Model에 담아서 보냄
        }

        ArrayList<String> dates = cafeService.AllReservationListByCafe(cafeId);
        model.addAttribute("dates", dates);
        model.addAttribute("cafeName", cafeService.findCafeByIdForDetail(cafeId).getCafeName());
        // 휴무일등록시, 등록 정보를 받아올 객체를 넘김
        model.addAttribute("requestDto", new CafeScheduleRequestDto());
        model.addAttribute("eventCreateRequestDto", new EventCreateRequestDto());  // binding 할 정보 폼
        
        return "event/createEventForm";    // 해당 html과 연결
    }

    // 이벤트 예약
    @PostMapping("/events")
    public String createEvent(User loginUser, @Validated @ModelAttribute EventCreateRequestDto requestDto, BindingResult result) {
																// requestDto의 정보를 binding
        eventService.saveEvent(requestDto, loginUser);  // 담아온 정보로 메소드 실행

        if (result.hasErrors()) {
            return "event/createEventForm";
        } else {
            return "redirect:/cafes/" + requestDto.getCafeNumber()+ "/detail";
        }
    }


EventService

@RequiredArgsConstructor
@Service
public class EventService {

    private final EventRepository eventRepository;
    private final CafeRepository cafeRepository;
    private final UserRepository userRepository;
    private final S3Service s3Service;

    // 이벤트 예약
    @Transactional           // 메소드 실행
    public void saveEvent(EventCreateRequestDto requestDto, User securityUser) {

        User user = userRepository.getById(securityUser.getId());

        Cafe cafe = cafeRepository.findById(requestDto.getCafeNumber()).orElseThrow(
                () -> new IllegalArgumentException(CAFE_NOT_FOUND.getMessage())
        );

        Event event = new Event(requestDto);
        event.addCafe(cafe);
        event.addUser(user);     // 연관 관계 메소드 실행

        List<MultipartFile> files = requestDto.getFiles();
        List<String> eventImageUrls = s3Service.upload(files, "eventImage");

        // 이벤트 이미지 생성, S3의 URL을 가져와서 하나씩 eventImage로 만듦
        MultipartFile file;
        String eventImageUrl;

        for (int i = 0; i < files.size(); i++) {
            file = files.get(i);
            eventImageUrl = eventImageUrls.get(i);
            EventImage eventImage = new EventImage(file.getOriginalFilename(), eventImageUrl);
            event.addEventImage(eventImage);   // 연관 관계 메소드 실행
        }
        eventRepository.save(event);     // DB에 저장
    }



Event Read & Get

1. Read 요청이 들어오면 (@GetMapping)
2. EventReadResponseDto, EventListResponseDto에 필요정보들을 담아
3. 해당 api에 응답

EventListResponseDto

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Setter
@Getter
public class EventListResponseDto {
    private Long eventNumber;
    private String eventName;
    private EventCategory eventCategory;
    private String eventStartDate;
    private String eventEndDate;
    private List<String> eventImageUrls;
    private int eventCmtCount;
    private int eventBookmarkCount;

    public EventListResponseDto(Event event) {
        this.eventNumber = event.getId();
        this.eventName = event.getEventName();
        this.eventCategory = event.getEventCategory();
        this.eventStartDate = event.getEventStartDate();
        this.eventEndDate = event.getEventEndDate();
        eventImageUrls = event.getEventImages().stream()
                .map(i -> i.getEventImageUrl())
                .collect(Collectors.toList());
        this.eventCmtCount = event.getEventComments().size();
        eventBookmarkCount = event.getEventBookmarks().size();
    }
}


EventReadResponseDto

@NoArgsConstructor(access = AccessLevel.PROTECTED) // 외부의 접근을 막기 위해
@Setter
@Getter
public class EventReadResponseDto {
    private String eventName;
    private EventCategory eventCategory;
    private String eventStartDate;
    private String eventEndDate;
    private String eventInfo;
    private boolean isCancel;
    private Long userNumber;
    private String userNickname;
    private Long cafeNumber;
    private String cafeName;
    private Integer cafeZonecode;
    private String cafeAddress;
    private String cafeAddressDetail;
    private double cafeX;
    private double cafeY;
    private List<String> eventImageUrls;
    private String bookmarkByLoginUser;



    public EventReadResponseDto(Event event, boolean checkBookmarkByLoginUser) {
        this.eventName = event.getEventName();
        this.eventCategory = event.getEventCategory();
        this.eventStartDate = event.getEventStartDate();
        this.eventEndDate = event.getEventEndDate();
        this.eventInfo = event.getEventInfo();
        this.isCancel = eventCancelAvail(event.getEventStartDate());
        this.userNumber = event.getUser().getId();
        this.userNickname = event.getUser().getUserNickname();
        this.cafeNumber = event.getCafe().getId();
        this.cafeName = event.getCafe().getCafeName();
        this.cafeZonecode = event.getCafe().getCafeZonecode();
        this.cafeAddress = event.getCafe().getCafeAddress();
        this.cafeAddressDetail = event.getCafe().getCafeAddressDetail();
        this.cafeX = event.getCafe().getCafeX();
        this.cafeY = event.getCafe().getCafeY();
        eventImageUrls = event.getEventImages().stream()
                .map(i -> i.getEventImageUrl())
                .collect(Collectors.toList());
        bookmarkByLoginUser = String.valueOf(checkBookmarkByLoginUser);

    }

    public boolean eventCancelAvail(String eventStartDate) {
        Date now;
        Calendar cal = java.util.Calendar.getInstance();
        cal.add(Calendar.DATE, +7);
        now = cal.getTime();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String deadline = sdf.format(now);

        return eventStartDate.compareTo(deadline) > 0;
    }
}


Controller

// 이벤트 리스트 보기
    @GetMapping("/events")
    public String getEventList(@PageableDefault Pageable pageable,
                               @RequestParam(required = false, defaultValue = "", value = "keyword") String keyword,
                               @RequestParam(required = false, value = "eventCategory") EventCategory eventCategory,
                               User loginUser, Model model) {

        if (loginUser != null) {
            model.addAttribute("userNick", loginUser.getUserNickname());
            model.addAttribute("userId", loginUser.getId());
        }

        Page<EventListResponseDto> eventListResponseDtos = eventService.toDtoList(keyword, eventCategory, pageable);
        model.addAttribute("eventListResponseDtos", eventListResponseDtos);

        return "event/eventList";
    }

// 이벤트 상세 + 수정 폼
    @GetMapping("/events/{eventNumber}/detail")
    public String getEventDetail(User loginUser, @PathVariable Long eventNumber, Model model) {
        if (loginUser != null) {
            model.addAttribute("userNick", loginUser.getUserNickname());
            model.addAttribute("userId", loginUser.getId());
        }

        EventReadResponseDto eventReadResponseDto = eventService.findEventByIdForDetail(eventNumber, loginUser);
        model.addAttribute("eventReadResponseDto", eventReadResponseDto);
        model.addAttribute("eventUpdateRequestDto", new EventUpdateRequestDto());
        model.addAttribute("event", eventService.findEventById(eventNumber));
        return "event/eventDetail";
    }

Service

 // 전체 이벤트 목록
    public Page<EventListResponseDto> toDtoList(String keyword, EventCategory eventCategory, Pageable pageable) {
        int page = (pageable.getPageNumber() == 0) ? 0 : (pageable.getPageNumber() - 1);
        pageable = PageRequest.of(page, 12, Sort.Direction.DESC, "id");

        Page<Event> events = null;
        if (eventCategory == null) {
            events = eventRepository.findByEventNameContaining(keyword, pageable);
        } else {
            events = eventRepository.findByEventNameContainingAndEventCategory(keyword, eventCategory, pageable);
        }

        Page<EventListResponseDto> eventListResponseDtos = events.map(EventListResponseDto::new);

        return eventListResponseDtos;
    }


    // 이벤트 상세 + 북마크
    public EventReadResponseDto findEventByIdForDetail(Long eventNumber, User loginUser) {

        Event event = eventRepository.findById(eventNumber).orElseThrow(
                () -> new IllegalArgumentException(EVENT_NOT_FOUND.getMessage()));

        boolean checkBookmarkByLoginUser;

        if (loginUser != null) {
            checkBookmarkByLoginUser = eventBookmarkRepository.existsByEventIdAndUserId(eventNumber, loginUser.getId());
        } else {
            checkBookmarkByLoginUser = false;
        }

        return new EventReadResponseDto(event, checkBookmarkByLoginUser);
    }

Event Update&Modify

1. update 요청이 들어오면 (@PostMapping)
2. 요청 정보를 RequestDto에 담고 응답 정보를 ResponseDto담아 응답
* 모달이라 따로 페이지 반환하지 않고 Status code 반환

EventUpdateRequestDto & EventUpdateResponseDto

# RequestDto
@Setter
@Getter
public class EventUpdateRequestDto {
    @Length(min = 1,max = 24)
    private String eventName;
    @Length(min = 1)
    private String eventInfo;
}

# ResponseDto
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Setter
public class EventUpdateResponseDto {
    private String eventName;
    private String eventInfo;

    public EventUpdateResponseDto(String eventName, String eventInfo){
        this.eventName = eventName;
        this.eventInfo = eventInfo;
    }
}

controller

# 수정 폼은 상세페이지와 같이 있음

// 이벤트 수정
    @PostMapping("/events/{eventNumber}/detail")
    public String updateEvent(@PathVariable Long eventNumber, @Validated @ModelAttribute EventUpdateRequestDto requestDto, BindingResult result, User loginUser) {
        int statusCode = eventService.modifyEvent(eventNumber, requestDto, loginUser);
        if (statusCode == 500) {
            return "error/500";
        }
        return "redirect:/events/{eventNumber}/detail";
    }

Service

// 이벤트 수정
    @Transactional
    public int modifyEvent(Long eventNumber, EventUpdateRequestDto requestDto, User loginUser) {
        Event event = eventRepository.findById(eventNumber).orElseThrow(
                () -> new IllegalArgumentException(EVENT_NOT_FOUND.getMessage())
        );

        if (!event.getUser().getId().equals(loginUser.getId())) {
            return 500;
        }

        event.updateEvent(requestDto);
        EventUpdateResponseDto eventUpdateResponse = new EventUpdateResponseDto(event.getEventName(), event.getEventInfo());
        return 200;
    }

Event Delete&Remove

1. Delete 요청이 들어오면 (@DeleteMapping)
2. controller, service 거쳐 해당 eventNumber를 가진 event 삭제

controller

// 이벤트 삭제
    @DeleteMapping("/events/{eventNumber}/detail")
    public String deleteEvent(@PathVariable Long eventNumber) {
        boolean result = eventService.isEventCancelAvail(eventNumber);
        if (result) {
            eventService.removeEvent(eventNumber);
        } else {
            return "redirect:/events/" + eventNumber + "/detail";
        }
        return "redirect:/events";
    }

Service

// 이벤트 삭제
    public void removeEvent(Long eventNumber) {
        eventRepository.deleteById(eventNumber);
    }
profile
하루에 한 개념씩

0개의 댓글