國泰Java
===
## 需求項目
---
語言:
* Java 11
框架:
* Spring Boot
* Spring MVC
* Spring Data Jpa
專案類型:
* Maven
資料庫:
* H2
情境:
* 提供RestFul API,達到以下幾件事:
1. 查詢匯率資料 :「日期」為查詢條件
> 查詢時間格式範例:2024/01/01
---
## 資料庫設計
---
* 幣別資料表[CURRENCY_TYPE]
|欄位代號 |欄位名稱 |型別 |欄位大小 |必填 |
|--------------|---------------|----------|----------|---------|
|*EXCHANGE_ID |ID |INTEGER| |●|
|EXCHANGE_Date |匯率日期) |Date| |●|
|USD_TO_NTD |美金匯換台幣匯率 |DOUBLE| |●|
EXCHANGE_RATE.sql
---
```=sql
DROP TABLE IF EXISTS EXCHANGE_RATE;
-- 幣別對應表
CREATE TABLE EXCHANGE_RATE (
EXCHANGE_ID INTEGER PRIMARY KEY auto_increment, -- ID
EXCHANGE_Date Date NOT NULL,
USD_TO_NTD DOUBLE NOT NULL --美元兌換新台幣
);
-- 測試資料
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231201', '31.475');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231204', '31.415');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231205', '31.493');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231206', '31.505');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231207', '31.529');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231208', '31.374');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231211', '31.512');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231212', '31.509');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231213', '31.526');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231214', '31.33');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231215', '31.268');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231218', '31.314');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231219', '31.361');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231220', '31.31');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231221', '31.282');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231222', '31.203');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231225', '31.14');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231226', '31.065');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231227', '30.88');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231228', '30.718');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20231229', '30.735');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240102', '30.866');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240103', '31.01');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240104', '31.016');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240105', '31.025');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240108', '31.001');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240109', '31.023');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240110', '31.14');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240111', '31.103');
INSERT INTO EXCHANGE_RATE (EXCHANGE_DATE, USD_TO_NTD) VALUES ('20240112', '31.129');
```
---
## API設計
---
* ExchangeRate API[ExchangeRateController]
|Http狀態|URI |說明
|-------|-------------------|----------|
|POST |/getExchangeRates |查詢指定日期美金兌換台幣匯率
---
## URL
---
* URL : http://127.0.0.1:8080/Cathay/
* swagger-ui : http://127.0.0.1:8080/Cathay/swagger-ui.html#/
---
## 定時排程
---
排程清單
| 排程名稱 | 執行時間 | 內容說明 |
| -------- | -------- | -------- |
| fetchAndSaveForexData | 每日18:00 | 呼叫API,取得每日匯率資料,寫入DB Table |
## UnitTest
---
1. API測試
2. 排程測試
### API 測試
```=java
package com.cathay.controller;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@SpringBootTest
@AutoConfigureMockMvc
class ExchangeRateControllerTest {
@Autowired
private MockMvc mockMvc;
@DisplayName("測試API成功回傳")
@Test
public void getUsdToNtdExchangeRateData() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/ExchangeRate/v1/getExchangeRates")
.contentType(MediaType.APPLICATION_JSON)
.content("{\r\n"
+ " \"startDate\": \"2024/01/11\",\r\n"
+ " \"endDate\": \"2024/01/15\",\r\n"
+ " \"currency\": \"usd\"\r\n"
+ "}");
mockMvc.perform(requestBuilder)
.andDo(print())
.andExpect(jsonPath("$.currency[0].date",equalTo("20240111")))
.andExpect(jsonPath("$.currency[0].usd",equalTo(31.103)))
.andExpect(jsonPath("$.currency[1].date",equalTo("20240112")))
.andExpect(jsonPath("$.currency[1].usd",equalTo(31.129)))
.andExpect(jsonPath("$.error.code",equalTo("0000")))
.andExpect(jsonPath("$.error.message",equalTo("成功")))
.andExpect(status().is(200));
}
@DisplayName("測試API失敗回傳")
@Test
public void getUsdToNtdExchangeRateData2() throws Exception {
RequestBuilder requestBuilderDateError = MockMvcRequestBuilders
.post("/ExchangeRate/v1/getExchangeRates")
.contentType(MediaType.APPLICATION_JSON)
.content("{\r\n"
+ " \"startDate\": \"2023/01/01\",\r\n"
+ " \"endDate\": \"2024/01/16\",\r\n"
+ " \"currency\": \"usd\"\r\n"
+ "}");
mockMvc.perform(requestBuilderDateError)
.andDo(print())
.andExpect(jsonPath("$.error.code",equalTo("E001")))
.andExpect(jsonPath("$.error.message",equalTo("日期區間不符")))
.andExpect(status().is(400));
}
}
```
### 排程 測試
```=java
package com.cathay.scheduledtasks;
import static org.junit.jupiter.api.Assertions.*;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import com.cathay.dao.ExchangeRateDao;
import com.cathay.entity.ExchangeRateEntity;
@SpringBootTest
@Transactional
class ScheduledTasksTest {
@Autowired
private ScheduledTasks scheduledTasks;
@Autowired
private ExchangeRateDao exchangeRateDao;
@Test
public void fetchAndSaveForexData() throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
java.sql.Date date = new Date( dateFormat.parse("2024-01-15").getTime());
//手動執行 ScheduledTasks
scheduledTasks.fetchAndSaveForexData();
//驗證 ScheduledTasks執行過後的資料
ExchangeRateEntity exchangeRateEntity = exchangeRateDao.findByDate(date);
assertEquals("2024-01-15", exchangeRateEntity.getDate().toString());
assertEquals(31.215, exchangeRateEntity.getUsdToNtd());
}
}
```
## API 測試
---
### API 測試工具 : API Tester
### 1. 測試呼叫查詢美金兌換台幣匯率資料 API,成功並顯示其內容。


### 2. 測試呼叫查詢美金兌換台幣匯率資料 API,失敗並顯示其內容。

