Day 3: 1140112
一、目標:觀摩如何依照MVC架構,建立後端Java檔案
二、預計使用工具:
VS code
三、檔案架構:
今天要建立的是後端檔案,也就是Day 2 內文提到src/main/java的資料夾,今天談到的兩份檔案Product.java和ProductController.java分別對應到M和C,架構如下圖
四、放主類別/啟動(Spring Boot)類別的檔案: RestaurantMenuApplication.java
在 Java 中,package 是用來組織和管理類別 (classes) 和介面 (interfaces) 的結構化方式。
在第一行,我們先為package命名。
值得注意的是,取名的方式最好是遵循資料夾層級的檔名(可參考上圖)來編排。
接著,引入(import)啟動 Spring Boot 應用程式的套件。
package com.restuarant.menu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
再來,因為本程式使用spring boot 框架,所以下一個 @SpringBootApplication 註解,這個註解包含以下三個重要功能:
1.@Configuration:允許定義 bean 並將其註冊到 Spring 應用程式上下文中。
2.@EnableAutoConfiguration:自動配置 Spring Boot 的預設設定。
3.@ComponentScan:自動掃描 com.restaurant.menu package 下的 Spring 組件(如 @Controller, @Service)。
完成基本設定後,就來寫主類別的內容了!
SpringApplication.run(...) 用來啟動 Spring Boot 應用程式。
它會加載 Spring 上下文,啟動內建的 Tomcat 伺服器(預設埠是 8080)和所有註冊的 Spring 套件。
@SpringBootApplication
public class RestaurantMenuApplication {
public static void main(String[] args) {
SpringApplication.run(RestaurantMenuApplication.class, args);
}
}
當按下VSCode中,程式碼上方的Run main,就會啟動Tomcat 伺服器了,此時如果在瀏覽器輸入http://localhost:8080/
會看到Day 2 的Whitelabel Error Page,表示有建立成功。
五、放產品類別的檔案: Product.java
在第一行,我們一樣先為package命名。
接著我們為產品創設「類」(class),並定義他的屬性,像是id、名稱、價格等,還有他的資料型態,如id是整數(int)。
接著,會建立對應的建構子(constructor)和 getter、setter 方法。
1.建構子是用來創建新的 Product 對象,並初始化屬性。
2.所謂的getter、setter 方法,從程式設計的角度來看,是讓原本外部人無法任意修改的屬性如private int id;
,得以透過公開的方法來取得或寫入資訊,如此能確保封裝性(Encapsulation),也能更好地控制對屬性的訪問。
package com.restuarant.menu.model;
public class Product {
private int id;
private String name;
private double price;
//構造函數(Constructor)
public Product(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
//getter 是 Java Bean 標準的一部分,用來取得資訊,因為它會返回屬性的值
public int getId() {
return id;
}
//setter 是 Java Bean 標準的一部分,用來寫入資訊,也就是說,可以透過他設置屬性的值
public void setId(int id) {
this.id = id;
......(name和price的部分以此類推)
}
}
六、處理與產品相關的網頁請求: ProductController.java
在第一行,我們一樣先為package命名,並完成基本設定。
在此檔案中,因為會用到Product.java
中的Product類別,所以,需要引用該套件。
package com.restuarant.menu.controller;
//為了後續用List
import java.util.List;
//為了後續用@Controller
import org.springframework.stereotype.Controller;
//為了後續用Model
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//引用product.java裡面的product class
import com.restuarant.menu.model.Product;
接著,是主要內容的部分,以下內容都可以根據網頁功能調整!
(一)建立模擬的產品列表(productsList)
@Controller 是 Spring 控制器類,處理與網頁相關的 HTTP 請求。
@RequestMapping("/products") 意味著所有與 /products 相關的 URL 都會由這個控制器處理。這意味著在 ProductController 中定義的方法,處理的 URL 都會以 /products 為前綴。
之所以稱為「模擬的產品列表」,是因為它是硬編碼在 ProductController 類別的靜態資料集合(List)中。這意味著在這個控制器中,productsList 只是臨時用來模擬資料庫或外部資料源的資料,並且僅在應用啟動時存在,並不會從資料庫或其他來源讀取真實資料。
如果想從外部資料源(如資料庫)獲取資料,可以將把這段替換為資料庫查詢的程式碼。
@Controller
@RequestMapping("/products") // This means all URLs start with http://localhost:8080/products/
public class ProductController {
//引用product.java裡面的product class
private List<Product> productsList = List.of(
new Product(1, "Rice", 1.00),
new Product(2, "Dumpling", 3.50),
new Product(3, "Soup", 2.00),
);
(二)設定根路由(通常是首頁)訪問的內容 (/products/)
@RequestMapping("/") 將根路由 (/products/) 的請求映射到這個方法。
@ResponseBody表示返回的內容會直接顯示在瀏覽器中。也就是說,使用者在畫面上會直接看到 "Welcome to the Coffee Shop!"。
@RequestMapping("/") // This maps to the URL http://localhost:8080/products/
@ResponseBody
public String home() {
return "Welcome to the Coffee Shop!";
}
(三)設定顯示產品列表方法 (/products/list)
@RequestMapping("/list") 將 /products/list 的請求映射到這個方法。
這個方法使用 Model 參數來傳遞資料給視圖(V,View)。在這裡,將 productsList 添加到模型中,並指定將資料發送到名為 menu 的視圖。
return "menu"; 會返回視圖名稱 menu,Spring MVC 會根據視圖解析器來處理這個名稱,通常會尋找名為 menu.html 或 menu.jsp 的文件。
@RequestMapping("/list") // This maps to the URL http://localhost:8080/products/list
public String listProducts(Model productListModel) { // Model argument is used to pass data to the view
productListModel.addAttribute("products", productsList); // Add the productsList to the model
return "menu"; // This returns the view name, that is, the HTML file name
}
(四)設定特定產品資訊 (/products/details/{id})
@RequestMapping("/details/{id}") 將 /products/details/{id} 的請求映射到這個方法。{id} 是 URL 路徑中的一個變數,會對應到 @PathVariable 的 id 參數。
@PathVariable 從 URL 中提取 id 的值。
在遍歷 productsList 以後,根據傳入的 id 查找對應的產品,並返回一個包含產品詳情的 HTML 字串。若未找到該產品,則返回 "Product not found!"。
@RequestMapping("/details/{id}") // This maps to the URL http://localhost:8080/products/details/{id}
@ResponseBody
public String getProductDetailsByID(@PathVariable int id){
for (Product product : productsList) {
if (product.getId() == id) {
return "<strong>Requested Product Details: </strong> <hr> Product ID: " + product.getId() + "<br> Name: " + product.getName() + "<br> Price: $" + product.getPrice();
}
}
return "Product not found!";
}
}
七、補充小知識:
(一)requestMapping 是適用於所有 HTTP 請求的注解,與他相關的有以下幾種:
(二)Java 中的 List
Java 中的 List 是 mutable(可變的),不過,Java 中也有 immutable list 的概念。比如使用 List.of() 創建的 List 是不可變的。