diff --git a/README.md b/README.md index 6261d5b..11d12a1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,74 @@ # SELAB-TODO -> basic todo with spring-mvc +> basic diary with spring-mvc + +[테스트링크](http://localhost:8080/swagger-ui/index.html#/TODO%20API) + +# 요구명세서 +> 일기 작성 서비스 + +## 목차 +1. 소개 + 1. 목적 +2. 일반적인 기술 사항 + 1. 제품의 기능 + 2. 사용자 특성 + 3. 제약사항 + 4. 가정 및 의존성 +3. 상세기능 요구 사항 + 1. 기능적 요구 사항 + 1. 기본적인 CRUD + 1. 등록 + 2. 조회 + 3. 수정 + 4. 삭제 + +## 소개 +### 1.i 목적 +동건이형께 Todo 스터디를 완료했으므로 사이드 프로젝트를 진행하기 위하여 시작함 +## 일반적인 기술 사항 +### 2. i 제품의 기능 +앱은 아래와 같은 기능들을 주요 기능으로 갖는다 +* 단건 조회 +* 범위 조회 +* 전체 조회 +* 수정 +* 등록 +* 삭제 +* 전체 삭제 +### 2.ii 사용자 특정 +사용자는 일기를 생성할 수 있어야 한다. 생성은 Json 파일 형식으로 해야 한다 + + +사용자는 일기 조회를 할 수 있어야 한다. 단건 조회는 ID를 입력했을 때 가능하며, 범위 조회는 +월(Month)를 입력했을 때 가능해야 한다 + + +사용자는 일기 수정이 가능해야 한다. 수정하는 것은 ID로 수정할 수 있도록 한다. + + +사용자는 일기 삭제가 가능해야 한다. 삭제는 ID를 통해 이루어지도록 한다. +### 2.iii 제약사항 +* spring framework를 사용하여 구현한다 +* MySQL과 Jpa를 사용하여 데이터베이스와 연결한다 +* create-drop을 사용하기 때문에 데이터베이스에 데이터베이스 스키마를 만들지 않아도 된다 + +## 상세기능 요구 사항 +### 3.i. 기능적 요구 사항 +### 3.i.a 기본적인 CRUD +### 3.i.a.a 등록 +* request : id, 등록 날짜, 제목, 내용, 기분 +### 3.i.a.b 조회 +#### 단건 조회 +* request : id +#### 범위 조회 +* request : Month +* response : page +#### 전체 조회 +* request : none +* response : page +### 3.i.a.c 수정 +* request : id +### 3.i.a.d 삭제 +* request : none + + diff --git a/build.gradle b/build.gradle index 067172e..7393a6e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { group = 'com.selab' version = '0.0.1-SNAPSHOT' -sourceCompatibility = '11' +sourceCompatibility = "11" configurations { compileOnly { @@ -29,8 +29,12 @@ dependencies { annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + + // swagger + implementation "io.springfox:springfox-boot-starter:3.0.0" } tasks.named('test') { useJUnitPlatform() } +targetCompatibility = JavaVersion.VERSION_16 diff --git a/src/main/java/com/selab/todo/SelabTodoApplication.java b/src/main/java/com/selab/todo/SelabTodoApplication.java index b223492..18ac509 100644 --- a/src/main/java/com/selab/todo/SelabTodoApplication.java +++ b/src/main/java/com/selab/todo/SelabTodoApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +@EntityScan(basePackages = {"com.selab.todo.entity"}) @SpringBootApplication public class SelabTodoApplication { public static void main(String[] args) { diff --git a/src/main/java/com/selab/todo/common/BaseEntity.java b/src/main/java/com/selab/todo/common/BaseEntity.java new file mode 100644 index 0000000..ca155c1 --- /dev/null +++ b/src/main/java/com/selab/todo/common/BaseEntity.java @@ -0,0 +1,21 @@ +package com.selab.todo.common; + +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.time.LocalDateTime; + +@Getter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public abstract class BaseEntity { + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime modifiedAt; +} diff --git a/src/main/java/com/selab/todo/common/dto/PageDto.java b/src/main/java/com/selab/todo/common/dto/PageDto.java new file mode 100644 index 0000000..6df6c0b --- /dev/null +++ b/src/main/java/com/selab/todo/common/dto/PageDto.java @@ -0,0 +1,28 @@ +package com.selab.todo.common.dto; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; + +import java.util.List; + +@Data +@RequiredArgsConstructor +public class PageDto { + private final List data; + private final int page; + private final int size; + private final long totalElements; + + public static ResponseEntity> ok(Page data) { + var response = new PageDto( + data.getContent(), + data.getPageable().getPageNumber(), + data.getPageable().getPageSize(), + data.getTotalElements() + ); + + return ResponseEntity.ok(response); + } +} \ No newline at end of file diff --git a/src/main/java/com/selab/todo/common/dto/ResponseDto.java b/src/main/java/com/selab/todo/common/dto/ResponseDto.java new file mode 100644 index 0000000..457ba58 --- /dev/null +++ b/src/main/java/com/selab/todo/common/dto/ResponseDto.java @@ -0,0 +1,30 @@ +package com.selab.todo.common.dto; + +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +@Data +@RequiredArgsConstructor +public class ResponseDto { + private final T data; + + public static ResponseEntity> ok(T data) { + var response = new ResponseDto(data); + return ResponseEntity.ok(response); + } + + public static ResponseEntity> created(T data) { + var response = new ResponseDto(data); + return ResponseEntity + .status(HttpStatus.CREATED) + .body(response); + } + + public static ResponseEntity noContent() { + return ResponseEntity + .status(HttpStatus.NO_CONTENT) + .build(); + } +} diff --git a/src/main/java/com/selab/todo/config/JpaConfig.java b/src/main/java/com/selab/todo/config/JpaConfig.java new file mode 100644 index 0000000..bca8012 --- /dev/null +++ b/src/main/java/com/selab/todo/config/JpaConfig.java @@ -0,0 +1,9 @@ +package com.selab.todo.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@Configuration +@EnableJpaAuditing +public class JpaConfig { +} diff --git a/src/main/java/com/selab/todo/config/SwaggerConfig.java b/src/main/java/com/selab/todo/config/SwaggerConfig.java new file mode 100644 index 0000000..5a35176 --- /dev/null +++ b/src/main/java/com/selab/todo/config/SwaggerConfig.java @@ -0,0 +1,39 @@ +package com.selab.todo.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.oas.annotations.EnableOpenApi; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import javax.servlet.http.HttpServletRequest; + +@Configuration +@EnableOpenApi +public class SwaggerConfig { + @Bean + public Docket restApi() { + return new Docket(DocumentationType.OAS_30) + .ignoredParameterTypes( + HttpServletRequest.class + ) + .useDefaultResponseMessages(false) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.selab.todo")) + .paths(PathSelectors.regex("/api/.*")) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("Selab Diary api info") + .description("SE Diary API") + .version("1.0.0") + .build(); + } +} diff --git a/src/main/java/com/selab/todo/config/WebConfig.java b/src/main/java/com/selab/todo/config/WebConfig.java new file mode 100644 index 0000000..d14b427 --- /dev/null +++ b/src/main/java/com/selab/todo/config/WebConfig.java @@ -0,0 +1,29 @@ +package com.selab.todo.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +// CORS --> 가장 많이 발생 +@Configuration +@RequiredArgsConstructor +public class WebConfig implements WebMvcConfigurer { + @Bean + public UrlBasedCorsConfigurationSource corsConfigurationSource() { + var corsConfig = new CorsConfiguration(); + + corsConfig.addAllowedOriginPattern(CorsConfiguration.ALL); + corsConfig.addAllowedHeader(CorsConfiguration.ALL); + corsConfig.addAllowedMethod(CorsConfiguration.ALL); + + corsConfig.setAllowCredentials(true); + corsConfig.setMaxAge(3600L); + + var corsConfigSource = new UrlBasedCorsConfigurationSource(); + corsConfigSource.registerCorsConfiguration("/**", corsConfig); + return corsConfigSource; + } +} diff --git a/src/main/java/com/selab/todo/controller/CriteriaController.java b/src/main/java/com/selab/todo/controller/CriteriaController.java new file mode 100644 index 0000000..536d6c4 --- /dev/null +++ b/src/main/java/com/selab/todo/controller/CriteriaController.java @@ -0,0 +1,41 @@ +package com.selab.todo.controller; + +import com.selab.todo.common.dto.ResponseDto; +import com.selab.todo.dto.request.diary.DiaryRegisterRequest; +import com.selab.todo.service.CriteriaService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Api(tags = {"Diary API"}) +@RestController +@RequestMapping(value = "/api/v1/diaries/criteria", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +public class CriteriaController { + + private final CriteriaService criteriaService; + + @ApiOperation("Criteria Register") + @PostMapping(value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity register(@RequestBody DiaryRegisterRequest request){ + var response = criteriaService.register(request); + return ResponseDto.created(response); + } + + @ApiOperation("Criteria 단건 조회") + @GetMapping("/{id}") + public ResponseEntity get(@PathVariable Long id){ + var response = criteriaService.get(id); + return ResponseDto.ok(response); + } + + @ApiOperation("Criteria 전체 조회") + @GetMapping(value = "/getAll") + public ResponseEntity getAll(){ + var response = criteriaService.getAll(); + return ResponseDto.ok(response); + } +} diff --git a/src/main/java/com/selab/todo/controller/DiaryController.java b/src/main/java/com/selab/todo/controller/DiaryController.java new file mode 100644 index 0000000..73ff99c --- /dev/null +++ b/src/main/java/com/selab/todo/controller/DiaryController.java @@ -0,0 +1,97 @@ +package com.selab.todo.controller; + +import com.selab.todo.common.dto.PageDto; +import com.selab.todo.common.dto.ResponseDto; +import com.selab.todo.dto.request.diary.DiaryRegisterRequest; +import com.selab.todo.dto.request.diary.DiaryUpdateRequest; +import com.selab.todo.dto.request.feel.FeelingUpdateRequest; +import com.selab.todo.service.DiaryService; +import com.selab.todo.service.FeelingService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.MediaType; +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; + +@Api(tags = {"Diary API"}) +@RestController +@RequestMapping(value = "/api/v1/diaries", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +public class DiaryController { + private final DiaryService diaryService; + private final FeelingService feelingService; + + @ApiOperation(value = "Diary 등록하기") + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, value = "/register") + public ResponseEntity register(@RequestBody DiaryRegisterRequest request) { + var response = diaryService.register(request); + return ResponseDto.created(response); + } + + @ApiOperation(value = "Diary 단건 조회하기") + @GetMapping("/{id}") + public ResponseEntity get(@PathVariable Long id) { + var response = diaryService.get(id); + return ResponseDto.ok(response); + } + + @ApiOperation(value = "Diary 전체 조회하기") + @GetMapping("/search-all") + public ResponseEntity getAll( + @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ) { + var response = diaryService.getAll(pageable); + return PageDto.ok(response); + } + + @ApiOperation(value = "Diary 수정하기") + @PutMapping("/{id}") // @PatchMapping + public ResponseEntity update( + @PathVariable Long id, + @RequestBody DiaryUpdateRequest request + ) { + var response = diaryService.update(id, request); + return ResponseDto.ok(response); + } + + @ApiOperation(value = "Diary 삭제하기") + @DeleteMapping("/{id}") + public ResponseEntity delete( + @PathVariable Long id + ) { + diaryService.delete(id); + return ResponseDto.noContent(); + } + + @ApiOperation(value = "Diary 월별 삭제하기") + @DeleteMapping("/month/{month}") + public ResponseEntity monthDelete(@PathVariable int month) { + diaryService.monthDelete(month); + return ResponseDto.noContent(); + } + + @ApiOperation(value = "Feeling 수정하기") + @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE, value = "/feeling/{id}") + public ResponseEntity updateFeeling(@PathVariable Long id, @RequestBody FeelingUpdateRequest request) { + var response = feelingService.updateFeeling(id, request); + return ResponseDto.ok(response); + } + + @ApiOperation(value = "Feeling 전체 조회하기") + @GetMapping("/feeling-all") + public ResponseEntity getAllFeeling(@PageableDefault Pageable pageable) { + var response = feelingService.getAllFeeling(pageable); + return PageDto.ok(response); + } +} diff --git a/src/main/java/com/selab/todo/controller/SearchController.java b/src/main/java/com/selab/todo/controller/SearchController.java new file mode 100644 index 0000000..495b2d5 --- /dev/null +++ b/src/main/java/com/selab/todo/controller/SearchController.java @@ -0,0 +1,56 @@ +package com.selab.todo.controller; + +import com.selab.todo.dto.request.search.MonthSearchRequest; +import com.selab.todo.dto.request.search.SearchRequest; +import com.selab.todo.dto.request.search.YearSearchRequest; +import com.selab.todo.dto.request.search.FeelingSearchRequest; +import com.selab.todo.dto.response.DiaryResponse; +import com.selab.todo.service.DiaryService; +import com.selab.todo.service.DataSearchService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = {"Diary API"}) +@RestController +@RequestMapping(value = "/api/v1/diaries/search", produces = MediaType.APPLICATION_JSON_VALUE) +@RequiredArgsConstructor +public class SearchController { + private final DataSearchService dataSearchService; + private final DiaryService diaryService; + + @ApiOperation("Month 별로 검색") + @GetMapping(value = "/month",consumes = MediaType.APPLICATION_JSON_VALUE) + public Page searchMonth(@PageableDefault Pageable pageable, MonthSearchRequest request) { + Page diaryResponses = diaryService.getAll(pageable); + return dataSearchService.searchMonth(diaryResponses, request.getMonth()); + } + + @ApiOperation("Year 별로 검색") + @GetMapping(value = "/year",consumes = MediaType.APPLICATION_JSON_VALUE) + public Page searchYear(@PageableDefault Pageable pageable, YearSearchRequest request) { + Page diaryResponses = diaryService.getAll(pageable); + return dataSearchService.searchYear(diaryResponses, request.getYear()); + } + + @ApiOperation("Year, Month, Day 검색") + @GetMapping(value = "/year-month-day",consumes = MediaType.APPLICATION_JSON_VALUE) + public Page searchYear(@PageableDefault Pageable pageable, SearchRequest request) { + Page diaryResponses = diaryService.getAll(pageable); + return dataSearchService.search(diaryResponses, request); + } + + @ApiOperation("Feeling 검색") + @GetMapping(value = "/feel") + public Page searchFeeling(@PageableDefault Pageable pageable, FeelingSearchRequest request){ + Page diaryResponses = diaryService.getAll(pageable); + return dataSearchService.searchFeel(diaryResponses, request.getFeeling()); + } +} \ No newline at end of file diff --git a/src/main/java/com/selab/todo/controller/TodoController.java b/src/main/java/com/selab/todo/controller/TodoController.java deleted file mode 100644 index bef9fbe..0000000 --- a/src/main/java/com/selab/todo/controller/TodoController.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.selab.todo.controller; - -import com.selab.todo.dto.request.TodoRegisterRequest; -import com.selab.todo.dto.response.TodoResponse; -import com.selab.todo.service.TodoService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.MediaType; -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.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping(value = "/api/v1/todos", produces = MediaType.APPLICATION_JSON_VALUE) -@RequiredArgsConstructor -public class TodoController { - private final TodoService todoService; - - @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) - public TodoResponse register(@RequestBody TodoRegisterRequest request) { - return todoService.register(request); - } - - @GetMapping("/{id}") - public TodoResponse get(@PathVariable Long id) { - return todoService.get(id); - } -} diff --git a/src/main/java/com/selab/todo/dto/request/TodoRegisterRequest.java b/src/main/java/com/selab/todo/dto/request/TodoRegisterRequest.java deleted file mode 100644 index ab85829..0000000 --- a/src/main/java/com/selab/todo/dto/request/TodoRegisterRequest.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.selab.todo.dto.request; - -import lombok.Data; - -@Data -public class TodoRegisterRequest { - private final String title; - private final String content; -} diff --git a/src/main/java/com/selab/todo/dto/request/TodoUpdateRequest.java b/src/main/java/com/selab/todo/dto/request/TodoUpdateRequest.java deleted file mode 100644 index e445bff..0000000 --- a/src/main/java/com/selab/todo/dto/request/TodoUpdateRequest.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.selab.todo.dto.request; - -import lombok.Data; - -@Data -public class TodoUpdateRequest { - private final String title; - private final String content; -} diff --git a/src/main/java/com/selab/todo/dto/request/diary/DiaryRegisterRequest.java b/src/main/java/com/selab/todo/dto/request/diary/DiaryRegisterRequest.java new file mode 100644 index 0000000..625ea5f --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/diary/DiaryRegisterRequest.java @@ -0,0 +1,13 @@ +package com.selab.todo.dto.request.diary; + +import lombok.Data; + +@Data +public class DiaryRegisterRequest { + private final String title; + private final String content; + private final String feel; + private int year; + private int month; + private int day; +} diff --git a/src/main/java/com/selab/todo/dto/request/diary/DiaryUpdateRequest.java b/src/main/java/com/selab/todo/dto/request/diary/DiaryUpdateRequest.java new file mode 100644 index 0000000..8bdc19f --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/diary/DiaryUpdateRequest.java @@ -0,0 +1,10 @@ +package com.selab.todo.dto.request.diary; + +import lombok.Data; + +@Data +public class DiaryUpdateRequest { + private final String title; + private final String content; + private final String feel; +} diff --git a/src/main/java/com/selab/todo/dto/request/feel/FeelingRegisterRequest.java b/src/main/java/com/selab/todo/dto/request/feel/FeelingRegisterRequest.java new file mode 100644 index 0000000..006c26f --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/feel/FeelingRegisterRequest.java @@ -0,0 +1,9 @@ +package com.selab.todo.dto.request.feel; + +import lombok.Data; + +@Data +public class FeelingRegisterRequest { + private final Long id; + private final String feel; +} diff --git a/src/main/java/com/selab/todo/dto/request/feel/FeelingUpdateRequest.java b/src/main/java/com/selab/todo/dto/request/feel/FeelingUpdateRequest.java new file mode 100644 index 0000000..e101f61 --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/feel/FeelingUpdateRequest.java @@ -0,0 +1,8 @@ +package com.selab.todo.dto.request.feel; + +import lombok.Data; + +@Data +public class FeelingUpdateRequest { + private final String feel; +} diff --git a/src/main/java/com/selab/todo/dto/request/search/FeelingSearchRequest.java b/src/main/java/com/selab/todo/dto/request/search/FeelingSearchRequest.java new file mode 100644 index 0000000..8367306 --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/search/FeelingSearchRequest.java @@ -0,0 +1,8 @@ +package com.selab.todo.dto.request.search; + +import lombok.Data; + +@Data +public class FeelingSearchRequest { + private final String feeling; +} diff --git a/src/main/java/com/selab/todo/dto/request/search/MonthSearchRequest.java b/src/main/java/com/selab/todo/dto/request/search/MonthSearchRequest.java new file mode 100644 index 0000000..cfc7f6c --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/search/MonthSearchRequest.java @@ -0,0 +1,8 @@ +package com.selab.todo.dto.request.search; + +import lombok.Data; + +@Data +public class MonthSearchRequest { + private final int month; +} diff --git a/src/main/java/com/selab/todo/dto/request/search/SearchRequest.java b/src/main/java/com/selab/todo/dto/request/search/SearchRequest.java new file mode 100644 index 0000000..6b5be1a --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/search/SearchRequest.java @@ -0,0 +1,10 @@ +package com.selab.todo.dto.request.search; + +import lombok.Data; + +@Data +public class SearchRequest { + private final int year; + private final int month; + private final int day; +} diff --git a/src/main/java/com/selab/todo/dto/request/search/YearSearchRequest.java b/src/main/java/com/selab/todo/dto/request/search/YearSearchRequest.java new file mode 100644 index 0000000..19d8f2c --- /dev/null +++ b/src/main/java/com/selab/todo/dto/request/search/YearSearchRequest.java @@ -0,0 +1,8 @@ +package com.selab.todo.dto.request.search; + +import lombok.Data; + +@Data +public class YearSearchRequest { + private final int year; +} diff --git a/src/main/java/com/selab/todo/dto/response/DiaryResponse.java b/src/main/java/com/selab/todo/dto/response/DiaryResponse.java new file mode 100644 index 0000000..ad87145 --- /dev/null +++ b/src/main/java/com/selab/todo/dto/response/DiaryResponse.java @@ -0,0 +1,34 @@ +package com.selab.todo.dto.response; + +import com.selab.todo.entity.Diary; +import lombok.Data; + +import java.time.DayOfWeek; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.Year; + +@Data +public class DiaryResponse { + private final Long id; + private final String title; + private final String content; + private final LocalDateTime localDateTime; + private final String feel; + private final Year year; + private final Month month; + private final DayOfWeek day; + + public static DiaryResponse from(Diary diary) { + return new DiaryResponse( + diary.getId(), + diary.getTitle(), + diary.getContent(), + diary.getCreatedAt(), + diary.getFeel(), + diary.getYear(), + diary.getMonth(), + diary.getDay() + ); + } +} diff --git a/src/main/java/com/selab/todo/dto/response/FeelingResponse.java b/src/main/java/com/selab/todo/dto/response/FeelingResponse.java new file mode 100644 index 0000000..5238685 --- /dev/null +++ b/src/main/java/com/selab/todo/dto/response/FeelingResponse.java @@ -0,0 +1,25 @@ +package com.selab.todo.dto.response; + +import com.selab.todo.entity.Diary; +import com.selab.todo.entity.Feeling; +import lombok.Data; + +@Data +public class FeelingResponse { + private final Long id; + private final String feel; + + public static FeelingResponse from(Diary diary){ + return new FeelingResponse( + diary.getId(), + diary.getFeel() + ); + } + + public static FeelingResponse from(Feeling feeling){ + return new FeelingResponse( + feeling.getId(), + feeling.getFeel() + ); + } +} diff --git a/src/main/java/com/selab/todo/dto/response/TodoResponse.java b/src/main/java/com/selab/todo/dto/response/TodoResponse.java deleted file mode 100644 index 8b0f0be..0000000 --- a/src/main/java/com/selab/todo/dto/response/TodoResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.selab.todo.dto.response; - -import lombok.Data; - -@Data -public class TodoResponse { - private final Long id; - private final String title; - private final String content; -} diff --git a/src/main/java/com/selab/todo/entity/Diary.java b/src/main/java/com/selab/todo/entity/Diary.java new file mode 100644 index 0000000..3773bdc --- /dev/null +++ b/src/main/java/com/selab/todo/entity/Diary.java @@ -0,0 +1,71 @@ +package com.selab.todo.entity; + +import com.selab.todo.common.BaseEntity; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.DayOfWeek; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.Year; + +@Entity(name = "diary") +@Getter +@Table(name = "diary") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Diary extends BaseEntity { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "title") + private String title; + + @Column(name = "content") + private String content; + + @Column(name = "createdAt") + @CreatedDate + private LocalDateTime createdAt; + + @Column(name = "year") + private Year year; + + @Column(name = "month") + private Month month; + + @Column(name = "day") + private DayOfWeek day; + + @Column(name = "feel") + private String feel; + + + public Diary(String title, String content, String feel, Year year, Month month, DayOfWeek day) { + this.title = title; + this.content = content; + this.feel = feel; + this.year = year; + this.month = month; + this.day = day; + } + + public void update(String title, String content, String feel) { + this.title = title; + this.content = content; + this.feel = feel; + } + + public void feelingUpdate(String feel){ + this.feel = feel; + } +} \ No newline at end of file diff --git a/src/main/java/com/selab/todo/entity/Feeling.java b/src/main/java/com/selab/todo/entity/Feeling.java new file mode 100644 index 0000000..e68da0a --- /dev/null +++ b/src/main/java/com/selab/todo/entity/Feeling.java @@ -0,0 +1,23 @@ +package com.selab.todo.entity; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; + +@Entity(name = "feeling") +@Getter +@Table(name = "feeling") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Feeling { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "feel") + private String feel; +} diff --git a/src/main/java/com/selab/todo/entity/Todo.java b/src/main/java/com/selab/todo/entity/Todo.java deleted file mode 100644 index 7edcbf3..0000000 --- a/src/main/java/com/selab/todo/entity/Todo.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.selab.todo.entity; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; - -@Entity -@Getter -@Table(name = "todo") -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class Todo { - @Id - @Column(name = "id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "title") - private String title; - - @Column(name = "content") - private String content; - - public Todo(String title, String content) { - this.title = title; - this.content = content; - } -} diff --git a/src/main/java/com/selab/todo/exception/BusinessException.java b/src/main/java/com/selab/todo/exception/BusinessException.java new file mode 100644 index 0000000..37b354b --- /dev/null +++ b/src/main/java/com/selab/todo/exception/BusinessException.java @@ -0,0 +1,23 @@ +package com.selab.todo.exception; + +import lombok.Getter; + +@Getter +public abstract class BusinessException extends RuntimeException { + private final ErrorMessage errorMessage; + + public BusinessException(ErrorMessage message) { + super(message.getDescription()); + this.errorMessage = message; + } + + public BusinessException(ErrorMessage message, String reason) { + super(reason); + this.errorMessage = message; + } + + public BusinessException(String reason) { + super(reason); + this.errorMessage = ErrorMessage.CONFLICT_ERROR; + } +} diff --git a/src/main/java/com/selab/todo/exception/DiaryException.java b/src/main/java/com/selab/todo/exception/DiaryException.java new file mode 100644 index 0000000..a14fc0e --- /dev/null +++ b/src/main/java/com/selab/todo/exception/DiaryException.java @@ -0,0 +1,7 @@ +package com.selab.todo.exception; + +public class DiaryException extends BusinessException { + public DiaryException() { + super(ErrorMessage.TODO_NOT_FOUND_ERROR); + } +} diff --git a/src/main/java/com/selab/todo/exception/ErrorDto.java b/src/main/java/com/selab/todo/exception/ErrorDto.java new file mode 100644 index 0000000..f11f137 --- /dev/null +++ b/src/main/java/com/selab/todo/exception/ErrorDto.java @@ -0,0 +1,30 @@ +package com.selab.todo.exception; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class ErrorDto implements Serializable { + private final String name; + private final String message; + private final String reason; + + public ErrorDto(ErrorMessage message, String reason) { + this.name = message.name(); + this.message = message.getDescription(); + this.reason = reason; + } + + public ErrorDto(ErrorMessage message) { + this.name = message.name(); + this.message = message.getDescription(); + this.reason = ""; + } + + public ErrorDto(String name, String message) { + this.name = name; + this.message = message; + this.reason = ""; + } +} diff --git a/src/main/java/com/selab/todo/exception/ErrorMessage.java b/src/main/java/com/selab/todo/exception/ErrorMessage.java new file mode 100644 index 0000000..f3ecdcd --- /dev/null +++ b/src/main/java/com/selab/todo/exception/ErrorMessage.java @@ -0,0 +1,26 @@ +package com.selab.todo.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; + +@Getter +@RequiredArgsConstructor +public enum ErrorMessage { + /** + * Server Error Message + */ + CONFLICT_ERROR(HttpStatus.BAD_REQUEST, "예기치 못한 에러가 발생했습니다."), + INTERNAL_SERVER_ERROR_BY_MAPPER_ERROR(HttpStatus.BAD_REQUEST, "예기치 못한 에러가 발생했습니다."), + INTERNAL_SERVER_ERROR_BY_PROPERTIES_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "예기치 못한 에러가 발생했습니다."), + INVALID_REQUEST_PARMAETER_ERROR(HttpStatus.BAD_REQUEST, "잘못된 요청 입니다."), + + /** + * Todo Error Message + */ + TODO_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "Todo 정보를 찾을 수 없습니다."), + ; + + private final HttpStatus status; + private final String description; +} diff --git a/src/main/java/com/selab/todo/exception/GlobalExceptionHandler.java b/src/main/java/com/selab/todo/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..62f52a8 --- /dev/null +++ b/src/main/java/com/selab/todo/exception/GlobalExceptionHandler.java @@ -0,0 +1,44 @@ +package com.selab.todo.exception; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + @ExceptionHandler(BusinessException.class) + protected ResponseEntity handleBusinessException(final BusinessException e) { + var message = e.getErrorMessage(); + + log.error("[ERROR] BusinessException -> {}", message.getDescription()); + + return ResponseEntity + .status(message.getStatus()) + .body(new ErrorDto(message)); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + protected ResponseEntity handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) { + var message = ErrorMessage.CONFLICT_ERROR; + + log.error("[ERROR] MethodArgumentNotValidException -> {}", e.getBindingResult()); + + return ResponseEntity + .status(message.getStatus()) + .body(new ErrorDto(message, e.getMessage())); + } + + @ExceptionHandler(Exception.class) + protected ResponseEntity handleException(final Exception e) { + var message = ErrorMessage.CONFLICT_ERROR; + + log.error("[ERROR] Exception -> {}", e.getCause().toString()); + + return ResponseEntity + .status(message.getStatus()) + .body(new ErrorDto(message, e.getMessage())); + } +} diff --git a/src/main/java/com/selab/todo/repository/DiaryRepository.java b/src/main/java/com/selab/todo/repository/DiaryRepository.java new file mode 100644 index 0000000..4cd6bde --- /dev/null +++ b/src/main/java/com/selab/todo/repository/DiaryRepository.java @@ -0,0 +1,22 @@ +package com.selab.todo.repository; + +import com.selab.todo.entity.Diary; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface DiaryRepository extends JpaRepository, JpaSpecificationExecutor { + + //월별 삭제 쿼리 + @Query( + value = "delete diary" + + "where month > : month" + ,nativeQuery = true + ) + public List deleteDiariesByMonth(@Param(value = "month") int month); +} diff --git a/src/main/java/com/selab/todo/repository/FeelingRepository.java b/src/main/java/com/selab/todo/repository/FeelingRepository.java new file mode 100644 index 0000000..48deff5 --- /dev/null +++ b/src/main/java/com/selab/todo/repository/FeelingRepository.java @@ -0,0 +1,7 @@ +package com.selab.todo.repository; + +import com.selab.todo.entity.Feeling; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FeelingRepository extends JpaRepository { +} diff --git a/src/main/java/com/selab/todo/repository/TodoRepository.java b/src/main/java/com/selab/todo/repository/TodoRepository.java deleted file mode 100644 index c8f7e15..0000000 --- a/src/main/java/com/selab/todo/repository/TodoRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.selab.todo.repository; - -import com.selab.todo.entity.Todo; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface TodoRepository extends JpaRepository { - -} diff --git a/src/main/java/com/selab/todo/service/CriteriaService.java b/src/main/java/com/selab/todo/service/CriteriaService.java new file mode 100644 index 0000000..740b5b3 --- /dev/null +++ b/src/main/java/com/selab/todo/service/CriteriaService.java @@ -0,0 +1,141 @@ +package com.selab.todo.service; + +import com.selab.todo.dto.request.diary.DiaryRegisterRequest; +import com.selab.todo.dto.response.DiaryResponse; +import com.selab.todo.entity.Diary; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.Persistence; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.time.DayOfWeek; +import java.time.Month; +import java.time.Year; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class CriteriaService { + + private final EntityManagerFactory entityManagerFactory = + Persistence.createEntityManagerFactory("diary"); + + @Transactional + public DiaryResponse register(DiaryRegisterRequest request){ + EntityManager entityManager = entityManagerFactory.createEntityManager(); + EntityTransaction entityTransaction = entityManager.getTransaction(); + + Diary diary = new Diary( + request.getTitle(), + request.getContent(), + request.getFeel(), + Year.of(request.getYear()), + Month.of(request.getMonth()), + DayOfWeek.of(request.getDay()) + ); + + try{ + entityTransaction.begin(); + + entityManager.persist(diary); + + entityTransaction.commit(); + }catch (Exception e){ + log.info("Criteria Error. {}", e); + entityTransaction.rollback(); + + }finally { + entityManager.close(); + } + + return DiaryResponse.from(diary); + } + + @Transactional + public DiaryResponse get(Long id){ + EntityManager entityManager = entityManagerFactory.createEntityManager(); + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Diary.class); + Root root = criteriaQuery.from(Diary.class); + + Predicate idEquals = criteriaBuilder.equal(root.get("id"), id); + + criteriaQuery.select(root).where(idEquals); + + Diary diary = entityManager.createQuery(criteriaQuery).getSingleResult(); + + return DiaryResponse.from(diary); + } + + @Transactional + public Page getAll(){ + EntityManager entityManager = entityManagerFactory.createEntityManager(); + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Diary.class); + Root root = criteriaQuery.from(Diary.class); + + criteriaQuery.select(root); + + List result = entityManager.createQuery(criteriaQuery).getResultList(); + + List mapping = new ArrayList<>(); + + result.stream() + .forEach(a->{ + mapping.add(DiaryResponse.from(a)); + }); + + return makePage(mapping); + } + + + @Transactional + public Page searchFeel(String feeling){ + EntityManager entityManager = entityManagerFactory.createEntityManager(); + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Diary.class); + Root root = criteriaQuery.from(Diary.class); + + Predicate feelEqual = criteriaBuilder.equal(root.get("feeling"), feeling); + + javax.persistence.criteria.Order idDesc = criteriaBuilder.desc(root.get("id")); + + criteriaQuery.select(root) + .where(feelEqual) + .orderBy(idDesc); + + List result = entityManager.createQuery(criteriaQuery).getResultList(); + + List mapping = new ArrayList<>(); + + result.stream() + .forEach(a->{ + mapping.add(DiaryResponse.from(a)); + }); + + return makePage(mapping); + } + + private PageImpl makePage(List process) { + PageRequest pageRequest = PageRequest.of(0, 10); + int start = (int) pageRequest.getOffset(); + int end = Math.min((start + pageRequest.getPageSize()), process.size()); + return new PageImpl<>(process.subList(start, end), pageRequest, process.size()); + } +} diff --git a/src/main/java/com/selab/todo/service/DataSearchService.java b/src/main/java/com/selab/todo/service/DataSearchService.java new file mode 100644 index 0000000..e787432 --- /dev/null +++ b/src/main/java/com/selab/todo/service/DataSearchService.java @@ -0,0 +1,63 @@ +package com.selab.todo.service; + +import com.selab.todo.dto.request.search.SearchRequest; +import com.selab.todo.dto.response.DiaryResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DataSearchService { + public Page searchMonth(Page allPage, int month) { + List middleProcess = allPage.stream() + .filter(a -> a.getMonth().getValue() == month) + .collect(Collectors.toList()); + + log.info("Month 조회. {}", month); + return makePage(middleProcess); + } + + public Page searchYear(Page allPage, int year) { + List middleProcess = allPage.stream() + .filter(a -> a.getYear().getValue() == year) + .collect(Collectors.toList()); + + log.info("Year 조회. {}", year); + return makePage(middleProcess); + } + + public Page search(Page allPage, SearchRequest request) { + List middleProcess = allPage.stream() + .filter(a -> a.getYear().getValue() == request.getYear()) + .filter(a -> a.getMonth().getValue() == request.getMonth()) + .filter(a -> a.getDay() == a.getDay()) + .collect(Collectors.toList()); + + log.info("전체 날짜 조회."); + return makePage(middleProcess); + } + + public Page searchFeel(Page allPage, String feeling) { + List middleProcess = allPage.stream() + .filter(a -> a.getFeel().equals(feeling)) + .collect(Collectors.toList()); + + log.info("Feeling 조회. {}", feeling); + return makePage(middleProcess); + } + + private PageImpl makePage(List process) { + PageRequest pageRequest = PageRequest.of(0, 10); + int start = (int) pageRequest.getOffset(); + int end = Math.min((start + pageRequest.getPageSize()), process.size()); + return new PageImpl<>(process.subList(start, end), pageRequest, process.size()); + } +} \ No newline at end of file diff --git a/src/main/java/com/selab/todo/service/DiaryService.java b/src/main/java/com/selab/todo/service/DiaryService.java new file mode 100644 index 0000000..dee688c --- /dev/null +++ b/src/main/java/com/selab/todo/service/DiaryService.java @@ -0,0 +1,106 @@ +package com.selab.todo.service; + +import com.selab.todo.dto.request.diary.DiaryRegisterRequest; +import com.selab.todo.dto.request.diary.DiaryUpdateRequest; +import com.selab.todo.dto.response.DiaryResponse; +import com.selab.todo.entity.Diary; +import com.selab.todo.entity.Feeling; +import com.selab.todo.exception.DiaryException; +import com.selab.todo.repository.DiaryRepository; +import com.selab.todo.repository.FeelingRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +import java.time.DayOfWeek; +import java.time.Month; +import java.time.Year; +import java.util.LinkedList; +import java.util.List; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class DiaryService { + private final DiaryRepository diaryRepository; + private final FeelingRepository feelingRepository; + private final DataSearchService dataSearchService; + + // 삽입 + @Transactional + public DiaryResponse register(DiaryRegisterRequest request) { + Diary diary = new Diary( + request.getTitle(), + request.getContent(), + request.getFeel(), + Year.of(request.getYear()), + Month.of(request.getMonth()), + DayOfWeek.of(request.getDay()) + ); + + Feeling feeling = new Feeling( + diary.getId(), + request.getFeel() + ); + + Diary savedDiary = diaryRepository.save(diary); + feelingRepository.save(feeling); + + log.info("Diary 등록했습니다. {}", diary.getId()); + log.info("Feeling 등록했습니다. {}", feeling.getFeel()); + + return DiaryResponse.from(savedDiary); + } + + // 단건 조회 + @Transactional(readOnly = true) + public DiaryResponse get(Long id) { + Diary diary = diaryRepository.findById(id) + .orElseThrow(DiaryException::new); + log.info("Diary 조회했습니다, {}", diary.getId()); + return DiaryResponse.from(diary); + } + + // 페이징 조회 + @Transactional(readOnly = true) + public Page getAll(Pageable pageable) { + log.info("Diary 전체 조회"); + return diaryRepository.findAll(pageable) + .map(DiaryResponse::from); + } + + // 수정 + @Transactional + public DiaryResponse update(Long id, DiaryUpdateRequest request) { + Diary diary = diaryRepository.findById(id) + .orElseThrow(DiaryException::new); + + // 더티체킹 - 영속성 컨텍스트 + diary.update(request.getTitle(), request.getContent(), request.getFeel()); + + log.info("todo 수정했습니다. {}", diary.getId()); + + return DiaryResponse.from(diary); + } + + // 삭제 + @Transactional + public void delete(Long id) { + if (diaryRepository.existsById(id)) { + diaryRepository.deleteById(id); + log.info("todo 삭제했습니다.. {}", id); + } + } + + //월별 삭제 + @Transactional + public void monthDelete(int month) { + diaryRepository.deleteDiariesByMonth(month); + } + +} \ No newline at end of file diff --git a/src/main/java/com/selab/todo/service/FeelingService.java b/src/main/java/com/selab/todo/service/FeelingService.java new file mode 100644 index 0000000..f60eb48 --- /dev/null +++ b/src/main/java/com/selab/todo/service/FeelingService.java @@ -0,0 +1,51 @@ +package com.selab.todo.service; + +import com.selab.todo.dto.request.diary.DiaryUpdateRequest; +import com.selab.todo.dto.request.feel.FeelingRegisterRequest; +import com.selab.todo.dto.request.feel.FeelingUpdateRequest; +import com.selab.todo.dto.response.DiaryResponse; +import com.selab.todo.dto.response.FeelingResponse; +import com.selab.todo.entity.Diary; +import com.selab.todo.entity.Feeling; +import com.selab.todo.exception.DiaryException; +import com.selab.todo.repository.DiaryRepository; +import com.selab.todo.repository.FeelingRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class FeelingService { + private final DiaryRepository diaryRepository; + private final FeelingRepository feelingRepository; + + @Transactional + public FeelingResponse register(FeelingRegisterRequest request){ + Feeling feeling = new Feeling( + request.getId(), + request.getFeel() + ); + return FeelingResponse.from(feeling); + } + + @Transactional + public FeelingResponse updateFeeling(Long id, FeelingUpdateRequest request){ + Feeling feeling = feelingRepository.findById(id).orElseThrow(DiaryException::new); + + log.info("Diary feeling 수정했습니다. {}", feeling.getId()); + + return FeelingResponse.from(feeling); + } + + @Transactional(readOnly = true) + public Page getAllFeeling(Pageable pageable){ + log.info("Diary feeling 전체 조회"); + return diaryRepository.findAll(pageable) + .map(FeelingResponse::from); + } +} diff --git a/src/main/java/com/selab/todo/service/PersistenceService.java b/src/main/java/com/selab/todo/service/PersistenceService.java new file mode 100644 index 0000000..504b2ba --- /dev/null +++ b/src/main/java/com/selab/todo/service/PersistenceService.java @@ -0,0 +1,35 @@ +package com.selab.todo.service; + +import com.selab.todo.dto.request.diary.DiaryRegisterRequest; +import com.selab.todo.dto.response.DiaryResponse; +import com.selab.todo.entity.Diary; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import java.time.DayOfWeek; +import java.time.Month; +import java.time.Year; + +public class PersistenceService { + + EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("diaryManager"); + + @Transactional + public DiaryResponse register(DiaryRegisterRequest request){ + Diary diary = new Diary( + request.getTitle(), + request.getContent(), + request.getFeel(), + Year.of(request.getYear()), + Month.of(request.getMonth()), + DayOfWeek.of(request.getDay()) + ); + + EntityManager entityManager = entityManagerFactory.createEntityManager(); + entityManager.persist(diary); + + return DiaryResponse.from(diary); + } +} diff --git a/src/main/java/com/selab/todo/service/TodoService.java b/src/main/java/com/selab/todo/service/TodoService.java deleted file mode 100644 index 21b8f0a..0000000 --- a/src/main/java/com/selab/todo/service/TodoService.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.selab.todo.service; - -import com.selab.todo.dto.request.TodoRegisterRequest; -import com.selab.todo.dto.response.TodoResponse; -import com.selab.todo.entity.Todo; -import com.selab.todo.repository.TodoRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -public class TodoService { - private final TodoRepository todoRepository; - - // 삽입 - @Transactional - public TodoResponse register(TodoRegisterRequest request) { - Todo todo = new Todo( - request.getTitle(), - request.getContent() - ); - - Todo savedTodo = todoRepository.save(todo); - - return new TodoResponse( - savedTodo.getId(), - savedTodo.getTitle(), - savedTodo.getContent() - ); - } - - // 단건 조회 - @Transactional(readOnly = true) - public TodoResponse get(Long id) { - Todo todo = todoRepository.findById(id).get(); - - return new TodoResponse( - todo.getId(), - todo.getTitle(), - todo.getContent() - ); - } - - // 페이징 조회 - - // 수정 - - // 삭제 -} diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..8f7c33c --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,25 @@ + + + + + + com.selab.todo.entity.Diary + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 97c2378..d27265d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,10 +4,10 @@ spring: max-file-size: 10MB max-request-size: 10MB datasource: - url: jdbc:mysql://localhost:3306/se_todo?useUnicode=true&charset=utf8mb4&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Seoul&useSSL=false + url: jdbc:mysql://localhost:3306/todo?useUnicode=true&charset=utf8mb4&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Seoul&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver username: root - password: + password: kk020206** hikari: minimum-idle: 10 maximum-pool-size: 20 @@ -15,3 +15,6 @@ spring: open-in-view: false hibernate: ddl-auto: create-drop + mvc: + pathmatch: + matching-strategy: ant_path_matcher diff --git a/src/test/java/com/selab/todo/SelabDiaryApplicationTests.java b/src/test/java/com/selab/todo/SelabDiaryApplicationTests.java new file mode 100644 index 0000000..7ba6acd --- /dev/null +++ b/src/test/java/com/selab/todo/SelabDiaryApplicationTests.java @@ -0,0 +1,27 @@ +package com.selab.todo; + +import com.selab.todo.dto.response.DiaryResponse; +import com.selab.todo.entity.Diary; +import com.selab.todo.repository.DiaryRepository; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.time.DayOfWeek; +import java.time.Month; +import java.time.Year; +import java.util.List; +import java.util.stream.Collectors; + +@SpringBootTest +class SelabDiaryApplicationTests { +} diff --git a/src/test/java/com/selab/todo/SelabTodoApplicationTests.java b/src/test/java/com/selab/todo/SelabTodoApplicationTests.java deleted file mode 100644 index 79c47d1..0000000 --- a/src/test/java/com/selab/todo/SelabTodoApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.selab.todo; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class SelabTodoApplicationTests { - - @Test - void contextLoads() { - } - -}