use axum::body::Body;
use axum::extract::{Path, Query, State};
use axum::http::Request;
use axum::response::Response;
use axum::routing::{get, post};
use axum::Router;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::sync::{Arc, Mutex};
use sz_rust_core::controller::{BaseController, SzController};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
id: i64,
name: String,
age: i32,
}
struct Store {
users: Vec<User>,
next_id: i64,
}
type SharedStore = Arc<Mutex<Store>>;
struct UserController;
impl SzController for UserController {}
impl BaseController for UserController {
fn middlewares(&self) -> Vec<String> {
vec!["cors".to_string()]
}
}
impl UserController {
async fn list(store: &SharedStore, page: i64, size: i64) -> Response {
let ctrl = UserController;
let users = store.lock().expect("锁被毒化").users.clone();
let total = users.len() as i64;
let start = (((page - 1) * size).max(0) as usize).min(users.len());
let end = (start + size as usize).min(users.len());
let page_list: Vec<Value> = users[start..end]
.iter()
.map(|u| serde_json::to_value(u).expect("序列化用户数据失败"))
.collect();
let data = json!({
"list": page_list,
"total": total,
"page": page,
"size": size,
});
ctrl.render_success("success", data)
}
async fn detail(store: &SharedStore, id: i64) -> Response {
let ctrl = UserController;
let user = store
.lock()
.expect("锁被毒化")
.users
.iter()
.find(|u| u.id == id)
.cloned();
match user {
Some(user) => {
let data = serde_json::to_value(&user).expect("序列化用户数据失败");
ctrl.render_success("success", data)
}
None => ctrl.render_error("用户不存在", json!({"id": id}), 0),
}
}
async fn create(store: &SharedStore, req: Request<Body>) -> Response {
let ctrl = UserController;
ctrl.initialize();
let data = match ctrl.post_data(req).await {
Ok(d) => d,
Err(e) => return ctrl.render_error("参数解析失败", json!({"error": e}), 0),
};
let name = data["name"].as_str().unwrap_or("").to_string();
let age = data["age"].as_i64().unwrap_or(0) as i32;
if name.is_empty() {
return ctrl.render_error("用户名不能为空", json!({"field": "name"}), 0);
}
if age <= 0 || age > 200 {
return ctrl.render_error("年龄必须在 1-200 之间", json!({"field": "age"}), 0);
}
let mut store = store.lock().expect("锁被毒化");
let user = User {
id: store.next_id,
name,
age,
};
store.next_id += 1;
store.users.push(user.clone());
drop(store);
let data = serde_json::to_value(&user).expect("序列化用户数据失败");
ctrl.render_success("创建成功", data)
}
async fn update(store: &SharedStore, id: i64, req: Request<Body>) -> Response {
let ctrl = UserController;
ctrl.initialize();
let data = match ctrl.post_data(req).await {
Ok(d) => d,
Err(e) => return ctrl.render_error("参数解析失败", json!({"error": e}), 0),
};
let mut store = store.lock().expect("锁被毒化");
match store.users.iter_mut().find(|u| u.id == id) {
Some(user) => {
if let Some(name) = data.get("name").and_then(|v| v.as_str()) {
user.name = name.to_string();
}
if let Some(age) = data.get("age").and_then(|v| v.as_i64()) {
user.age = age as i32;
}
let user = user.clone();
drop(store);
let data = serde_json::to_value(&user).expect("序列化用户数据失败");
ctrl.render_success("更新成功", data)
}
None => ctrl.render_error("用户不存在", json!({"id": id}), 0),
}
}
async fn delete(store: &SharedStore, id: i64) -> Response {
let ctrl = UserController;
let mut store = store.lock().expect("锁被毒化");
match store.users.iter().position(|u| u.id == id) {
Some(idx) => {
let user = store.users.remove(idx);
drop(store);
let data = serde_json::to_value(&user).expect("序列化用户数据失败");
ctrl.render_success("删除成功", data)
}
None => ctrl.render_error("用户不存在", json!({"id": id}), 0),
}
}
}
#[derive(Deserialize)]
struct ListQuery {
#[serde(default = "default_page")]
page: i64,
#[serde(default = "default_size")]
size: i64,
}
fn default_page() -> i64 {
1
}
fn default_size() -> i64 {
10
}
async fn list_handler(
State(store): State<SharedStore>,
Query(query): Query<ListQuery>,
) -> Response {
UserController::list(&store, query.page, query.size).await
}
async fn detail_handler(State(store): State<SharedStore>, Path(id): Path<i64>) -> Response {
UserController::detail(&store, id).await
}
async fn create_handler(State(store): State<SharedStore>, req: Request<Body>) -> Response {
UserController::create(&store, req).await
}
async fn update_handler(
State(store): State<SharedStore>,
Path(id): Path<i64>,
req: Request<Body>,
) -> Response {
UserController::update(&store, id, req).await
}
async fn delete_handler(State(store): State<SharedStore>, Path(id): Path<i64>) -> Response {
UserController::delete(&store, id).await
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
let store: SharedStore = Arc::new(Mutex::new(Store {
users: vec![
User {
id: 1,
name: "张三".to_string(),
age: 28,
},
User {
id: 2,
name: "李四".to_string(),
age: 35,
},
User {
id: 3,
name: "王五".to_string(),
age: 42,
},
],
next_id: 4,
}));
let router = Router::new()
.route("/user/list", get(list_handler))
.route("/user/detail/{id}", get(detail_handler))
.route("/user/create", post(create_handler))
.route("/user/update/{id}", post(update_handler))
.route("/user/delete/{id}", post(delete_handler))
.with_state(store);
let addr = "127.0.0.1:9528";
let listener = tokio::net::TcpListener::bind(addr).await?;
tracing::info!("CRUD 示例服务监听 http://{}/", addr);
tracing::info!("端点:");
tracing::info!(" GET /user/list?page=1&size=10");
tracing::info!(" GET /user/detail/{{id}}");
tracing::info!(" POST /user/create body: {{\"name\":\"...\",\"age\":...}}");
tracing::info!(" POST /user/update/{{id}} body: {{\"name\":\"...\",\"age\":...}}");
tracing::info!(" POST /user/delete/{{id}}");
axum::serve(listener, router).await?;
Ok(())
}