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;
|
use axum::Router;
|
||||||
|
|
||||||
/// 生成可迭代的转化为路由定义的控制器列表。
|
/// 生成可迭代的转化为路由定义的控制器列表。
|
||||||
pub fn controllers() -> Box<dyn Iterator<Item = Box<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())
|
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 logging;
|
||||||
mod products;
|
mod products;
|
||||||
mod server_routes;
|
mod server_routes;
|
||||||
|
mod utils;
|
||||||
|
mod vo;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{fs::File, io::AsyncReadExt};
|
use tokio::{fs::File, io::AsyncReadExt};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Product {
|
pub struct Product {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: 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