-
Notifications
You must be signed in to change notification settings - Fork 120
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_권도윤_1주차 과제(1~3단계) #200
base: doyooon
Are you sure you want to change the base?
Changes from all commits
267aef9
cde117a
d28d62b
bf10c23
218f4e5
f6ea301
e6883f7
c1cf02b
376a6f9
0ba4c7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,13 @@ | ||
# spring-gift-product | ||
# spring-gift-product | ||
- [x] 상품을 조회, 추가, 수정, 삭제할 수 있는 HTTP API를 구현한다. | ||
- [x] 조회 | ||
- [x] 추가 | ||
- [x] 수정 | ||
- [x] 삭제 | ||
- [x] Thymeleaf를 사용하여 상품을 조회, 추가, 수정, 삭제할 수 있는 관리자 화면을 구현한다. | ||
- [x] 관리자 페이지 구현 | ||
- [x] 페이지와 상호작용 할 수 있도록 api 수정 | ||
- [x] 상품 정보를 데이터베이스에 저장한다. | ||
- [x] H2 데이터베이스를 사용 설정한다. | ||
- [x] 데이터베이스와 통신할 repository를 생성한다. | ||
- [x] repository를 통해서 DB에 요청을 보내도록 api 수정 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,13 @@ | |
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.web.filter.HiddenHttpMethodFilter; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 불필요한 import 문은 제거해도 좋을 것 같습니다 🙏 |
||
|
||
@SpringBootApplication | ||
public class Application { | ||
public static void main(String[] args) { | ||
|
||
SpringApplication.run(Application.class, args); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,58 @@ | ||||||
package gift; | ||||||
|
||||||
public class Product { | ||||||
Long id; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. private과 같은 적절한 접근제어자를 사용하면 접근을 제한할 수 있습니다ㅎㅎ
Suggested change
|
||||||
String name; | ||||||
int price; | ||||||
String imageUrl; | ||||||
|
||||||
public Product(){ | ||||||
|
||||||
} | ||||||
|
||||||
public Product(Long id, String name, int price, String imageUrl){ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 불필요한 set 관련 메서드는 최소화하는 것이 좋을 것 같습니다 |
||||||
this.id = id; | ||||||
this.name = name; | ||||||
this.price = price; | ||||||
this.imageUrl = imageUrl; | ||||||
} | ||||||
|
||||||
public Long getId(){ | ||||||
return this.id; | ||||||
} | ||||||
|
||||||
public void setId(Long id){ | ||||||
this.id = id; | ||||||
} | ||||||
|
||||||
public String getName(){ | ||||||
return this.name; | ||||||
} | ||||||
|
||||||
public void setName(String name){ | ||||||
this.name = name; | ||||||
} | ||||||
|
||||||
public int getPrice(){ | ||||||
return this.price; | ||||||
} | ||||||
|
||||||
public void setPrice(int price){ | ||||||
this.price = price; | ||||||
} | ||||||
|
||||||
public String getImageUrl(){ | ||||||
return this.imageUrl; | ||||||
} | ||||||
|
||||||
public void setImageUrl(String imageUrl){ | ||||||
this.imageUrl = imageUrl; | ||||||
} | ||||||
|
||||||
public void setProduct(Product product){ | ||||||
this.id = product.id; | ||||||
this.name = product.name; | ||||||
this.price = product.price; | ||||||
this.imageUrl = product.imageUrl; | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package gift; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.ui.Model; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.ModelAttribute; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
|
||
|
||
@Controller | ||
public class ProductController { | ||
|
||
@Autowired | ||
private ProductRepository productRepository; | ||
|
||
@GetMapping("/") | ||
public String listProducts(Model model) { | ||
model.addAttribute("products", productRepository.findAll()); | ||
model.addAttribute("newProduct", new Product()); // 새 상품 객체 | ||
model.addAttribute("product", new Product()); // 편집을 위한 빈 객체*/ | ||
return "home"; // Thymeleaf 템플릿 이름 | ||
} | ||
|
||
@PostMapping("/post") | ||
public String createProduct(@ModelAttribute Product newProduct){ | ||
productRepository.save(newProduct); | ||
return "redirect:/"; | ||
} | ||
|
||
@PostMapping ("/update") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수정을 위한 HTTP Method로는 PUT, PATCH 그리고 삭제를 위해서는 DELETE가 존재합니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그리고 API 요청의 prefix로 |
||
public String updateProduct(@ModelAttribute Product changeProduct){ | ||
productRepository.update(changeProduct); | ||
|
||
return "redirect:/"; | ||
} | ||
|
||
@GetMapping ("/delete/{id}") | ||
public String deleteProduct(@PathVariable Long id){ | ||
productRepository.deleteById(id); | ||
|
||
return "redirect:/"; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package gift; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import javax.sql.DataSource; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.jdbc.core.BeanPropertyRowMapper; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.jdbc.core.simple.SimpleJdbcInsert; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public class ProductRepository { | ||
private final JdbcTemplate jdbcTemplate; | ||
private final SimpleJdbcInsert insertProduct; | ||
|
||
@Autowired | ||
public ProductRepository(JdbcTemplate jdbcTemplate, DataSource dataSource) { | ||
this.jdbcTemplate = jdbcTemplate; | ||
this.insertProduct = new SimpleJdbcInsert(dataSource) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
.withTableName("products") | ||
.usingGeneratedKeyColumns("id"); | ||
} | ||
|
||
public List<Product> findAll() { | ||
return jdbcTemplate.query("SELECT * FROM products", new BeanPropertyRowMapper<>(Product.class)); | ||
} | ||
|
||
public Product findById(Long id) { | ||
return jdbcTemplate.queryForObject("SELECT * FROM products WHERE id = ?", new BeanPropertyRowMapper<>(Product.class), id); | ||
} | ||
|
||
public long save(Product product) { | ||
Map<String, Object> parameters = new HashMap<>(); | ||
parameters.put("name", product.getName()); | ||
parameters.put("price", product.getPrice()); | ||
parameters.put("image_url", product.getImageUrl()); | ||
return insertProduct.executeAndReturnKey(parameters).longValue(); | ||
} | ||
|
||
public int update(Product product) { | ||
return jdbcTemplate.update("UPDATE products SET name = ?, price = ?, image_url = ? WHERE id = ?", | ||
product.getName(), product.getPrice(), product.getImageUrl(), product.getId()); | ||
} | ||
|
||
public int deleteById(Long id) { | ||
return jdbcTemplate.update("DELETE FROM products WHERE id = ?", id); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,8 @@ | ||
spring.application.name=spring-gift | ||
spring.datasource.url=jdbc:h2:mem:testdb | ||
spring.datasource.driverClassName=org.h2.Driver | ||
spring.datasource.username=sa | ||
spring.datasource.password=password | ||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect | ||
spring.h2.console.enabled=true | ||
spring.sql.init.mode=always |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
CREATE TABLE IF NOT EXISTS products ( | ||
id BIGINT AUTO_INCREMENT PRIMARY KEY, | ||
name VARCHAR(255) NOT NULL, | ||
price DECIMAL(10, 2) NOT NULL, | ||
image_url VARCHAR(255) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. image url이 null이 될 수 없다면, 해당 부분에도 not-null 제약 조건을 걸어주는 것이 좋을 것 같습니다ㅎㅎ |
||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
<!DOCTYPE html> | ||
<html xmlns:th="http://www.thymeleaf.org"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Title</title> | ||
<style> | ||
table, th, td { | ||
border: 1px solid black; | ||
border-collapse: collapse; | ||
} | ||
th, td { | ||
padding: 10px; | ||
} | ||
form { | ||
margin-bottom: 20px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<h1>Product Management</h1> | ||
|
||
<h2>Product List</h2> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>ID</th> | ||
<th>Name</th> | ||
<th>Price</th> | ||
<th>Image</th> | ||
<th>Actions</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr th:each="product : ${products}"> | ||
<td th:text="${product.id}">1</td> | ||
<td th:text="${product.name}">Product Name</td> | ||
<td th:text="${product.price}">100.00</td> | ||
<td><img th:src="@{product.imageUrl}" alt="no image" /></td> | ||
<td> | ||
<a th:href="@{/delete/{id}(id=${product.id})}">Delete</a> | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
<h2>Create New Product</h2> | ||
<form th:action="@{/post}" th:object="${newProduct}" method="post"> | ||
<div> | ||
<label>Id:</label> | ||
<input type="text" th:field="*{id}" /> | ||
</div> | ||
<div> | ||
<label>Name:</label> | ||
<input type="text" th:field="*{name}" /> | ||
</div> | ||
<div> | ||
<label>Price:</label> | ||
<input type="text" th:field="*{price}" /> | ||
</div> | ||
<div> | ||
<label>ImageUrl:</label> | ||
<input type="text" th:field="*{imageUrl}" /> | ||
</div> | ||
<div> | ||
<button type="submit">Save</button> | ||
</div> | ||
</form> | ||
|
||
<h2>Update Product</h2> | ||
<form th:action="@{/update}" th:object="${product}" method="post"> | ||
<div> | ||
<label>Id:</label> | ||
<input type="text" th:field="*{id}" /> | ||
</div> | ||
<div> | ||
<label>Name:</label> | ||
<input type="text" th:field="*{name}" /> | ||
</div> | ||
<div> | ||
<label>Price:</label> | ||
<input type="text" th:field="*{price}" /> | ||
</div> | ||
<div> | ||
<label>Image:</label> | ||
<input type="text" th:field="*{imageUrl}" /> | ||
</div> | ||
<div> | ||
<button type="submit">Update</button> | ||
</div> | ||
</form> | ||
</body> | ||
</html> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요구사항 정리한 부분 좋네요 👍