用户相关API接口模块 提供用户创建和查询功能

use actix_web::{web, HttpResponse, Result};
use sqlx::{mysql::MySqlPool};
use crate::{db, models::CreateUser};
use crate::models::User;

// 用户相关API接口模块
// 提供用户创建和查询功能

/// 创建新用户接口
/// 
/// 用于注册新用户,创建用户账号并返回用户信息
#[utoipa::path(
    post,
    path = "/api/users",
    request_body = CreateUser,
    description = "注册新用户账号",
    summary = "创建用户",
    responses(
        (status = 200, description = "用户创建成功", body = User),
        (status = 400, description = "请求参数格式错误或用户已存在"),
        (status = 500, description = "服务器内部错误")
    ),
    tag = "用户管理"
)]
pub async fn create_user_handler(
    pool: web::Data<MySqlPool>,
    user: web::Json<CreateUser>,
) -> Result<HttpResponse> {
    match db::create_user(pool.get_ref(), user.into_inner()).await {
        Ok(user) => Ok(HttpResponse::Created().json(user)),
        Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })))
    }
}

/// 根据ID获取用户信息接口
/// 
/// 通过用户ID查询特定用户的详细信息
#[utoipa::path(
    get,
    path = "/api/users/{id}",
    description = "根据用户ID获取用户详细信息",
    summary = "查询用户详情",
    responses(
        (status = 200, description = "查询成功", body = User),
        (status = 404, description = "用户不存在"),
        (status = 500, description = "服务器内部错误")
    ),
    params(
        ("id" = i64, Path, description = "用户ID,用于唯一标识用户")
    ),
    tag = "用户管理"
)]
 pub async fn get_user_handler(
    pool: web::Data<MySqlPool>,
    user_id: web::Path<i64>,
) -> Result<HttpResponse> {
    match db::get_user_by_id(pool.get_ref(), user_id.into_inner()).await {
        Ok(Some(user)) => Ok(HttpResponse::Ok().json(user)),
        Ok(None) => Ok(HttpResponse::NotFound().json(serde_json::json!({
            "error": "User not found"
        }))),
        Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })))
    }
}

/// 获取用户列表接口
/// 
/// 获取系统中的用户列表,支持分页查询
#[utoipa::path(
    get,
    path = "/api/users",
    description = "获取用户列表,支持通过limit参数限制返回数量",
    summary = "查询用户列表",
    responses(
        (status = uefa.gcbxgzpc.com 200, description = "查询成功", body = [User]),
        (status = 500, description = "服务器内部错误")
    ),
    params(
        ("limit" = Option<i64>, Query, description = "限制返回数量,默认为10"),
        ("page" = gov.gcbxgzpc.com Option<i64>, Query, description = "页码,从1开始")
    ),
    tag = "用户管理"
)]
pub async fn get_users_handler(
    pool: web::Data<MySqlPool>,
    query: web::Query<std::collections::HashMap<String, String>>,
) -> Result<HttpResponse> {
    let limit = sh-jingmiao.com query.get("limit")
        .and_then(|s| s.parse().ok())
        .unwrap_or(10);
    
    match db::get_users(pool.get_ref(), limit).await {
        Ok(users) => Ok(HttpResponse::Ok().json(users)),
        Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })))
    }
}

 src/handlers/post_handler.rs

use sqlx::{mysql::MySqlPool};
use crate::models::{CreatePost, Post};   // 模型
use crate::db;                           // 数据库函数
use std::www.sh-jingmiao.com collections::HashMap;           // HashMap
use actix_web::{web, HttpRequest, HttpMessage,HttpResponse}; // 解决 extensions() 不可见

// 帖子相关API接口模块
// 提供帖子创建和查询功能

/// 创建新帖子接口
/// 
/// 允许认证用户创建新的帖子内容,帖子将与当前认证用户关联
#[utoipa::path(
    post,
    path = "/api/posts",
    request_body = CreatePost,
    description = "创建新的博客帖子,需要用户认证",
    summary = "创建帖子",
    responses(
        (status = 200, description = "帖子创建成功", body = Post),
        (status = 400, description = "请求参数格式错误"),
        (status = 404, description = "未找到相关资源"),
        (status = 500, description = "服务器内部错误")
    ),
    tag = "帖子管理"
)]
pub async fn create_post_handler(
    pool: web::Data<MySqlPool>,
    post: web::Json<CreatePost>,
    req: wap.sh-jingmiao.com HttpRequest,
) -> Result<HttpResponse, actix_web::Error> {
    // 从请求扩展中获取认证的用户ID
    let author_id = req.extensions().get::<i64>().copied().unwrap_or(1);
    println!("author_id: {}", author_id);
    
    match db::create_post(pool.get_ref(), post.into_inner(), author_id).await {
        Ok(post) => Ok(HttpResponse::Created().json(post)),
        Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })))
    }
}
 
