访问users数据库

This commit is contained in:
2025-09-05 15:10:30 +08:00
parent 7570bfd50b
commit f567e66485
6 changed files with 1266 additions and 70 deletions

2
.env Normal file
View File

@@ -0,0 +1,2 @@
# .env
DATABASE_URL=postgres://milkydata:44n6FdB8CdDAk5rk@154.37.213.24:5432/milkydata

1158
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,4 +5,7 @@ edition = "2024"
[dependencies]
actix-web = "4.11.0"
serde = "1.0.219"
chrono = "0.4.41"
dotenvy = "0.15.7"
serde = { version = "1.0.219", features = ["derive"] }
sqlx = { version = "0.8.6", features = ["runtime-tokio-rustls", "postgres", "chrono", "uuid"] }

10
src/db.rs Normal file
View File

@@ -0,0 +1,10 @@
use sqlx::postgres::PgPool; // 修改导入路径
use std::env;
pub async fn create_pool() -> Result<PgPool, sqlx::Error> {
dotenvy::dotenv().ok();
let database_url = env::var("DATABASE_URL")
.expect("DATABASE_URL must be set in .env file");
PgPool::connect(&database_url).await
}

View File

@@ -1,61 +1,98 @@
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
use serde::{Deserialize, Serialize};
use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use models::User;
use db::create_pool;
use sqlx::postgres::PgPool;
// 定义响应数据结构
#[derive(Serialize)]
struct GreetingResponse {
message: String,
mod models;
mod db;
#[get("/users")]
async fn get_users(pool: web::Data<PgPool>) -> impl Responder {
let query = r#"
SELECT id, "name", openid, phone, "type", "desc"
FROM users
LIMIT 10
"#;
let result = sqlx::query_as::<_, User>(query)
.fetch_all(pool.get_ref())
.await;
match result {
Ok(users) => {
println!("Successfully fetched {} users", users.len());
HttpResponse::Ok().json(users)
},
Err(e) => {
eprintln!("Database error: {}", e);
HttpResponse::InternalServerError().body(format!("Database error: {}", e))
}
}
}
// 定义请求数据结构
#[derive(Deserialize)]
struct UserRequest {
name: String,
age: u8,
}
// 健康检查端点
#[get("/health")]
async fn health_check() -> impl Responder {
HttpResponse::Ok().body("Service is healthy")
}
// 根路径处理
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("Welcome to Rust Web Backend!")
}
// 带参数的问候端点
#[get("/greet/{name}")]
async fn greet(name: web::Path<String>) -> impl Responder {
let response = GreetingResponse {
message: format!("Hello, {}!", name),
};
HttpResponse::Ok().json(response)
}
// POST 请求处理
#[post("/user")]
async fn create_user(user: web::Json<UserRequest>) -> impl Responder {
let response = GreetingResponse {
message: format!("Created user: {} (age {})", user.name, user.age),
};
HttpResponse::Created().json(response)
// 创建服务器配置的函数
fn create_server_config(pool: PgPool) -> App<impl actix_web::dev::ServiceFactory<
actix_web::dev::ServiceRequest,
Config = (),
Response = actix_web::dev::ServiceResponse,
Error = actix_web::Error,
InitError = (),
>> {
App::new()
.app_data(web::Data::new(pool))
.service(get_users)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Starting server at http://localhost:80");
// 初始化数据库连接池
let pool = match create_pool().await {
Ok(pool) => pool,
Err(e) => {
eprintln!("Failed to create database pool: {}", e);
eprintln!("Please check your database connection configuration in .env file");
std::process::exit(1);
}
};
HttpServer::new(|| {
App::new()
.service(health_check)
.service(index)
.service(greet)
.service(create_user)
})
.bind("0.0.0.0:80")?
.run()
.await
println!("Attempting to start server...");
// 尝试多个端口
let ports = vec![8080, 3000, 8000, 8888];
let mut server = None;
for port in ports {
let addr = format!("127.0.0.1:{}", port);
println!("Trying to bind to {}", addr);
// 为每个服务器创建克隆的连接池
let pool_clone = pool.clone();
match HttpServer::new(move || create_server_config(pool_clone.clone()))
.bind(&addr) {
Ok(s) => {
println!("Successfully bound to {}", addr);
server = Some(s);
break;
}
Err(e) => {
eprintln!("Failed to bind to {}: {}", addr, e);
if e.kind() == std::io::ErrorKind::PermissionDenied {
eprintln!(" -> Permission denied. Try running with sudo or use a port > 1024");
}
continue;
}
}
}
match server {
Some(s) => {
println!("Server started successfully");
s.run().await
}
None => {
eprintln!("Failed to bind to any port. Please check your system configuration.");
std::process::exit(1);
}
}
}

20
src/models.rs Normal file
View File

@@ -0,0 +1,20 @@
use serde::Serialize;
use sqlx::FromRow;
#[derive(Debug, Serialize, FromRow)]
pub struct User {
pub id: i32,
#[serde(rename = "name")]
#[sqlx(rename = "name")]
pub name: String,
#[sqlx(rename = "openid")]
pub openid: Option<String>,
#[sqlx(rename = "phone")]
pub phone: Option<String>,
#[serde(rename = "type")]
#[sqlx(rename = "type")]
pub user_type: i32,
#[serde(rename = "desc")]
#[sqlx(rename = "desc")]
pub description: Option<String>,
}