Rust新增优化

举报
林太白 发表于 2025/08/07 15:11:11 2025/08/07
【摘要】 Rust新增优化

Rust新增优化

接下来我们抽离新增接口,将新增接口的代码抽离出来,方便我们后续的调用

🍎旧的写法

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

// 新增用户
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::<()>,
            })
        }
    }
}

🍎抽离写法

// 通用新增公共方法
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: "新增失败",
            }))
        }
    }
}

🍎使用方法新增


// 使用更高级的公共方法
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

🍎测试接口

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


// 通用新增
// 使用高级公共方法的新增角色接口
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,说明我们新增成功!

{
    "code": 200,
    "msg": "新增成功"
}

🍎抽离密码

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

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

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: "新增失败",
            }))
        }
    }
}

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

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。