rust-模块方法封装
【摘要】 rust-模块方法封装
👉rust-模块方法封装
🍎角色菜单方法封装
之前我们写项目的时候很多接口都是随意调取,这里我们接下来就将我们项目的接口进行封装,达到我们需要的效果
通过角色ID获取对应的菜单ID并且筛选重复的,我们封装一下
先来看看我们旧的写法,每次使用都需要频繁的调用
// 查询这些角色对应的菜单ID
let menu_ids: Vec<i32> = if role_ids.is_empty() {
Vec::new() // 如果没有角色,返回空数组
} else {
// 创建 IN 查询的占位符
let placeholders: String = role_ids.iter().map(|_| "?").collect::<Vec<_>>().join(",");
// 使用占位符构建查询
let query = format!(
"SELECT DISTINCT menu_id FROM sys_role_menu WHERE role_id IN ({})",
placeholders
);
// 创建查询并绑定每个参数
let mut query_builder = sqlx::query_as::<_, MenuId>(&query);
for role_id in &role_ids {
query_builder = query_builder.bind(role_id);
}
match query_builder.fetch_all(pool.get_ref()).await {
Ok(menu_ids) => menu_ids
.into_iter()
.map(|menu_id| menu_id.menu_id)
.collect(),
Err(_) => {
return HttpResponse::InternalServerError().json(ApiResponse {
code: 500,
msg: "获取用户菜单失败",
data: None::<()>,
});
}
}
};
将这个方法进行封装以后我们可以放入hook方法逻辑之中
// 定义返回的结构体
/// 根据角色ID列表获取对应的菜单ID列表(已去重)
///
/// # Arguments
/// * `pool` - 数据库连接池
/// * `role_ids` - 角色ID列表
///
/// # Returns
/// * `Result<Vec<i32>, sqlx::Error>` - 返回去重后的菜单ID列表,如果查询失败则返回错误
///
#[allow(unused_imports)]
use sqlx::{ MySqlPool, Pool, Row};
#[allow(unused_imports)]
use crate::types::menu::MenuId;
use crate::types::user; // 添加 Row trait
pub async fn get_menu_ids_by_roles(
pool: &MySqlPool,
role_ids: &[i32],
) -> Result<Vec<i32>, sqlx::Error> {
// 如果没有角色,直接返回空数组
if role_ids.is_empty() {
return Ok(Vec::new());
}
// 创建 IN 查询的占位符
let placeholders: String = role_ids.iter().map(|_| "?").collect::<Vec<_>>().join(",");
// 使用占位符构建查询,使用 DISTINCT 确保去重
let query = format!(
"SELECT DISTINCT menu_id FROM sys_role_menu WHERE role_id IN ({})",
placeholders
);
// 创建查询并绑定每个参数
let mut query_builder = sqlx::query_as::<_, MenuId>(&query);
for role_id in role_ids {
query_builder = query_builder.bind(role_id);
}
// 执行查询并返回结果
let menu_ids = query_builder
.fetch_all(pool)
.await?
.into_iter()
.map(|menu_id| menu_id.menu_id)
.collect();
Ok(menu_ids)
}
在需要的地方使用这个逻辑
// 根据角色ID查询菜单ID并去重
let menu_ids: Vec<i32> = match get_menu_ids_by_roles(pool.get_ref(), &role_ids).await {
Ok(ids) => ids,
Err(e) => {
eprintln!("获取菜单ID失败: {}", e);
return HttpResponse::InternalServerError().json(ApiResponse {
code: 500,
msg: "获取用户菜单失败",
data: None::<()>,
});
}
};
🍎根据菜单ID获取菜单信息
封装一个方法,根据菜单的ID可以得到所有的菜单完整的信息
// src/hooks/get_menu_ids_by_roles.rs
use sqlx::MySqlPool;
use crate::modules::auth::handlers::Menu;
/// 根据菜单ID列表获取菜单详细信息
///
/// # Arguments
/// * `pool` - 数据库连接池
/// * `menu_ids` - 菜单ID列表
/// * `exclude_menu_type` - 要排除的菜单类型,如果为 None 则不过滤
///
/// # Returns
/// * `Result<Vec<Menu>, sqlx::Error>` - 返回菜单列表,如果查询失败则返回错误
pub async fn get_menus_by_ids(
pool: &MySqlPool,
menu_ids: &[i32],
exclude_menu_type: Option<&str>, // 新增参数,用于指定要排除的菜单类型
) -> Result<Vec<Menu>, sqlx::Error> {
// 如果没有菜单ID,直接返回空数组
if menu_ids.is_empty() {
return Ok(Vec::new());
}
// 创建 IN 查询的占位符
let placeholders: String = menu_ids
.iter()
.map(|_| "?")
.collect::<Vec<_>>()
.join(",");
// 构建基础查询
let mut query = format!(
"SELECT * FROM sys_menu WHERE menu_id IN ({})",
placeholders
);
// 如果指定了要排除的菜单类型,添加条件
if let Some(menu_type) = exclude_menu_type {
query.push_str(&format!(" AND `menu_type` != '{}'", menu_type));
}
// 添加排序
query.push_str(" ORDER BY parent_id, order_num");
// 创建查询并绑定每个参数
let mut query_builder = sqlx::query_as::<_, Menu>(&query);
for menu_id in menu_ids {
query_builder = query_builder.bind(menu_id);
}
// 执行查询
let menus = query_builder.fetch_all(pool).await?;
println!("查询到的菜单: {:?}", menus);
Ok(menus)
}
使用这个接口,排除我们不想要的类型
// 排除类型为 'F' 的菜单
let menus = get_menus_by_ids(pool.get_ref(), &menu_ids, Some("F")).await?;
// 不过滤任何菜单类型
let all_menus = get_menus_by_ids(pool.get_ref(), &menu_ids, None).await?;
// 排除类型为 'M' 的菜单
let non_directory_menus = get_menus_by_ids(pool.get_ref(), &menu_ids, Some("M")).await?;
项目使用
// 根据菜单ID查询菜单信息
let menus = match get_menus_by_ids(pool.get_ref(), &menu_ids, Some("F")).await {
Ok(menus) => menus,
Err(e) => {
eprintln!("获取菜单信息失败: {}", e);
return HttpResponse::InternalServerError().json(ApiResponse {
code: 500,
msg: "获取菜单信息失败",
data: None::<()>,
});
}
};
🍎根据用户ID获取用户角色id
#[allow(unused_imports)]
use sqlx::{ MySqlPool, Pool, Row};
#[allow(unused_imports)]
use crate::types::menu::MenuId;
#[allow(unused_imports)]
use crate::types::role::Role;
// 添加这些导入
use actix_web::HttpResponse;
// 返回信息
#[allow(unused_imports)]
use crate::common::response::ApiResponse;
/// 根据用户ID获取用户角色id
pub async fn get_user_roles_by_ids(pool: &MySqlPool, user_id: i32) -> Result<Vec<Role>, HttpResponse> {
match sqlx::query_as::<_, Role>(
"SELECT * FROM sys_role r
INNER JOIN sys_user_role ur ON r.role_id = ur.role_id
WHERE ur.user_id = ?",
)
.bind(user_id)
.fetch_all(pool)
.await
{
Ok(data) => {
println!("用户角色==== {:?}", data);
Ok(data)
}
Err(_) => Err(HttpResponse::InternalServerError().json(ApiResponse {
code: 500,
msg: "获取用户角色失败",
data: None::<()>,
})),
}
}
使用查询用户角色
let roles: Vec<Role> = match get_user_roles_by_ids(pool.get_ref(), user.user_id).await {
Ok(data) => {
println!("用户角色==== {:?}", data);
data
}
Err(e) => return e, // 直接返回错误响应
};
🍎根据角色信息获取角色信息
这里我们将根据角色信息获取角色信息的方法也给封装起来
// src/hooks/get_roles_by_ids.rs
use sqlx::MySqlPool;
/// 根据角色ID列表获取角色信息
///
/// # Arguments
/// * `pool` - 数据库连接池
/// * `role_ids` - 角色ID列表
///
/// # Returns
/// * `Result<Vec<(String, String)>, sqlx::Error>` - 返回角色键值对列表,如果查询失败则返回错误
pub async fn get_roles_by_ids(
pool: &MySqlPool,
role_ids: &[i32],
) -> Result<Vec<(String, String)>, sqlx::Error> {
// 如果没有角色ID,直接返回空数组
if role_ids.is_empty() {
return Ok(Vec::new());
}
// 构建IN查询的占位符
let placeholders = role_ids.iter().map(|_| "?").collect::<Vec<_>>().join(",");
// 构建查询
let query_str = format!("SELECT role_key, role_name FROM sys_role WHERE role_id IN ({}) AND status = 0", placeholders);
// 构建查询
let mut query = sqlx::query_as::<_, (String, String)>(&query_str);
// 逐个绑定每个角色ID
for role_id in role_ids {
query = query.bind(role_id);
}
// 执行查询
let roles = query.fetch_all(pool).await?;
println!("查询到的角色: {:?}", roles);
Ok(roles)
}
使用
// 收集所有角色ID
let role_ids: Vec<i32> = roles.iter().map(|role| role.role_id).collect();
// 使用 get_roles_by_ids 获取角色信息
let role_info = match get_roles_by_ids(pool.get_ref(), &role_ids).await {
Ok(info) => info,
Err(e) => {
eprintln!("获取角色信息失败: {}", e);
return HttpResponse::InternalServerError().json(ApiResponse {
code: 500,
msg: "获取角色信息失败",
data: None::<()>,
});
}
};
🍎验证头部token信息
use actix_web::{HttpRequest, HttpResponse};
use jsonwebtoken::{decode, DecodingKey, Validation};
use crate::common::response::{Claims};
use crate::types::response::{ApiResponse};
use crate::config::JWT_SECRET; // 引入 JWT_SECRET
/// 从请求中提取并验证 token
pub async fn validate_token(req: &HttpRequest) -> Result<Claims, HttpResponse> {
// 从 header 获取 token
let token = match req.headers().get("Authorization") {
Some(t) => t.to_str().unwrap_or("").replace("Bearer ", ""),
None => {
return Err(HttpResponse::Unauthorized().json(ApiResponse {
code: 401,
msg: "未提供Token",
data: None::<()>,
}));
}
};
// 校验 token
match decode::<Claims>(
&token,
&DecodingKey::from_secret(JWT_SECRET),
&Validation::default(),
) {
Ok(data) => Ok(data.claims),
Err(_) => Err(HttpResponse::Unauthorized().json(ApiResponse {
code: 401,
msg: "Token无效或已过期",
data: None::<()>,
})),
}
}
使用方法
// 在 get_routers 函数中使用
let token_data = match validate_token(&req).await {
Ok(data) => data,
Err(_) => {
return HttpResponse::Unauthorized().json(ApiResponse {
code: 401,
msg: "Token无效或已过期",
data: None::<()>,
});
}
};
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)