Rust新增优化

Rust新增优化

接下来我们抽离新增接口

🍎旧的写法

我们现在的新增的写法如下

javascript 复制代码
// 新增用户
pub async fn post_add_users(
    pool: web::Data<MySqlPool>,
    form: web::Json<AddUserRequest>,
) -> HttpResponse {
    // 1. 检查用户名是否已存在
    let exists: (i64,) = match sqlx::query_as("SELECT COUNT(*) FROM sys_user WHERE username = ?")
        .bind(&form.username)
        .fetch_one(pool.get_ref())
        .await
    {
        Ok(count) => count,
        Err(_) => {
            return HttpResponse::InternalServerError().json(ApiResponse {
                code: 500,
                msg: "数据库错误",
                data: None::<()>,
            })
        }
    };
    if exists.0 > 0 {
        return HttpResponse::Ok().json(ApiResponse {
            code: 400,
            msg: "用户名已存在",
            data: None::<()>,
        });
    }

    // 2. 密码加密
    let hashed_pwd = match hash(&form.password, DEFAULT_COST) {
        Ok(pwd) => pwd,
        Err(_) => {
            return HttpResponse::InternalServerError().json(ApiResponse {
                code: 500,
                msg: "密码加密失败",
                data: None::<()>,
            })
        }
    };

    // 3. 插入新用户
    // 插入新用户 
    let result = sqlx::query(
        "INSERT INTO sys_user (username,password, age, address, sex, phone,disease,name) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
    )
   
    .bind(&form.username)
    .bind(&hashed_pwd)
    .bind(&form.age)
    .bind(&form.address)
   .bind(form.sex)
   .bind(&form.phone)
   .bind(&form.disease)
   .bind(&form.name)
    .execute(pool.get_ref())
    .await;
    match result {
        Ok(_) => HttpResponse::Ok().json(ApiResponse {
            code: 200,
            msg: "新增用户成功",
            data: None::<()>,
        }),
        Err(e) => {
            eprintln!("新增用户失败: {:?}", e);
            HttpResponse::InternalServerError().json(ApiResponse {
                code: 500,
                msg: "新增用户失败",
                data: None::<()>,
            })
        }
    }
}

🍎抽离写法

javascript 复制代码
// 通用新增公共方法
pub async fn create_api(
    pool: &sqlx::MySqlPool,
    table_name: &str,
    data: &std::collections::HashMap<String, String>,
    unique_fields: &[String],
    password_field: Option<&str>,
) -> Result<HttpResponse, sqlx::Error> {
    // 1. 检查唯一性约束
    for field in unique_fields {
        if let Some(value) = data.get(field) {
            let exists: (i64,) = sqlx::query_as(&format!("SELECT COUNT(*) FROM {} WHERE {} = ?", table_name, field))
                .bind(value)
                .fetch_one(pool)
                .await?;
            
            if exists.0 > 0 {
                return Ok(HttpResponse::Ok().json(BasicResponse {
                    code: 400,
                    msg: "数据已存在",
                }));
            }
        }
    }

    // 2. 处理密码加密(如果存在密码字段)
    let mut processed_data = data.clone();
    if let Some(pwd_field) = password_field {
        if let Some(password) = processed_data.get(pwd_field) {
            let hashed_pwd = match hash(password, DEFAULT_COST) {
                Ok(pwd) => pwd,
                Err(_) => {
                    return Ok(HttpResponse::InternalServerError().json(BasicResponse {
                        code: 500,
                        msg: "密码加密失败",
                    }))
                }
            };
            processed_data.insert(pwd_field.to_string(), hashed_pwd);
        }
    }

    // 3. 构建插入SQL
    let fields: Vec<String> = processed_data.keys().cloned().collect();
    let placeholders: Vec<String> = fields.iter().map(|_| "?".to_string()).collect();
    
    let sql = format!(
        "INSERT INTO {} ({}) VALUES ({})",
        table_name,
        fields.join(", "),
        placeholders.join(", ")
    );

    // 4. 执行插入
    let mut query = sqlx::query(&sql);
    for field in &fields {
        if let Some(value) = processed_data.get(field) {
            query = query.bind(value);
        }
    }

    match query.execute(pool).await {
        Ok(_) => Ok(HttpResponse::Ok().json(BasicResponse {
            code: 200,
            msg: "新增成功",
        })),
        Err(e) => {
            eprintln!("新增失败: {:?}", e);
            Ok(HttpResponse::InternalServerError().json(BasicResponse {
                code: 500,
                msg: "新增失败",
            }))
        }
    }
}

🍎使用方法新增

javascript 复制代码
// 使用更高级的公共方法
pub async fn post_add_users(
    pool: web::Data<MySqlPool>,
    form: web::Json<AddUserRequest>,
) -> HttpResponse {
    // 将请求数据转换为HashMap
    let mut data = std::collections::HashMap::new();
    data.insert("username".to_string(), form.username.clone());
    data.insert("password".to_string(), form.password.clone());
    data.insert("age".to_string(), form.age.clone());
    data.insert("address".to_string(), form.address.clone());
    data.insert("sex".to_string(), form.sex.to_string());
    data.insert("phone".to_string(), form.phone.clone());
    data.insert("disease".to_string(), form.disease.clone());
    data.insert("name".to_string(), form.name.clone());

    // 使用高级公共方法
    match crate::common::apimethods::create_api(
        pool.get_ref(),
        "sys_user",
        &data,
        &["username".to_string()], // 唯一性检查字段
        Some("password"), // 密码字段
    ).await {
        Ok(response) => response,
        Err(_) => HttpResponse::InternalServerError().json(ApiResponse {
            code: 500,
            msg: "数据库操作失败",
            data: None::<()>,
        }),
    }
}

