feat(controller):增加控制器功能以及产品检索控制器。
This commit is contained in:
parent
55dd3c0cc0
commit
e068143f60
0
license_server/src/controllers/license.rs
Normal file
0
license_server/src/controllers/license.rs
Normal file
|
@ -1,8 +1,11 @@
|
|||
mod license;
|
||||
mod products;
|
||||
|
||||
use axum::Router;
|
||||
|
||||
/// 生成可迭代的转化为路由定义的控制器列表。
|
||||
pub fn controllers() -> Box<dyn Iterator<Item = Box<Router>>> {
|
||||
let controllers: Vec<Box<Router>> = vec![];
|
||||
let controllers: Vec<Box<Router>> = vec![Box::new(products::ProductsController::init().into())];
|
||||
|
||||
Box::from(controllers.into_iter())
|
||||
}
|
||||
|
|
43
license_server/src/controllers/products.rs
Normal file
43
license_server/src/controllers/products.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use axum::{extract::Query, http::StatusCode, response::IntoResponse, routing, Json, Router};
|
||||
|
||||
use tracing::info;
|
||||
|
||||
use crate::vo::KeywordQuery;
|
||||
|
||||
pub struct ProductsController {
|
||||
routes: Router,
|
||||
}
|
||||
|
||||
impl Into<Router> for ProductsController {
|
||||
fn into(self) -> Router {
|
||||
self.routes
|
||||
}
|
||||
}
|
||||
|
||||
impl ProductsController {
|
||||
pub fn init() -> Self {
|
||||
let routes = Router::new().route("/products", routing::get(search_products));
|
||||
|
||||
Self { routes }
|
||||
}
|
||||
}
|
||||
|
||||
async fn search_products(Query(keyword_query): Query<KeywordQuery>) -> impl IntoResponse {
|
||||
info!(keyword = keyword_query.keyword(), "search products");
|
||||
let response_products = {
|
||||
if let Some(keyword) = keyword_query.keyword() {
|
||||
crate::products::get()
|
||||
.iter()
|
||||
.filter(|&p| p.name.to_lowercase().contains(&(keyword.to_lowercase())))
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
crate::products::get().iter().collect::<Vec<_>>()
|
||||
}
|
||||
};
|
||||
let products_length = response_products.len();
|
||||
info!(
|
||||
fetched_length = ?products_length,
|
||||
"retrieved {} products", products_length
|
||||
);
|
||||
(StatusCode::OK, Json(response_products))
|
||||
}
|
|
@ -7,6 +7,8 @@ mod controllers;
|
|||
mod logging;
|
||||
mod products;
|
||||
mod server_routes;
|
||||
mod utils;
|
||||
mod vo;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::{fs::File, io::AsyncReadExt};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Product {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
|
8
license_server/src/utils.rs
Normal file
8
license_server/src/utils.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
pub fn empty_to_none<S: Into<String>>(s: S) -> Option<String> {
|
||||
let s = s.into();
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(s)
|
||||
}
|
||||
}
|
3
license_server/src/vo/mod.rs
Normal file
3
license_server/src/vo/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
mod shared;
|
||||
|
||||
pub use shared::*;
|
12
license_server/src/vo/shared.rs
Normal file
12
license_server/src/vo/shared.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct KeywordQuery {
|
||||
pub keyword: Option<String>,
|
||||
}
|
||||
|
||||
impl KeywordQuery {
|
||||
pub fn keyword(&self) -> Option<String> {
|
||||
self.keyword.clone().and_then(crate::utils::empty_to_none)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user