本章将通过一个实战项目演示如何应用前面所学的Java知识,构建一个完整的个人记账本Web应用。

10.1 实战项目:个人记账本Web应用

10.1.1 项目概述

我们将构建一个简单的个人记账本Web应用,用户可以记录和查看他们的收入和支出。

10.1.2 技术栈

  • Spring Boot:用于快速构建和部署Web应用。
  • Spring Data JPA:用于数据持久化。
  • H2 Database:嵌入式数据库,用于快速开发和测试。
  • Thymeleaf:用于服务器端模板引擎,生成动态HTML页面。

10.2 项目架构设计与实现

10.2.1 创建项目结构

使用Spring Initializr创建一个新的Spring Boot项目,包含以下依赖:

  • Spring Web
  • Spring Data JPA
  • H2 Database
  • Thymeleaf

10.2.2 定义实体类

示例:定义交易记录实体类

  1. import javax.persistence.Entity;
  2. import javax.persistence.GeneratedValue;
  3. import javax.persistence.GenerationType;
  4. import javax.persistence.Id;
  5. import java.time.LocalDate;
  6. @Entity
  7. public class Transaction {
  8. @Id
  9. @GeneratedValue(strategy = GenerationType.IDENTITY)
  10. private Long id;
  11. private String type; // "income" or "expense"
  12. private double amount;
  13. private String description;
  14. private LocalDate date;
  15. // Getters and setters
  16. // ... 省略getter和setter代码
  17. }

10.2.3 创建JPA仓库接口

示例:创建交易记录仓库

  1. import org.springframework.data.jpa.repository.JpaRepository;
  2. public interface TransactionRepository extends JpaRepository<Transaction, Long> {
  3. // JPA会自动生成CRUD操作的方法
  4. }

10.2.4 创建服务类

示例:创建交易记录服务

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.stereotype.Service;
  3. import java.util.List;
  4. import java.util.Optional;
  5. @Service
  6. public class TransactionService {
  7. private final TransactionRepository transactionRepository;
  8. @Autowired
  9. public TransactionService(TransactionRepository transactionRepository) {
  10. this.transactionRepository = transactionRepository;
  11. }
  12. public List<Transaction> getAllTransactions() {
  13. return transactionRepository.findAll();
  14. }
  15. public Optional<Transaction> getTransactionById(Long id) {
  16. return transactionRepository.findById(id);
  17. }
  18. public Transaction saveTransaction(Transaction transaction) {
  19. return transactionRepository.save(transaction);
  20. }
  21. public void deleteTransaction(Long id) {
  22. transactionRepository.deleteById(id);
  23. }
  24. }

10.2.5 创建控制器类

示例:创建交易记录控制器

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.ui.Model;
  4. import org.springframework.web.bind.annotation.*;
  5. import java.util.List;
  6. @Controller
  7. @RequestMapping("/transactions")
  8. public class TransactionController {
  9. private final TransactionService transactionService;
  10. @Autowired
  11. public TransactionController(TransactionService transactionService) {
  12. this.transactionService = transactionService;
  13. }
  14. @GetMapping
  15. public String getAllTransactions(Model model) {
  16. List<Transaction> transactions = transactionService.getAllTransactions();
  17. model.addAttribute("transactions", transactions);
  18. return "transactions"; // 返回的视图名称
  19. }
  20. @GetMapping("/new")
  21. public String showNewTransactionForm(Model model) {
  22. model.addAttribute("transaction", new Transaction());
  23. return "new_transaction";
  24. }
  25. @PostMapping
  26. public String saveTransaction(@ModelAttribute("transaction") Transaction transaction) {
  27. transactionService.saveTransaction(transaction);
  28. return "redirect:/transactions";
  29. }
  30. @GetMapping("/delete/{id}")
  31. public String deleteTransaction(@PathVariable Long id) {
  32. transactionService.deleteTransaction(id);
  33. return "redirect:/transactions";
  34. }
  35. }

10.2.6 创建视图模板

示例:创建显示交易记录的视图模板

transactions.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <title>Transaction List</title>
  5. </head>
  6. <body>
  7. <h1>All Transactions</h1>
  8. <table>
  9. <tr>
  10. <th>ID</th>
  11. <th>Type</th>
  12. <th>Amount</th>
  13. <th>Description</th>
  14. <th>Date</th>
  15. <th>Actions</th>
  16. </tr>
  17. <tr th:each="transaction : ${transactions}">
  18. <td th:text="${transaction.id}">1</td>
  19. <td th:text="${transaction.type}">income</td>
  20. <td th:text="${transaction.amount}">100.0</td>
  21. <td th:text="${transaction.description}">Salary</td>
  22. <td th:text="${transaction.date}">2024-05-24</td>
  23. <td>
  24. <a th:href="@{/transactions/delete/{id}(id=${transaction.id})}">Delete</a>
  25. </td>
  26. </tr>
  27. </table>
  28. <a href="/transactions/new">Add New Transaction</a>
  29. </body>
  30. </html>

示例:创建新增交易记录的视图模板

new_transaction.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <title>New Transaction</title>
  5. </head>
  6. <body>
  7. <h1>New Transaction</h1>
  8. <form th:action="@{/transactions}" th:object="${transaction}" method="post">
  9. <label>Type:</label>
  10. <select th:field="*{type}">
  11. <option value="income">Income</option>
  12. <option value="expense">Expense</option>
  13. </select>
  14. <br>
  15. <label>Amount:</label>
  16. <input type="text" th:field="*{amount}" />
  17. <br>
  18. <label>Description:</label>
  19. <input type="text" th:field="*{description}" />
  20. <br>
  21. <label>Date:</label>
  22. <input type="date" th:field="*{date}" />
  23. <br>
  24. <button type="submit">Save</button>
  25. </form>
  26. </body>
  27. </html>

10.3 测试与部署

10.3.1 单元测试

使用JUnit和Spring Test来编写和运行单元测试,以确保代码的正确性。

示例:测试交易记录服务

  1. import org.junit.jupiter.api.Test;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import static org.junit.jupiter.api.Assertions.*;
  6. @SpringBootTest
  7. class TransactionServiceTest {
  8. @Autowired
  9. private TransactionService transactionService;
  10. @Test
  11. void testSaveTransaction() {
  12. Transaction transaction = new Transaction();
  13. transaction.setType("income");
  14. transaction.setAmount(100.0);
  15. transaction.setDescription("Test Income");
  16. transaction.setDate(LocalDate.now());
  17. Transaction savedTransaction = transactionService.saveTransaction(transaction);
  18. assertNotNull(savedTransaction);
  19. assertEquals("income", savedTransaction.getType());
  20. }
  21. }

10.3.2 集成测试

集成测试用于测试完整系统的功能,确保各个部分协同工作。

10.3.3 部署应用

将应用打包为JAR文件或WAR文件,并部署到服务器(如Tomcat)或云平台(如AWS、Heroku)。

示例:打包和运行Spring Boot应用

  1. # 打包应用
  2. mvn clean package
  3. # 运行JAR文件
  4. java -jar target/myapp-0.0.1-SNAPSHOT.jar