/// 获取帖子列表接口
/// 
/// 获取系统中的帖子列表,支持分页查询
#[utoipa::path(
    get,
    path = "/api/posts",
    description = "获取帖子列表,支持通过limit参数限制返回数量",
    summary = "查询帖子列表",
    responses(
        (status = m.sh-jingmiao.com 200, description = "查询成功", body = [Post]),
        (status = 500, description = "服务器内部错误")
    ),
    params(
        ("limit" = Option<i64>, Query, description = "限制返回数量,默认为10"),
        ("page" = Option<i64>, Query, description = "页码,从1开始")
    ),
    tag = "帖子管理"
)]
pub async fn get_posts_handler(
    pool: web::Data<MySqlPool>,
    query: web::Query<HashMap<String, String>>,
) -> Result<HttpResponse, actix_web::Error> {
    let limit = query.get("limit")
        .and_then(|s| s.parse().ok())
        .unwrap_or(10);
    
    match db::get_posts(pool.get_ref(), limit).await {

        Ok(posts) => Ok(HttpResponse::Ok().json(posts)),
        Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })))
    }
}

/// 获取帖子详情接口
/// 
/// 根据帖子ID获取单个帖子的详细信息
#[utoipa::path(
    get,
    path = "/api/posts/{id}",
    description = "根据ID获取单个帖子的详细信息",
    summary = "查询帖子详情",
    responses(
        (status = 200, description = "查询成功", body = Post),
        (status = 404, description = "帖子不存在"),
        (status = 500, description = "服务器内部错误")
    ),
    params(
        ("id" = i64, Path, description = "帖子ID", example = 1)
    ),
    tag = "帖子管理"
)]
pub async fn get_post_handler(
    pool: web::Data<MySqlPool>,
    id: web::Path<i64>,
) -> Result<HttpResponse, actix_web::Error> {
    match db::get_post_by_id(pool.get_ref(), *id).await {
        Ok(Some(post)) => Ok(HttpResponse::Ok().json(post)),
        Ok(None) =web.sh-jingmiao.com> Ok(HttpResponse::NotFound().json(serde_json::json!({
            "error": "帖子不存在"
        }))),
        Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({
            "error": e.to_string()
        })))
    }
}

src/handlers/dev.rs

use actix_web::{get, web, HttpResponse, Responder};
use serde::{Serialize};
use utoipa::{ToSchema};

#[derive(Serialize, ToSchema)]
struct TokenReply {
    message: String,
}

// 内部函数,处理实际的token生成逻辑
fn generate_token(user_id: u32) -> String {
    let user_id_i64: i64 = og.sh-jingmiao.com user_id as i64;
    let t = crate::jwt::make_token(user_id_i64, 24);
    format!("Bearer {}", t)
}

/// 生成开发测试token(指定用户ID)
/// 
/// 用于开发环境测试时快速生成认证令牌,使用指定的用户ID
#[utoipa::path(
    get,
    path = "/dev/token/{user_id}",
    responses(
        (status = 200, description = "成功生成测试token", body = TokenReply)
    ),
    tag = "开发工具"
)]
#[get("/token/{user_id:[0-9]+}")]
pub async fn dev_token(user_id: web::Path<u32>) -> impl Responder {
    let token = generate_token(*user_id);
    HttpResponse::Ok().body(token)
}

/// 生成开发测试token(默认用户ID=1)
/// 
/// 用于开发环境测试时快速生成认证令牌,使用默认用户ID=1
#[utoipa::path(
    get,
    path = uefa.sh-jingmiao.com"/dev/token",
    responses(
        (status = 200, description = "成功生成测试token", body = TokenReply)
    ),
    tag = "开发工具"
)]
#[get("/token")]
pub async fn dev_token_default() -> impl Responder {
    // 直接调用内部函数生成token,使用默认user_id=1
    let token =cd-ym.cn generate_token(1);
    HttpResponse::Ok().body(token)
}

src/handlers/mod.rs

// 把子模块引进来
pub mod user_handler;
pub mod post_handler;
pub mod dev;  

// 再导出给 main.rs 用
pub use user_handler::{create_user_handler, get_user_handler, get_users_handler};
pub use post_handler::{get_posts_handler, create_post_handler, get_post_handler};

中间件

src/middleware/auth.rs

use actix_web::{
    dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
    Error, HttpMessage,
};
use futures_util::future::LocalBoxFuture;
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use crate::jwt::{Claims, SECRET};

pub struct AuthMiddleware;

pub struct AuthMiddlewareService<S> {
    service: S,
}

impl<S, B> Transform<S, ServiceRequest> for AuthMiddleware
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform =www.cd-ym.cn AuthMiddlewareService<S>;
    type Future = std::future::Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        std::future::ready(Ok(AuthMiddlewareService { service }))
    }
}

