Skip to content

Commit

Permalink
#16 - Feat: 도서 등록폼에서 QueryDSL 으로 내 글의 해시태그 키워드/개수 조회, 도서 등록 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
ahah525 committed Oct 24, 2022
1 parent 59dee4e commit c1e3a31
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.mutbooks.app.postKeyword.exception;

public class PostKeywordNotFoundException extends RuntimeException {
public PostKeywordNotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@

import java.util.Optional;

public interface PostKeywordRepository extends JpaRepository<PostKeyword, Long> {
public interface PostKeywordRepository extends JpaRepository<PostKeyword, Long>, PostKeywordRepositoryCustom {
Optional<PostKeyword> findByContent(String content);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.mutbooks.app.postKeyword.repository;

import com.example.mutbooks.app.postKeyword.dto.PostKeywordDto;

import java.util.List;

public interface PostKeywordRepositoryCustom {
List<PostKeywordDto> getQslAllByAuthorId(Long authorId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.mutbooks.app.postKeyword.repository;

import com.example.mutbooks.app.postKeyword.dto.PostKeywordDto;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;

import java.util.List;

import static com.example.mutbooks.app.postHashTag.entity.QPostHashTag.postHashTag;
import static com.example.mutbooks.app.postKeyword.entity.QPostKeyword.postKeyword;

@RequiredArgsConstructor
public class PostKeywordRepositoryImpl implements PostKeywordRepositoryCustom {
private final JPAQueryFactory jpaQueryFactory;

@Override
public List<PostKeywordDto> getQslAllByAuthorId(Long authorId) {
// 생성자를 이용해 List<PostKeywordDto> 로 반환
return jpaQueryFactory
.select(Projections.constructor(PostKeywordDto.class,
postKeyword.id,
postKeyword.content,
postHashTag.count()
))
.from(postKeyword)
.innerJoin(postHashTag)
.on(postKeyword.eq(postHashTag.postKeyword))
.where(postHashTag.member.id.eq(authorId))
.orderBy(postKeyword.content.asc()) // 키워드 명 오름차순 정렬
.groupBy(postKeyword.id) // 키워드 중복 제거
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.example.mutbooks.app.postKeyword.service;

import com.example.mutbooks.app.postKeyword.dto.PostKeywordDto;
import com.example.mutbooks.app.postKeyword.entity.PostKeyword;
import com.example.mutbooks.app.postKeyword.exception.PostKeywordNotFoundException;
import com.example.mutbooks.app.postKeyword.repository.PostKeywordRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
Expand Down Expand Up @@ -34,4 +38,15 @@ public PostKeyword save(String content) {
public PostKeyword findByContent(String content) {
return postKeywordRepository.findByContent(content).orElse(null);
}

// 작가가 등록한 글과 관련된 모든 해시태그 키워드 조회
public List<PostKeywordDto> findByMemberId(Long authorId) {
return postKeywordRepository.getQslAllByAuthorId(authorId);
}

public PostKeyword findById(Long id) {
return postKeywordRepository.findById(id).orElseThrow(() -> {
throw new PostKeywordNotFoundException("해당 키워드는 존재하지 않습니다.");
});
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
package com.example.mutbooks.app.product.controller;

import com.example.mutbooks.app.base.security.dto.MemberContext;
import com.example.mutbooks.app.member.entity.Member;
import com.example.mutbooks.app.postKeyword.dto.PostKeywordDto;
import com.example.mutbooks.app.postKeyword.service.PostKeywordService;
import com.example.mutbooks.app.product.entity.Product;
import com.example.mutbooks.app.product.form.ProductForm;
import com.example.mutbooks.app.product.service.ProductService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;

@Controller
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {
private final ProductService productService;
private final PostKeywordService postKeywordService;

// TODO: 작가회원인지 검증
// 도서 등록폼
@PreAuthorize("isAuthenticated()")
@GetMapping("/create")
public String showCreate() {
public String showCreate(@AuthenticationPrincipal MemberContext memberContext, Model model) {
List<PostKeywordDto> postKeywords = postKeywordService.findByMemberId(memberContext.getId());
model.addAttribute("postKeywords", postKeywords);

return "/product/create";
}

// 도서 등록
@PreAuthorize("isAuthenticated()")
@PostMapping("/create")
public String create(@AuthenticationPrincipal MemberContext memberContext, @Valid ProductForm productForm) {
Member author = memberContext.getMember();
Product product = productService.create(author, productForm);

return "redirect:/product/" + product.getId();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
package com.example.mutbooks.app.product.service;

import com.example.mutbooks.app.member.entity.Member;
import com.example.mutbooks.app.postKeyword.entity.PostKeyword;
import com.example.mutbooks.app.postKeyword.service.PostKeywordService;
import com.example.mutbooks.app.product.entity.Product;
import com.example.mutbooks.app.product.form.ProductForm;
import com.example.mutbooks.app.product.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ProductService {
private final ProductRepository productRepository;
private final PostKeywordService postKeywordService;

@Transactional
public Product create(Member author, ProductForm productForm) {
PostKeyword postKeyword = postKeywordService.findById(productForm.getPostKeywordId());

Product product = Product.builder()
.author(author)
.postKeyword(postKeyword)
.subject(productForm.getSubject())
.content(productForm.getContent())
.price(productForm.getPrice())
.build();

productRepository.save(product);

// TODO : 도서 해시태그 저장

return product;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,24 @@ <h1 class="font-bold text-lg">
return;
}

form.postTagContents.value = form.postTagContents.value.trim();
form.content.value = form.content.value.trim();

if (form.postTagContents.value.length == 0) {
warningModal("태그를 입력해주세요.");
form.postTagContents.focus();
if (form.content.value.length == 0) {
warningModal("설명을 입력해주세요.");
form.content.focus();

return;
}

// form.productKeywords.value = form.productKeywords.value.trim();
//
// if (form.productKeywords.value.length == 0) {
// warningModal("도서 해시태그를 입력해주세요.");
// form.productKeywords.focus();
//
// return;
// }

form.submit();

ProductCreate__submitDone = true;
Expand All @@ -66,9 +75,9 @@ <h1 class="font-bold text-lg">
</label>
<select class="select select-bordered" name="postKeywordId">
<option disabled="disabled" selected>- 글 태그 선택 -</option>
<option th:each="postKeyword : ${postKeywords}"
th:value="${postKeyword.id}"
th:text="|${postKeyword.content} : 글 ${@ut.nf(postKeyword.extra_postTagsCount)}건|"></option>
<option th:each="postKeywordDto : ${postKeywords}"
th:value="${postKeywordDto.id}"
th:text="|${postKeywordDto.content} : 글 ${postKeywordDto.postCount}건|"></option>
</select>
</div>

Expand All @@ -90,9 +99,14 @@ <h1 class="font-bold text-lg">

<div class="form-control">
<label class="label">
<span class="label-text">태그</span>
<span class="label-text">설명</span>
</label>
<input type="text" name="productTagContents" placeholder="#태그1 #태그2 #태그3 ..."
<textarea autofocus type="text" name="content" placeholder="도서 설명을 입력해주세요.(200자 이하)" class="input input-bordered"
maxlength="200"> </textarea>
</div>

<div class="form-control">
<input type="text" name="productKeywords" placeholder="#태그1 #태그2 #태그3 ..."
class="input input-bordered"
maxlength="50">
</div>
Expand Down

0 comments on commit c1e3a31

Please sign in to comment.