diff --git a/README.md b/README.md index cafde8a2c..94e0431b4 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ -# spring-gift-product \ No newline at end of file +# spring-gift-product + + +### 1. Search Products + +### 2. Add Product + +### 3. Edit Product + +### 4. Delete Product diff --git a/build.gradle b/build.gradle index df7db9334..d7798dbf4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,31 +1,25 @@ plugins { + id 'org.springframework.boot' version '3.1.2' + id 'io.spring.dependency-management' version '1.0.15.RELEASE' id 'java' - id 'org.springframework.boot' version '3.3.1' - id 'io.spring.dependency-management' version '1.1.5' } -group = 'camp.nextstep.edu' +group = 'com.example' version = '0.0.1-SNAPSHOT' - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} +sourceCompatibility = '17' repositories { mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } -tasks.named('test') { +test { useJUnitPlatform() } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c4..d64cd4917 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f..1af9e0930 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/gift/Application.java b/src/main/java/gift/GiftApplication.java similarity index 69% rename from src/main/java/gift/Application.java rename to src/main/java/gift/GiftApplication.java index 61603cca0..aef96ac6f 100644 --- a/src/main/java/gift/Application.java +++ b/src/main/java/gift/GiftApplication.java @@ -4,8 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -public class Application { +public class GiftApplication { + public static void main(String[] args) { - SpringApplication.run(Application.class, args); + SpringApplication.run(GiftApplication.class, args); } + } diff --git a/src/main/java/gift/Product.java b/src/main/java/gift/Product.java new file mode 100644 index 000000000..299872c8b --- /dev/null +++ b/src/main/java/gift/Product.java @@ -0,0 +1,50 @@ +package gift; + +public class Product { + private long id; + private String name; + private int price; + private String imageUrl; + + public Product() {} + + public Product(long id, String name, int price, String imageUrl) { + this.id = id; + this.name = name; + this.price = price; + this.imageUrl = imageUrl; + } + + // Getter and Setter methods + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } +} diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java new file mode 100644 index 000000000..95baa108a --- /dev/null +++ b/src/main/java/gift/ProductController.java @@ -0,0 +1,52 @@ +package gift; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@RequestMapping("/admin/products") +public class ProductController { + + private final ProductService productService; + + public ProductController(ProductService productService) { + this.productService = productService; + } + + @GetMapping + public String listProducts(Model model) { + List products = productService.getAllProducts(); + model.addAttribute("products", products); + return "products"; + } + @GetMapping("/add") + public String showAddProductForm(Model model) { + model.addAttribute("product", new Product()); + return "add-product"; + } + + @PostMapping("/add") + public String addProduct(@ModelAttribute Product product) { + productService.addProduct(product); + return "redirect:/admin/products"; + } + + @GetMapping("/edit/{id}") + public String showEditProductForm(@PathVariable Long id, Model model) { + Product product = productService.getProductById(id); + if (product == null) { + return "redirect:/admin/products"; + } + model.addAttribute("product", product); + return "edit-product"; + } + + @GetMapping("/delete/{id}") + public String deleteProduct(@PathVariable Long id) { + productService.deleteProduct(id); + return "redirect:/admin/products"; + } +} diff --git a/src/main/java/gift/ProductService.java b/src/main/java/gift/ProductService.java new file mode 100644 index 000000000..4cba28dc8 --- /dev/null +++ b/src/main/java/gift/ProductService.java @@ -0,0 +1,61 @@ +package gift; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class ProductService { + private final JdbcTemplate jdbcTemplate; + private final SimpleJdbcInsert simpleJdbcInsert; + + public ProductService(JdbcTemplate jdbcTemplate, DataSource dataSource) { + this.jdbcTemplate = jdbcTemplate; + this.simpleJdbcInsert = new SimpleJdbcInsert(dataSource) + .withTableName("products") + .usingGeneratedKeyColumns("id"); + } + + public List getAllProducts() { + String sql = "SELECT * FROM products"; + return jdbcTemplate.query(sql, (rs, rowNum) -> new Product( + rs.getLong("id"), + rs.getString("name"), + rs.getInt("price"), + rs.getString("image_url") + )); + } + + public Product getProductById(long id) { + String sql = "SELECT * FROM products WHERE id = ?"; + return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> new Product( + rs.getLong("id"), + rs.getString("name"), + rs.getInt("price"), + rs.getString("image_url") + )); + } + + public void addProduct(Product product) { + Map parameters = new HashMap<>(); + parameters.put("name", product.getName()); + parameters.put("price", product.getPrice()); + parameters.put("image_url", product.getImageUrl()); + Number newId = simpleJdbcInsert.executeAndReturnKey(parameters); + product.setId(newId.longValue()); + } + public void updateProduct(long id, Product product) { + String sql = "UPDATE products SET name = ?, price = ?, image_url = ? WHERE id = ?"; + jdbcTemplate.update(sql, product.getName(), product.getPrice(), product.getImageUrl(), id); + } + + public void deleteProduct(long id) { + String sql = "DELETE FROM products WHERE id = ?"; + jdbcTemplate.update(sql, id); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3d16b65f4..b01962918 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,15 @@ spring.application.name=spring-gift + +# ?? ?? ?? +server.port=8000 + +# H2 ?????? ?? +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console + +# SQL ???? ?? +spring.sql.init.mode=always diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 000000000..600bcfbb2 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE products ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + price INT NOT NULL, + image_url VARCHAR(255) +); diff --git a/src/main/resources/templates/add-product.html b/src/main/resources/templates/add-product.html new file mode 100644 index 000000000..791151ecf --- /dev/null +++ b/src/main/resources/templates/add-product.html @@ -0,0 +1,26 @@ + + + + + Add Product + + +

Add Product

+ +
+
+
+ +
+
+ +
+
+ + +
+ +Cancel + + + diff --git a/src/main/resources/templates/edit-product.html b/src/main/resources/templates/edit-product.html new file mode 100644 index 000000000..567edbfa7 --- /dev/null +++ b/src/main/resources/templates/edit-product.html @@ -0,0 +1,28 @@ + + + + + Edit Product + + +

Edit Product

+ +
+ + +
+
+ +
+
+ +
+
+ + +
+ +Cancel + + + diff --git a/src/main/resources/templates/products.html b/src/main/resources/templates/products.html new file mode 100644 index 000000000..4201fb404 --- /dev/null +++ b/src/main/resources/templates/products.html @@ -0,0 +1,33 @@ + + + + + Product List + + +

Product List

+ + + + + + + + + + + + + + + +
IDNamePriceImageActions
+ + + Edit + Delete +
+
+Add Product + +