测试新增接口,新增用户ok

🍎测试接口

我们尝试写一个角色的新增接口测试一下

javascript 复制代码
// 通用新增
// 使用高级公共方法的新增角色接口
pub async fn post_add(
    pool: web::Data<MySqlPool>,
    form: web::Json<AddRoleRequest>,
) -> HttpResponse {
    // 将请求数据转换为HashMap,注意字段名映射到数据库字段名
    let mut data = std::collections::HashMap::new();
    data.insert("role_name".to_string(), form.roleName.clone());
    data.insert("role_key".to_string(), form.roleKey.clone());
    data.insert("role_sort".to_string(), form.roleSort.to_string());
    data.insert("status".to_string(), form.status.clone());
    data.insert("remark".to_string(), form.remark.clone());
    
    // 处理布尔值字段
    data.insert("menu_check_strictly".to_string(), if form.menuCheckStrictly { "1" } else { "0" }.to_string());
    data.insert("dept_check_strictly".to_string(), if form.deptCheckStrictly { "1" } else { "0" }.to_string());
    
    // 处理数组字段 - 转换为JSON字符串存储
    // data.insert("menu_ids".to_string(), serde_json::to_string(&form.menuIds).unwrap_or_default());
    // data.insert("dept_ids".to_string(), serde_json::to_string(&form.deptIds).unwrap_or_default());

    // 使用高级公共方法(角色不需要密码)
    match crate::common::apimethods::create_api(
        pool.get_ref(),
        "sys_role",
        &data,
        &[
            "role_name".to_string(),
            "role_key".to_string()
        ], // 唯一性检查字段
        None, // 没有密码字段
    ).await {
        Ok(response) => response,
        Err(_) => HttpResponse::InternalServerError().json(ApiResponse {
            code: 500,
            msg: "数据库操作失败",
            data: None::<()>,
        }),
    }
}

测试返回信息ok,说明我们新增成功!

javascript 复制代码
{
    "code": 200,
    "msg": "新增成功"
}

🍎抽离密码

上面我们密码的方法是在外面传入参数,这就导致我们每次使用密码的时候,都需要外部传入

别的没有密码的新增需要传入data: None::<()>

javascript 复制代码
pub async fn create_api(
    pool: &sqlx::MySqlPool,
    table_name: &str,
    data: &std::collections::HashMap<String, String>,
    unique_fields: &[String],
) -> Result<HttpResponse, sqlx::Error> {
    // 1. 检查唯一性约束
    for field in unique_fields {
        if let Some(value) = data.get(field) {
            let exists: (i64,) = sqlx::query_as(&format!("SELECT COUNT(*) FROM {} WHERE {} = ?", table_name, field))
                .bind(value)
                .fetch_one(pool)
                .await?;
            if exists.0 > 0 {
                return Ok(HttpResponse::Ok().json(BasicResponse {
                    code: 400,
                    msg: "数据已存在",
                }));
            }
        }
    }

    // 2. 处理密码加密(如果 data 里有 "password" 字段)
    let mut processed_data = data.clone();
    if let Some(password) = processed_data.get("password") {
        let hashed_pwd = match hash(password, DEFAULT_COST) {
            Ok(pwd) => pwd,
            Err(_) => {
                return Ok(HttpResponse::InternalServerError().json(BasicResponse {
                    code: 500,
                    msg: "密码加密失败",
                }))
            }
        };
        processed_data.insert("password".to_string(), hashed_pwd);
    }

    // 3. 构建插入SQL
    let fields: Vec<String> = processed_data.keys().cloned().collect();
    let placeholders: Vec<String> = fields.iter().map(|_| "?".to_string()).collect();
    
    let sql = format!(
        "INSERT INTO {} ({}) VALUES ({})",
        table_name,
        fields.join(", "),
        placeholders.join(", ")
    );

    // 4. 执行插入
    let mut query = sqlx::query(&sql);
    for field in &fields {
        if let Some(value) = processed_data.get(field) {
            query = query.bind(value);
        }
    }

    match query.execute(pool).await {
        Ok(_) => Ok(HttpResponse::Ok().json(BasicResponse {
            code: 200,
            msg: "新增成功",
        })),
        Err(e) => {
            eprintln!("新增失败: {:?}", e);
            Ok(HttpResponse::InternalServerError().json(BasicResponse {
                code: 500,
                msg: "新增失败",
            }))
        }
    }
}

测试我们的接口,接口正常!

相关推荐
大学生资源网1 分钟前
基于springboot的万亩助农网站的设计与实现源代码(源码+文档)
java·spring boot·后端·mysql·毕业设计·源码
苏三的开发日记10 分钟前
linux端进行kafka集群服务的搭建
后端
苏三的开发日记29 分钟前
windows系统搭建kafka环境
后端
爬山算法39 分钟前
Netty(19)Netty的性能优化手段有哪些?
java·后端
Tony Bai40 分钟前
Cloudflare 2025 年度报告发布——Go 语言再次“屠榜”API 领域,AI 流量激增!
开发语言·人工智能·后端·golang
想用offer打牌1 小时前
虚拟内存与寻址方式解析(面试版)
java·后端·面试·系统架构
無量1 小时前
AQS抽象队列同步器原理与应用
后端
9号达人2 小时前
支付成功订单却没了?MyBatis连接池的坑我踩了
java·后端·面试
用户497357337982 小时前
【轻松掌握通信协议】C#的通信过程与协议实操 | 2024全新
后端
草莓熊Lotso2 小时前
C++11 核心精髓:类新功能、lambda与包装器实战
开发语言·c++·人工智能·经验分享·后端·nginx·asp.net