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 小时前
浅析二叉树、B树、B+树和MySQL索引底层原理
后端
文艺理科生1 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling1 小时前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
南极企鹅1 小时前
springBoot项目有几个端口
java·spring boot·后端
Luke君607971 小时前
Spring Flux方法总结
后端
define95272 小时前
高版本 MySQL 驱动的 DNS 陷阱
后端
忧郁的Mr.Li2 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
暮色妖娆丶3 小时前
SpringBoot 启动流程源码分析 ~ 它其实不复杂
spring boot·后端·spring
Coder_Boy_3 小时前
Deeplearning4j+ Spring Boot 电商用户复购预测案例中相关概念
java·人工智能·spring boot·后端·spring
Java后端的Ai之路3 小时前
【Spring全家桶】-一文弄懂Spring Cloud Gateway
java·后端·spring cloud·gateway