变更宏路由实现
This commit is contained in:
parent
44bbc846df
commit
2ea3813a32
@ -1,6 +1,6 @@
|
|||||||
use axum::routing::MethodRouter;
|
use axum::routing::MethodRouter;
|
||||||
|
|
||||||
type TypedHandler<S = ()> = fn() -> (&'static str, MethodRouter<S>);
|
type TypedHandler<S = ()> = fn() -> Vec<(&'static str, MethodRouter<S>)>;
|
||||||
|
|
||||||
/// A trait that allows typed routes, created with the [`route`] macro to
|
/// A trait that allows typed routes, created with the [`route`] macro to
|
||||||
/// be added to an axum router.
|
/// be added to an axum router.
|
||||||
@ -25,9 +25,10 @@ where
|
|||||||
S: Send + Sync + Clone + 'static,
|
S: Send + Sync + Clone + 'static,
|
||||||
{
|
{
|
||||||
type State = S;
|
type State = S;
|
||||||
|
|
||||||
fn typed_route(self, handler: TypedHandler<Self::State>) -> Self {
|
fn typed_route(self, handler: TypedHandler<Self::State>) -> Self {
|
||||||
let (path, method_router) = handler();
|
let routes = handler();
|
||||||
self.route(path, method_router)
|
routes.into_iter().fold(self, |router, (path, method_router)| {
|
||||||
|
router.route(path, method_router)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,45 +23,45 @@ pub fn responsable(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_route(attr, item)
|
route::gen_route(attr, item, "route")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn get(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "get")
|
route::gen_route(attr, item, "get")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn post(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "post")
|
route::gen_route(attr, item, "post")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn put(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "put")
|
route::gen_route(attr, item, "put")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn patch(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn patch(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "patch")
|
route::gen_route(attr, item, "patch")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn delete(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "delete")
|
route::gen_route(attr, item, "delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn options(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn options(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "options")
|
route::gen_route(attr, item, "options")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn head(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn head(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "head")
|
route::gen_route(attr, item, "head")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn trace(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn trace(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
route::gen_dyn_route(attr, item, "trace")
|
route::gen_route(attr, item, "trace")
|
||||||
}
|
}
|
@ -5,14 +5,89 @@ extern crate syn;
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use parse::{Parse, ParseStream};
|
use parse::{Parse, ParseStream};
|
||||||
use proc_macro::{Span, TokenStream}; use punctuated::Punctuated;
|
use proc_macro::{Span, TokenStream};
|
||||||
|
use punctuated::Punctuated;
|
||||||
// 用于处理宏输入
|
// 用于处理宏输入
|
||||||
use quote::quote; use spanned::Spanned;
|
use quote::quote;
|
||||||
|
use spanned::Spanned;
|
||||||
// 用于生成代码
|
// 用于生成代码
|
||||||
use syn::*;
|
use syn::*;
|
||||||
|
use syn::{parse_macro_input, ItemFn};
|
||||||
|
|
||||||
|
struct RouteArgs {
|
||||||
|
path: String,
|
||||||
|
methods: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现 Parse trait 以支持解析参数
|
||||||
|
impl Parse for RouteArgs {
|
||||||
|
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
|
||||||
|
// 使用Meta解析 begin
|
||||||
|
// let args = Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated(input)?;
|
||||||
|
// let mut path = None;
|
||||||
|
// let mut methods = Vec::new();
|
||||||
|
// for arg in args {
|
||||||
|
// if let Meta::NameValue(nv) = arg {
|
||||||
|
// if nv.path.is_ident("method") {
|
||||||
|
// if let Expr::Array(ExprArray { elems, .. }) = nv.value {
|
||||||
|
// for elem in elems {
|
||||||
|
// if let Expr::Lit(syn::ExprLit { lit: Lit::Str(lit_str), .. }) = elem {
|
||||||
|
// methods.push(lit_str.value());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if nv.path.is_ident("path") {
|
||||||
|
// if let Expr::Lit(ExprLit { lit: Lit::Str(lit_str), .. }) = nv.value {
|
||||||
|
// path = Some(lit_str.value());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// let path = path.expect("Expected a path argument");
|
||||||
|
// 使用Meta解析 end
|
||||||
|
|
||||||
|
let args = Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated(input)?;
|
||||||
|
|
||||||
|
let mut path = None;
|
||||||
|
let mut methods = Vec::new();
|
||||||
|
|
||||||
|
for expr in args {
|
||||||
|
match expr {
|
||||||
|
Expr::Lit(ExprLit {
|
||||||
|
lit: Lit::Str(lit_str),
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
path = Some(lit_str.value());
|
||||||
|
}
|
||||||
|
Expr::Assign(assign) => {
|
||||||
|
if let Expr::Path(path) = *assign.left {
|
||||||
|
if path.path.is_ident("method") {
|
||||||
|
if let Expr::Array(ExprArray { elems, .. }) = *assign.right {
|
||||||
|
for elem in elems {
|
||||||
|
if let Expr::Lit(ExprLit {
|
||||||
|
lit: Lit::Str(lit_str),
|
||||||
|
..
|
||||||
|
}) = elem
|
||||||
|
{
|
||||||
|
methods.push(lit_str.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = path.expect("路由参数不能为空");
|
||||||
|
|
||||||
|
Ok(RouteArgs { path, methods })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Args {
|
struct Args {
|
||||||
vars: Vec<syn::Expr>
|
vars: Vec<syn::Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Args {
|
impl Parse for Args {
|
||||||
@ -32,52 +107,54 @@ impl Args {
|
|||||||
None => {
|
None => {
|
||||||
// 第一个参数使路由url,必须存在,其他的参数根据实际需求进一步解析
|
// 第一个参数使路由url,必须存在,其他的参数根据实际需求进一步解析
|
||||||
if index != 0 {
|
if index != 0 {
|
||||||
return Ok(None)
|
return Ok(None);
|
||||||
} else {
|
} else {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
Span::call_site().into(),
|
Span::call_site().into(),
|
||||||
"route must have one argument"
|
"route must have one argument",
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn gen_route(attr: TokenStream, item: TokenStream, method: &str) -> TokenStream {
|
||||||
pub fn gen_route(attr: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
let args = parse_macro_input!(attr as Args);
|
|
||||||
let func = parse_macro_input!(item as ItemFn);
|
let func = parse_macro_input!(item as ItemFn);
|
||||||
|
// 解析宏的参数
|
||||||
|
let RouteArgs { path, methods } = parse_macro_input!(attr as RouteArgs);
|
||||||
|
|
||||||
|
// 将 method 转换为小写并生成标识符
|
||||||
let vis = func.vis.clone();
|
let vis = func.vis.clone();
|
||||||
let ident = func.sig.ident.clone();
|
let ident = func.sig.ident.clone();
|
||||||
|
|
||||||
let method = args.get_arg(0).unwrap();
|
let mut method_routers = Vec::new();
|
||||||
let route = args.get_arg(1).unwrap();
|
if methods.is_empty() {
|
||||||
|
let method_name = syn::Ident::new(&method.to_lowercase(), method.span());
|
||||||
|
method_routers.push(quote! {
|
||||||
|
(#path, axum::routing::#method_name(#ident))
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
for method in methods {
|
||||||
|
let method_name = syn::Ident::new(&method.to_lowercase(), method.span());
|
||||||
|
method_routers.push(quote! {
|
||||||
|
(#path, axum::routing::#method_name(#ident))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let expanded = quote! {
|
let generated = quote! {
|
||||||
#[allow(non_camel_case_types)]
|
#vis fn #ident () -> Vec<(&'static str, axum::routing::method_routing::MethodRouter)> {
|
||||||
#vis struct #ident;
|
#func
|
||||||
|
|
||||||
impl #ident {
|
vec![#(#method_routers),*]
|
||||||
#vis fn route() -> axum::Router {
|
|
||||||
#func
|
|
||||||
|
|
||||||
axum::Router::new().route(#route, #method (#ident))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
expanded.into()
|
TokenStream::from(generated)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// todo
|
#[allow(dead_code)]
|
||||||
///
|
|
||||||
/// 计划采用
|
|
||||||
/// ```#[route("path"), methods = [Get, Post]]```
|
|
||||||
/// 的形式进行完善,使方法支持多种网络请求
|
|
||||||
///
|
|
||||||
/// gen_dyn_route 生成的代码不再是的单独的MethodRouter,而是MethodRouter集合
|
|
||||||
pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> TokenStream {
|
pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> TokenStream {
|
||||||
let args = parse_macro_input!(attr as Args);
|
let args = parse_macro_input!(attr as Args);
|
||||||
let func = parse_macro_input!(item as ItemFn);
|
let func = parse_macro_input!(item as ItemFn);
|
||||||
@ -87,6 +164,26 @@ pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> Toke
|
|||||||
|
|
||||||
let route = args.get_arg(0).unwrap().unwrap();
|
let route = args.get_arg(0).unwrap().unwrap();
|
||||||
|
|
||||||
|
let method_option = args.get_arg(1);
|
||||||
|
match method_option {
|
||||||
|
Ok(method) => {
|
||||||
|
if let Some(Expr::Assign(methods_value)) = method {
|
||||||
|
println!("method is {:?}", methods_value);
|
||||||
|
// if let Expr::Path(left) = methods_value.left {
|
||||||
|
// left.path.segments[0].ident.eq("d") {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if let Expr::Lit(right) = methods_value.right {
|
||||||
|
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("error is {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let method_name: Ident = Ident::new(method, route.span());
|
let method_name: Ident = Ident::new(method, route.span());
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
@ -97,4 +194,4 @@ pub fn gen_dyn_route(attr: TokenStream, item: TokenStream, method: &str) -> Toke
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
expanded.into()
|
expanded.into()
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use library::extractor::path_extractor::PathVar;
|
|||||||
use library::model::response::ResResult;
|
use library::model::response::ResResult;
|
||||||
use library::extractor::body_extractor::JsonBody;
|
use library::extractor::body_extractor::JsonBody;
|
||||||
use library::extractor::query_extractor::QueryParams;
|
use library::extractor::query_extractor::QueryParams;
|
||||||
use macros::{get, post};
|
use macros::{get, post, route};
|
||||||
|
|
||||||
use crate::service;
|
use crate::service;
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ pub async fn get_feedback_list_by_page(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/feedback/:page/:pageSize", d = "a")]
|
#[route("/feedback/:page/:pageSize", method = ["get", "post"])]
|
||||||
pub async fn get_feedback_list(
|
pub async fn get_feedback_list(
|
||||||
context: Context,
|
context: Context,
|
||||||
PathVar(page_params): PathVar<PageParams>,
|
PathVar(page_params): PathVar<PageParams>,
|
||||||
|
@ -5,7 +5,7 @@ pub mod account_controller;
|
|||||||
pub mod feedback_controller;
|
pub mod feedback_controller;
|
||||||
|
|
||||||
pub fn init() -> Router {
|
pub fn init() -> Router {
|
||||||
Router::new()
|
let mut app = Router::new()
|
||||||
// 用户登录、用户管理相关路由
|
// 用户登录、用户管理相关路由
|
||||||
.typed_route(account_controller::authenticate_google)
|
.typed_route(account_controller::authenticate_google)
|
||||||
.typed_route(account_controller::authenticate_with_password)
|
.typed_route(account_controller::authenticate_with_password)
|
||||||
@ -13,5 +13,10 @@ pub fn init() -> Router {
|
|||||||
// 反馈相关路由
|
// 反馈相关路由
|
||||||
.typed_route(feedback_controller::add_feedback)
|
.typed_route(feedback_controller::add_feedback)
|
||||||
.typed_route(feedback_controller::get_feedback_list_by_page)
|
.typed_route(feedback_controller::get_feedback_list_by_page)
|
||||||
.typed_route(feedback_controller::get_feedback_list)
|
// .typed_route(feedback_controller::get_feedback_list)
|
||||||
|
;
|
||||||
|
for (path, method_router) in feedback_controller::get_feedback_list() {
|
||||||
|
app = app.route(path, method_router);
|
||||||
|
}
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user