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 小时前
分布式事务Seata、LCN的原理深度剖析
spring boot·分布式·后端·spring·spring cloud·中间件·架构
Absinthe_苦艾酒4 小时前
JVM学习专题(四)对象创建过程
java·jvm·后端
hweiyu005 小时前
IDEA搭建GO环境
开发语言·后端·golang·intellij-idea·idea·intellij idea
Real_man5 小时前
RAG系统全景:架构详解与落地实践指南
后端
若梦plus5 小时前
Xata低代码服务器端数据库平台之技术分析
前端·后端
若梦plus5 小时前
Xano低代码后端开发平台之技术分析
前端·后端
柊二三6 小时前
spring boot开发中的资源处理等问题
java·spring boot·后端
GetcharZp7 小时前
Weaviate从入门到实战:带你3步上手第一个AI应用!
人工智能·后端·搜索引擎
爷_7 小时前
用 Python 打造你的专属 IOC 容器
后端·python·架构
_码农121388 小时前
简单spring boot项目,之前练习的,现在好像没有达到效果
java·spring boot·后端