前篇文章介紹了一個後端系統使用三層式架構大概應該要長的樣子,這篇文章會補齊裡面所需的程式碼。
以下是本次 Entity 會用到的程式碼,本次的後端流程為 先註冊,註冊完後會傳送驗證碼,使用者獲取驗證碼後要再輸入相關資料驗證
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.*;
// 標示這個 Class 為 Entity
@Entity
// 為資料表命名
@Table(name = "_user")
// Lombok 提供的註解,可以加速開發過程
@Builder
@Data
// 為全部的變數建立建構元
@AllArgsConstructor
// 建立一個空的建構元
@NoArgsConstructor
public class UserEntity {
// 當標示為 Entity時,就必須要有一個變數被註解為 ID,也就是設定主Key
@Id
// 設定新增資料時 id 會自動累加
@GeneratedValue
private long id;
// 標記新增資料時此欄位的資料不得為空
@NonNull
private String name;
@NonNull
private String password;
@NonNull
private String email;
private String verifyCode;
private boolean isVerified = false;
}
這裡會是我們 API 方法的地方,這個設計使用到 ResponseEntity 來設定回傳資料的型態,ResponseEntity 可以幫忙將回傳的內容設定為 Json 格式,再丟給前端使用
大概流程就像這樣,Controller 負責接收指令,接到了再根據指令的路徑去分配使用到的功能,回傳內容我們交給 Service去回傳,因此 return 就是完全以 service 回傳回來的資料為主,這裡不做任何邏輯處理的工作
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 標記為 Controller
@RestController
// 設定路徑
@RequestMapping("api/user")
// 建立一個會自動幫使用 final 標記的變數建立一個建構元
@RequiredArgsConstructor
public class UserController {
// 呼叫 Service 進行資料判斷、邏輯處理
private final UserService userService;
// 設定 RESTful API 跟細項路徑
@PostMapping("/register")
public ResponseEntity<UserResponse> register(@RequestBody UserRequest request){
return ResponseEntity.ok(userService.register(request));
}
@PostMapping("/sendVerifyCode")
public ResponseEntity<UserResponse> sendVerifyCode(@RequestBody UserRequest request){
return ResponseEntity.ok(userService.sendVerifyCode(request));
}
@PostMapping("/auth")
public ResponseEntity<UserResponse> authentication(@RequestBody UserRequest request){
return ResponseEntity.ok(userService.authentication(request));
}
}
service 設定的部分比較長,我們先拆分每一項功能,最後再附上完整程式碼
跟前面 Controller 一樣,我們會用一個註解去標記這個 class 是 service
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
}
在這個功能我們要完成的工作是新增資料表,為了避免資料有重複的問題,我們先判斷這個資料是否已經要帳號註冊過,如果沒有才會進行新增資料表的工作,這個部份我們也可以透過在 Entity 對指定的欄位設定不可重複來實現。
public UserResponse register(UserRequest request) {
var response = UserResponse.builder();
try {
String userName = request.userName();
// 判斷此帳號是否已被註冊過
if (userRepository.findByName(userName).isEmpty()) {
// 新增資料表的方法
var user = UserEntity.builder()
.name(userName)
.email(request.email())
.password(request.password())
.build();
// 永遠記得當資料表資料變動時,要儲存這個資料表
userRepository.save(user);
// 撰寫回傳內容
response.status("1");
response.message("The account registration is successful.");
} else {
// 撰寫回傳內容
response.status("0");
response.message("The account has been registered.");
}
// 回傳內容
return response.build();
} catch (Exception e) {
// 以防有問題的例外處理,或者我們也可以寫一個全域的錯誤例外處理
// 這次先簡單的 try catch 就好
response.status("0");
response.message("There is something went wrong : " + e.getMessage());
// 回傳內容
return response.build();
}
}
在這裡我們會將驗證碼跟帳號綁定,並將驗證碼傳給使用者,使用者就必須先驗證這個帳戶,才算是完整建立整個帳號
public UserResponse sendVerifyCode(UserRequest request) {
var response = UserResponse.builder();
try {
// 先尋找是否有使用者輸入的帳戶
String userName = request.userName();
if (userRepository.findByName(userName).isPresent() &&
!request.email().isEmpty() ) {
// 亂數生成驗證碼
String verifyCode = generateVerifyCode();
// 透過 repository 寫好的功能更新資料庫中的資料,這種情況可以不用save,因為是透過 repository 執行的
userRepository.updateVerifyCodeByEmail(verifyCode, request.email());
// 回文內容設定
response.status("1");
response.message("Success");
response.verifyCode(verifyCode);
} else {
// 回文內容設定
response.status("0");
response.message("Please check all the data and try again.");
}
// 回傳回文
return response.build();
} catch (Exception e) {
// 回文內容設定
response.status("0");
response.message("There is something went wrong : " + e.getMessage());
return response.build();
}
}
// 亂數生成驗證碼
private String generateVerifyCode() {
int verifyCode = new Random(System.currentTimeMillis()).nextInt(100000,999999);
return String.valueOf(verifyCode);
}
這裡負責的工作是比對使用者輸入的驗證碼跟上一個發送驗證碼時,設定的是否是一致的,如果是一致的就會再設定對應帳號的 isVarify 欄位為 true,代表這個帳號已經完成認證,就可以接續執行其他功能,
public UserResponse authentication(UserRequest request) {
var response = UserResponse.builder();
try {
if (userRepository.findByName(request.userName()).isPresent()) {
UserEntity user = userRepository.findByName(request.userName()).orElseThrow();
// 判斷帳戶儲存的驗證碼是否跟使用者傳入的一致
if (user.getVerifyCode().equals(request.verifyCode())){
user.setVerified(true);
userRepository.save(user);
// 回文內容設定
response.status("1");
response.message("Welcome ! You are logged in successfully.");
} else {
// 回文內容設定
response.status("0");
response.message("Please check your verify code and try again.");
}
} else {
// 回文內容設定
response.status("0");
response.message("Please check your username and try again.");
}
return response.build();
} catch (Exception e) {
// 回文內容設定
response.status("0");
response.message("There is something went wrong : " + e.getMessage());
// 回傳回文
return response.build();
}
}
在 service 我們有用到一些控制資料庫的功能,但是 service 本身是沒辦法直接使用資料庫的,所以我們會透過 repository 去撰寫一些想要使用的方法,來達到使用資料庫的效果
// 標記為 Repository
@Repository
// 繼承 JpaRepository 並指定這個 Repositorty可以互動的資料庫,以及這個資料庫的 主key 是什麼型態
public interface UserRepository extends JpaRepository<UserEntity, Long> {
// 使用 Spring Data Jpa 的關鍵字建立方法快速建立功能
Optional<UserEntity> findByName(String username);
@Transactional
@Modifying
// 使用 SQL 語法客製化自己的功能
@Query("update UserEntity u set u.verifyCode = :verifyCode where u.email = :email")
void updateVerifyCodeByEmail(String verifyCode, String email);
}
本次範例中使用的是 record 而不是 class 來建立 Request跟Response,先說結論,這兩種方式都是常用的方法,只是 record 撰寫上會比較簡潔,所以這次使用 record做
public record UserRequest(
String userName,
String email,
String password,
String verifyCode
) {
}
public record UserResponse(
String status,
String message,
String verifyCode
) {
}
到此所有東西都設定完畢,我們就可以啟動服務,並且透過 postman 來測試是否成功囉~
點選這個綠色箭頭就可以開啟服務了
看到這段就代表成功建立服務了,port號預設為8080,這邊我有設定過所以才會是9000,這個就看自己方便設定就好
postman 的使用方式這邊就不贅述了,直接放上測試結果
這個時候回去看建立好的資料表,就會發現資料建立好囉
本篇文章補上程式碼的部分,並且使用 postman 進行測試,下篇文章會稍微修改一些程式碼,並且製作一個簡單的 APP 與我們架設的後端系統對接。