第七章:完整的 CRUD 專案實作
7.1 專案結構總覽
在這一章節中,我們將整合前幾章學習的所有知識,創建一個完整的 Spring Boot CRUD 專案。這個專案將包含:
- User 實體(對應資料庫表)
- Repository 層(資料存取)
- Service 層(業務邏輯)
- Controller 層(REST API)
- DTO 類(資料傳輸對象)
- 異常處理
- 統一響應格式
專案結構如下:
src/main/java/com/example/myfirstapp/
├── MyFirstAppApplication.java # 主應用程式類
├── config/
│ ├── AppConfig.java # 應用配置
│ ├── GlobalExceptionHandler.java # 全局異常處理
│ └── ResourceNotFoundException.java # 自定義異常
├── controller/
│ └── UserController.java # REST 控制器
├── dto/
│ ├── ApiResponse.java # 統一響應格式
│ ├── CreateUserRequest.java # 創建用戶請求
│ └── UserResponse.java # 用戶響應
├── entity/
│ └── User.java # 用戶實體
├── repository/
│ └── UserRepository.java # 資料存取層
└── service/
└── UserService.java # 業務邏輯層
src/main/resources/
├── application.properties # 應用配置
└── application.yml # 應用配置(YAML格式)
7.2 完整的程式碼清單
以下是完整的專案程式碼,你可以直接複製使用。
主應用程式類:
package com.example.myfirstapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyFirstAppApplication {
public static void main(String[] args) {
SpringApplication.run(MyFirstAppApplication.class, args);
}
}
User 實體類:
package com.example.myfirstapp.entity;
import java.time.LocalDateTime;
public class User {
private Long id;
private String username;
private String email;
private String password;
private String fullName;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private Boolean active;
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getFullName() { return fullName; }
public void setFullName(String fullName) { this.fullName = fullName; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
public Boolean isActive() { return active; }
public void setActive(Boolean active) { this.active = active; }
}
Repository 類:
package com.example.myfirstapp.repository;
import com.example.myfirstapp.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public class UserRepository {
private final JdbcTemplate jdbcTemplate;
@Autowired
public UserRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<User> findAll() {
String sql = "SELECT id, username, email, password, full_name, " +
"created_at, updated_at, active FROM users ORDER BY id";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
}
public Optional<User> findById(Long id) {
String sql = "SELECT id, username, email, password, full_name, " +
"created_at, updated_at, active FROM users WHERE id = ?";
try {
User user = jdbcTemplate.queryForObject(sql,
new BeanPropertyRowMapper<>(User.class), id);
return Optional.ofNullable(user);
} catch (Exception e) {
return Optional.empty();
}
}
public User save(User user) {
if (user.getId() == null) {
String sql = "INSERT INTO users (username, email, password, full_name, " +
"created_at, updated_at, active) VALUES (?, ?, ?, ?, ?, ?, ?)";
java.time.LocalDateTime now = java.time.LocalDateTime.now();
jdbcTemplate.update(sql,
user.getUsername(), user.getEmail(), user.getPassword(),
user.getFullName(), now, now,
user.isActive() != null ? user.isActive() : true);
String currSql = "SELECT currval(pg_get_serial_sequence('users', 'id'))";
Long id = jdbcTemplate.queryForObject(currSql, Long.class);
user.setId(id);
user.setCreatedAt(now);
user.setUpdatedAt(now);
} else {
String sql = "UPDATE users SET username = ?, email = ?, password = ?, " +
"full_name = ?, updated_at = ?, active = ? WHERE id = ?";
jdbcTemplate.update(sql,
user.getUsername(), user.getEmail(), user.getPassword(),
user.getFullName(), java.time.LocalDateTime.now(),
user.isActive(), user.getId());
user.setUpdatedAt(java.time.LocalDateTime.now());
}
return user;
}
public void deleteById(Long id) {
String sql = "DELETE FROM users WHERE id = ?";
jdbcTemplate.update(sql, id);
}
public boolean existsByUsername(String username) {
String sql = "SELECT COUNT(*) FROM users WHERE username = ?";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, username);
return count != null && count > 0;
}
public boolean existsByEmail(String email) {
String sql = "SELECT COUNT(*) FROM users WHERE email = ?";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, email);
return count != null && count > 0;
}
}
Service 類:
package com.example.myfirstapp.service;
import com.example.myfirstapp.config.ResourceNotFoundException;
import com.example.myfirstapp.entity.User;
import com.example.myfirstapp.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<User> findAll() {
return userRepository.findAll();
}
public User findById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User", id));
}
public User save(User user) {
return userRepository.save(user);
}
public void deleteById(Long id) {
if (!userRepository.findById(id).isPresent()) {
throw new ResourceNotFoundException("User", id);
}
userRepository.deleteById(id);
}
public boolean existsByUsername(String username) {
return userRepository.existsByUsername(username);
}
public boolean existsByEmail(String email) {
return userRepository.existsByEmail(email);
}
}
Top comments (0)