이벤트 추가하기
- 지난 게시글에서 이벤트 추가 Dialog를 생성하였다.
- 오늘은 Dialog를 통해 이벤트를 추가하면 해당 유저의 Event Table에 데이터가 삽입되고 캘린더에 추가된 이벤트가 보이도록 해볼 것이다.
Spring Boot
Event Entity
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Event extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "event_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
private LocalDate startDate;
private LocalDate endDate;
private LocalTime startTime;
private LocalTime endTime;
private String title;
private String content;
// 연관관계 편의 메서드
public void setMember(Member member){
this.member = member;
member.getEvents().add(this);
}
}
- 우선 이벤트 엔티티를 추가해준다.
- member와 다대일 연관관계를 맺고 일정에 필요한 필드들을 가지고 있다.
- Date와 Time을 분리한 이유는 일정에서 날짜만 정해지고 시간이 정해지지 않는 경우가 있기 때문이다.
Event Repository, Service
public interface EventRepository extends JpaRepository<Event, Long> {
}
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class EventService {
private final EventRepository eventRepository;
private final MemberRepository memberRepository;
@Transactional
public EventResponseDto save(EventSaveRequestDto dto, String email) {
Member member = memberRepository.findByEmail(email)
.orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다."));
Event event = dto.toEntity(member);
eventRepository.save(event);
return new EventResponseDto(event);
}
}
- EventRepository는 기본 Spring Data JPA가 지원해주는 메서드들을 사용할 것이다.
- EventService의 save에서 EventSaveRequestDto, email 매개변수를 통해 event를 생성한 후 event를 저장한다.
- 그 후 EventResponseDto로 변환하여 return 해준다.
@NoArgsConstructor
@Getter
public class EventSaveRequestDto {
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
@DateTimeFormat(pattern = "HH:mm")
private LocalTime startTime;
@DateTimeFormat(pattern = "HH:mm")
private LocalTime endTime;
private String title;
private String content;
public Event toEntity(Member member){
Event event = Event.builder()
.startDate(startDate)
.endDate(endDate)
.startTime(startTime)
.endTime(endTime)
.title(title)
.content(content)
.build();
event.setMember(member);
return event;
}
}
- EventSaveRequestDto를 보면 @DateTimeFormat으로 직렬화된 JSON 데이터들을 LocalDate, LocalTime으로 변환할 수 있다.
EventApiController
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/events")
public class EventApiController {
private final EventService eventService;
@PostMapping
public ResponseEntity saveEvent(@RequestBody EventSaveRequestDto dto,
@TokenMemberEmail String email){
EventResponseDto saveDto = eventService.save(dto, email);
return ResponseEntity.ok(saveDto);
}
}
- EventApiController에서 클라이언트의 요청을 받아 이벤트를 저장해준다.
- @ToeknMemberEmail은 HandlerMethodArgumentResolver를 이용하여 클라이언트에서 보낸 Token을 디코딩하여 회원의 email을 반환해준다.
- 클라이언트단에서 로그인 회원을 검증할 테지만 여기서 한번 더 검증을 통해 토큰이 없다면 이벤트는 추가되지 않을 것이다.
Vue.js
- 지난 게시글에서 구현한 일정 추가 Dialog 이후를 구현할 것이다.
Calendar Store
State
const state = {
event: initEvent(),
events: [],
dialog: false,
};
function initEvent(){
return {
startDate: '',
startTime: '',
endDate: '',
endTime: '',
content: '',
title: '',
}
}
- Calendar의 state이다.
- event는 일정 추가 Dialog의 각 속성의 값들이다.
- events는 추가된 이벤트들을 받아오고 그 값을 캘린더에 보여주기 위한 state이다.
EventDialog.vue Methods
methods: {
submit() {
if (this.event.title === '' || this.event.endDate === '') {
store.commit('SET_SNACKBAR',
setSnackBarInfo('제목과 종료일자를 작성해주세요.', 'error', 'top'));
} else {
this.$store.dispatch('REQUEST_ADD_EVENT', this.event);
}
},
}
- 일정 추가 모달에서 추가 버튼을 누르게 되면 호출되는 submit() 메서드이다.
- 일정 제목과 종료일은 필수이므로 검증을 한 후 dispatch를 통해 actions를 호출한다.
Actions
const actions = {
async REQUEST_ADD_EVENT(context, calendar) {
try {
const response = await requestAddEvent(calendar);
const addedEvent = makeEvent(response.data);
context.commit('ADD_EVENT', addedEvent);
store.commit('SET_SNACKBAR', setSnackBarInfo('일정이 추가 되었습니다.', 'info', 'top'))
} catch (e) {
console.log('일정 추가 에러' + e);
}
},
}
const colors = ['blue', 'indigo', 'deep-purple', 'green', 'orange', 'red'];
const makeEvent = (event) => {
return {
name: event.title,
start: event.startDate + getTime(event.startTime),
end: event.endDate + getTime(event.endTime),
color: colors[Math.floor(Math.random() * 6)]
}
};
- 캘린더의 actions 부분이다.
- 우선 비동기 통신으로 requestAddEvent를 통해 서버에게 저장을 요청한다.
- 저장된 이벤트를 서버는 응답을 해줄 것이다.
- 그 후 makeEvent를 통해 이벤트를 따로 생성해줘야 한다.
- name, start, end, color 프로퍼티를 가지는 event여야 vuetify 캘린더가 인식하여 캘린더에 보여주기 때문이다.
- name은 일정 제목이 되고 start는 startDate와 Time을 합친 것이다.
- color는 현재는 랜덤으로 배정하였다.
- 그렇게 만든 이벤트를 mutations에 넘겨준다.
Mutations
const mutations = {
ADD_EVENT(state, getEvent) {
state.events.push(getEvent);
state.dialog = false;
state.event = initEvent();
}
};
- actions에서 받은 이벤트를 events state에 추가해준다.
- 이렇게 추가된 이벤트를 캘린더에서 받아 화면에 보이게 될 것이다.
Calendar.vue
<v-calendar
:event-color="getEventColor"
:events="events"
:start="start"
:type="type"
@click:date="open"
@click:event="showEvent"
@click:more="moreEvent"
@click:time="open"
dark
ref="calendar"
v-model="start"
></v-calendar>
- 캘린더 컴포넌트이다.
- 저번 게시글 이후에 추가된 속성들이 조금 있다.
- 순서대로 event-color는 말 그대로 event의 color에 맞게 캘린더에 일정이 표시된다.
- events는 데이터 배열로 실제 일정들을 가지고 있다.
- @click. date는 캘린더의 날짜를 클릭했을 때 발생하는 것으로 Event추가 Dialog를 띄워준다.
- @click.event는 추후에 선택된 이벤트를 자세히 보여줄 때 사용한다.
- @click.more은 같을 날에 이벤트가 많을 때 more 표시가 잇는데 그것을 누르면 캘린더의 type을 day로 변경하여 자세시 볼 수 있게 해 준다.
- @click.time은 @click.date와 동일하게 시간을 클릭하면 이벤트 추가 Dialog를 띄어준다.
events computed
computed: {
events() {
return this.$store.state.calendar.events;
}
},
- mutations에서 추가한 state의 events 받아와 위에서 설명한 events 넣어주었다.
결과 확인
- 이벤트 추가가 정상적으로 이루어지고 캘린더에 즉시 반영되는 것을 확인할 수 있다.
- 데이터베이스를 확인해봐도 정상적으로 데이터가 들어간 것을 알 수 있다.
'Study' 카테고리의 다른 글
Spring Boot, Vue.js 캘린더 일정 조회 및 세부사항 조회 (0) | 2020.01.30 |
---|---|
Vue.js 캘린더 UI 구현, Event 추가 Dialog 구현 (1) | 2020.01.16 |
Vue.js GitHub와 Netlify에 배포하기 (0) | 2020.01.14 |
SpringBoot와 Vue.js를 이용한 회원가입, 로그인 기능, 권한별 라우터 설정 (1) | 2020.01.04 |
SpringSecurity OAuth CORS 문제 (0) | 2019.12.31 |