Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

전남대 BE 조홍식 4주차(step1제출) #255

Open
wants to merge 12 commits into
base: daolove0323
Choose a base branch
from
98 changes: 97 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,97 @@
# spring-gift-enhancement
# spring-gift-product

## 과제 진행 요구 사항

- 기능을 구현하기 전 README.md에 구현할 기능 목록을 정리해 추가한다.

- Git의 커밋 단위는 앞 단계에서 README.md에 정리한 기능 목록 단위로 추가한다.

- AngularJS Git Commit Message Conventions을 참고해 커밋 메시지를 작성한다.



## 기능 요구 사항
상품 정보에 카테고리를 추가한다. 상품과 카테고리 모델 간의 관계를 고려하여 설계하고 구현한다.

- 상품에는 항상 하나의 카테고리가 있어야 한다.
- 상품 카테고리는 수정할 수 있다.
- 관리자 화면에서 상품을 추가할 때 카테고리를 지정할 수 있다.
- 카테고리는 1차 카테고리만 있으며 2차 카테고리는 고려하지 않는다.
- 카테고리의 예시는 아래와 같다.
- 교환권, 상품권, 뷰티, 패션, 식품, 리빙/도서, 레저/스포츠, 아티스트/캐릭터, 유아동/반려, 디지털/가전, 카카오프렌즈, 트렌드 선물, 백화점, ...
아래 예시와 같이 HTTP 메시지를 주고받도록 구현한다.

```
Request
GET /api/categories HTTP/1.1
Response
HTTP/1.1 200
Content-Type: application/json
```

```
[
{
"id": 91,
"name": "교환권",
"color": "#6c95d1",
"imageUrl": "https://gift-s.kakaocdn.net/dn/gift/images/m640/dimm_theme.png",
"description": ""
}
]
```

## 프로그래밍 요구 사항
- 구현한 기능에 대해 적절한 테스트 전략을 생각하고 작성한다.

- 힌트
아래의 DDL을 보고 유추한다.

```
create table category
(
color varchar(7) not null,
id bigint not null auto_increment,
description varchar(255),
image_url varchar(255) not null,
name varchar(255) not null,
primary key (id)
) engine=InnoDB
```

```
create table product
(
price integer not null,
category_id bigint not null,
id bigint not null auto_increment,
name varchar(15) not null,
image_url varchar(255) not null,
primary key (id)
) engine=InnoDB
```

```
alter table category
add constraint uk_category unique (name)

alter table product
add constraint fk_product_category_id_ref_category_id
foreign key (category_id)
references category (id)
```

## 프로그래밍 요구 사항

- 자바 코드 컨벤션을 지키면서 프로그래밍한다.
- 기본적으로 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html)를 원칙으로 한다.
- 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다.
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다.
- 3항 연산자를 쓰지 않는다.
- 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
- 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
- else 예약어를 쓰지 않는다.
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다.
9 changes: 8 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'

implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
54 changes: 49 additions & 5 deletions src/main/java/gift/admin/AdminController.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package gift.admin;

