博客系统 #

项目结构 #

text
blog-project/
├── Cargo.toml
├── src/
│   ├── main.rs
│   ├── models/
│   │   ├── mod.rs
│   │   ├── user.rs
│   │   ├── post.rs
│   │   └── comment.rs
│   ├── handlers/
│   │   ├── mod.rs
│   │   ├── auth.rs
│   │   ├── post.rs
│   │   └── comment.rs
│   └── repository/
│       └── mod.rs
└── templates/
    ├── base.html
    ├── index.html
    └── post.html

核心模型 #

rust
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Post {
    id: u32,
    title: String,
    content: String,
    author_id: u32,
    created_at: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Comment {
    id: u32,
    post_id: u32,
    author_id: u32,
    content: String,
    created_at: String,
}

#[derive(Deserialize)]
struct CreatePost {
    title: String,
    content: String,
}

#[derive(Deserialize)]
struct CreateComment {
    content: String,
}

处理函数 #

rust
use actix_web::{web, HttpResponse, Responder};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

struct AppState {
    posts: Mutex<HashMap<u32, Post>>,
    comments: Mutex<HashMap<u32, Vec<Comment>>>,
    next_post_id: Mutex<u32>,
    next_comment_id: Mutex<u32>,
}

#[actix_web::get("/posts")]
async fn list_posts(state: web::Data<Arc<AppState>>) -> impl Responder {
    let posts = state.posts.lock().unwrap();
    let posts: Vec<&Post> = posts.values().collect();
    HttpResponse::Ok().json(posts)
}

#[actix_web::post("/posts")]
async fn create_post(
    body: web::Json<CreatePost>,
    state: web::Data<Arc<AppState>>,
) -> impl Responder {
    let mut next_id = state.next_post_id.lock().unwrap();
    let id = *next_id;
    *next_id += 1;
    
    let post = Post {
        id,
        title: body.title.clone(),
        content: body.content.clone(),
        author_id: 1,
        created_at: chrono::Utc::now().to_rfc3339(),
    };
    
    state.posts.lock().unwrap().insert(id, post.clone());
    HttpResponse::Created().json(post)
}

#[actix_web::get("/posts/{id}")]
async fn get_post(
    path: web::Path<u32>,
    state: web::Data<Arc<AppState>>,
) -> impl Responder {
    let posts = state.posts.lock().unwrap();
    match posts.get(&path.into_inner()) {
        Some(post) => HttpResponse::Ok().json(post),
        None => HttpResponse::NotFound().finish(),
    }
}

#[actix_web::post("/posts/{id}/comments")]
async fn add_comment(
    path: web::Path<u32>,
    body: web::Json<CreateComment>,
    state: web::Data<Arc<AppState>>,
) -> impl Responder {
    let post_id = path.into_inner();
    
    let mut next_id = state.next_comment_id.lock().unwrap();
    let id = *next_id;
    *next_id += 1;
    
    let comment = Comment {
        id,
        post_id,
        author_id: 1,
        content: body.content.clone(),
        created_at: chrono::Utc::now().to_rfc3339(),
    };
    
    state.comments.lock().unwrap()
        .entry(post_id)
        .or_insert_with(Vec::new)
        .push(comment.clone());
    
    HttpResponse::Created().json(comment)
}

主函数 #

rust
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let state = Arc::new(AppState {
        posts: Mutex::new(HashMap::new()),
        comments: Mutex::new(HashMap::new()),
        next_post_id: Mutex::new(1),
        next_comment_id: Mutex::new(1),
    });
    
    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(state.clone()))
            .service(list_posts)
            .service(create_post)
            .service(get_post)
            .service(add_comment)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

恭喜完成! #

你已经完成了 Actix Web 框架的学习之旅!现在你已经掌握了:

  • 基础入门和项目结构
  • 路由系统和动态路由
  • 请求处理和响应处理
  • 中间件和错误处理
  • 状态管理和数据库集成
  • 安全特性和 WebSocket
  • 测试、部署和性能优化
  • 完整的实战项目

继续实践,构建更多精彩的应用!

最后更新:2026-03-29