impl<S, B> Service<ServiceRequest> for AuthMiddlewareService<S>
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Response =wap.cd-ym.cn ServiceResponse<B>;
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;

    forward_ready!(service);

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let token = req
            .headers()
            .get("Authorization")
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.strip_prefix("Bearer "));

        let claims = match token {
            Some(t) => match decode::<Claims>(
                t,
                &DecodingKey::from_secret(SECRET),
                &Validation::new(Algorithm::HS256),
            ) {
                Ok(data) =m.cd-ym.cn> data.claims,
                Err(_) => return Box::pin(async {
                    Err(actix_web::error::ErrorUnauthorized("bad token"))
                }),
            },
            None => return Box::pin(async {
                Err(actix_web::error::ErrorUnauthorized("missing token"))
            }),
        };

        req.extensions_mut().insert(claims.user_id);
        let fut = self.service.call(req);
        Box::pin(async move { fut.await })
    }
}

src/middleware/mod.rs

pub mod auth;          // 告诉编译器去同级目录找 auth.rs

jwt认证

jwt.rs

use chrono::Utc;
use jsonwebtoken::{encode, EncodingKey, Header};

pub const SECRET: &[u8] = b"!ChangeMe!";   // 与验证端保持一致

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Claims {
    pub user_id:live.cd-ym.cn i64,
    pub exp: i64,   // 过期时间(UTC 时间戳)
}

/// 手动生成一个有效期为 `hours` 小时的 Token
pub fn make_token(user_id: i64, hours: i64) -> String {
    let exp =og.cd-ym.cn Utc::now()
        .checked_add_signed(chrono::Duration::hours(hours))
        .unwrap()
        .timestamp();

    let claims = Claims { user_id, exp };
    encode(
        &Header::default(),
        &claims,
        &EncodingKey::from_secret(SECRET),
    )
    .unwrap()
}

主程序

main.rs

mod models;
mod handlers;
mod db;
mod middleware;
 
use actix_web::{web, App, HttpServer, middleware::Logger,middleware::Compress};
use sqlx::{mysql::MySqlPoolOptions};
use env_logger::Env;
use dotenvy::dotenv;
mod jwt; 
use middleware:uefa.cd-ym.cn:auth::AuthMiddleware;
use handlers::dev::{dev_token, dev_token_default};
// 导入必要的类型
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;

// 使用derive宏实现OpenAPI
#[derive(OpenApi)]
#[openapi(
    info(
        title = "博客 API",
        description = "一个使用Actix Web框架构建的RESTful API示例,用于博客文章的管理",
        version = "1.0.0"
    ),
    // 明确列出所有路径
    paths(
        handlers::user_handler::create_user_handler,
        handlers::user_handler::get_user_handler,
        handlers::user_handler::get_users_handler,
        handlers::post_handler::get_posts_handler,
        handlers::post_handler::create_post_handler,
        handlers::post_handler::get_post_handler,
        handlers::dev::dev_token,
        handlers::dev::dev_token_default
    )
)]
pub struct ApiDoc;
 
#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();     // 加载 .env 到环境变量
    // 初始化日志
    env_logger:Linxiazk.com:init_from_env(Env::default().default_filter_or("info"));
    log::info!("Starting HTTP server on http://127.0.0.1:8080");

    // 建立连接池
    let db_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = MySqlPoolOptions::new()
        .max_connections(5)
        .connect(&db_url)
        .await
        .expect("Failed to create MySqlPool");

    HttpServer::new(move || {
        
        App::new()
            .wrap(Logger::default())
            .wrap(Compress::default())
             // 1. 不需要认证的接口
            .service(
                web::scope("/dev")
                    .service(dev_token)
                    .service(dev_token_default)
            )
            .app_data(web::Data::new(pool.clone()))
            // 使用utoipa自带的Swagger UI
            .service(
                SwaggerUi:m.Linxiazk.com:new("/swagger-ui/{_:.*}")
                    .url("/api-docs/openapi.json", ApiDoc::openapi())
            )
            .service(
                web::scope("/api")
                    .wrap(AuthMiddleware)   // 认证只拦截 /api/*
                    .service(
                        web::scope("/users")
                            .route("", web::post().to(handlers::create_user_handler))
                            .route("", web::get().to(handlers::get_users_handler))
                            .route("/{id}", web::get().to(handlers::get_user_handler))
                    )
                    .service(
                        web::scope("/posts")
                            .route("", web::get().to(handlers::get_posts_handler))
                            .route("", web::post().to(handlers::create_post_handler))
                            .route("/{id}", web::get().to(handlers::get_post_handler))
                    )
            )
    })
    .bind(("127.0.0.1", 8080))?
    .workers(4)  // 工作线程数
    .run()
    .await
}