import gift.controller.category.CategoryRequest;
import gift.controller.category.CategoryResponse;
import gift.controller.member.MemberRequest;
import gift.controller.member.MemberResponse;
import gift.controller.member.SignUpRequest;
import gift.controller.product.ProductRequest;
import gift.controller.product.ProductResponse;
import gift.service.CategoryService;
import gift.service.MemberService;
import gift.service.ProductService;
import jakarta.validation.Valid;
Expand All @@ -27,10 +30,52 @@ public class AdminController {

private final ProductService productService;
private final MemberService memberService;
private final CategoryService categoryService;

public AdminController(ProductService productService, MemberService memberService) {
public AdminController(ProductService productService, MemberService memberService,
CategoryService categoryService) {
this.productService = productService;
this.memberService = memberService;
this.categoryService = categoryService;
}

@GetMapping("/categories")
public String listCategories(Model model, @RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "5") int size) {
Pageable pageable = PageRequest.of(page, size);
Page<CategoryResponse> categories = categoryService.findAll(pageable);
model.addAttribute("categories", categories);
return "categories";
}

@GetMapping("/categories/add")
public String categoryAddForm(Model model) {
model.addAttribute("category", new CategoryRequest("", "", "", ""));
return "category-add-form";
}

@PostMapping("/categories/add")
public String addCategory(@ModelAttribute CategoryRequest category) {
categoryService.save(category);
return "redirect:/admin/categories";
}

@GetMapping("/categories/edit/{id}")
public String categoryEditForm(@PathVariable UUID id, Model model) {
model.addAttribute("category", categoryService.find(id));
return "category-edit-form";
}

@PostMapping("/categories/edit/{id}")
public String editCategory(@PathVariable UUID id, @ModelAttribute CategoryRequest category) {
categoryService.update(id, category);
return "redirect:/admin/categories";
}

@GetMapping("/categories/delete/{id}")
public String deleteCategory(@PathVariable UUID id) {
categoryService.delete(id);
return "redirect:/admin/categories";
}

@GetMapping("/members")
Expand Down Expand Up @@ -66,9 +111,8 @@ public String editMember(@PathVariable UUID id, @ModelAttribute MemberRequest me
return "redirect:/admin/members";
}

@GetMapping("/members/delete/{email}")
public String deleteMember(@PathVariable String email) {
UUID id = memberService.findByEmail(email).id();
@GetMapping("/members/delete/{id}")
public String deleteMember(@PathVariable UUID id) {
memberService.delete(id);
return "redirect:/admin/members";
}
Expand All @@ -88,7 +132,7 @@ public String listProducts(Model model, @RequestParam(defaultValue = "0") int pa

@GetMapping("/products/add")
public String productAddForm(Model model) {
model.addAttribute("product", new ProductRequest("", 0L, ""));
model.addAttribute("product", new ProductRequest("", 0L, "", ""));
return "product-add-form";
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/java/gift/controller/auth/LoginResponse.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package gift.controller.auth;

import gift.domain.Grade;
import java.util.UUID;

public record LoginResponse(UUID id, String email, String nickname, String grade) {
public record LoginResponse(UUID id, String email, String nickname, Grade grade) {

public boolean isAdmin() {
return grade != null && grade.equals("admin");
return grade != null && grade == Grade.ADMIN;
}
}
61 changes: 61 additions & 0 deletions src/main/java/gift/controller/category/CategoryController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package gift.controller.category;

import gift.config.LoginMember;
import gift.controller.auth.AuthController;
import gift.controller.auth.LoginResponse;
import gift.controller.product.ProductRequest;
import gift.controller.product.ProductResponse;
import gift.service.CategoryService;
import java.util.UUID;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
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;

@RestController
@RequestMapping("/api/categories")
public class CategoryController {
CategoryService categoryService;

public CategoryController(CategoryService categoryService) {
this.categoryService = categoryService;
}

@GetMapping
public ResponseEntity<Page<CategoryResponse>> getAllCategories(
@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "5") int size) {
Pageable pageable = PageRequest.of(page, size);
return ResponseEntity.status(HttpStatus.OK).body(categoryService.findAll(pageable));
}

@PostMapping
public ResponseEntity<CategoryResponse> createCategory(@LoginMember LoginResponse loginMember,
@RequestBody CategoryRequest product) {
return ResponseEntity.status(HttpStatus.CREATED).body(categoryService.save(product));
}

@PutMapping("/{categoryId}")
public ResponseEntity<CategoryResponse> updateCategory(@LoginMember LoginResponse loginMember,
@PathVariable UUID categoryId, @RequestBody CategoryRequest category) {
AuthController.validateAdmin(loginMember);
return ResponseEntity.status(HttpStatus.OK).body(categoryService.update(categoryId, category));
}

@DeleteMapping("/{categoryId}")
public ResponseEntity<Void> deleteCategory(@LoginMember LoginResponse loginMember,
@PathVariable UUID categoryId) {
AuthController.validateAdmin(loginMember);
categoryService.delete(categoryId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
}
}
16 changes: 16 additions & 0 deletions src/main/java/gift/controller/category/CategoryMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package gift.controller.category;

import gift.domain.Category;

public class CategoryMapper {

public static CategoryResponse toCategoryResponse(Category category) {
return new CategoryResponse(category.getId(), category.getName(), category.getColor(),
category.getDescription(), category.getImage_url());
}

public static Category from(CategoryRequest categoryRequest) {
return new Category(categoryRequest.name(), categoryRequest.color(),
categoryRequest.description(), categoryRequest.imageUrl());
}
}
5 changes: 5 additions & 0 deletions src/main/java/gift/controller/category/CategoryRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package gift.controller.category;

public record CategoryRequest (String name, String color, String description, String imageUrl){

}
7 changes: 7 additions & 0 deletions src/main/java/gift/controller/category/CategoryResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gift.controller.category;

import java.util.UUID;

public record CategoryResponse(UUID id, String name, String color, String description, String imageUrl) {

}
4 changes: 3 additions & 1 deletion src/main/java/gift/controller/member/MemberRequest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package gift.controller.member;

public record MemberRequest(String email, String password, String grade) {
import gift.domain.Grade;

public record MemberRequest(String email, String password, Grade grade) {

}
3 changes: 2 additions & 1 deletion src/main/java/gift/controller/member/MemberResponse.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package gift.controller.member;

import gift.domain.Grade;
import java.util.UUID;

public record MemberResponse(UUID id, String email, String password, String nickName,
String grade) {
Grade grade) {

}
4 changes: 3 additions & 1 deletion src/main/java/gift/controller/product/ProductRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public record ProductRequest(

@PositiveOrZero Long price,

String imageUrl) {
String imageUrl,

String categoryName) {

}
Loading