欢迎光临
我们一直在努力

salvo封装

我帮你把 ruwebframe 框架封装一下,核心思路是把 Salvo 的底层细节(路由构建、OpenAPI 文档、服务启动)全部隐藏到框架内部,对外暴露简洁的 API。这样业务代码只需要关注 Handler 和中间件,不用重复写样板代码。


封装后的框架结构

ruwebframe/
├── src/
│ ├── lib.rs # 框架入口,导出公共 API
│ ├── server.rs # 服务器启动封装
│ ├── router.rs # 路由构建 + OpenAPI 文档生成
│ ├── middleware.rs # 中间件辅助工具
│ └── prelude.rs # 预导入模块


1. lib.rs — 框架入口

// ruwebframe/src/lib.rs
pub mod server;
pub mod router;
pub mod middleware;
pub mod prelude;

pub use salvo;
pub use salvo::prelude::*;
pub use salvo::oapi::{self, OpenApi, Info, Server, SwaggerUi, ReDoc};
pub use ruconf::find_bean_ru_config;
pub use rupage::pagemodel::ru_result::RuResult;


2. prelude.rs — 预导入(用户只需 use ruwebframe::prelude::*)

// ruwebframe/src/prelude.rs
pub use crate::server::RuServer;
pub use crate::router::RuRouterBuilder;
pub use crate::middleware::{auth_middleware, AuthUser};
pub use salvo::prelude::*;
pub use salvo::oapi::{endpoint, ToSchema};
pub use crate::RuResult;


3. middleware.rs — 中间件封装

// ruwebframe/src/middleware.rs
use salvo::prelude::*;
use serde::{Serialize, Deserialize};

/// 鉴权后注入的用户信息
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthUser {
pub id: u64,
pub username: String,
pub role: String,
}

/// 鉴权中间件:检查 Authorization header
pub async fn auth_middleware(
req: &mut Request,
depot: &mut Depot,
res: &mut Response,
ctrl: &mut FlowCtrl,
) {
let token = req
.headers()
.get("Authorization")
.and_then(|v| v.to_str().ok())
.unwrap_or("");

// 模拟 token 解析(实际项目中替换为 JWT 验证)
if token == "Bearer valid-token" {
let user = AuthUser {
id: 1001,
username: "rust-dev".into(),
role: "admin".into(),
};
depot.insert("current_user", user);
ctrl.call_next(req, depot, res).await;
} else {
res.status_code(StatusCode::UNAUTHORIZED);
res.render(Text::Plain("Token 无效"));
ctrl.skip_rest();
}
}


4. router.rs — 路由构建器(核心封装)

// ruwebframe/src/router.rs
use salvo::prelude::*;
use salvo::oapi::{OpenApi, Info, Server, SwaggerUi, ReDoc};

/// 路由构建器:封装路由注册 + OpenAPI 文档生成
pub struct RuRouterBuilder {
router: Router,
title: String,
version: String,
server_url: String,
}

impl RuRouterBuilder {
pub fn new(title: &str, version: &str) -> Self {
Self {
router: Router::new(),
title: title.to_string(),
version: version.to_string(),
server_url: "/api".to_string(),
}
}

/// 设置服务器基础路径
pub fn server_url(mut self, url: &str) -> Self {
self.server_url = url.to_string();
self
}

/// 添加路由
pub fn push(mut self, router: Router) -> Self {
self.router = self.router.push(router);
self
}

/// 构建最终路由(自动生成 OpenAPI 文档 + Swagger UI + ReDoc)
pub fn build(self) -> Router {
let doc = OpenApi::new(Info::new(&self.title, &self.version))
.merge_router(&self.router)
.add_server(Server::new(&self.server_url));

self.router
.unshift(doc.into_router("/api-doc/openapi.json"))
.unshift(
SwaggerUi::new("/api-doc/openapi.json")
.title(&format!("{} – SwaggerUI", self.title))
.into_router("/swagger-ui"),
)
.unshift(
ReDoc::new("/api-doc/openapi.json")
.title(&format!("{} – ReDoc", self.title))
.into_router("/redoc"),
)
}
}


5. server.rs — 服务器启动封装

// ruwebframe/src/server.rs
use salvo::prelude::*;
use crate::ruconf::find_bean_ru_config;

/// 服务器启动器:封装配置读取 + 服务启动
pub struct RuServer;

impl RuServer {
/// 从配置文件读取端口并启动服务
pub async fn serve(router: Router) {
let conf = find_bean_ru_config().expect("Failed to load config");
let port = conf.read_web_server().port;
let addr = format!("0.0.0.0:{}", port);

println!("🚀 服务已启动: http://{}", addr);
println!("📖 Swagger UI: http://{}/swagger-ui", addr);
println!("📖 ReDoc: http://{}/redoc", addr);

salvo::Server::new(TcpListener::new(&addr).bind().await)
.serve(router)
.await
.expect("Server failed to start");
}

/// 指定地址启动服务
pub async fn serve_at(router: Router, addr: &str) {
println!("🚀 服务已启动: http://{}", addr);

salvo::Server::new(TcpListener::new(addr).bind().await)
.serve(router)
.await
.expect("Server failed to start");
}
}


6. 用户业务代码(封装后的简洁写法)

use ruwebframe::prelude::*;

/// 公开接口:无需鉴权
#[endpoint(tags("公开接口"), summary = "Hello World")]
async fn hello() -> &'static str {
"Hello, Salvo!"
}

/// 受保护接口:需要鉴权
#[endpoint(
tags("受保护接口"),
summary = "获取受保护资源",
security(
("BearerAuth" = [])
)
)]
async fn rets() -> Json<RuResult<String>> {
Json(RuResult::<String>::default())
}

#[tokio::main]
async fn main() {
// 构建路由:链式调用,简洁清晰
let router = RuRouterBuilder::new("用户管理API", "1.0.0")
.server_url("/api")
// 公开路由
.push(Router::with_path("pub").get(hello))
// 受保护路由:挂载鉴权中间件
.push(
Router::with_path("rets")
.hoop(auth_middleware) // 中间件作用域
.get(rets),
)
.build();

// 启动服务:一行搞定
RuServer::serve(router).await;
}


封装前后对比

维度封装前封装后
路由构建 手动 Router::new().push() + 手动 unshift 文档路由 RuRouterBuilder::new().push().build() 链式调用
OpenAPI 文档 手动写 OpenApi::new(Info::new(…)).merge_router().add_server() 内部自动完成,用户无感知
服务启动 手动读配置 + TcpListener::new().bind().await + Server::new().serve() RuServer::serve(router) 一行
中间件 手写 auth_middleware 函数 框架提供 auth_middleware,用户直接 .hoop(auth_middleware)
代码行数 ~60 行样板代码 ~15 行业务代码

后续扩展方向

  • 统一响应封装:在 middleware.rs 中添加全局响应拦截器,自动包装 RuResult
  • 错误处理:提供 RuError 类型 + IntoResponse 实现,统一错误格式
  • 数据库集成:封装 RuDb 模块,提供开箱即用的 ORM 连接池
  • 更多中间件:日志中间件、限流中间件、CORS 中间件等

  • 需要我继续补充"统一响应封装"或"错误处理"模块吗?

    赞(0)
    未经允许不得转载:171主机测评 » salvo封装
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址