728x90
BaseEntity
@MappedSuperclass
@EntityListeners(AuditingEntityListener::class)
abstract class BaseEntity(
@CreatedDate
var createdAt: LocalDateTime? = null,
@LastModifiedDate
var updatedAt: LocalDateTime? = null,
) { //추상 클래스
}
- 공통 엔티티로 만들 BaseEntity 추가
- 모든 엔티티에서 사용할 공통된 속성을 정의하고 싶은 경우 @MappedSuperclass를 사용해 부모 엔티티에서 공통 속성을 정의하고, 하위 엔티티에서 상속받아 사용할 수 있다.
- @EntityListeners는 엔티티에 특정한 이벤트가 발생하면 정해진 콜백 처리를 할 수 있다.
- AudidingEventListener를 사용하면, 엔티티가 생성될 때 @CreatedDate 가 붙은 프로퍼티에 생성일을 넣어주고, 엔티티 변경이 일어날 때, @LastModifiedDate가 붙은 프로퍼티에 변경 일시를 자동으로 넣어준다.
@SpringBootApplication
@EnableJpaAuditing
class FastcampusIssueServiceApplication
fun main(args: Array<String>) {
runApplication<FastcampusIssueServiceApplication>(*args)
}
- AudidingEventListener를 사용하기 위해서는 @EnableJpaAuditing 어노테이션이 필요하다
Issue
@Entity
@Table
class Issue(
@Id @GeneratedValue(strategy = IDENTITY)
val id: Long? = null,
@Column
var userId: Long,
@Column
var summary: String,
@Column
var description: String,
@Column
@Enumerated(STRING)
var type: IssueType,
@Column
@Enumerated(STRING)
var priority: IssuePriority,
@Column
@Enumerated(STRING)
var status: IssueStatus,
) : BaseEntity() {
}
IssueType, IssuePriority, IssueStatus
enum class IssueType {
BUG, TASK;
companion object {
//fun of(type: String) = valueOf(type.uppercase())
operator fun invoke(type: String) = valueOf(type.uppercase())
}
}
enum class IssueStatus {
TODO, IN_PROGRESS, RESOLVED;
companion object {
operator fun invoke(status: String) = valueOf(status.uppercase())
}
}
enum class IssuePriority {
LOW, MEDIUM, HIGH;
companion object{
operator fun invoke(priority: String) = valueOf(priority.uppercase())
}
}
- of 메서드로 생성할 수도 있지만, 코틀린에서 제공하는 operator 키워드를 사용해 마치 생성자를 호출하듯 함수명 없이 호출이 가능하다.
Repository
interface IssueRepository : JpaRepository<Issue, Long> {
}
Servicer
@Service
class IssueService(
private val issueRepository: IssueRepository,
) {
@Transactional
fun create(userId: Long, request: IssueRequest): IssueResponse {
val issue = Issue(
summary = request.summary,
description = request.description,
userId = userId,
type = request.type,
priority = request.priority,
status = request.status
)
return IssueResponse(issueRepository.save(issue))
}
}
IssueRequest, IssueResponse
data class IssueRequest(
val summary: String,
val description: String,
val type: IssueType,
val priority: IssuePriority,
val status: IssueStatus,
)
data class IssueResponse(
val id: Long,
val summary: String,
val description: String,
val userId: Long,
val type: IssueType,
val priority: IssuePriority,
val status: IssueStatus,
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
val createdAt: LocalDateTime?,
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
val updatedAt: LocalDateTime?,
) {
companion object {
operator fun invoke(issue: Issue) =
with(issue) {
IssueResponse(
id = id!!,
summary = summary,
description = description,
userId = userId,
type = type,
priority = priority,
status = status,
createdAt = createdAt,
updatedAt = updatedAt
)
}
}
}
- 생성자를 호출하는 것처럼 생성할 수 있도록 invoke를 정의하였다.
- with안에서는 자기 자신을 가리키는 this 키워드를 생략할 수 있다.
- @JsonFormat을 통해 생성일, 수정일을 json 포멧을 변경할 수 있다.
Controller
@RestController
@RequestMapping("/api/v1/issues")
class IssueController(
private val issueService: IssueService,
) {
@PostMapping
fun create(
authUser: AuthUser, //HandlerMethodArgumentResolver를 통해 값을 주입받는다.
@RequestBody request: IssueRequest,
) = issueService.create(authUser.userId, request)
}
- 이 전에 ArgumentResolver를 통해, authUser를 등록해 두었기 때문에 파라미터로 AuthUser만 사용해도 자동으로 주입해 준다.
728x90
'실무 프로젝트로 배우는 Kotlin & Spring > 이슈 관리 서비스 개발하기' 카테고리의 다른 글
| 이슈 수정 / 이슈 삭제 (0) | 2022.11.27 |
|---|---|
| 이슈 목록 조회/ 이슈 상세 조회 (0) | 2022.11.27 |
| 공통 에러 처리 (0) | 2022.11.26 |
| API 스펙 정의 (0) | 2022.11.26 |
| 요구 사항 & 프로젝트 구성 (0) | 2022.11.26 |