SPARTA 과제/SPRING

Schedule README

kjw81024 2026. 2. 5. 11:52

schedule project 는 사용자가 일정을 입력하고, 해당 일정에 접근하여 비밀번호를 확인 후 수정 및 삭제를 할 수 있게합니다. 또한 사용자는 일정에 댓글을 작성할 수 있습니다. 

사용자는 사용자명 (작성자명) 을 통해 리스트로 일정을 확인할 수 있고, 단일 일정을 조회하여 댓글을 함께 확인할 수 있습니다. 


해당 과제는 3 Layer Architecture(Controller, Service, Repository)를 적용했습니다.

이러한 3 Layer Architecture 를 사용한 이유는 기본적으로 한 계층을 수정해도 다른 계층에 영향을 최소화하는것을 목적으로 합니다. 관심사를 분리하여 각 요소의 응집도가 높아지고 결합도는 낮아지게 합니다. 

결합도가 낮아지면 각 계층을 독립적으로 테스트 할 수 있습니다. 

  • Controller 계층: 클라이언트로부터 HTTP 요청을 수신하고 응답을 반환해주는 역할을 담당하기 때문에 비즈니스로직이 존재하지 않고, 입출력에만 집중합니다. GET, POST, PUT, DELETE 를 각각 구분하여 작성할 수 있습니다.
  • Service 계층: 비즈니스 로직을 구현합니다. Repository 에서 정보를 가져와 하나의 응답을 어떻게 구성할지 결정합니다. 원자성이 충족되어야하는 단계는 트랜잭션으로 묶어져서 관리됩니다.
  • Repository 계층: 데이터를 저장, 조회하기 위해 DB에 직접 접근하고 CRUD 작업을 실제로 처리합니다. 

컨트롤러에서 데이터를 전달하는 방법인 아래 세 어노테이션에 대한 정리입니다.

  특징
@RequestParam URI의 queryString 으로 데이터를 받습니다.
? 뒤에 작성하여 사용합니다. ex) http://localhost:8080/schedules?writer=”{writerId}”
해당하는 데이터 하나를 받아와서 사용해서 각 변수별로 데이터를 저장할 수 있지만 객체생성이 불가합니다.
@PathVariable URL 의 일부를 파라미터로 사용합니다
/ 뒤에 작성하여 사용합니다. ex) http://localhost:8080/schedules/{id}
@RequestBody body 에 json 형태로 작성합니다. 
데이터가 담긴 객체 (DTO) 를 받아와서 사용합니다. 

 


API 명세서

https://www.notion.so/API-2fc55c64ceb28017ac38da3959e4289b

 

일정 관리 앱 API 명세서 | Notion

API 명세서: 일정 관리 앱 - version: 1.0.0 - Base URL: http://localhost:8080

www.notion.so

GitHub

https://github.com/jiwon-e-e/schedule

 

GitHub - jiwon-e-e/schedule: sparta bootcamp basic spring assignment

sparta bootcamp basic spring assignment . Contribute to jiwon-e-e/schedule development by creating an account on GitHub.

github.com

과제 진행 및 트러블 슈팅 문서 

더보기

 

ERD


1. Entity

일정과 댓글이 저장되는 Table 입니다.

각각은 id 를 고유값으로 가지고 있습니다.

 

/ Schedules 

더보기
데이터명 예시 비고
아이디 id 1 Id, JPA 가 순차적으로 부여
생성자에 포함되지 않음
일정 제목 name “10시 flow chart” 최대 길이 30, 필수값
일정 내용 contents “ flow chart notion 에 업로드” 최대 길이 200, 필수값
작성자명 writer “권지원” 필수값
비밀번호 pw “1234” 필수값
작성일 createAt 2026-02-03T13:45:20.4547789 BaseEntity 에서 자동으로 부여
생성자에 포함되지 않음
수정일 modifiedAt 2026-02-03T13:45:20.4547789 BaseEntity 에서 자동으로 부여
생성자에 포함되지 않음
public void update(String name, String writer)

사용자는 일정 제목과 작성자명만 업데이트 할 수 있습니다. 


/ Comments 

더보기
데이터명 예시 비고
아이디 id 1 Id, JPA 가 순차적으로 부여
생성자에 포함되지 않음
일정 아이디 schedule_id 1 Schedules 와 연결되는 FK
일정 내용 contents “내인생이더재밌음” 최대 길이 100, 필수값
작성자명 writer “냐냐냥” 필수값
비밀번호 pw “1234aa” 필수값
작성일 createAt 2026-02-03T13:45:20.4547789 BaseEntity 에서 자동으로 부여
생성자에 포함되지 않음
수정일 modifiedAt 2026-02-03T13:45:20.4547789 BaseEntity 에서 자동으로 부여
생성자에 포함되지 않음

위 두 Entity 는 BaseEntity 를 상속받아 작성일과 수정일 정보를 자동으로 갖습니다.

작성일 (createAt) 과 수정일 (modifiedAt) 은 LocalDateTime 형식으로 저장되며, 해당 Entity 가 update 되면 자동으로 modifiedAt 이 해당 시간으로 수정되어 저장됩니다.