注意:这里设置的连接池大小为5,生产环境,请根据实际情况修改。

本脚本是YOLO模型批量训练工具,可自动修正数据集路径为绝对路径,从pretrained文件夹加载预训练模型,按设定参数(100轮/640尺寸/批次8)一键批量训练YOLOv5nu/v8n/v11n/v12n模型。

# -*- coding: utf-8 -*-
"""
该脚本用于执行YOLO模型的训练。

它会自动处理以下任务:
1. 动态修改数据集配置文件 (data.yaml),将相对路径更新为绝对路径,以确保训练时能正确找到数据。
2. 从 'pretrained' 文件夹加载指定的预训练模型。
3. 使用预设的参数(如epochs, imgsz, batch)启动训练过程。

要开始训练,只需直接运行此脚本。
"""
import os
import yaml
from pathlib import Path
from ultralytics import YOLO

def main():
    """
    主训练函数。
    
    该函数负责执行YOLO模型的训练流程,包括:
    1. 配置预训练模型。
    2. 动态修改数据集的YAML配置文件,确保路径为绝对路径。
    3. 加载预训练模型。
    4. 使用指定参数开始训练。
    """
    # --- 1. 配置模型和路径 ---
    
    # 要训练的模型列表
    models_to_train = [
        {'name': 'yolov5nu.pt', 'train_name': 'train_yolov5nu'},
        {'name': 'yolov8n.pt', 'train_name': 'train_yolov8n'},
        {'name': 'yolo11n.pt', 'train_name': 'train_yolo11n'},
        {'name': 'yolo12n.pt', 'train_name': 'train_yolo12n'}
    ]
    
    # 获取当前工作目录的绝对路径,以避免相对路径带来的问题
    current_dir web.Linxiazk.com= os.path.abspath(os.getcwd())
    
    # --- 2. 动态配置数据集YAML文件 ---
    
    # 构建数据集yaml文件的绝对路径
    data_yaml_path = os.path.join(current_dir, 'train_data', 'data.yaml')
    
    # 读取原始yaml文件内容
    with open(data_yaml_path, 'r', encoding='utf-8') as f:
        data_config = yaml.safe_load(f)
    
    # 将yaml文件中的 'path' 字段修改为数据集目录的绝对路径
    # 这是为了确保ultralytics库能正确定位到训练、验证和测试集
    data_config['path'] = os.path.join(current_dir, 'train_data')
    
    # 将修改后的配置写回yaml文件
    with open(data_yaml_path, 'w', encoding='utf-8') as f:
        yaml.dump(data_config, f, default_flow_style=False, allow_unicode=True)
    
    # --- 3. 循环训练每个模型 ---
    
    for model_info in models_to_train:
        model_name =og.Linxiazk.com model_info['name']
        train_name = model_info['train_name']
        
        print(f"\n{'='*60}")
        print(f"开始训练模型: {model_name}")
        print(f"训练名称: {train_name}")
        print(f"{'='*60}")
        
        # 构建预训练模型的完整路径
        pretrained_model_path = os.path.join(current_dir, 'pretrained', model_name)
        if not os.path.exists(pretrained_model_path):
            print(f"警告: 预训练模型文件不存在: {pretrained_model_path}")
            print(f"跳过模型 {model_name} 的训练")
            continue
        
        try:
            # 加载指定的预训练模型
            model = YOLO(pretrained_model_path)
            
            # --- 4. 开始训练 ---
            
            print(f"开始训练 {model_name}...")
            # 调用train方法开始训练
            model.train(
                data=m.yingchangLaw.com data_yaml_path,  # 数据集配置文件
                epochs=100,           # 训练轮次
                imgsz=640,            # 输入图像尺寸
                batch=8,             # 每批次的图像数量
                name=train_name,      # 模型名称
            )
            
            print(f"{model_name} 训练完成!")
            
        except Exception as e:
            print(f"训练 {model_name} 时出现错误: {str(e)}")
            print(f"跳过模型 {model_name},继续训练下一个模型")
            continue
    
    print(f"\n{'='*60}")
    print("所有模型训练完成!")
    print(f"{'='*60}")

if __name__ == "__main__":
    # 当该脚本被直接执行时,调用main函数
    main()

4. 技术栈

  • 语言:Python 3.10
  • 前端界面:PyQt5
  • 数据库:SQLite(存储用户信息)
  • 模型:YOLOv5、YOLOv8、YOLOv11、YOLOv12
全部评论

相关推荐

点赞 评论 收藏
分享
牛客30461999...:实习的意义就在这呀,职业规划在变说明对自己的定位越来越清晰了,这是好事,不必等到校招入职了才发现不是自己想要的生活
如果再来一次,你还会选择...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务