-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] 여행후기 기본 구현 완료 #39
Changes from 4 commits
8eeeaea
a336fcb
762d733
312171d
ba7106d
516c7c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.controller; | ||
|
||
import com.haejwo.tripcometrue.domain.triprecord.dto.request.TripRecordRequestDto; | ||
import com.haejwo.tripcometrue.domain.triprecord.dto.response.TripRecordResponseDto; | ||
import com.haejwo.tripcometrue.domain.triprecord.service.TripRecordService; | ||
import com.haejwo.tripcometrue.global.util.ResponseDTO; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/v1/trip-record") | ||
@RequiredArgsConstructor | ||
public class TripRecordController { | ||
|
||
private final TripRecordService tripRecordService; | ||
|
||
@PostMapping | ||
public ResponseEntity<ResponseDTO<TripRecordResponseDto>> tripRecordAdd( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 컨트롤러의 메소드에선 서비스 계층의 메소드와 다르게 동사를 뒤에 배치한 이유가 있나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 구분을 위해서 그렇게 했습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아하 그렇군요! 제가 알기로도 정해진 건 없다고 들었습니다! 메소드명까지 굳이 통일할 필요가 없다면 재량껏 사용해도 될듯 해요. 다른 분들은 어떻게 생각하시는지 궁금하네요 ㅎㅎ |
||
@RequestBody TripRecordRequestDto requestDto | ||
) { | ||
|
||
TripRecordResponseDto responseDto = tripRecordService.addTripRecord(requestDto); | ||
ResponseDTO<TripRecordResponseDto> responseBody = ResponseDTO.okWithData(responseDto); | ||
|
||
return ResponseEntity | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 등록한 여행 후기 내용 전체를 다시 프론트로 돌려주는 이유가 있나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 그냥 습관, 성향 차이로 알고 있습니다. |
||
.status(responseBody.getCode()) | ||
.body(responseBody); | ||
} | ||
|
||
@GetMapping("/{tripRecordId}") | ||
public ResponseEntity<ResponseDTO<TripRecordResponseDto>> tripRecordDetails( | ||
@PathVariable Long tripRecordId | ||
) { | ||
|
||
TripRecordResponseDto responseDto = tripRecordService.findTripRecord(tripRecordId); | ||
ResponseDTO<TripRecordResponseDto> responseBody = ResponseDTO.okWithData(responseDto); | ||
|
||
return ResponseEntity | ||
.status(responseBody.getCode()) | ||
.body(responseBody); | ||
} | ||
|
||
@PutMapping("/{tripRecordId}") | ||
public ResponseEntity<ResponseDTO<TripRecordResponseDto>> tripRecordModify( | ||
@PathVariable Long tripRecordId, | ||
@RequestBody TripRecordRequestDto requestDto | ||
) { | ||
|
||
TripRecordResponseDto responseDto = tripRecordService.modifyTripRecord(tripRecordId, requestDto); | ||
ResponseDTO<TripRecordResponseDto> responseBody = ResponseDTO.okWithData(responseDto); | ||
|
||
return ResponseEntity | ||
.status(responseBody.getCode()) | ||
.body(responseBody); | ||
|
||
} | ||
|
||
@DeleteMapping("/{tripRecordId}") | ||
public ResponseEntity<ResponseDTO> tripRecordRemove( | ||
@PathVariable Long tripRecordId | ||
) { | ||
|
||
tripRecordService.removeTripRecord(tripRecordId); | ||
ResponseDTO responseBody = ResponseDTO.ok(); | ||
|
||
return ResponseEntity | ||
.status(responseBody.getCode()) | ||
.body(responseBody); | ||
} | ||
|
||
|
||
|
||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.dto.request; | ||
|
||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
import com.haejwo.tripcometrue.domain.triprecord.entity.ExpenseType; | ||
import com.haejwo.tripcometrue.domain.triprecord.entity.TripRecord; | ||
import java.time.LocalDate; | ||
import lombok.Builder; | ||
|
||
public record TripRecordRequestDto( | ||
String title, | ||
String content, | ||
ExpenseType expenseType, | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") LocalDate tripStartDay, | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") LocalDate tripEndDay, | ||
String countries | ||
) { | ||
|
||
@Builder | ||
public TripRecordRequestDto(String title, String content, ExpenseType expenseType, | ||
LocalDate tripStartDay, LocalDate tripEndDay, String countries) { | ||
this.title = title; | ||
this.content = content; | ||
this.expenseType = expenseType; | ||
this.tripStartDay = tripStartDay; | ||
this.tripEndDay = tripEndDay; | ||
this.countries = countries; | ||
} | ||
|
||
public TripRecord toEntity() { | ||
return TripRecord.builder() | ||
.title(this.title) | ||
.content(this.content) | ||
.expenseType(this.expenseType) | ||
.tripStartDay(this.tripStartDay) | ||
.tripEndDay(this.tripEndDay) | ||
.countries(this.countries) | ||
.build(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.dto.response; | ||
|
||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
import com.haejwo.tripcometrue.domain.triprecord.entity.ExpenseType; | ||
import com.haejwo.tripcometrue.domain.triprecord.entity.TripRecord; | ||
import java.time.LocalDate; | ||
import lombok.Builder; | ||
|
||
public record TripRecordResponseDto( | ||
Long id, | ||
String title, | ||
String content, | ||
Integer average_rating, | ||
ExpenseType expenseType, | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") LocalDate tripStartDay, | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") LocalDate tripEndDay, | ||
Integer totalDays, | ||
String countries, | ||
Integer viewCount | ||
|
||
) { | ||
|
||
@Builder | ||
public TripRecordResponseDto(Long id, String title, String content, Integer average_rating, | ||
ExpenseType expenseType, LocalDate tripStartDay, LocalDate tripEndDay, Integer totalDays, | ||
String countries, Integer viewCount) { | ||
this.id = id; | ||
this.title = title; | ||
this.content = content; | ||
this.average_rating = average_rating; | ||
this.expenseType = expenseType; | ||
this.tripStartDay = tripStartDay; | ||
this.tripEndDay = tripEndDay; | ||
this.totalDays = totalDays; | ||
this.countries = countries; | ||
this.viewCount = viewCount; | ||
} | ||
|
||
|
||
public static TripRecordResponseDto fromEntity(TripRecord entity) { | ||
return TripRecordResponseDto.builder() | ||
.id(entity.getId()) | ||
.title(entity.getTitle()) | ||
.content(entity.getContent()) | ||
.average_rating(entity.getAverage_rating()) | ||
.expenseType(entity.getExpenseType()) | ||
.tripStartDay(entity.getTripStartDay()) | ||
.tripEndDay(entity.getTripEndDay()) | ||
.totalDays(entity.getTotalDays()) | ||
.countries(entity.getCountries()) | ||
.viewCount(entity.getViewCount()) | ||
.build(); | ||
|
||
} | ||
|
||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 처음 ExpenseType을 봤을 때 지출 유형이라고 이해했어요. 지출 유형은 카드, 현금, 계좌이체 등을 먼저 떠올릴 수 있으니, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 고려해보겠습니다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.entity; | ||
|
||
import java.util.stream.Stream; | ||
|
||
public enum ExpenseType { | ||
|
||
BELOW_50(50), | ||
BELOW_100(100), | ||
BELOW_200(200), | ||
BELOW_300(300), | ||
ABOVE_300(Integer.MAX_VALUE); | ||
|
||
private int max; | ||
|
||
ExpenseType(int max) { | ||
this.max = max; | ||
} | ||
|
||
public static ExpenseType findByMax(int max) { | ||
return Stream.of(ExpenseType.values()) | ||
.filter(p -> p.max == max) | ||
.findFirst() | ||
.orElseThrow(); // TODO: ExpenseType 예외 추가 | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.entity; | ||
|
||
import com.haejwo.tripcometrue.domain.triprecord.dto.request.TripRecordRequestDto; | ||
import jakarta.persistence.CascadeType; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.OneToMany; | ||
import jakarta.persistence.PrePersist; | ||
import jakarta.persistence.PreUpdate; | ||
import java.time.LocalDate; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.List; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class TripRecord { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "trip_record_id") | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private String title; | ||
private String content; | ||
|
||
private ExpenseType expenseType; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Enumerated 애노테이션이 빠진 것 같아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추가하겠습니다. |
||
|
||
private String countries; | ||
|
||
private LocalDate tripStartDay; | ||
private LocalDate tripEndDay; | ||
|
||
private Integer totalDays; | ||
private Integer average_rating; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 변수명에 카멜 케이스가 아닌 스네이크 케이스를 사용하신 이유가 있나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 실수 같네요 수정하겠습니다. |
||
private Integer viewCount; | ||
|
||
|
||
@OneToMany(mappedBy = "tripRecord", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) | ||
private List<TripRecordSchedule> tripRecordSchedules; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 김영한님 말씀으론 관례적으로 바로 ArrayList를 만든다고 하네요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 적용하겠습니다 |
||
|
||
@Builder | ||
public TripRecord(Long id, String title, String content, Integer average_rating, | ||
ExpenseType expenseType, LocalDate tripStartDay, LocalDate tripEndDay, Integer totalDays, | ||
String countries, Integer viewCount) { | ||
this.id = id; | ||
this.title = title; | ||
this.content = content; | ||
this.average_rating = average_rating; | ||
this.expenseType = expenseType; | ||
this.tripStartDay = tripStartDay; | ||
this.tripEndDay = tripEndDay; | ||
this.totalDays = totalDays; | ||
this.countries = countries; | ||
this.viewCount = viewCount; | ||
} | ||
|
||
// TODO: update 함수 | ||
public void update(TripRecordRequestDto requestDto) { | ||
this.title = requestDto.title(); | ||
this.content = requestDto.content(); | ||
this.expenseType = requestDto.expenseType(); | ||
this.tripStartDay = requestDto.tripStartDay(); | ||
this.tripEndDay = requestDto.tripEndDay(); | ||
this.countries = requestDto.countries(); | ||
} | ||
|
||
@PrePersist | ||
public void prePersist() { | ||
this.totalDays = calculateTotalDays(); | ||
} | ||
|
||
@PreUpdate | ||
public void preUpdate() { | ||
this.totalDays = calculateTotalDays(); | ||
} | ||
|
||
private int calculateTotalDays() { | ||
if (this.tripStartDay == null || this.tripEndDay == null) { | ||
return 0; | ||
} | ||
return (int) ChronoUnit.DAYS.between(this.tripStartDay, this.tripEndDay); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.entity; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class TripRecordSchedule { | ||
|
||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "trip_record_schedule_id") | ||
private Long id; | ||
|
||
@Column(nullable = false) | ||
private Integer dayNumber; | ||
|
||
@Column(nullable = false) | ||
private Integer ordering; | ||
|
||
private String content; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "tripRecord_id") | ||
private TripRecord tripRecord; | ||
|
||
@Builder | ||
public TripRecordSchedule(Long id, Integer dayNumber, Integer ordering, String content) { | ||
this.id = id; | ||
this.dayNumber = dayNumber; | ||
this.ordering = ordering; | ||
this.content = content; | ||
} | ||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.haejwo.tripcometrue.domain.triprecord.repository; | ||
|
||
import com.haejwo.tripcometrue.domain.triprecord.entity.TripRecord; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface TripRecordRepository extends JpaRepository<TripRecord, Long> { | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL에 도메인을 어떻게 표시할지는 추후에 논의해서 통일하면 좋을듯 합니다 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
원래는 restful 기준에 따르면 소문자와 - _ 이 두개로 표현하는게 정석으로 알고 있습니다.