Skip to content

Commit

Permalink
카테고리 우선순위 저장 기능을 구현한다. (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
shin-jisong authored Jul 23, 2024
2 parents 91863de + d1f610a commit 2f1c2e4
Show file tree
Hide file tree
Showing 17 changed files with 371 additions and 15 deletions.
1 change: 1 addition & 0 deletions backend/bang-ggood/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ bin/

### IntelliJ IDEA ###
src/main/resources/application.yml
src/test/resources/application-test.yml
.idea
*.iws
*.iml
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.bang_ggood.category.controller;

import com.bang_ggood.category.dto.CategoriesReadResponse;
import com.bang_ggood.category.dto.CategoryPriorityCreateRequest;
import com.bang_ggood.category.service.CategoryService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
Expand All @@ -15,6 +18,13 @@ public CategoryController(CategoryService categoryService) {
this.categoryService = categoryService;
}

@PostMapping("/categories/priority")
public ResponseEntity<Void> createCategoriesPriority(@RequestBody CategoryPriorityCreateRequest request) {
// TODO: List 요소 null check 필요
categoryService.createCategoriesPriority(request);
return ResponseEntity.noContent().build();
}

@GetMapping("/categories")
public ResponseEntity<CategoriesReadResponse> readCategories() {
return ResponseEntity.ok(categoryService.readCategories());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.bang_ggood.category.domain;

import java.util.Arrays;

public enum Category {

CLEAN(1, "청결"),
Expand All @@ -18,6 +20,11 @@ public enum Category {
this.description = description;
}

public static boolean contains(int id) {
return Arrays.stream(values())
.anyMatch(category -> category.id == id);
}

public int getId() {
return id;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.bang_ggood.category.domain;

import com.bang_ggood.BaseEntity;
import com.bang_ggood.user.domain.User;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import java.util.Objects;

@Entity
public class CategoryPriority extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private Integer categoryId;

@ManyToOne(fetch = FetchType.LAZY)
private User user;

protected CategoryPriority() {
}

public CategoryPriority(Integer categoryId, User user) {
this.categoryId = categoryId;
this.user = user;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CategoryPriority that = (CategoryPriority) o;
return Objects.equals(id, that.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

@Override
public String toString() {
return "CategoryPriority{" +
"id=" + id +
", categoryId=" + categoryId +
", user=" + user +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.bang_ggood.category.dto;

import java.util.List;

public record CategoryPriorityCreateRequest(List<Integer> categoryIds) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.bang_ggood.category.repository;

import com.bang_ggood.category.domain.CategoryPriority;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CategoryPriorityRepository extends JpaRepository<CategoryPriority, Long> {
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,71 @@
package com.bang_ggood.category.service;

import com.bang_ggood.category.domain.Category;
import com.bang_ggood.category.domain.CategoryPriority;
import com.bang_ggood.category.dto.CategoriesReadResponse;
import com.bang_ggood.category.dto.CategoryPriorityCreateRequest;
import com.bang_ggood.category.dto.CategoryReadResponse;
import com.bang_ggood.category.repository.CategoryPriorityRepository;
import com.bang_ggood.exception.BangggoodException;
import com.bang_ggood.user.domain.User;
import com.bang_ggood.user.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static com.bang_ggood.exception.ExceptionCode.CATEGORY_DUPLICATED;
import static com.bang_ggood.exception.ExceptionCode.CATEGORY_NOT_FOUND;
import static com.bang_ggood.exception.ExceptionCode.CATEGORY_PRIORITY_INVALID_COUNT;

@Service
public class CategoryService {

private static final int MAX_CATEGORY_PRIORITY_COUNT = 3;

private final CategoryPriorityRepository categoryPriorityRepository;
private final UserRepository userRepository;

public CategoryService(CategoryPriorityRepository categoryPriorityRepository, UserRepository userRepository) {
this.categoryPriorityRepository = categoryPriorityRepository;
this.userRepository = userRepository;
}

@Transactional
public void createCategoriesPriority(CategoryPriorityCreateRequest request) {
validateDuplication(request);
validateCategoryCount(request);
validateCategoryId(request);

User user = userRepository.getUserById(1L);
List<CategoryPriority> categoryPriorities = request.categoryIds().stream()
.map(id -> new CategoryPriority(id, user))
.toList();

categoryPriorityRepository.saveAll(categoryPriorities);
}

private void validateDuplication(CategoryPriorityCreateRequest request) {
if (request.categoryIds().size() != Set.copyOf(request.categoryIds()).size()) {
throw new BangggoodException(CATEGORY_DUPLICATED);
}
}

private void validateCategoryCount(CategoryPriorityCreateRequest request) {
if (request.categoryIds().size() > MAX_CATEGORY_PRIORITY_COUNT) {
throw new BangggoodException(CATEGORY_PRIORITY_INVALID_COUNT);
}
}

private void validateCategoryId(CategoryPriorityCreateRequest request) {
for (Integer id : request.categoryIds()) {
if (!Category.contains(id)) {
throw new BangggoodException(CATEGORY_NOT_FOUND);
}
}
}

public CategoriesReadResponse readCategories() {
List<CategoryReadResponse> categoryReadResponses = Arrays.stream(Category.values())
.map(CategoryReadResponse::from)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

public enum ExceptionCode {

INVALID_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 인자입니다.");
INVALID_PARAMETER(HttpStatus.BAD_REQUEST, "잘못된 인자입니다."),
USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "유저가 존재하지 않습니다."),
CATEGORY_PRIORITY_INVALID_COUNT(HttpStatus.BAD_REQUEST, "카테고리 개수가 유효하지 않습니다."),
CATEGORY_NOT_FOUND(HttpStatus.BAD_REQUEST, "카테코리가 존재하지 않습니다."),
CATEGORY_DUPLICATED(HttpStatus.BAD_REQUEST, "중복된 카테고리가 존재합니다."),
;

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.bang_ggood.user.domain;

import com.bang_ggood.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Objects;

@Table(name = "users")
@Entity
public class User extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private String name;

protected User() {
}

public User(String name) {
this.name = name;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
User user = (User) o;
return Objects.equals(id, user.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.bang_ggood.user.repository;

import com.bang_ggood.exception.BangggoodException;
import com.bang_ggood.exception.ExceptionCode;
import com.bang_ggood.user.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

default User getUserById(Long id) {
return findById(id).orElseThrow(() -> new BangggoodException(ExceptionCode.USER_NOT_FOUND));
}
}
2 changes: 2 additions & 0 deletions backend/bang-ggood/src/main/resources/data.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INSERT INTO users(id, name, created_at, modified_at)
VALUES (1, '방방이', '2024-07-22 07:56:42', '2024-07-22 07:56:42');
19 changes: 19 additions & 0 deletions backend/bang-ggood/src/main/resources/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
CREATE TABLE users
(
id bigint generated by default as identity,
name varchar(255) not null,
created_at TIMESTAMP not null,
modified_at TIMESTAMP not null,
primary key (id)
);

CREATE TABLE category_priority
(
id bigint generated by default as identity,
category_id tinyint not null,
user_id bigint not null,
created_at TIMESTAMP not null,
modified_at TIMESTAMP not null,
primary key (id),
foreign key (user_id) references users
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.bang_ggood;


import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles("test")
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class IntegrationTestSupport {
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,16 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.annotation.DirtiesContext;
import java.time.LocalDateTime;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
class JpaAuditingTest {
class JpaAuditingTest extends IntegrationTestSupport{

@Autowired
private TestRepository testRepository;
Expand Down Expand Up @@ -56,6 +52,7 @@ void jpaAuditing_modifyEntity() {
);
}

@Table(name = "test_entity")
@Entity
static class TestEntity extends BaseEntity {

Expand Down
Loading

0 comments on commit 2f1c2e4

Please sign in to comment.