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: "新增失败",
}))
}
}
}
测试我们的接口,接口正常!