To-Do Calendar - Day16 實作條件查詢功能
接著來開發查詢功能,以下將以原子習慣追蹤為例,繼續練習 CRUD 在 Spring Boot 與 MongoTemplate 的寫法。
原子習慣追蹤的條件查詢功能
- 開發流程:以前端傳來的參數 habitId 與年份作為查詢條件,到 MongoDB 中取得符合條件的 habitTracker Document 並返回前端,最後再實作前端呼叫 API 與顯示查詢結果。
設計 RESTful API
查詢指定原子習慣追蹤 原子習慣追蹤(顯示年曆上圈選的日期)
getHabitTracker API
- Request URL
GET http://localhost:8080/users/{userId}/habitTrackers?habitId=<habitId>&year=<year>
- Response Body
{ "id": "6294f0123d1b551c205e3b71", "habitId": "habit01", "year": "2022", "pickedDays":[ { "id": "2022-01-06", "date": "2022-01-05T16:00:00.000Z" }, { "id": "2022-01-07", "date": "2022-01-06T16:00:00.000Z" }, { "id": "2022-01-08", "date": "2022-01-07T16:00:00.000Z" } ], "createdTime": 1653405213436, "lastModifiedTime": 1653405213436 }
實作 Dao 層
- 在 dao package 底下建立 HabitTrackerDao
- 在 impl package 底下再建立 HabitTrackerDaoImpl class
- 為讓 HabitTrackerDaoImpl class 成為 Bean,在 HabitTrackerDaoImpl class 上加上
@component
註解,並 implements HabitTrackerDao interface,然後使用@Autowired
註解注入 MongoTemplate - 在 HabitTrackerDao interface 宣告一個 getHabitTracker 方法,返回類型為 HabitTracker
- 實作之前可先在 Query Console 測試 MongoDB 原生語法
- 接著再回到 HabitTrackerDaoImpl class,實作 getHabitTracker 方法
Query Console
HabitTrackerDao class
HabitTrackerDaoImpl class
實作 Service 層
- 在 service package 底下建立 HabitTrackerService interface
- 在 impl package 底下建立 HabitTrackerServiceImpl class
- 為讓 HabitTrackerServiceImpl class 成為 Bean,在 HabitTrackerServiceImpl class 上加上
@component
註解,並 implements HabitTrackerService interface,然後使用@Autowired
註解注入 HabitTrackerDao - 回到 HabitTrackerService interface,宣告一個 getHabitTracker 方法,返回類型為 HabitTracker
- 接著再到 HabitTrackerServiceImpl class,實作 getHabitTracker 方法(call habitTrackerDao 的 getHabitTracker 方法)
HabitTrackerService interface
HabitsServiceImpl class
實作 Controller 層
- 在 controller package 底下建立 HabitTrackerController class
- 在 HabitTrackerController class 上加上
@RestController
註解,並使用@Autowired
註解注入 HabitTrackerService - 新增 getHabitTracker 方法,返回類型為
ResponseEntity<HabitTracker>
- 根據 RESTful 的設計原則,查詢所對應的是 GET 方法,所以在方法上加上
@GetMapping
註解,表示前端要使用 GET 方法來請求 API - 在
@GetMapping
註解括號中指定 url 路徑,並使用@RequestParam
註解去取得 url 路徑的參數 - 接著實作 getHabitTracker 方法(call habitTrackerService 的 getHabitTracker 方法)
HabitsController class
- 接著運行 Spring Boot 程式,使用 API Tester 測試一下效果
實作前端串接 API
- 在 src/axios/index.js 新增 apiHabitTrackerQuery 方法,然後再 export 出去給外面的組件 import
// HabitTracker 相關的 api export const apiHabitTrackerQuery = (userId, habitId, year) => instance.get(`/users/${userId}/habitTracker?habitId=${habitId}&year=${year}`);
getHabitTracker API 呼叫時機
進 Habit trackers 頁面

進 Habit trackers 頁面時,呼叫 getHabitTracker API
- 如果後端返回的原子習慣列表長度大於0,就預設顯示第一筆的原子習慣追蹤
import { apiHabitsQuery, apiHabitTrackerQuery } from "../../api/index.js"; ... mounted() { apiHabitsQuery(this.$store.state.userId).then((res) => { console.log(res.data); this.habitList = res.data.habitList; if (this.habitList.length > 0) { this.pickedHabit = this.habitList[0]; apiHabitTrackerQuery( this.$store.state.userId, this.pickedHabit.habitId, this.pageYear ).then((res) => { this.pickedDays = res.data.pickedDays; }); } }); },
點選列表中的原子習慣

點選列表中的原子習慣時,呼叫 getHabitTracker API
- 如果切換到的年份是還沒有建立 HabitTracker Document 的年份,後端仍返回200和預設值。
sendQueryHabitTracker(item) { let self = this; self.pickedHabit = item; apiHabitTrackerQuery(self.$store.state.userId, item.habitId, self.pageYear).then( (res) => { this.pickedDays = res.data.pickedDays; } ); },
切換原子習慣追蹤年份

切換原子習慣追蹤年份時,呼叫 getHabitTracker API
- 如果原子習慣列表長度大於0,才去呼叫 getHabitTracker API
updatePage(page) { let self = this; if (self.habitList.length > 0) { self.pageYear = page.year; apiHabitTrackerQuery( self.$store.state.userId, self.pickedHabit.habitId, page.year ).then((res) => { console.log(res.data); self.pickedDays = res.data.pickedDays; }); } },