Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
# spring-gift-wishlist
# spring-gift-product
KTC step2 클론코딩 선물하기 구현

## Product 객체
- **id** : 상품 id
- **name** : 상품 이름
- **price** : 상품 가격
- **imageUrl** : 상품 사진 url

## 기능 소개
### ProductDao
- **selectAllProduct** : 모든 상품 목록 List반환
- **selectProduct** : id에 해당하는 상품 하나를 반환
- **insertProduct** : 상품 추가
- **deleteProduct** : 상품 삭제
- **updateProduct** : 상품 수정

### IndexController
- **index** : index.html 연결
- **postform** : postform.html 연결
- **editform** : editform.html 연결

### ProductController
- **getProductsController** : 모든 상품 목록 List index.html로 반환
- **getProductsListController** : 모든 상품 목록 List반환
- **getProductByIdController** : id에 해당하는 상품 하나를 반환
- **postProductController** : 상품 추가 후 index로 리다이렉트
- **deleteProductController** : 상품 삭제 후 index로 리다이렉트
- **updateProductController** : 상품 수정 후 index로 리다이렉트

### CatchError
- **isCorrectName** : 이름의 유효성을 검사한다
- **isContainsKakao** : 이름에 Kakao가 포함되 있는지 검사한다
-
### 유효성
- 클라이언트가 어떤 부분이 왜 잘못되었는지 인지할 수 있도록 응답제공
- 상품 이름 : 공백포함 최대 15자
- 특수 문자 : ( ), [ ], +, -, &, /, _ 이외 사용불가
- "카카오"가 포함된 문구는 담당 MD와 협의한 경우에만 사용 가능
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ dependencies {

tasks.named('test') {
useJUnitPlatform()
}
}
21 changes: 21 additions & 0 deletions src/main/java/gift/Controller/CatchError.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package gift.Controller;

public class CatchError {
public static boolean isCorrectName(String name){
if(name.length()>15){
return false;
}
String letters = "()[]+-&/_ ";
for(int i=0; i<name.length(); i++){
char one = name.charAt(i);
if(!Character.isLetterOrDigit(one) && !letters.contains(Character.toString(one))){
return false;
}
}
return true;
}

public static boolean isContainsKakao(String name){
return name.contains("카카오");
}
}
33 changes: 33 additions & 0 deletions src/main/java/gift/Controller/IndexController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gift.Controller;

import gift.model.Product;
import gift.model.ProductDao;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
public class IndexController {
private final ProductDao ProductDao;

public IndexController(gift.model.ProductDao productDao) {
ProductDao = productDao;
}

@GetMapping("/")
public String index() {
return "redirect:/api/getAllProducts";
}

@GetMapping("/postform")
public String postform(){
return "postform";
}

@PostMapping("/editform/{id}")
public String editform(@PathVariable Long id, Model model){
Product product = ProductDao.selectProduct(id);
model.addAttribute("product", product);
return "editform";
}
}
38 changes: 38 additions & 0 deletions src/main/java/gift/Controller/InitCreateTable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package gift.Controller;

import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

