diff --git a/build.gradle b/build.gradle index 34ece7c..dba4f5c 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,10 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'javax.validation:validation-api:2.0.1.Final' + implementation 'org.hibernate.validator:hibernate-validator:6.0.13.Final' + implementation 'org.glassfish:javax.el:3.0.0' + implementation 'org.springframework.boot:spring-boot-starter-validation' } tasks.named('test') { diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/controller/ArticleController.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/controller/ArticleController.java new file mode 100644 index 0000000..efdafc5 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/controller/ArticleController.java @@ -0,0 +1,70 @@ +package com.gsm._8th.class4.backed.task._1._1.controller; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.dto.ArticleRequestDTO; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@RestController +@RequestMapping("/articles") +@RequiredArgsConstructor +public class ArticleController { + + @Qualifier("articleServiceImpl") + private final ArticleService articleService; + + @GetMapping + public CompletableFuture>> getAllArticles() { + return articleService.getAllArticles().thenApply(ResponseEntity::ok); + } + + @GetMapping("/{articleId}") + public CompletableFuture> getArticleById(@PathVariable Long articleId) { + return articleService.getArticleById(articleId) + .thenApply(article -> article.map(ResponseEntity::ok) + .orElseGet(() -> ResponseEntity.notFound().build())); + } + + @PostMapping + public CompletableFuture> createArticle(@RequestBody ArticleRequestDTO articleDTO) { + validateArticleDTO(articleDTO); + Article article = articleDTO.toEntity(); + return articleService.createArticle(article).thenApply(ResponseEntity::ok); + } + + @PatchMapping("/{articleId}") + public CompletableFuture> updateArticle(@PathVariable Long articleId, @RequestBody ArticleRequestDTO articleDTO) { + validateArticleDTO(articleDTO); + Article articleDetails = articleDTO.toEntity(); + return articleService.updateArticle(articleId, articleDetails) + .thenApply(updatedArticle -> updatedArticle.map(ResponseEntity::ok) + .orElseGet(() -> ResponseEntity.notFound().build())); + } + + @DeleteMapping("/{articleId}") + public CompletableFuture> deleteArticle(@PathVariable Long articleId) { + return articleService.deleteArticle(articleId) + .thenApply(deleted -> deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build()); + } + + private void validateArticleDTO(ArticleRequestDTO articleDTO) { + if (articleDTO.getTitle() == null || articleDTO.getTitle().isBlank()) { + throw new IllegalArgumentException("Title에 뭐라도 써주세요..."); + } + if (articleDTO.getTitle().length() > 100) { + throw new IllegalArgumentException("Title은 100자를 넘을 수 없습니다."); + } + if (articleDTO.getContent() == null || articleDTO.getContent().isBlank()) { + throw new IllegalArgumentException("Content에 뭐라도 써주세요..."); + } + if (articleDTO.getContent().length() > 1000) { + throw new IllegalArgumentException("Content는 1000자를 넘을 수 없습니다."); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/Article.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/Article.java new file mode 100644 index 0000000..861918a --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/Article.java @@ -0,0 +1,30 @@ +package com.gsm._8th.class4.backed.task._1._1.domain; + +import com.gsm._8th.class4.backed.task._1._1.global.entity.BaseIdxEntity; + +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +@Table(name = "articles") +public class Article extends BaseIdxEntity { + private String title; + private String content; + + @Builder + public Article(String title, String content) { + this.title = title; + this.content = content; + } + + public void update(String title, String content) { + this.title = title; + this.content = content; + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/ArticleDTO.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/ArticleDTO.java new file mode 100644 index 0000000..e8e80d2 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/ArticleDTO.java @@ -0,0 +1,14 @@ +package com.gsm._8th.class4.backed.task._1._1.domain; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class ArticleDTO { + private String title; + private String content; +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/ArticleMapper.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/ArticleMapper.java new file mode 100644 index 0000000..11621d5 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/ArticleMapper.java @@ -0,0 +1,14 @@ +package com.gsm._8th.class4.backed.task._1._1.domain; + +public class ArticleMapper { + public static ArticleDTO toDTO(Article article) { + return new ArticleDTO(article.getTitle(), article.getContent()); + } + + public static Article toEntity(ArticleDTO articleDTO) { + return Article.builder() + .title(articleDTO.getTitle()) + .content(articleDTO.getContent()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/README.md b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/README.md deleted file mode 100644 index 589add4..0000000 --- a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/domain/README.md +++ /dev/null @@ -1,2 +0,0 @@ -여기서부터 작업을 시작해주시면 됩니다! -Entity의 경우에는 API 명세서를 참고하셔서 필요한 요소들을 모두 적용해주세요! \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/dto/ArticleRequestDTO.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/dto/ArticleRequestDTO.java new file mode 100644 index 0000000..3d7ae38 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/dto/ArticleRequestDTO.java @@ -0,0 +1,33 @@ +package com.gsm._8th.class4.backed.task._1._1.dto; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; + +public class ArticleRequestDTO { + + private String title; + + private String content; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Article toEntity() { + return Article.builder() + .title(this.title) + .content(this.content) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/GlobalExceptionHandler.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/GlobalExceptionHandler.java new file mode 100644 index 0000000..e0728a0 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/GlobalExceptionHandler.java @@ -0,0 +1,16 @@ +package com.gsm._8th.class4.backed.task._1._1.global; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception e) { + return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/annotation/task/info/TaskInfo.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/annotation/task/info/TaskInfo.java index c68daf8..0381495 100644 --- a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/annotation/task/info/TaskInfo.java +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/annotation/task/info/TaskInfo.java @@ -1,19 +1,11 @@ package com.gsm._8th.class4.backed.task._1._1.global.annotation.task.info; -import jakarta.annotation.PostConstruct; import jdk.jfr.Name; import org.springframework.stereotype.Component; -import java.lang.annotation.Retention; +import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** - * 과제 정보를 출력하는 클래스에 적용되는 어노테이션 - * - * @Componset 어노테이션을 사용하여 빈으로 등록된 클래스에 적용 - * @Slf4j 어노테이션을 사용하여 로깅을 위한 Logger 객체를 생성 - * 어노테이션은 런타임에도 유지되어야 하므로 @Retention 어노테이션을 사용하여 런타임에도 유지되도록 함 - */ @Name("TaskInfo") @Retention(RetentionPolicy.RUNTIME) @Component diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/config/WebConfig.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/config/WebConfig.java new file mode 100644 index 0000000..9edbebf --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/config/WebConfig.java @@ -0,0 +1,17 @@ +package com.gsm._8th.class4.backed.task._1._1.global.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("*") + .allowedHeaders("*"); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/entity/BaseIdxEntity.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/entity/BaseIdxEntity.java index 72bf006..0b286af 100644 --- a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/entity/BaseIdxEntity.java +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/global/entity/BaseIdxEntity.java @@ -7,7 +7,7 @@ @Getter @MappedSuperclass -abstract class BaseIdxEntity { +public abstract class BaseIdxEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idx", nullable = false, updatable = false, insertable = false, unique = true) diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/repository/ArticleRepository.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/repository/ArticleRepository.java new file mode 100644 index 0000000..16b55d9 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/repository/ArticleRepository.java @@ -0,0 +1,9 @@ +package com.gsm._8th.class4.backed.task._1._1.repository; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ArticleRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/ArticleService.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/ArticleService.java new file mode 100644 index 0000000..e8beeb3 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/ArticleService.java @@ -0,0 +1,19 @@ +package com.gsm._8th.class4.backed.task._1._1.service; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public interface ArticleService { + + CompletableFuture> getAllArticles(); + + CompletableFuture> getArticleById(Long id); + + CompletableFuture
createArticle(Article article); + + CompletableFuture> updateArticle(Long id, Article articleDetails); + + CompletableFuture deleteArticle(Long id); +} diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/ArticleServiceImpl.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/ArticleServiceImpl.java new file mode 100644 index 0000000..59a6571 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/ArticleServiceImpl.java @@ -0,0 +1,65 @@ +package com.gsm._8th.class4.backed.task._1._1.service.impl; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.repository.ArticleRepository; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import com.gsm._8th.class4.backed.task._1._1.util.ExceptionHandlerUtil; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +@Service +public class ArticleServiceImpl implements ArticleService { + + private final ArticleRepository articleRepository; + + public ArticleServiceImpl(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @Override + @Async + public CompletableFuture> getAllArticles() { + return CompletableFuture.supplyAsync(() -> articleRepository.findAll()) + .exceptionally(ex -> ExceptionHandlerUtil.handleListException(ex)); + } + + @Override + @Async + public CompletableFuture> getArticleById(Long id) { + return CompletableFuture.supplyAsync(() -> articleRepository.findById(id)) + .exceptionally(ex -> ExceptionHandlerUtil.handleOptionalException(ex)); + } + + @Override + @Async + public CompletableFuture
createArticle(Article article) { + return CompletableFuture.supplyAsync(() -> articleRepository.save(article)) + .exceptionally(ex -> ExceptionHandlerUtil.handleException(ex, null)); + } + + @Override + @Async + public CompletableFuture> updateArticle(Long id, Article articleDetails) { + return CompletableFuture.supplyAsync(() -> articleRepository.findById(id) + .map(existingArticle -> { + existingArticle.update(articleDetails.getTitle(), articleDetails.getContent()); + return articleRepository.save(existingArticle); + })) + .exceptionally(ex -> ExceptionHandlerUtil.handleOptionalException(ex)); + } + + @Override + @Async + public CompletableFuture deleteArticle(Long id) { + return CompletableFuture.supplyAsync(() -> { + Optional
article = articleRepository.findById(id); + article.ifPresent(articleRepository::delete); + return article.isPresent(); + }) + .exceptionally(ex -> ExceptionHandlerUtil.handleBooleanException(ex)); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/CreateArticleService.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/CreateArticleService.java new file mode 100644 index 0000000..aae170a --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/CreateArticleService.java @@ -0,0 +1,50 @@ +package com.gsm._8th.class4.backed.task._1._1.service.impl; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.repository.ArticleRepository; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.concurrent.CompletableFuture; +import java.util.List; +import java.util.Optional; + +@Service +public class CreateArticleService implements ArticleService { + + private final ArticleRepository articleRepository; + + public CreateArticleService(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @Override + @Async + public CompletableFuture
createArticle(Article article) { + return CompletableFuture.supplyAsync(() -> articleRepository.save(article)) + .exceptionally(ex -> { + return null; + }); + } + + @Override + public CompletableFuture> getAllArticles() { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> getArticleById(Long id) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> updateArticle(Long id, Article articleDetails) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture deleteArticle(Long id) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/DeleteArticleService.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/DeleteArticleService.java new file mode 100644 index 0000000..0b18cf7 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/DeleteArticleService.java @@ -0,0 +1,54 @@ +package com.gsm._8th.class4.backed.task._1._1.service.impl; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.repository.ArticleRepository; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.concurrent.CompletableFuture; +import java.util.List; +import java.util.Optional; + +@Service +public class DeleteArticleService implements ArticleService { + + private final ArticleRepository articleRepository; + + public DeleteArticleService(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @Override + @Async + public CompletableFuture deleteArticle(Long id) { + return CompletableFuture.supplyAsync(() -> { + Optional
article = articleRepository.findById(id); + article.ifPresent(articleRepository::delete); + return article.isPresent(); + }) + .exceptionally(ex -> { + return false; + }); + } + + @Override + public CompletableFuture> getAllArticles() { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> getArticleById(Long id) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture
createArticle(Article article) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> updateArticle(Long id, Article articleDetails) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/GetAllArticlesService.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/GetAllArticlesService.java new file mode 100644 index 0000000..225022d --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/GetAllArticlesService.java @@ -0,0 +1,50 @@ +package com.gsm._8th.class4.backed.task._1._1.service.impl; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.repository.ArticleRepository; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.Optional; + +@Service +public class GetAllArticlesService implements ArticleService { + + private final ArticleRepository articleRepository; + + public GetAllArticlesService(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @Override + @Async + public CompletableFuture> getAllArticles() { + return CompletableFuture.supplyAsync(() -> articleRepository.findAll()) + .exceptionally(ex -> { + return List.of(); + }); + } + + @Override + public CompletableFuture> getArticleById(Long id) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture
createArticle(Article article) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> updateArticle(Long id, Article articleDetails) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture deleteArticle(Long id) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/GetArticleByIdService.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/GetArticleByIdService.java new file mode 100644 index 0000000..579576d --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/GetArticleByIdService.java @@ -0,0 +1,50 @@ +package com.gsm._8th.class4.backed.task._1._1.service.impl; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.repository.ArticleRepository; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.List; + +@Service +public class GetArticleByIdService implements ArticleService { + + private final ArticleRepository articleRepository; + + public GetArticleByIdService(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @Override + @Async + public CompletableFuture> getArticleById(Long id) { + return CompletableFuture.supplyAsync(() -> articleRepository.findById(id)) + .exceptionally(ex -> { + return Optional.empty(); + }); + } + + @Override + public CompletableFuture> getAllArticles() { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture
createArticle(Article article) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> updateArticle(Long id, Article articleDetails) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture deleteArticle(Long id) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/UpdateArticleService.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/UpdateArticleService.java new file mode 100644 index 0000000..6bf4ec7 --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/service/impl/UpdateArticleService.java @@ -0,0 +1,54 @@ +package com.gsm._8th.class4.backed.task._1._1.service.impl; + +import com.gsm._8th.class4.backed.task._1._1.domain.Article; +import com.gsm._8th.class4.backed.task._1._1.repository.ArticleRepository; +import com.gsm._8th.class4.backed.task._1._1.service.ArticleService; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.List; + +@Service +public class UpdateArticleService implements ArticleService { + + private final ArticleRepository articleRepository; + + public UpdateArticleService(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @Override + @Async + public CompletableFuture> updateArticle(Long id, Article articleDetails) { + return CompletableFuture.supplyAsync(() -> articleRepository.findById(id) + .map(existingArticle -> { + existingArticle.update(articleDetails.getTitle(), articleDetails.getContent()); + return articleRepository.save(existingArticle); + })) + .exceptionally(ex -> { + return Optional.empty(); + }); + } + + @Override + public CompletableFuture> getAllArticles() { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture> getArticleById(Long id) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture
createArticle(Article article) { + throw new UnsupportedOperationException(); + } + + @Override + public CompletableFuture deleteArticle(Long id) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/util/ExceptionHandlerUtil.java b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/util/ExceptionHandlerUtil.java new file mode 100644 index 0000000..824102f --- /dev/null +++ b/src/main/java/com/gsm/_8th/class4/backed/task/_1/_1/util/ExceptionHandlerUtil.java @@ -0,0 +1,23 @@ +package com.gsm._8th.class4.backed.task._1._1.util; + +import java.util.List; +import java.util.Optional; + +public class ExceptionHandlerUtil { + + public static T handleException(Throwable ex, T defaultValue) { + return defaultValue; + } + + public static Optional handleOptionalException(Throwable ex) { + return Optional.empty(); + } + + public static List handleListException(Throwable ex) { + return List.of(); + } + + public static Boolean handleBooleanException(Throwable ex) { + return false; + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 743a92a..b127227 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -3,13 +3,13 @@ spring: name: task.1-1 datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${RDB_HOST:localhost}:${RDB_PORT:3306}/${RDB_NAME:task_1_1} - username: ${RDB_USER:root} - password: ${RDB_PASSWORD:123456} + url: jdbc:mysql://localhost:3306/task_1_1 + username: root + password: 1234 jpa: hibernate: - ddl-auto: ${DDL_AUTO:update} + ddl-auto: update show-sql: true properties: hibernate: - dialect: org.hibernate.dialect.MySQL8Dialect \ No newline at end of file + dialect: org.hibernate.dialect.MySQL8Dialect