繼上一篇的模組化重構後,今天我們將進一步增加新的功能:產生電話號碼的 QR Code。
在商務或社交活動中,經常需要與他人交換聯繫方式。傳統上,我們會交換名片或手動輸入電話號碼,但這些方式都不夠有效率。生為一個工程師,使用一個包含電話號碼的 QR Code ,才能夠快速而簡單地分享你的聯繫方式。
目前專案中的 QR code 是基於一般文字所產生的,也就是說你可以任意輸入一段文字,都可以給你一個 QR code,而 URL 不用做特別處理,現代手機中的相機或是 QR code 掃描 app 都可以自動辨識 URL,讓使用者點擊後就可以自動到瀏覽器顯示該 URL 的內容。
我們可以實際嘗試看看,在送出的 JSON 中的 url 填入任一電話號碼。
還是有回傳 QR code,不過這裡用不同手機去掃描會有不同的結果。
經過 iPhone 實測,會出現電話提示。而用 Android 手機(Pixel 5)則會出現 Google 搜尋。
既然有這種不同的差異,我們就要考慮為電話號碼加上產生 QR code 的功能。
首先,在 models
資料夾下的 mod.rs
中,我們增加一個新的欄位來儲存電話號碼。
#[derive(serde::Deserialize)]
pub struct Info {
pub url: Option<String>,
pub phone: Option<String>,
pub foreground: Option<String>,
pub background: Option<String>,
pub dimension: Option<u32>,
}
這裡要注意的是,我把 url
和 phone
都設為 Option
,這樣我們可以根據使用者的需求去產生不同類型的 QR Code。
接下來,在 api
資料夾下的 mod.rs
中,我們更新 API,使其能夠處理電話號碼。
#[get("/generate_qr")]
async fn index(data: web::Query<Info>) -> HttpResponse {
let code_data = if let Some(url) = &data.url {
url.as_bytes().to_vec()
} else if let Some(phone_number) = &data.phone {
let formatted_number = format!("tel:{}", phone_number);
formatted_number.as_bytes().to_vec()
} else {
return HttpResponse::BadRequest().body("至少需要填入 URL 或電話號碼");
};
let code = match QrCode::new(code_data) {
Ok(c) => c,
Err(_) => return HttpResponse::BadRequest().body("你輸入的字串無法處理"),
};
// 省略
}
#[post("/generate_qr_svg")]
async fn generate_svg(data: web::Json<Info>) -> HttpResponse {
// 省略
let code_data = if let Some(url) = &data.url {
url.as_bytes().to_vec()
} else if let Some(phone_number) = &data.phone {
let formatted_number = format!("tel:{}", phone_number);
formatted_number.as_bytes().to_vec()
} else {
return HttpResponse::BadRequest().body("至少需要填入 URL 或電話號碼");
};
let code = match QrCode::new(code_data) {
Ok(c) => c,
Err(_) => return HttpResponse::BadRequest().body("你輸入的字串無法處理"),
};
// 省略
}
接著在 Postman 來測試一下,在 JSON 中傳入:
{
"phone": "0900000000",
"foreground": "#0375a6",
"background": "ffff80",
"dimensions": 20
}
現在不管用任何手機來掃描這個 QR code,都可以從電話去做接下來的動作了。
不過剛剛那一段處理 code_date
的部分有點囉嗦,用了 else if
和 else
做了判斷,我自己是不太喜歡,覺得不好閱讀,所以來重寫一下。
#[get("/generate_qr")]
async fn index(data: web::Query<Info>) -> HttpResponse {
let code_data = match data
.url
.as_ref()
.map(|url| url.as_bytes().to_vec())
.or_else(|| {
data.phone
.as_ref()
.map(|phone| format!("tel:{}", phone).as_bytes().to_vec())
}) {
Some(data) => data,
None => return HttpResponse::BadRequest().body("缺少有效數據"),
};
// 省略
}
#[post("/generate_qr_svg")]
async fn generate_svg(data: web::Json<Info>) -> HttpResponse {
// 省略
let code_data = match data
.url
.as_ref()
.map(|url| url.as_bytes().to_vec())
.or_else(|| {
data.phone
.as_ref()
.map(|phone| format!("tel:{}", phone).as_bytes().to_vec())
}) {
Some(data) => data,
None => return HttpResponse::BadRequest().body("缺少有效數據"),
};
// 省略
}
看起來清爽多了!👍
透過今天的實作,我們成功地擴充了 QR Code 的服務,能夠產生包含電話號碼的 QR Code。這不僅增加了我們服務的多樣性,也展示了如何在模組化的設計下方便地增加新功能。
我們明天見!