整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          python如何進行網(wǎng)站維護?有什么優(yōu)勢?

          python如何進行網(wǎng)站維護?有什么優(yōu)勢?

          ython 是一種強大的編程語言,可以用于網(wǎng)站維護和開發(fā)。下面是一些常見的 Python 工具和技術(shù),可用于網(wǎng)站維護:

          Web 框架:使用 Python 的 Web 框架可以更輕松地構(gòu)建和維護網(wǎng)站。一些流行的 Python Web 框架包括 Django、Flask 和 Pyramid。這些框架提供了路由、模板引擎、數(shù)據(jù)庫集成等功能,使得開發(fā)和維護網(wǎng)站變得更加簡單。

          數(shù)據(jù)庫:Python 提供了許多與數(shù)據(jù)庫交互的庫,例如 SQLite、MySQL、PostgreSQL 等。你可以使用這些庫來存儲和管理網(wǎng)站的數(shù)據(jù)。

          HTML/CSS:網(wǎng)站維護中經(jīng)常需要對 HTML 和 CSS 進行修改和調(diào)整。Python 可以使用第三方庫如 BeautifulSoup 來解析和操作 HTML,使用庫如 CSSutils 來處理 CSS。

          自動化任務(wù):Python 可以用于編寫腳本來自動執(zhí)行一些網(wǎng)站維護任務(wù),例如定期備份數(shù)據(jù)庫、清理日志文件、更新網(wǎng)站內(nèi)容等。你可以使用 Python 的標準庫或第三方庫來完成這些任務(wù)。

          測試:在進行網(wǎng)站維護時,測試是非常重要的。Python 提供了多種測試框架,例如 unittest、pytest 等,可以幫助你編寫和運行測試用例,確保網(wǎng)站的功能和性能正常。

          Web 抓取:有時候需要從其他網(wǎng)站抓取數(shù)據(jù)來更新自己的網(wǎng)站。Python 提供了一些強大的庫如 Requests 和 Scrapy,可以幫助你編寫網(wǎng)絡(luò)爬蟲,從其他網(wǎng)站獲取數(shù)據(jù)。

          以上只是一些基本的步驟和工具,具體的網(wǎng)站維護任務(wù)可能因項目而異。如果有什么需要和問題請咨詢我們通遼網(wǎng)站建設(shè)|通遼網(wǎng)站制作|通遼做網(wǎng)站公司|通遼軟件開發(fā)-通遼易聯(lián)通達-通遼最專業(yè)的企業(yè)營銷型網(wǎng)站建設(shè)專家公司

          眾號、企業(yè)官網(wǎng)、個人博客等各類網(wǎng)站建設(shè)日益火爆,而選擇一個合適的官網(wǎng)模板成為許多人的關(guān)注焦點。在眾多的官網(wǎng)模板中,publicCms 官網(wǎng)模板憑借其獨特的設(shè)計風格和豐富的功能備受矚目。本文將對publicCms 官網(wǎng)模板進行評測對比,幫助您找到最適合自己需求的官網(wǎng)模板。

          一、外觀設(shè)計

          publicCms 官網(wǎng)模板以簡潔大氣的設(shè)計風格為主,注重用戶體驗和信息傳達。無論是顏色搭配還是排版布局,都力求簡潔明了,同時又不失個性和創(chuàng)意。與其他官網(wǎng)模板相比,publicCms 官網(wǎng)模板更加注重細節(jié)處理,使得整體視覺效果更加舒適和美觀。

          二、響應(yīng)式布局

          現(xiàn)如今,移動設(shè)備的普及使得響應(yīng)式布局成為一個必備特性。publicCms 官網(wǎng)模板充分考慮到了這一點,采用了響應(yīng)式設(shè)計,能夠自動適配各種屏幕尺寸。無論是在電腦、平板還是手機上瀏覽,用戶都能得到良好的瀏覽體驗,這一點在選擇官網(wǎng)模板時非常重要。

          三、豐富的功能模塊

          publicCms 官網(wǎng)模板內(nèi)置了許多實用的功能模塊,滿足了各類網(wǎng)站建設(shè)的需求。例如,公眾號模塊可以方便地集成微信公眾號,實現(xiàn)與用戶的互動;新聞資訊模塊可以方便地發(fā)布和管理新聞內(nèi)容;產(chǎn)品展示模塊可以展示企業(yè)的產(chǎn)品和服務(wù)等。這些功能模塊的豐富性使得publicCms 官網(wǎng)模板具備了更大的靈活性和擴展性。

          四、友好的后臺管理

          作為一個官網(wǎng)模板,易于使用和管理是至關(guān)重要的。publicCms 官網(wǎng)模板提供了簡潔明了的后臺管理界面,使得用戶能夠輕松進行網(wǎng)站的配置和內(nèi)容更新。無需專業(yè)技術(shù)背景,即可快速上手操作,這對于不熟悉編程的用戶來說是一個巨大的優(yōu)勢。

          五、高效的加載速度

          對于一個官網(wǎng)來說,加載速度直接影響用戶體驗和SEO優(yōu)化。publicCms 官網(wǎng)模板采用了優(yōu)化過的代碼和圖片壓縮技術(shù),使得頁面加載速度得到了有效提升。用戶不需要長時間等待,能夠快速訪問到所需的內(nèi)容,提高了用戶的滿意度和留存率。

          六、良好的兼容性和安全性

          publicCms 官網(wǎng)模板經(jīng)過嚴格測試和優(yōu)化,確保在不同瀏覽器和操作系統(tǒng)下都能正常展示和運行。同時,它還采用了一系列的安全機制,保護網(wǎng)站免受惡意攻擊和數(shù)據(jù)泄露的威脅。這對于企業(yè)和個人網(wǎng)站來說,是非常重要的保障。

          七、優(yōu)質(zhì)的售后服務(wù)

          選擇一個官網(wǎng)模板除了考慮產(chǎn)品本身,還要考慮供應(yīng)商的售后服務(wù)。publicCms 官網(wǎng)模板提供了專業(yè)的售后支持團隊,能夠及時解答用戶遇到的問題,并提供技術(shù)支持和升級服務(wù)。無論是初次使用還是后期維護,都能得到及時幫助,這對于用戶來說是一個很大的安心點。

          綜上所述,publicCms 官網(wǎng)模板以其獨特的設(shè)計風格、豐富的功能模塊、友好的后臺管理以及良好的兼容性和安全性等優(yōu)勢,成為眾多用戶的首選。如果你正在尋找一款適合自己的官網(wǎng)模板,不妨考慮一下publicCms 官網(wǎng)模板,相信它會給你帶來驚喜!


          章涵蓋

          • 設(shè)計用戶身份驗證
          • 設(shè)置項目結(jié)構(gòu)
          • 實現(xiàn)用戶身份驗證
          • 路由 HTTP 請求
          • 使用 HTTP POST 方法創(chuàng)建資源
          • 使用 HTTP PUT 方法更新資源
          • 使用 HTTP DELETE 方法刪除資源

          在上一章中,我們研究了導師的注冊。您可能還記得,當用戶注冊為導師時,有關(guān)導師的信息存儲在兩個數(shù)據(jù)庫中。導師的個人資料詳細信息(如姓名圖像專業(yè)領(lǐng)域)保存在后端導師 Web 服務(wù)內(nèi)的數(shù)據(jù)庫中。用戶的注冊詳細信息(如用戶標識密碼)存儲在 Web 應(yīng)用程序的本地數(shù)據(jù)庫中。

          在本章中,我們將在上一章的代碼之上進行構(gòu)建。我們將學習編寫一個 Rust 前端 Web 應(yīng)用程序,該應(yīng)用程序允許用戶登錄到應(yīng)用程序、與本地數(shù)據(jù)庫交互以及與后端 Web 服務(wù)通信

          請注意,本章的重點不是為Web應(yīng)用程序編寫HTML/javascript用戶界面(因為這不是本書的重點)。相反,我們將專注于編寫在 Rust 中構(gòu)成 Web 應(yīng)用程序的所有其他組件,包括路由請求處理程序和數(shù)據(jù)模型,并學習如何在后端 Web 服務(wù)上調(diào)用 API。代替用戶界面,我們將從命令行 HTTP 工具測試 Web 應(yīng)用程序的 API。使用 Tera 模板為 Web 應(yīng)用程序編寫基于 HTML/javascript 的 UI 的任務(wù)主要留給讀者作為練習。

          讓我們首先從導師登錄(身份驗證)功能開始。

          9.1 設(shè)計用戶身份驗證

          對于導師登錄,我們將接受兩個字段 - 用戶名和密碼,并使用它來向 Web 應(yīng)用程序驗證導師

          圖 1 顯示了導師登錄窗體。


          圖 9.1.導師登錄表單

          現(xiàn)在,讓我們看一下圖 2 中導師登錄的工作流。請注意,圖 2 中的術(shù)語 Actix Web 服務(wù)器是指前端 Web 應(yīng)用程序服務(wù)器,而不是后端導師 Web 服務(wù)


          圖 9.2.導師登錄流

          1. 用戶訪問著陸頁網(wǎng)址。將顯示導師登錄表單
          2. 用戶名和密碼的基本驗證是使用 HTML 功能在表單本身內(nèi)執(zhí)行的,而無需向 Web Actix 服務(wù)器發(fā)送請求。
          3. 如果驗證中存在錯誤,則會向用戶提供反饋。
          4. 用戶提交登錄表單POST 請求將發(fā)送到登錄路由上的 Actix Web 服務(wù)器,然后該服務(wù)器將請求路由到相應(yīng)的路由處理程序
          5. 路由處理程序函數(shù)通過從本地數(shù)據(jù)庫檢索用戶憑據(jù)來驗證用戶名和密碼。
          6. 如果身份驗證不成功,則會向用戶顯示登錄表單,并顯示相應(yīng)的錯誤消息。錯誤消息的示例包括不正確的用戶名或密碼。
          7. 如果用戶身份驗證成功,用戶將被定向到導師 Web 應(yīng)用程序的主頁。

          現(xiàn)在我們已經(jīng)清楚了本章將要開發(fā)的內(nèi)容,讓我們設(shè)置項目代碼結(jié)構(gòu)和基本腳手架。

          9.2 設(shè)置項目結(jié)構(gòu)

          首先克隆第 8 章中的 ezytutors 存儲庫。

          然后,讓我們將PROJECT_ROOT環(huán)境變量設(shè)置為 /path-to-folder/ezytutors/tutor-web-app-ssr。此后,我們將此文件夾稱為 $PROJECT_ROOT。

          讓我們在項目根目錄下組織代碼,如下所示:

          1. 復制文件夾 $PROJECT_ROOT/src/iter5,并將其重命名為 $PROJECT_ROOT/src/iter6
          2. 復制文件夾 $PROJECT_ROOT/static/iter5,并將其重命名為 $PROJECT_ROOT/static/iter6。此文件夾將包含 html/tera 模板。
          3. 復制文件 $PROJECT_ROOT/src/bin/iter5-ssr.rs,并將其重命名為 $PROJECT_ROOT/src/bin/iter6-ssr.rs。此文件包含 main() 函數(shù),該函數(shù)將配置和啟動 Actix Web 服務(wù)器(為我們正在構(gòu)建的 Web 應(yīng)用程序提供服務(wù))。在 iter6-ssr.rs 中,將所有對 iter5 的引用替換為 iter6

          還要確保為 HOST_PORTDATABASE_URL環(huán)境變量正確配置 $PROJECT_ROOT 中的 .env 文件。

          我們已準備好開始編碼。

          讓我們從 $PROJECT_ROOT/src/iter6/routes.rs 中的路由定義開始。

          use crate::handler::{handle_register, show_register_form, show_signin_form,
          [CA]handle_signin}; #1
          use actix_files as fs;
          use actix_web::web;
          
          pub fn app_config(config: &mut web::ServiceConfig) {
            config.service(
              web::scope("")
                .service(fs::Files::new("/static", "./static").show_files_listing())
                .service(web::resource("/").route(web::get().to(show_register_form)))
                .service(web::resource("/signinform").route(web::get().to(
                [CA]show_signin_form)))   #2
                .service(web::resource("/signin").route(web::post().to(
                [CA]handle_signin)))         #3
                .service(web::resource("/register").route(web::post().to(
                [CA]handle_register))),
              );
          }

          有了這個,我們可以繼續(xù)在 $PROJECT_ROOT/src/iter6/model.rs 中進行模型定義。

          TutorSigninForm 數(shù)據(jù)結(jié)構(gòu)添加到 model.rs

          // Form to enable tutors to sign in
          #[derive(Serialize, Deserialize, Debug)]
          pub struct TutorSigninForm {            #1
              pub username: String,
              pub password: String,
          }

          通過項目設(shè)置的基本結(jié)構(gòu),我們現(xiàn)在可以開始編寫用于登錄用戶的代碼。

          9.3 實現(xiàn)用戶身份驗證

          定義路由和數(shù)據(jù)模型后,讓我們在 $PROJECT_ROOT/src/iter6/handler/auth.rs 中編寫用于登錄用戶的處理程序函數(shù)。

          首先,對導入進行以下更改:

          use crate::model::{TutorRegisterForm, TutorResponse, TutorSigninForm, User};  #1

          將以下處理程序函數(shù)添加到同一文件。在此文件中,將對 iter5 的引用替換為 iter6

          pub async fn show_signin_form(tmpl: web::Data<tera::Tera>) ->
          [CA]Result<HttpResponse, Error> { #1
              let mut ctx=tera::Context::new();
              ctx.insert("error", "");
              ctx.insert("current_name", "");
              ctx.insert("current_password", "");
              let s=tmpl
                  .render("signin.html", &ctx)
                  .map_err(|_| EzyTutorError::TeraError(
                  [CA]"Template error".to_string()))?;
          
              Ok(HttpResponse::Ok().content_type("text/html").body(s))
          }
          pub async fn handle_signin(                                     #2
              tmpl: web::Data<tera::Tera>,
              app_state: web::Data<AppState>,
              params: web::Form<TutorSigninForm>,
          ) -> Result<HttpResponse, Error> {
          
          Ok(HttpResponse::Ok().finish())
          }

          回想一下,調(diào)用show_signin_form處理程序函數(shù)是為了響應(yīng)到達路由 /signinform 的請求,如路由定義中所定義。

          讓我們以 html 形式設(shè)計實際的登錄。當用戶選擇登錄EzyTutor Web應(yīng)用程序時,將顯示此表單。在 $PROJECT_ROOT/static/iter6 下創(chuàng)建一個新的文件 signin.html 文件,并向其中添加以下內(nèi)容。請注意,應(yīng)該已經(jīng)有另一個文件寄存器.html已經(jīng)存在于同一個文件夾中。

          清單 9.1.導師登錄表單

          <!doctype html>
          <html>
          
          <head>
              <meta charset=utf-8>
              <title>Tutor registration</title>
          
              <style>                                         #1
                  .header {
                      padding: 20px;
                      text-align: center;
                      background: #fad980;
                      color: rgb(48, 40, 43);
                      font-size: 30px;
                  }
          
                  .center {
                      margin: auto;
                      width: 20%;
                      min-width: 150px;
                      border: 3px solid #ad5921;
                      padding: 10px;
                  }
          
                  body,
                  html {
                      height: 100%;
                      margin: 0;
                      font-kerning: normal;
                  }
          
                  h1 {
                      text-align: center;
                  }
          
                  p {
                      text-align: center;
                  }
          
                  div {
                      text-align: center;
                  }
          
                  div {
                      background-color: rgba(241, 235, 235, 0.719);
                  }
          
                  body {
                      background-image: url('/static/background.jpg');
                      background-repeat: no-repeat;
                      background-attachment: fixed;
                      background-size: cover;
                      height: 500px;
                  }
          
                  #button1,
                  #button2 {
                      display: inline-block;
                  }
          
                  #footer {
                      position: fixed;
                      padding: 10px 10px 0px 10px;
                      bottom: 0;
                      width: 100%;
                      /* Height of the footer*/
                      height: 20px;
          
                  }
              </style>
          </head>
          
          <body>
              <div class="header">
                  <h1>Welcome to EzyTutor</h1>
                  <p>Start your own online tutor business in a few minutes</p>
              </div>
          
              <div class="center">
                  <h2>
                      Tutor sign in
                  </h2>
                  <form action=/signin method=POST>       #2
          
                      <label for="userid">Enter username</label><br>            #3
                      <input type="text" name="username" autocomplete="username"
                      [CA]value="{{current_name}}" minlength="6"
                          maxlength="12" required><br>
                      <label for="password">Enter password</label><br>        #4
                      <input type="password" name="password"
                      [CA]autocomplete="new-password" value="{{current_password}}"
                          minlength="8" maxlength="12" required><br>
                      <label for="error">                                     #5
                          <p style="color:red">{{error}}</p>
                      </label><br>
                      <button type=submit id="button2">Sign in</button>       #6
          
                  </form>
                  <form action=/ method=GET>                                  #7
                      <button type=submit id="button2">Register</button>
                  </form>
              </div>
              <p>
              <div id="footer">
                  (c)Photo by Author
              </div>
          
              </p>
          
          </html>

          將另一個文件用戶.html添加到 $PROJECT_ROOT/static/iter6。這將在用戶成功登錄后顯示。

          清單 9.2.用戶通知屏幕

          <!DOCTYPE html>
          <html>
          
          <head>
              <meta charset=\"utf-8\" />
              <title>{{title}}</title>
          </head>
          
          <body>
              <h1>Hi, {{name}}!</h1>
              <p>{{message}}</p>
          </body>
          
          </html>

          最后,讓我們看看 $PROJECT_ROOT/src/bin/iter6-ssr.rs__ 中的 main() 函數(shù)。將其修改為如下所示:

          以下是導入:

          #[path="../iter6/mod.rs"]
          mod iter6;
          use actix_web::{web, App, HttpServer};
          use actix_web::web::Data;
          use dotenv::dotenv;
          use iter6::{dbaccess, errors, handler, model, routes, state};
          use routes::app_config;
          use sqlx::postgres::PgPool;
          use std::env;
          use tera::Tera;

          而且,這是main()函數(shù):

          清單 9.3.main() 函數(shù)

          #[actix_web::main]
          async fn main() -> std::io::Result<()> {
              dotenv().ok();
              //Start HTTP server
              let host_port=env::var("HOST_PORT").expect(
                [CA]"HOST:PORT address is not set in .env file");
              println!("Listening on: {}", &host_port);
              let database_url=env::var("DATABASE_URL").expect(
                [CA]"DATABASE_URL is not set in .env file");
              let db_pool=PgPool::connect(&database_url).await.unwrap();
              // Construct App State
              let shared_data=web::Data::new(state::AppState { db: db_pool });
          
              HttpServer::new(move || {
                  let tera=Tera::new(concat!(env!("CARGO_MANIFEST_DIR"),
                  [CA]"/static/iter6/**/*")).unwrap();
          
                  App::new()
                      .app_data(Data::new(tera))
                      .app_data(shared_data.clone())
                      .configure(app_config)
              })
              .bind(&host_port)?
              .run()
              .await
          }

          我們現(xiàn)在可以測試了。從 $PROJECT_ROOT 運行以下命令。

          cargo run --bin iter6-ssr

          注意:如果您收到錯誤:沒有針對 'u32 - usize 的實現(xiàn)

          運行以下命令:

          cargo update -p lexical-core

          從瀏覽器中,訪問以下路由:

          localhost:8080/signinform

          您應(yīng)該能夠看到登錄表單。您還可以通過訪問顯示注冊表單的索引路由 / 以及使用顯示的按鈕切換到登錄表單來調(diào)用簽名表單。

          完成此操作后,即可實現(xiàn)用于登錄用戶的邏輯。將以下內(nèi)容添加到 $PROJECT_ROOT/src/iter6/handler.rs。不要忘記刪除具有之前創(chuàng)建的相同名稱的占位符函數(shù)。

          清單 9.4.用于登錄的處理程序函數(shù)

          pub async fn handle_signin(
              tmpl: web::Data<tera::Tera>,
              app_state: web::Data<AppState>,
              params: web::Form<TutorSigninForm>,
          ) -> Result<HttpResponse, Error> {
              let mut ctx=tera::Context::new();
              let s;
              let username=params.username.clone();
              let user=get_user_record(&app_state.db, username.to_string()).await; #1
              if let Ok(user)=user {
                  let does_password_match=argon2::verify_encoded(
                      &user.user_password.trim(),
                      params.password.clone().as_bytes(),
                  )
                  .unwrap();
                  if !does_password_match {                                       #2
                      ctx.insert("error", "Invalid login");
                      ctx.insert("current_name", ?ms.username);
                      ctx.insert("current_password", ?ms.password);
                      s=tmpl
                          .render("signin.html", &ctx)
                          .map_err(|_| EzyTutorError::TeraError(
                          [CA]"Template error".to_string()))?;
                  } else {                                                        #3
                      ctx.insert("name", ?ms.username);
                      ctx.insert("title", &"Signin confirmation!".to_owned());
                      ctx.insert(
                          "message",
                          &"You have successfully logged in to EzyTutor!".to_owned(),
                      );
                      s=tmpl
                          .render("user.html", &ctx)
                          .map_err(|_| EzyTutorError::TeraError(
                          [CA]"Template error".to_string()))?;
                  }
              } else {                                                            #4
                  ctx.insert("error", "User id not found");
                  ctx.insert("current_name", ?ms.username);
                  ctx.insert("current_password", ?ms.password);
                  s=tmpl
                      .render("signin.html", &ctx)
                      .map_err(|_| EzyTutorError::TeraError(
                      [CA]"Template error".to_string()))?;
              };
          
              Ok(HttpResponse::Ok().content_type("text/html").body(s))
          }

          Let’s test the signin function now. Run the following command from $PROJECT_ROOT.

          cargo run --bin iter6-ssr

          從瀏覽器中,訪問以下路由:

          localhost:8080/signinform

          輸入正確的用戶名和密碼。您應(yīng)該會看到確認消息。

          再次加載登錄表單,這次為有效用戶名輸入錯誤的密碼。驗證是否收到錯誤消息。

          嘗試第三次輸入表單,這次使用無效的用戶名。同樣,您應(yīng)該會看到一條錯誤消息。

          至此,我們結(jié)束本節(jié)。到目前為止,我們已經(jīng)了解了如何使用Tera模板庫定義模板來生成動態(tài)網(wǎng)頁,以及如何向用戶顯示注冊登錄表單。我們還實現(xiàn)了用于注冊登錄用戶以及處理用戶輸入中的錯誤的代碼。我們還定義了自定義錯誤類型來統(tǒng)一錯誤處理。

          現(xiàn)在讓我們繼續(xù)管理課程詳細信息。

          9.4 路由 HTTP 請求

          在本節(jié)中,我們將添加導師維護課程的功能。

          我們目前將所有處理程序函數(shù)都放在一個文件中。我們現(xiàn)在還必須添加處理程序以進行課程維護。因此,讓我們首先將處理程序函數(shù)組織到它自己的模塊中,以便能夠跨多個源文件拆分處理程序函數(shù)。

          首先在 $PROJECT_ROOT/src/iter6 下創(chuàng)建一個新的處理程序文件夾。

          將$PROJECT_ROOT/src/iter6/handler.rs移動到$PROJECT_ROOT/src/iter6/handler中,并將其重命名為 auth.rs,因為這涉及注冊和登錄功能。(即 mv $PROJECT_ROOT/src/iter6/handler.rs $PROJECT_ROOT/src/iter6/handler/auth.rs in linux)。

          $PROJECT_ROOT/src/iter6/handler 文件夾下 course.rs 和 mod.rs 創(chuàng)建新文件。在 mod.rs 中添加以下代碼來構(gòu)建處理程序文件夾中的文件,并將它們導出為 Rust 模塊。

          pub mod auth;   #1
          pub mod course; #2

          修改 $PROJECT_ROOT/src/iter6/routes.rs,如下所示:

          清單 9.5.添加路線維護路線

          use crate::handler::auth::{handle_register, handle_signin,
          [CA]show_register_form, show_signin_form}; #1
          use crate::handler::course::{handle_delete_course, handle_insert_course,
          [CA]handle_update_course}; #2
          
          use actix_files as fs;
          use actix_web::web;
          
          pub fn app_config(config: &mut web::ServiceConfig) {            #3
            config.service(
              web::scope("")
                .service(fs::Files::new("/static", "./static").show_files_listing())
                .service(web::resource("/").route(web::get().to(show_register_form)))
                .service(web::resource("/signinform").route(web::get().to(
                [CA]show_signin_form)))
                .service(web::resource("/signin").route(web::post().to(
                [CA]handle_signin)))
                .service(web::resource("/register").route(web::post().to(
                [CA]handle_register))),
              );
          }
          
          pub fn course_config(config: &mut web::ServiceConfig) {             #4
            config.service(
              web::scope("/courses")                                      #5
                .service(web::resource("new/{tutor_id}").route(web::post().to(
                [CA]handle_insert_course)))   #6
                .service(                                               #7
                  web::resource("{tutor_id}/{course_id}").route(web::put().to(
                  [CA]handle_update_course)),
                )
                .service(                                               #8
                  web::resource("delete/{tutor_id}/{course_id}")
                    .route(web::delete().to(handle_delete_course)),
                ),
            );
          }

          請注意,在我們指定 {tutor_id} 和 {course_id} 作為路徑參數(shù)的地方,可以在 Actix Web 框架提供的提取器的幫助下從請求的路徑中提取它們。

          另外,請確保在 $PROJECT_ROOT/bin/iter6-ssr.rs 中添加新的課程維護路由,如下所示:

          對導入語句:應(yīng)用名稱進行以下更改:

          use routes::{app_config, course_config};

          main() 函數(shù)中,進行更改以添加course_config路由。

              HttpServer::new(move || {
                  let tera=Tera::new(concat!(env!("CARGO_MANIFEST_DIR"),
                  [CA]"/static/iter6/**/*")).unwrap();
          
                  App::new()
                      .app_data(Data::new(tera))
                      .app_data(shared_data.clone())
                      .configure(course_config)      #1
                      .configure(app_config)   #2
              })
              .bind(&host_port)?
              .run()
              .await

          接下來,讓我們現(xiàn)在在 $PROJECT_ROOT/src/iter6/handler/course.rs 中添加用于課程維護的占位符處理程序函數(shù)。稍后我們將編寫實際邏輯來調(diào)用后端 Web 服務(wù)。

          清單 9.6.課程維護處理程序函數(shù)的占位符

          use actix_web::{web, Error, HttpResponse, Result};
          use crate::state::AppState;
          
          pub async fn handle_insert_course(
              _tmpl: web::Data<tera::Tera>,
              _app_state: web::Data<AppState>,
          ) -> Result<HttpResponse, Error> {
              println!("Got insert request");
              Ok(HttpResponse::Ok().body("Got insert request"))
          }
          
          pub async fn handle_update_course(
              _tmpl: web::Data<tera::Tera>,
              _app_state: web::Data<AppState>,
          ) -> Result<HttpResponse, Error> {
              Ok(HttpResponse::Ok().body("Got update request"))
          }
          
          pub async fn handle_delete_course(
              _tmpl: web::Data<tera::Tera>,
              _app_state: web::Data<AppState>,
          ) -> Result<HttpResponse, Error> {
              Ok(HttpResponse::Ok().body("Got delete request"))
          }

          正如您將注意到的,處理程序函數(shù)現(xiàn)在除了返回消息外什么都不做。我們將在本章后面實現(xiàn)預期的處理程序功能。

          請注意在變量名稱前使用下劃線 (_)。這是因為,我們還沒有在處理程序函數(shù)的主體中使用這些參數(shù),因此在變量名稱之前添加下劃線將防止編譯器警告。

          讓我們對這四條路線進行快速測試:

          使用以下命令運行服務(wù)器:

          cargo run --bin iter6-ssr

          要測試 POSTPUTDELETE 請求,請從命令行嘗試以下操作:

          curl -H "Content-Type: application/json" -X POST -d '{}'
          [CA]localhost:8080/courses/new/1
          curl -H "Content-Type: application/json" -X PUT -d '{}'
          [CA]localhost:8080/courses/1/2
          curl -H "Content-Type: application/json" -X DELETE -d '{}'
          [CA]localhost:8080/courses/delete/1/2

          您應(yīng)該看到從服務(wù)器返回的以下消息,對應(yīng)于上面顯示的三個 HTTP 請求:

          Got insert request
          Got update request
          Got delete request

          現(xiàn)在,我們已驗證路由是否已正確建立,并且 HTTP 請求正在路由到正確的處理程序函數(shù)。在下一節(jié)中,讓我們實現(xiàn)在處理程序函數(shù)中為導師添加課程的實際邏輯。

          9.5 使用 HTTP POST 方法創(chuàng)建資源

          在本部分中,我們將通過向后端導師 Web 服務(wù)發(fā)送 API 請求,為給定導師添加新課程。

          轉(zhuǎn)到第 6 章的代碼存儲庫(即 /path-to-chapter4-folder/ezytutors/tutor-db ),并使用以下命令啟動 tutor Web 服務(wù)

          cargo run --bin iter5

          導師 Web 服務(wù)現(xiàn)在應(yīng)該已準備好接收來自導師 Web 應(yīng)用程序的請求。現(xiàn)在讓我們在 Web 應(yīng)用程序中編寫課程處理程序的代碼,在 $PROJECT_ROOT/src/iter6/handler/course.rs 中。

          修改 $PROJECT_ROOT/src/iter6/model.rs 以添加以下內(nèi)容:

          清單 9.7.課程維護的數(shù)據(jù)模型更改

          #[derive(Deserialize, Debug, Clone)]
          pub struct NewCourse {                      #1
              pub course_name: String,
              pub course_description: String,
              pub course_format: String,
              pub course_duration: String,
              pub course_structure: Option<String>,
              pub course_price: Option<i32>,
              pub course_language: Option<String>,
              pub course_level: Option<String>,
          }
          
          #[derive(Deserialize, Serialize, Debug, Clone)]
          pub struct NewCourseResponse {                  #2
              pub course_id: i32,
              pub tutor_id: i32,
              pub course_name: String,
              pub course_description: String,
              pub course_format: String,
              pub course_structure: Option<String>,
              pub course_duration: String,
              pub course_price: Option<i32>,
              pub course_language: Option<String>,
              pub course_level: Option<String>,
              pub posted_time: String,
          }
          
          impl From<web::Json<NewCourseResponse>> for NewCourseResponse {     #3
              fn from(new_course: web::Json<NewCourseResponse>) -> Self {
                  NewCourseResponse {
                      tutor_id: new_course.tutor_id,
                      course_id: new_course.course_id,
                      course_name: new_course.course_name.clone(),
                      course_description: new_course.course_description.clone(),
                      course_format: new_course.course_format.clone(),
                      course_structure: new_course.course_structure.clone(),
                      course_duration: new_course.course_duration.clone(),
                      course_price: new_course.course_price,
                      course_language: new_course.course_language.clone(),
                      course_level: new_course.course_level.clone(),
                      posted_time: new_course.posted_time.clone(),
                  }
              }
          }

          此外,請確保添加以下模塊導入,這是 From 特征實現(xiàn)所必需的。

          use actix_web::web;

          接下來,讓我們重寫處理程序函數(shù)以創(chuàng)建新課程。在 $PROJECT_ROOT/src/iter6/handler/course.rs 中,添加以下模塊導入:

          use actix_web::{web, Error, HttpResponse, Result};  #1
          use crate::state::AppState;
          use crate::model::{NewCourse, NewCourseResponse, UpdateCourse, UpdateCourseResponse}; #2
          use serde_json::json;                               #3
          
          use crate::state::AppState;

          然后修改handle_insert_course處理程序函數(shù),如下所示:

          清單 9.8.用于插入新課程的處理程序函數(shù)

          pub async fn handle_insert_course(                  #1
              _tmpl: web::Data<tera::Tera>,                   #2
              _app_state: web::Data<AppState>,                #3
              path: web::Path<i32>,
              params: web::Json<NewCourse>,                   #4
          ) -> Result<HttpResponse, Error> {
              let tutor_id=path.into_inner();               #5
              let new_course=json!({                        #6
                  "tutor_id": tutor_id,
                  "course_name": ?ms.course_name,
                  "course_description": ?ms.course_description,
                  "course_format": ?ms.course_format,
                  "course_structure": ?ms.course_structure,
                  "course_duration": ?ms.course_duration,
                  "course_price": ?ms.course_price,
                  "course_language": ?ms.course_language,
                  "course_level": ?ms.course_level
          
              });
              let awc_client=awc::Client::default();        #7
              let res=awc_client                            #8
                  .post("http://localhost:3000/courses/")
                  .send_json(&new_course)
                  .await
                  .unwrap()
                  .body()
                  .await?;
              println!("Finished call: {:?}", res);
              let course_response: NewCourseResponse=serde_json::from_str(
              [CA]&std::str::from_utf8(&res)?)?;    #9
              Ok(HttpResponse::Ok().json(course_response))                #10
          }

          從 $PROJECT_ROOT 構(gòu)建并運行 Web ssr 客戶端,如下所示:

          cargo run --bin iter6-ssr

          讓我們使用 curl 請求測試新課程的創(chuàng)建。確保導師 Web 服務(wù)正在運行。從另一個終端,運行以下命令:

          curl -X POST localhost:8080/courses/new/1 -d '{"course_name":"Rust web
          [CA]development", "course_description":"Teaches how to write web apps in
          [CA]Rust", "course_format":"Video", "course_duration":"3 hours",
          [CA]"course_price":100}' -H "Content-Type: application/json"

          通過在導師 Web 服務(wù)上運行 GET 請求來驗證是否已添加新課程:

          curl localhost:3000/courses/1

          您應(yīng)該在檢索到 tutor-id=1 的課程列表中看到新課程。

          在下一節(jié)中,我們將編寫處理程序函數(shù)來更新課程。

          9.6 使用 HTTP PUT 方法更新資源

          讓我們在 $PROJECT_ROOT/src/iter6/model.rs 文件中編寫用于更新課程的數(shù)據(jù)結(jié)構(gòu)。

          清單 9.9.更新課程的數(shù)據(jù)模型更改

          // Update course
          #[derive(Deserialize, Serialize, Debug, Clone)]
          pub struct UpdateCourse {                           #1
              pub course_name: Option<String>,
              pub course_description: Option<String>,
              pub course_format: Option<String>,
              pub course_duration: Option<String>,
              pub course_structure: Option<String>,
              pub course_price: Option<i32>,
              pub course_language: Option<String>,
              pub course_level: Option<String>,
          }
          
          #[derive(Deserialize, Serialize, Debug, Clone)]
          pub struct UpdateCourseResponse {                   #2
              pub course_id: i32,
              pub tutor_id: i32,
              pub course_name: String,
              pub course_description: String,
              pub course_format: String,
              pub course_structure: String,
              pub course_duration: String,
              pub course_price: i32,
              pub course_language: String,
              pub course_level: String,
              pub posted_time: String,
          }
          
          impl From<web::Json<UpdateCourseResponse>> for UpdateCourseResponse {   #3
              fn from(new_course: web::Json<UpdateCourseResponse>) -> Self {
                  UpdateCourseResponse {
                      tutor_id: new_course.tutor_id,
                      course_id: new_course.course_id,
                      course_name: new_course.course_name.clone(),
                      course_description: new_course.course_description.clone(),
                      course_format: new_course.course_format.clone(),
                      course_structure: new_course.course_structure.clone(),
                      course_duration: new_course.course_duration.clone(),
                      course_price: new_course.course_price,
                      course_language: new_course.course_language.clone(),
                      course_level: new_course.course_level.clone(),
                      posted_time: new_course.posted_time.clone(),
                  }
              }
          }

          您還會注意到,我們已經(jīng)定義了類似的數(shù)據(jù)結(jié)構(gòu),用于創(chuàng)建課程(NewCourse,NewCourseResponse)和更新課程(UpdateCourseUpdateCourseResponse)。 是否可以通過在創(chuàng)建和更新操作中重用相同的結(jié)構(gòu)來優(yōu)化?在實際項目場景中,可能會進行一些優(yōu)化。但是,為了編寫此示例代碼,我們假設(shè)創(chuàng)建新課程所需的必填字段集與更新課程所需的必填字段集不同(其中沒有必填字段)。此外,分離用于創(chuàng)建和更新操作的數(shù)據(jù)結(jié)構(gòu)可以在學習時更容易理解。

          接下來,讓我們重寫處理程序函數(shù)以更新 $PROJECT_ROOT/src/iter6/handler/course.rs 中的課程詳細信息。

          清單 9.10.用于更新課程的處理程序函數(shù)

          pub async fn handle_update_course(
              _tmpl: web::Data<tera::Tera>,
              _app_state: web::Data<AppState>,
              web::Path((tutor_id, course_id)): web::Path<(i32, i32)>,
              params: web::Json<UpdateCourse>,
          ) -> Result<HttpResponse, Error> {
              let update_course=json!({                 #1
                  "course_name": ?ms.course_name,
                  "course_description": ?ms.course_description,
                  "course_format": ?ms.course_format,
                  "course_duration": ?ms.course_duration,
                 "course_structure": ?ms.course_structure,
                  "course_price": ?ms.course_price,
                  "course_language": ?ms.course_language,
                  "course_level": ?ms.course_level,
          
              });
              let awc_client=awc::Client::default();    #2
              let update_url=format!("http://localhost:3000/courses/{}/{}",
              [CA]tutor_id, course_id);   #3
              let res=awc_client                #4
                  .put(update_url)
                  .send_json(&update_course)
                  .await
                  .unwrap()
                  .body()
                  .await?;
              let course_response: UpdateCourseResponse=serde_json::from_str(
              [CA]&std::str::from_utf8(&res)?)?; #5
          
              Ok(HttpResponse::Ok().json(course_response))
          
          }

          確保導入與更新相關(guān)的結(jié)構(gòu),如下所示:

          use crate::model::{NewCourse, NewCourseResponse, UpdateCourse, UpdateCourseResponse};

          從 $PROJECT_ROOT 構(gòu)建并運行 Web ssr 客戶端,如下所示:

          cargo run --bin iter6-ssr

          讓我們使用 curl 請求進行測試,以更新我們之前創(chuàng)建的課程。確保導師 Web 服務(wù)正在運行。在新終端中,運行以下命令。將導師 ID 和課程 ID 替換為之前創(chuàng)建的新課程的導師 ID 和課程 ID

          curl  -X PUT -d '{"course_name":"Rust advanced web development",
          [CA]"course_description":"Teaches how to write advanced web apps in Rust",
          [CA]"course_format":"Video", "course_duration":"4 hours",
          [CA]"course_price":100}' localhost:8080/courses/1/27 -H
          [CA]"Content-Type: application/json"

          通過在導師 Web 服務(wù)上運行 GET 請求來驗證課程詳細信息是否已更新:

          curl localhost:3000/courses/1

          注意:將 course_id:1 替換為您更新課程的tutor_id的正確值。

          您應(yīng)該會看到更新的課程詳細信息已反映。

          讓我們繼續(xù)刪除課程。

          9.7 使用 HTTP DELETE 方法刪除資源

          讓我們更新處理程序函數(shù)以刪除 $PROJECT_ROOT/src/iter6/handler/course.rs 中的課程。

          示例 9.11.用于刪除課程的處理程序函數(shù)

          pub async fn handle_delete_course(
              _tmpl: web::Data<tera::Tera>,
              _app_state: web::Data<AppState>,
              path: web::Path<(i32, i32)>,    #1
          ) -> Result<HttpResponse, Error> {
              let (tutor_id, course_id)=path.into_inner();
              let awc_client=awc::Client::default();                    #2
              let delete_url=format!("http://localhost:3000/courses/{}/{}",
              [CA]tutor_id, course_id);   #3
              let _res=awc_client.delete(delete_url).send().await.unwrap(); #4
              Ok(HttpResponse::Ok().body("Course deleted"))                   #5
          }

          從 $PROJECT_ROOT 生成并運行導師 Web 應(yīng)用,如下所示:

          cargo run --bin iter6-ssr

          運行刪除請求,如下所示:

          curl -X DELETE localhost:8080/courses/delete/1/19

          tutor_idcourse_id替換為您自己的。

          通過在導師 Web 服務(wù)上運行查詢來驗證課程是否已被刪除。

          curl localhost:3000/courses/1

          tutor_id替換為您自己的。您應(yīng)該看到該課程已在_tutor Web 服務(wù)中刪除。

          有了這個,我們已經(jīng)看到了如何從用 Rust 編寫的 Web 客戶端前端添加、更新和刪除課程。

          作為練習,讀者可以執(zhí)行以下附加任務(wù):

          1. 實現(xiàn)新路由以檢索導師的課程列表
          2. 創(chuàng)建用于創(chuàng)建、更新和刪除課程的 HTML/Tera 模板
          3. 為具有無效用戶輸入的情況添加其他錯誤處理。

          9.8 小結(jié)

          • 在本章中,我們學習了如何在 Rust 中構(gòu)建和編寫一個與后端 Web 服務(wù)通信的 Web 應(yīng)用程序項目。
          • 我們設(shè)計并實現(xiàn)了用戶身份驗證功能,允許用戶在 HTML 表單中輸入憑據(jù),然后將其存儲在本地數(shù)據(jù)庫中。還介紹了用戶輸入中錯誤的處理。
          • 我們討論了如何構(gòu)建項目并模塊化 Web 前端應(yīng)用程序的代碼,其中包括 HTTP 請求處理程序數(shù)據(jù)庫交互邏輯數(shù)據(jù)模型Web UI/Html 模板
          • 我們編寫了代碼來創(chuàng)建、更新刪除數(shù)據(jù)庫中的特定數(shù)據(jù),以響應(yīng) HTTP POSTPUTDELETE 方法請求。我們還了解如何提取作為 HTTP 請求的一部分發(fā)送的參數(shù)。
          • 我們學習了如何構(gòu)造 HTTP 請求以在后端 Web 服務(wù)上調(diào)用 API,以及如何解釋收到的響應(yīng),包括數(shù)據(jù)序列化和反序列化。
          • 總之,您已經(jīng)學習了如何在 Rust 中構(gòu)建一個 Web 應(yīng)用程序,該應(yīng)用程序可以與后端 Web 服務(wù)通信,與本地數(shù)據(jù)庫交互,并對數(shù)據(jù)執(zhí)行基本的創(chuàng)建、更新和刪除操作以響應(yīng)傳入的 HTTP 請求。

          至此,我們得出本章的結(jié)論,以及關(guān)于 Rust Web 應(yīng)用程序開發(fā)的這一部分。

          在下一章中,我們將介紹與 Rust 中的異步服務(wù)器相關(guān)的高級主題。

          下一章見。


          主站蜘蛛池模板: 国产精品亚洲一区二区在线观看| 99精品国产高清一区二区三区| 麻豆精品人妻一区二区三区蜜桃| 亚洲欧美日韩中文字幕一区二区三区 | 国产综合无码一区二区三区| 国内精品视频一区二区三区| 国产中的精品一区的| 日韩熟女精品一区二区三区| 久久无码人妻精品一区二区三区| 国产午夜精品一区二区三区嫩草 | 亚洲变态另类一区二区三区| 无码视频免费一区二三区| 国产精品无码一区二区三区在| 国产精品女同一区二区久久| 看电影来5566一区.二区| 99久久精品日本一区二区免费| 日韩精品一区二区三区老鸦窝| 国产精品被窝福利一区| 日韩一区二区三区无码影院 | 日韩精品中文字幕视频一区| 国产福利电影一区二区三区,亚洲国模精品一区 | 亚洲日韩国产一区二区三区在线| 国产一区二区三区在线电影| 日韩精品无码一区二区三区四区| 精品永久久福利一区二区| 成人h动漫精品一区二区无码| 一区二区日韩国产精品| 日本午夜精品一区二区三区电影| 相泽南亚洲一区二区在线播放| 国产美女视频一区| 国产美女一区二区三区| 成人精品一区二区三区中文字幕| 精品无码人妻一区二区三区品| 精品一区二区三区视频在线观看 | 日韩人妻一区二区三区蜜桃视频| 精品国产一区二区麻豆| 亚洲一区综合在线播放| 一区免费在线观看| 亚洲AV日韩综合一区| 亚洲AV无码一区二区二三区入口| 视频精品一区二区三区|