Skip to content

Commit

Permalink
feat: 블로그 소개 기능 추가 (#87)
Browse files Browse the repository at this point in the history
* [#20] feat: About 도메인 로직 작성

* [#20] feat: About 서비스 로직 작성

* [#20] feat: 블로그 소개(About) API 작성

* [#20] feat: 블로그 소개(About) 조회 API 작성
  • Loading branch information
shin-mallang authored Nov 21, 2023
1 parent e41f138 commit 44b16cd
Show file tree
Hide file tree
Showing 23 changed files with 883 additions and 21 deletions.
30 changes: 9 additions & 21 deletions src/main/java/com/mallang/auth/config/AuthConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,21 @@ public void addInterceptors(InterceptorRegistry registry) {

private AuthInterceptor setUpAuthInterceptor() {
authInterceptor.setNoAuthRequiredConditions(
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/members/**"))
.httpMethods(Set.of(GET))
.build(),
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/posts/**"))
.httpMethods(Set.of(GET))
.build(),
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/categories"))
.httpMethods(Set.of(GET))
.build(),
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/comments/**"))
.httpMethods(Set.of(POST, PUT, DELETE))
.params(Map.of("unauthenticated", "true"))
.build(),
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/comments"))
.httpMethods(Set.of(GET))
.build(),
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/blog-subscribes/*"))
.httpMethods(Set.of(GET))
.build(),
UriAndMethodAndParamCondition.builder()
.uriPatterns(Set.of("/post-stars/**"))
.uriPatterns(Set.of(
"/members/*",
"/posts/**",
"/categories",
"/comments",
"/blog-subscribes/*",
"/post-stars",
"/abouts"
))
.httpMethods(Set.of(GET))
.build()
);
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/com/mallang/blog/application/AboutService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.mallang.blog.application;

import com.mallang.auth.domain.Member;
import com.mallang.auth.domain.MemberRepository;
import com.mallang.blog.application.command.DeleteAboutCommand;
import com.mallang.blog.application.command.UpdateAboutCommand;
import com.mallang.blog.application.command.WriteAboutCommand;
import com.mallang.blog.domain.About;
import com.mallang.blog.domain.AboutRepository;
import com.mallang.blog.domain.AboutValidator;
import com.mallang.blog.domain.Blog;
import com.mallang.blog.domain.BlogRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Transactional
@Service
public class AboutService {

private final MemberRepository memberRepository;
private final BlogRepository blogRepository;
private final AboutRepository aboutRepository;
private final AboutValidator aboutValidator;

public Long write(WriteAboutCommand command) {
Member member = memberRepository.getById(command.memberId());
Blog blog = blogRepository.getByNameAndOwnerId(command.blogName(), command.memberId());
About about = command.toAbout(member, blog);
about.write(aboutValidator);
return aboutRepository.save(about)
.getId();
}

public void update(UpdateAboutCommand command) {
About about = aboutRepository.getByIdAndWriterIdAndBlogName(
command.aboutId(), command.memberId(), command.blogName()
);
about.update(command.content());
}

public void delete(DeleteAboutCommand command) {
About about = aboutRepository.getByIdAndWriterIdAndBlogName(
command.aboutId(), command.memberId(), command.blogName()
);
aboutRepository.delete(about);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mallang.blog.application.command;

public record DeleteAboutCommand(
Long aboutId,
Long memberId,
String blogName
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.mallang.blog.application.command;

public record UpdateAboutCommand(
Long aboutId,
Long memberId,
String blogName,
String content
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mallang.blog.application.command;

import com.mallang.auth.domain.Member;
import com.mallang.blog.domain.About;
import com.mallang.blog.domain.Blog;

public record WriteAboutCommand(
Long memberId,
String blogName,
String content
) {
public About toAbout(Member member, Blog blog) {
return new About(blog, content, member);
}
}
46 changes: 46 additions & 0 deletions src/main/java/com/mallang/blog/domain/About.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.mallang.blog.domain;

import static jakarta.persistence.FetchType.LAZY;

import com.mallang.auth.domain.Member;
import com.mallang.common.domain.CommonDomainModel;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class About extends CommonDomainModel {

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "blog_id", nullable = false, unique = true)
private Blog blog;

@Column(nullable = false, columnDefinition = "TEXT")
private String content;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "writer_id", nullable = false)
private Member writer;

public About(Blog blog, String content, Member writer) {
this.blog = blog;
this.content = content;
this.writer = writer;
}

public void write(AboutValidator validator) {
validator.validateAlreadyExist(blog);
}

public void update(String content) {
this.content = content;
}
}
24 changes: 24 additions & 0 deletions src/main/java/com/mallang/blog/domain/AboutRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.mallang.blog.domain;

import com.mallang.blog.exception.NotFoundAboutException;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface AboutRepository extends JpaRepository<About, Long> {

boolean existsByBlog(Blog blog);

default About getByIdAndWriterIdAndBlogName(Long aboutId, Long memberId, String blogName) {
return findByWriterIdAndBlogName(aboutId, memberId, blogName)
.orElseThrow(NotFoundAboutException::new);
}

@Query("SELECT a FROM About a WHERE a.id = :aboutId AND a.writer.id = :writerId AND a.blog.name.value = :blogName")
Optional<About> findByWriterIdAndBlogName(
@Param("aboutId") Long aboutId,
@Param("writerId") Long writerId,
@Param("blogName") String blogName
);
}
18 changes: 18 additions & 0 deletions src/main/java/com/mallang/blog/domain/AboutValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.mallang.blog.domain;

import com.mallang.blog.exception.AlreadyExistAboutException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class AboutValidator {

private final AboutRepository aboutRepository;

public void validateAlreadyExist(Blog blog) {
if (aboutRepository.existsByBlog(blog)) {
throw new AlreadyExistAboutException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mallang.blog.exception;

import com.mallang.common.execption.ErrorCode;
import com.mallang.common.execption.MallangLogException;
import org.springframework.http.HttpStatus;

public class AlreadyExistAboutException extends MallangLogException {

public AlreadyExistAboutException() {
super(new ErrorCode(HttpStatus.CONFLICT, "이미 작성된 ABOUT이 있습니다."));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mallang.blog.exception;

import static org.springframework.http.HttpStatus.NOT_FOUND;

import com.mallang.common.execption.ErrorCode;
import com.mallang.common.execption.MallangLogException;

public class NotFoundAboutException extends MallangLogException {

public NotFoundAboutException(String message) {
super(new ErrorCode(NOT_FOUND, message));
}

public NotFoundAboutException() {
super(new ErrorCode(NOT_FOUND, "존재하지 않는 About입니다."));
}
}
66 changes: 66 additions & 0 deletions src/main/java/com/mallang/blog/presentation/AboutController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.mallang.blog.presentation;

import com.mallang.auth.presentation.support.Auth;
import com.mallang.blog.application.AboutService;
import com.mallang.blog.presentation.request.DeleteAboutRequest;
import com.mallang.blog.presentation.request.UpdateAboutRequest;
import com.mallang.blog.presentation.request.WriteAboutRequest;
import com.mallang.blog.query.AboutQueryService;
import com.mallang.blog.query.data.AboutResponse;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RequestMapping("/abouts")
@RestController
public class AboutController {

private final AboutService aboutService;
private final AboutQueryService aboutQueryService;

@PostMapping
public ResponseEntity<Long> write(
@Auth Long memberId,
@RequestBody WriteAboutRequest request
) {
Long aboutId = aboutService.write(request.toCommand(memberId));
return ResponseEntity.created(URI.create("/abouts/" + aboutId)).build();
}

@PutMapping("/{id}")
public ResponseEntity<Void> update(
@PathVariable("id") Long aboutId,
@Auth Long memberId,
@RequestBody UpdateAboutRequest request
) {
aboutService.update(request.toCommand(aboutId, memberId));
return ResponseEntity.ok().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(
@PathVariable("id") Long aboutId,
@Auth Long memberId,
@RequestBody DeleteAboutRequest request
) {
aboutService.delete(request.toCommand(aboutId, memberId));
return ResponseEntity.noContent().build();
}

@GetMapping
public ResponseEntity<AboutResponse> findByBlogName(
@RequestParam(name = "blogName") String blogName
) {
return ResponseEntity.ok(aboutQueryService.findByBlogName(blogName));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mallang.blog.presentation.request;

import com.mallang.blog.application.command.DeleteAboutCommand;

public record DeleteAboutRequest(
String blogName
) {
public DeleteAboutCommand toCommand(Long aboutId, Long memberId) {
return new DeleteAboutCommand(aboutId, memberId, blogName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mallang.blog.presentation.request;

import com.mallang.blog.application.command.UpdateAboutCommand;

public record UpdateAboutRequest(
String blogName,
String content
) {
public UpdateAboutCommand toCommand(Long aboutId, Long memberId) {
return new UpdateAboutCommand(aboutId, memberId, blogName, content);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mallang.blog.presentation.request;

import com.mallang.blog.application.command.WriteAboutCommand;

public record WriteAboutRequest(
String blogName,
String content
) {
public WriteAboutCommand toCommand(Long memberId) {
return new WriteAboutCommand(memberId, blogName, content);
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/mallang/blog/query/AboutQueryService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.mallang.blog.query;

import com.mallang.blog.query.dao.AboutResponseDao;
import com.mallang.blog.query.data.AboutResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class AboutQueryService {

private final AboutResponseDao aboutResponseDao;

public AboutResponse findByBlogName(String blogName) {
return aboutResponseDao.find(blogName);
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/mallang/blog/query/dao/AboutResponseDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.mallang.blog.query.dao;

import com.mallang.blog.query.dao.support.AboutQuerySupport;
import com.mallang.blog.query.data.AboutResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Component
public class AboutResponseDao {

private final AboutQuerySupport aboutQuerySupport;

public AboutResponse find(String blogName) {
return AboutResponse.from(aboutQuerySupport.getByBlogName(blogName));
}
}
Loading

0 comments on commit 44b16cd

Please sign in to comment.