2. Repository

JpaRepository 를 상속받아 사용하며 직접적으로 Entity 에 접근하고 관리합니다.

 

/ScheduleRepository

Schedule 과 관련된 Repository 단계 역할을 수행합니다.

더보기
List<Schedule> findAllByOrderByModifiedAtDesc()

Schedule 다건조회 시 일정목록을 수정일 기준으로 내림차순 정렬

JPA 가 query를 만들어주는 형식이므로 구체화가 필요없고 형식을 지켜야함


/CommentRepository

Comment 와 관련된 Repository 단계 역할을 수행합니다.

더보기
List<Comment> findByScheduleId(Long scheduleId)

특정 Schedule ID 를 가지는 CommentList를 반환 

JPA 가 query를 만들어주는 형식이므로 구체화가 필요없고 형식을 지켜야함


3. Service

/ScheduleService

scheduleRepository 와 commentService 에 접근 할 수 있습니다.

Schedule 과 관련된 Service 단계 역할을 수행합니다.

더보기
@Transactional
public CreateScheduleResponse save(CreateScheduleRequest request)

사용자의 입력으로 들어온 request 에서 filed 값을 가져와서 Schedule 생성자에 넣어 Repository에 저장하고 저장된 Schedule 을 기준으로 하여 Response DTO 를 만들어 (ID 와 생성,수정일이 포함됨, PW 미포함) 반환

 

@Transactional(readOnly = true)
public GetScheduleResponse getOneSchedule(Long id)

조회할 단건 일정 ID 를 매개변수로 받아와서 해당 ID 를 가진 일정이 존재하는지 확인, 존재한다면 Response DTO 를 만들어 (ID 와 생성,수정일, 댓글 리스트 이 포함됨, PW 미포함) 반환
commentList 는 commentService 에 구현된 findCommentsByScheduleId 함수를 사용

 

@Transactional(readOnly = true)
public List<GetSchedulesResponse> getUserSchedule(String writer)

writer 를 매개변수로 받아와서 (null 또는 공백)-> 전체리스트 반환/ (존재) -> 해당 writer 가 작성한 게시물 리스트만 반환

반환 형태는 List 이며 반환할 List 가 없다면 빈 리스트로 반환됨 

 

@Transactional
public UpdateScheduleResponse updateSchedule(Long id, UpdateScheduleRequest request)

수정할 단건 일정 ID 를 매개변수로 받아와서 해당 ID 를 가진 일정이 존재하는지 확인, 존재한다면 request 에 담긴 pw 와 비교하여 원래 일정에 저장된 pw 와 동일한지 확인, 동일하면 update로직 수행 후 DTO 형태로 return

각각에서 예외가 발생하면 해당하는 Exception 을 Throw 

 

@Transactional
public void deleteSchedule(Long id, DeleteScheduleRequest request)

삭제할 단건 일정 ID 를 매개변수로 받아와서 해당 ID 를 가진 일정이 존재하는지 확인, 존재한다면 request 에 담긴 pw 와 비교하여 원래 일정에 저장된 pw 와 동일한지 확인, 동일하면 delete로직 수행, 반환값 없음 


/CommentService

scheduleRepository 와 commentService 에 접근할 수 있습니다.

Comment와 관련된 Service 단계 역할을 수행합니다.

더보기
@Transactional
public CreateCommentResponse save(CreateCommentRequest request, Long scheduleId)

매개변수로 받아온 scheduleId 가 존재하는지 확인, 없으면 NonExistentException 을 Throw

해당 Schedule 에 달린 댓글 개수를 확인하여 10개가 넘었으면 TooManyCommentsException Throw

모두 만족하면, 사용자의 입력으로 들어온 request 에서 filed 값을 가져와서 Comment 생성자에 넣어 Repository에 저장하고 저장된 Comment를 기준으로 하여 Response DTO 를 만들어 (ID 와 생성,수정일이 포함됨, PW 미포함) 반환

 

@Transactional
public void delete(Long id, DeleteCommentRequest request)

삭제할 댓글 ID 를 매개변수로 받아와서 해당 ID 를 가진 댓글이 존재하는지 확인, 존재한다면 request 에 담긴 pw 와 비교하여 원래 댓글에 저장된 pw 와 동일한지 확인, 동일하면 delete로직 수행, 반환값 없음 

 

public List<GetCommentResponse> findCommentsByScheduleId(Long scheduleId)

해당 scheduleId 를 가진 List (Comment 형태) 를 DTO 형태로 바꿔서 반환 

 

public int getCommentCountByScheduleId(Long scheduleId)

해당 scheduleId 를 가진 List 의 size 반환


4. Controller 

/ScheduleController

scheduleservice 와 validate class 에 접근할 수 있습니다

Schedule과 관련된 Controller 단계 역할을 수행합니다. 

