今日目標,實現註冊功能。
package com.example.user;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends CrudRepository<UserModel, Integer> {
UserModel findByEmail(String email);
UserModel findByUsername(String username);
}
@Repository
:用於聲明這個 class 或 interface 可以用來執行資料庫的相關操作,並支援自動處理資料庫操作的異常CrudRepository
:已經寫好的 interface,可以在資料庫進行 CRUD 操作,後方的類型先後分別為「資料表的類、主鍵的類」,此處的資料表為 UserModel,而其主鍵 Id 為 Integer@EnableJpaRepositories
用來掃描 JPA Repository,檔案完整內容為:
package com.example.cards;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@ComponentScan({
"com.example",
})
@EnableJpaRepositories({
"com.example",
})
@EntityScan({
"com.example",
})
public class CardsApplication {
public static void main(String[] args) {
SpringApplication.run(CardsApplication.class, args);
}
}
package com.example.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Integer addUser(UserModel user) {
UserModel newUser = userRepository.save(user);
return newUser.getId();
}
}
@Service
:用於聲明其為 service,並由 Spring Boot 負責管理@Autowired
:會自動根據所要注入對象的類型,將其自動配對並注入,產生一個實例(instance),更詳細的在下方「注入」解說@ComponentScan
就包含了 service<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${name}"></h1>
<form method="post" action="/register" th:object="${user}">
<input type="email" id="email" name="email" placeholder="Email" th:field="*{email}" />
<input type="text" id="username" name="username" placeholder="Username" th:field="*{username}" />
<input type="password" id="password" name="password" placeholder="Password" th:field="*{password}" />
<button type="submit">註冊</button>
</form>
</body>
</html>
package com.example.user;
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.PostMapping;
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/register")
public String viewRegisterPage(Model model) {
model.addAttribute("name", "註冊");
model.addAttribute("user", new UserModel());
return "register";
}
@PostMapping("/register")
public String registerProcess(UserModel user) {
userService.addUser(user);
return "redirect:/";
}
}
model.addAttribute("user", new UserModel())
:這是因為前端模板還是需要一個變數名稱為 user 的資料做傳遞,否則會報錯,所以給他一個空的 user 物件@PostMapping("/register")
:類似 @GetMapping
,只差在這是 post 請求registerProcess(UserModel user)
:參數的部分可以直接放我們期望接收到的類型,會將這邊的資料(也就是我們在 register.html 用 th:filed 所綁定的),自動解析成我們要求的類型return "redirect:/"
:重新導向頁面,使用 redirect 關鍵字,搭配絕對路徑,這邊表示會回到根路徑/
要來這次教學的重點之一了~~
@Component
、@Service
、@Repository
... 等註解所聲明的類別,這些類別受到 spring boot 管理,他們只會在這次運行時生成一次,並在後續用注入(autowired)的方式來使用,也因為在本次運行時只會執行一次,所以也可以作為不同 controller 之間共享的資料@Autowired
聲明即可,但要注意每一個實例都要宣告一次,這是新手常犯的錯誤如果你剛自己亂玩了一下註冊功能,應該會發現幾個小問題,
這些問題將在明天的文章做改善,明天就會說明如何在 Entity 添加限制(constraint),並自定義 unique 的註解聲明~~