//app실행 했을 때 테이블 생성
@Service
public class InitCreateTable {

private final JdbcTemplate jdbcTemplate;

@Autowired
public InitCreateTable(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@PostConstruct
public void init() {
//System.out.println("init");
createProductTable();
//System.out.println("create");
}

public void createProductTable() {
var sql = """
create table product (
id bigint auto_increment,
name varchar(255),
price int,
image_url varchar(255),
primary key (id)
)
""";
jdbcTemplate.execute(sql);
}
}
99 changes: 99 additions & 0 deletions src/main/java/gift/Controller/ProductController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package gift.Controller;

import gift.model.Product;
import gift.model.ProductDao;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.ui.Model;
import java.util.List;

@Controller
@RequestMapping("/api")
public class ProductController {
long id = 0L;

private final ProductDao ProductDao;

public ProductController(gift.model.ProductDao productDao) {
ProductDao = productDao;
}

//모든 상품 반환
@GetMapping("/getAllProducts")
public String getProductsController(Model model) {
List<Product> productList = ProductDao.selectAllProduct();
model.addAttribute("productList", productList);
return "index";
}

@GetMapping("/getAllProductList")
@ResponseBody
public List<Product> getProductsListController(Model model) {
List<Product> productList = ProductDao.selectAllProduct();
return productList;
}

//id 상품 하나 반환
@GetMapping("/getProduct/{id}")
@ResponseBody
public Product getProductByIdController(@PathVariable Long id) {
Product product = ProductDao.selectProduct(id);
return product;
}

//상품 추가
@PostMapping("/postProduct")
public String postProductController(@ModelAttribute Product product) {
if (!CatchError.isCorrectName(product.getName())) {
throw new IllegalArgumentException("이름은 15자 이내, 특수문자는 (),[],+,-,&,/,_ 만 사용 가능합니다.");
}
if (CatchError.isContainsKakao(product.getName())) {
throw new IllegalArgumentException("\"카카오\"는 MD와 협의 후에 사용 가능합니다.");
}
id++;
product.setId(id);
ProductDao.insertProduct(product);
return "redirect:/api/getAllProducts";
}

//상품 삭제
@GetMapping("/deleteProduct/{id}")
public String deleteProductController(@PathVariable Long id) {
ProductDao.deleteProduct(id);
return "redirect:/api/getAllProducts";
}

//상품 업데이트
@PostMapping("/updateProduct/{id}")
public String updateProductController(@PathVariable Long id, @ModelAttribute Product newProduct) {
Product oldProduct = ProductDao.selectProduct(id);

if (!CatchError.isCorrectName(newProduct.getName())) {
throw new IllegalArgumentException("이름은 15자 이내, 특수문자는 (),[],+,-,&,/,_ 만 사용 가능합니다.");
}
if (CatchError.isContainsKakao(newProduct.getName())) {
throw new IllegalArgumentException("\"카카오\"는 MD와 협의 후에 사용 가능합니다.");
}

if (newProduct.getName() != null && !newProduct.getName().isEmpty()) {
oldProduct.setName(newProduct.getName());
}
if (newProduct.getPrice() != null) {
oldProduct.setPrice(newProduct.getPrice());
}
if (newProduct.getImageUrl() != null && !newProduct.getImageUrl().isEmpty()) {
oldProduct.setImageUrl(newProduct.getImageUrl());
}
ProductDao.updateProduct(oldProduct);
return "redirect:/api/getAllProducts";
}

//이름 오류 발생시 이유 리턴
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArgumentException(IllegalArgumentException e, Model model) {
model.addAttribute("error", e.getMessage());
return "errorPage";
}
}
17 changes: 17 additions & 0 deletions src/main/java/gift/Controller/ProductExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package gift.Controller;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.NoSuchElementException;

@ControllerAdvice
public class ProductExceptionHandler {
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ExceptionHandler(NoSuchElementException.class)
public String handleNoSuchElementException(NoSuchElementException e){
return e.getMessage();
}
}
50 changes: 50 additions & 0 deletions src/main/java/gift/model/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package gift.model;

public class Product {
private long id;
private String name;
private Integer price;
private String imageUrl;

public Product(long id, String name, int price, String imageUrl) {
this.id = id;
this.name = name;
this.price = price;
this.imageUrl = imageUrl;
}

public Product() {
}

public String getImageUrl() {
return imageUrl;
}

public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

public Integer getPrice() {
return price;
}

public void setPrice(Integer price) {
this.price = price;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}
}
74 changes: 74 additions & 0 deletions src/main/java/gift/model/ProductDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package gift.model;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
public class ProductDao {
private final JdbcTemplate jdbcTemplate;

public ProductDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

//상품 테이블 생성
public void createCustomerTable(){
var sql = """
create table customer (
id bigint,
name varchar(255),
price int,
image_url varchar(255),
primary key (id)
)
""";
jdbcTemplate.execute(sql); //여닫는 과정X, throws가 안나옴(내부에서 관리) excetion 추상화 해서 제공
}

//데이터베이스 반환결과인 Result Set 객체로 변환
public RowMapper<Product> ProductRowMapper() {
return ( (resultSet, rowNum) -> {
Product product = new Product();
product.setId(resultSet.getLong("id"));
product.setName(resultSet.getString("name"));
product.setPrice(resultSet.getInt("price"));
product.setImageUrl(resultSet.getString("image_url"));
return product;
});
}

//모든 상품 리스트 반환
public List<Product> selectAllProduct(){
var sql = "select * from product";
List<Product> list = new ArrayList<>();
return jdbcTemplate.query(sql, ProductRowMapper(), list.toArray());
}

//상품 하나 반환
public Product selectProduct(Long id){
var sql = "select id, name, price, image_url from product where id = ?";
return jdbcTemplate.queryForObject(sql, ProductRowMapper(), id);
}

//상품 추가
public void insertProduct(Product product){
var sql = "insert into product (id, name, price, image_url) values (?, ?, ?, ?)";
jdbcTemplate.update(sql, product.getId(), product.getName(), product.getPrice(), product.getImageUrl());
}

//상품 삭제
public void deleteProduct(Long id){
var sql = "delete from product where id = ?";
jdbcTemplate.update(sql, id);
}

//상품 업데이트
public void updateProduct(Product product){
var sql = "update product set name = ?, price = ?, image_url = ? where id = ?";
jdbcTemplate.update(sql, product.getName(), product.getPrice(), product.getImageUrl(), product.getId());
}
}
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
spring.application.name=spring-gift
spring.h2.console.enabled=true
Loading