iT邦幫忙

2023 iThome 鐵人賽

DAY 8
1
SideProject30

30 天用 Rust 打造 QR Code 製造機系列 第 8

Day 8 - 產生電話版本的 QR code

  • 分享至 

  • xImage
  •  

繼上一篇的模組化重構後,今天我們將進一步增加新的功能:產生電話號碼的 QR Code。

為什麼要電話的 QR Code?

在商務或社交活動中,經常需要與他人交換聯繫方式。傳統上,我們會交換名片或手動輸入電話號碼,但這些方式都不夠有效率。生為一個工程師,使用一個包含電話號碼的 QR Code ,才能夠快速而簡單地分享你的聯繫方式。

目前產生的 QR code 不行嗎?

目前專案中的 QR code 是基於一般文字所產生的,也就是說你可以任意輸入一段文字,都可以給你一個 QR code,而 URL 不用做特別處理,現代手機中的相機或是 QR code 掃描 app 都可以自動辨識 URL,讓使用者點擊後就可以自動到瀏覽器顯示該 URL 的內容。

我們可以實際嘗試看看,在送出的 JSON 中的 url 填入任一電話號碼。

https://ithelp.ithome.com.tw/upload/images/20230923/20120293PC1BVB7eQl.png

還是有回傳 QR code,不過這裡用不同手機去掃描會有不同的結果。

經過 iPhone 實測,會出現電話提示。而用 Android 手機(Pixel 5)則會出現 Google 搜尋。

既然有這種不同的差異,我們就要考慮為電話號碼加上產生 QR code 的功能。

加入電話號碼到 Info 結構

首先,在 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>,
}

這裡要注意的是,我把 urlphone 都設為 Option,這樣我們可以根據使用者的需求去產生不同類型的 QR Code。

更新 API

接下來,在 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,都可以從電話去做接下來的動作了。

https://ithelp.ithome.com.tw/upload/images/20230923/20120293F2Ub8UK3tH.png

重構程式碼

不過剛剛那一段處理 code_date 的部分有點囉嗦,用了 else ifelse 做了判斷,我自己是不太喜歡,覺得不好閱讀,所以來重寫一下。

#[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。這不僅增加了我們服務的多樣性,也展示了如何在模組化的設計下方便地增加新功能。

我們明天見!


上一篇
Day 7 - 模組化重構
下一篇
Day 9 - 產生地址和 Mail 的 QR code
系列文
30 天用 Rust 打造 QR Code 製造機30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言