더보기
@PostMapping("/schedules")
ResponseEntity<CreateScheduleResponse> createSchedule (@RequestBody CreateScheduleRequest request){

필수값, 길이 확인, throw 되지 않았다면 save method 호출 후 반환값을 response 에 담아 body 로 반환

Status : 201 CREATED

 

@GetMapping("/schedules/{id}")
ResponseEntity<GetScheduleResponse> getOneSchedule (@PathVariable Long id)

단건조회 response 를 body 로 반환

Status : 200 OK

 

@GetMapping("/schedules")
ResponseEntity<List<GetSchedulesResponse>> getUserSchedule (@RequestParam(required = false) String writer)

다건조회 response 를 body 로 반환

Status : 200 OK

 

@PutMapping("/schedules/{id}")
ResponseEntity<UpdateScheduleResponse> updateSchedule (
	@PathVariable Long id, @RequestBody UpdateScheduleRequest request)

필수값, 길이 확인, throw 되지 않았다면 update method 호출 후 반환값을 response 에 담아 body 로 반환

Status : 200 OK

 

@DeleteMapping("/schedules/{id}")
ResponseEntity<Void> deleteSchedule (@PathVariable Long id, @RequestBody DeleteScheduleRequest request)

delete method 호출 

Status : 204 NO_CONTENT


/CommentController

scheduleservice 와 validate class 에 접근할 수 있습니다.

Comment와 관련된 Controller단계 역할을 수행합니다.

더보기
@PostMapping("/comments")
ResponseEntity<CreateCommentResponse> createComment

필수값, 길이 확인, throw 되지 않았다면 save method 호출 후 반환값을 response 에 담아 body 로 반환

Status : 201 CREATED

 

@DeleteMapping("/comments/{id}")
ResponseEntity<Void> deleteComment(@PathVariable Long id, @RequestBody DeleteCommentRequest request)

delete method 호출 

Status : 204 NO_CONTENT


/ValidateString

String 값을 받아와서 해당 값이 API 명세서에 주어진 조건을 만족시켰는지 확인하는 메서드 선언

더보기
void validateNullableAndLength(String str, int length)

필수값, 길이 확인

 

void validateNullable(String str)

필수값 확인 


5. DTO

/scheduleDto/

Schedule와 관련된 Data transfer 매개변수, 반환값으로 사용됩니다.

더보기
DTO 명 기본 Schedule Entity 를 기준으로 작성
CreateScheduleRequest id, 생성일, 수정일을 제외한 field 를 갖습니다.
CreateScheduleResponse 모든 final 형태의 field 를 갖습니다. 생성자가 존재합니다.
GetScheduleResponse 모든 final 형태의 field 를 갖습니다. 추가로 List<GetCommentResponse> field 를 갖습니다. 댓글 리스트를 출력할 때 사용됩니다. 생성자가 존재합니다.
GetSchedulesResponse 모든 final 형태의 field 를 갖습니다. 생성자가 존재합니다.
UpdateScheduleRequest id, 내용, 생성일, 수정일을 제외한 field 를 갖습니다.
UpdateScheduleResponse 내용, 생성일을 제외한 final 형태의 field 를 갖습니다. 생성자가 존재합니다. 
DeleteScheduleRequest pw 를 유일한 field 로 갖습니다. 

/commentDto/

Comment 와 관련된 Data transfer 매개변수, 반환값으로 사용됩니다.

현재 comment 는 수정과 관련된 기능을 구현하지 않았기 때문에 수정일 modifiedAt 은 생성시점에만 생성일과 동일한 시점으로 저장되고 이후 사용되지 않습니다. 

더보기
DTO 명 기본 Comment Entity 를 기준으로 작성
CreateCommentRequest id, 생성일, 수정일을 제외한 field 를 갖습니다.
CreateCommentResponse 모든 final 형태의 field 를 갖습니다. 생성자가 존재합니다.
GetCommentResponse 수정일을 제외한 모든 final 형태의 field 를 갖습니다. 생성자가 존재합니다.
DeleteCommentRequest pw 를 유일한 field 로 갖습니다. 

6. Exception

개별 예외를 생성하여 처리하였습니다. 

더보기
BlankFieldException 필수적으로 있어야하는 field 가 공백 또는 null 이면 발생 
ResponseStatusException 을 상속받아 상태값 BAD_REQUEST 반환
NonExistentException 존재하지 않는 스케줄을 조회, 수정, 삭제하려고 하면 발생
OverLengthException field 최대 길이를 초과하면 발생
ResponseStatusException 을 상속받아 상태값 BAD_REQUEST 반환
ToomManyCommentsException 한 schedule 에 comment 가 10개 이상이 되면 발생
WrongPasswordException 수정, 삭제 기능에서 입력받은 pw 가 저장된 pw 와 다르면 발생

 

'SPARTA 과제 > SPRING' 카테고리의 다른 글

숙련) 일정관리앱 트러블슈팅 (1)  (0) 2026.02.11
숙련) 일정관리앱 업그레이드 초기설정  (1) 2026.02.10
유저 입력 검증  (0) 2026.02.04
댓글 기능 구현, 정렬  (0) 2026.02.04
기본 DTO 작성  (0) 2026.02.03