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)模板,相信它會給你帶來驚喜!
在上一章中,我們研究了導師的注冊。您可能還記得,當用戶注冊為導師時,有關(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ù)主要留給讀者作為練習。
讓我們首先從導師登錄(身份驗證)功能開始。
對于導師登錄,我們將接受兩個字段 - 用戶名和密碼,并使用它來向 Web 應(yīng)用程序驗證導師。
圖 1 顯示了導師登錄窗體。
圖 9.1.導師登錄表單
現(xiàn)在,讓我們看一下圖 2 中導師登錄的工作流。請注意,圖 2 中的術(shù)語 Actix Web 服務(wù)器是指前端 Web 應(yīng)用程序服務(wù)器,而不是后端導師 Web 服務(wù)。
圖 9.2.導師登錄流
現(xiàn)在我們已經(jīng)清楚了本章將要開發(fā)的內(nèi)容,讓我們設(shè)置項目代碼結(jié)構(gòu)和基本腳手架。
首先克隆第 8 章中的 ezytutors 存儲庫。
然后,讓我們將PROJECT_ROOT環(huán)境變量設(shè)置為 /path-to-folder/ezytutors/tutor-web-app-ssr。此后,我們將此文件夾稱為 $PROJECT_ROOT。
讓我們在項目根目錄下組織代碼,如下所示:
還要確保為 HOST_PORT 和DATABASE_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)在可以開始編寫用于登錄用戶的代碼。
定義路由和數(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)存在于同一個文件夾中。
<!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。這將在用戶成功登錄后顯示。
<!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ù):
#[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ù)。
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ù)管理課程詳細信息。
在本節(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,如下所示:
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ù)。
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
要測試 POST 、PUT 和 DELETE 請求,請從命令行嘗試以下操作:
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ù)中為導師添加課程的實際邏輯。
在本部分中,我們將通過向后端導師 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)容:
#[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ù),如下所示:
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ù)來更新課程。
讓我們在 $PROJECT_ROOT/src/iter6/model.rs 文件中編寫用于更新課程的數(shù)據(jù)結(jié)構(gòu)。
// 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)和更新課程(UpdateCourse,UpdateCourseResponse)。 是否可以通過在創(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 中的課程詳細信息。
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ù)刪除課程。
讓我們更新處理程序函數(shù)以刪除 $PROJECT_ROOT/src/iter6/handler/course.rs 中的課程。
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_id和course_id替換為您自己的。
通過在導師 Web 服務(wù)上運行查詢來驗證課程是否已被刪除。
curl localhost:3000/courses/1
將tutor_id替換為您自己的。您應(yīng)該看到該課程已在_tutor Web 服務(wù)中刪除。
有了這個,我們已經(jīng)看到了如何從用 Rust 編寫的 Web 客戶端前端添加、更新和刪除課程。
作為練習,讀者可以執(zhí)行以下附加任務(wù):
至此,我們得出本章的結(jié)論,以及關(guān)于 Rust Web 應(yīng)用程序開發(fā)的這一部分。
在下一章中,我們將介紹與 Rust 中的異步服務(wù)器相關(guān)的高級主題。
下一章見。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。