To-Do Calendar - Day16 實作條件查詢功能

接著來開發查詢功能,以下將以原子習慣追蹤為例,繼續練習 CRUD 在 Spring Boot 與 MongoTemplate 的寫法。

原子習慣追蹤的條件查詢功能

  • 開發流程:以前端傳來的參數 habitId 與年份作為查詢條件,到 MongoDB 中取得符合條件的 habitTracker Document 並返回前端,最後再實作前端呼叫 API 與顯示查詢結果。

設計 RESTful API

image

查詢指定原子習慣追蹤

image

原子習慣追蹤(顯示年曆上圈選的日期)

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 方法
    image

    Query Console

    image

    HabitTrackerDao class

    image

    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 方法)
    image

    HabitTrackerService interface

    image

    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 方法)
    image

    HabitsController class

  • 接著運行 Spring Boot 程式,使用 API Tester 測試一下效果
    image


實作前端串接 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 頁面

image

進 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;
          });
        }
      });
    },  
    

點選列表中的原子習慣

image

點選列表中的原子習慣時,呼叫 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;
        }
      );
    },
    

切換原子習慣追蹤年份

image

切換原子習慣追蹤年份時,呼叫 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;
        });
      }
    },
    


延伸閱讀

參考資料

comments

comments powered by Disqus