返回
Rust全栈开发——带实例的完整教程:从基础到精通
后端
2024-01-08 12:17:38
Rust全栈开发——带实例的完整教程
Rust是一种多范式系统编程语言,以其安全性、性能和可靠性而著称。近年来,Rust在Web开发领域也越来越受欢迎,因为它可以构建高性能、安全可靠的Web服务和应用程序。
本教程将指导您使用Rust构建一个完整的Web应用,从后端到前端,涵盖Rust网络服务、Rust前端应用、Rust CRUD操作、Rust Yew、Rust Warp、Rust Rocket等内容。
先决条件
在开始本教程之前,您需要确保已经安装了以下软件:
- Rust
- Cargo
- Node.js
- npm
项目结构
我们的项目结构如下:
├── backend
│ ├── Cargo.toml
│ ├── src
│ │ ├── main.rs
│ │ ├── routes.rs
│ │ ├── models.rs
│ │ ├── db.rs
│ └── package.json
├── frontend
│ ├── Cargo.toml
│ ├── src
│ │ ├── main.rs
│ │ ├── components
│ │ │ ├── todo_list.rs
│ │ │ ├── todo_item.rs
│ │ │ ├── add_todo.rs
│ │ │ └── filter_todos.rs
│ │ ├── pages
│ │ │ ├── home.rs
│ │ │ ├── todos.rs
│ │ │ └── not_found.rs
│ │ ├── App.js
│ │ ├── index.html
│ │ └── package.json
└── package.json
后端
后端使用Rust编写,并使用Warp框架构建Web服务。
安装依赖项
cd backend
cargo install warp
创建项目
cargo new rust-todo-api
添加依赖项
在Cargo.toml
文件中添加以下依赖项:
[dependencies]
warp = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
创建模型
在src/models.rs
文件中创建模型:
#[derive(Serialize, Deserialize)]
pub struct Todo {
id: i32,
title: String,
completed: bool,
}
创建数据库
在src/db.rs
文件中创建数据库:
use std::collections::HashMap;
pub struct Db {
todos: HashMap<i32, Todo>,
}
impl Db {
pub fn new() -> Self {
Self {
todos: HashMap::new(),
}
}
pub fn get_all_todos(&self) -> Vec<&Todo> {
self.todos.values().collect()
}
pub fn get_todo(&self, id: i32) -> Option<&Todo> {
self.todos.get(&id)
}
pub fn add_todo(&mut self, todo: Todo) -> i32 {
let id = self.todos.len() as i32 + 1;
self.todos.insert(id, todo);
id
}
pub fn update_todo(&mut self, id: i32, todo: Todo) {
self.todos.insert(id, todo);
}
pub fn delete_todo(&mut self, id: i32) {
self.todos.remove(&id);
}
}
创建路由
在src/routes.rs
文件中创建路由:
use warp::{Filter, reply};
use crate::models::Todo;
use crate::db::Db;
pub fn routes(db: Db) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> {
let todos = warp::path("todos");
todos.and(warp::get()).map(move || {
let todos = db.get_all_todos();
warp::reply::json(&todos)
})
.or(todos.and(warp::post()).and(warp::body::json()).map(move |todo: Todo| {
let id = db.add_todo(todo);
warp::reply::json(&id)
}))
.or(todos.and(warp::path::param::<i32>()).and(warp::get()).map(move |id| {
let todo = db.get_todo(id).unwrap();
warp::reply::json(&todo)
}))
.or(todos.and(warp::path::param::<i32>()).and(warp::put()).and(warp::body::json()).map(move |id, todo: Todo| {
db.update_todo(id, todo);
warp::reply::json(&todo)
}))
.or(todos.and(warp::path::param::<i32>()).and(warp::delete()).map(move |id| {
db.delete_todo(id);
warp::reply::json(&())
}))
}
创建主函数
在src/main.rs
文件中创建主函数:
use warp::Filter;
use crate::routes;
use crate::db::Db;
#[tokio::main]
async fn main() {
let db = Db::new();
let routes = routes(db);
warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}
前端
前端使用Rust编写,并使用Yew框架构建Web应用程序。
安装依赖项
cd frontend
cargo install yew
创建项目
cargo new rust-todo-app
添加依赖项
在Cargo.toml
文件中添加以下依赖项:
[dependencies]
yew = "0.19"
创建应用程序
在src/main.rs
文件中创建应用程序:
use yew::prelude::*;
struct App {
todos: Vec<String>,
}
impl Component for App {
type Message = ();
fn create(_: &Context<Self>) -> Self {
Self {
todos: vec![],
}
}
fn update(&mut self, _: &Context<Self>, _: Self::Message) -> bool {
false
}
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div>
<h1>Todo List</h1>
<ul>
{ for self.todos.iter().map(|todo| html! { <li>{ todo }</li> }) }
</ul>
<button onclick={ ctx.link().callback(|_| ()) }>Add Todo</button>
</div>
}
}
}
fn main() {
yew::start_app::<App>();
}
创建组件
在src/components
目录中创建组件:
// todo_list.rs
use yew::prelude::*;
#[function_component(TodoList)]
pub fn todo_list(props: &Props<()>) -> Html {
html! {
<ul>
{ for props.todos.iter().map(|todo| html! { <li>{ todo }</li> }) }
</ul>
}
}
// todo_item.rs
use yew::prelude::*;
#[function_component(TodoItem)]
pub fn todo_item(props: &Props<String>) -> Html {
html! {
<li>{ &props.0 }</li>
}
}
// add_todo.rs
use yew::prelude::*;
#[function_component(AddTodo)]
pub fn add_todo(props: &Props<()>) -> Html {
html! {
<button onclick={ props.callback(|_| ()) }>Add Todo</button>
}
}
// filter_todos.rs
use yew::prelude::*;
#[function_component(FilterTodos)]
pub fn filter_todos(props: &Props<()>) -> Html {
html! {
<div>
<label for="all">All</label>
<input type="radio" id="all" name="filter" />
<label