Angular中如何复用getProducts控制器适配3类带不同查询参数的商品列表页
实现方案
你完全可以复用同一个getProducts控制器支持三种参数组合的页面,只需要调整前后端的参数传递、校验逻辑即可,具体修改步骤如下:
一、前端修改
1. 修复Resolver参数转换逻辑
移除参数的强制非空断言,没有对应查询参数时传入undefined即可:
class ProductsResolver implements Resolve<Pick<IProductInterface, 'image' | 'title' | 'price' | 'description'>[]> { constructor(private productService: ProductService) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Pick< IProductInterface, 'image' | 'title' | 'price' | 'description'>[]> { const gender = route.queryParamMap.get('gender'); const category = route.queryParamMap.get('category'); return this.productService.getProducts( gender ? +gender as ProductGender : undefined, category ? +category as ProductCategory : undefined, ); } }
2. 修改HTTP请求Service参数传递方式
不要把可选参数塞到URL路径中,改为通过查询参数传递,避免缺参数时URL路径不符合预期:
public getProducts( gender?: ProductGender, category?: ProductCategory ): Observable<IGetProductsResponse> { const baseUrl = ENDPOINT; let params = new HttpParams(); if (gender != null) params = params.set('gender', gender); if (category != null) params = params.set('category', category); return this.http.get<IGetProductsResponse>( `${baseUrl}list`, { params } ); }
3. 优化路由配置
添加runGuardsAndResolvers配置,确保查询参数变化时Resolver会重新执行获取新数据,无需手动调用刷新方法:
{ path: 'product-list', component: ProductsComponent, resolve: { products: ProductsResolver }, // 这里建议把原来的key从users改成products,语义更清晰 runGuardsAndResolvers: 'paramsOrQueryParamsChange' }
二、后端修改
1. 调整路由配置
移除路径参数占位符,改为接收查询参数:
router.get("/list", getProducts);
2. 修改请求参数接口定义
把原来从params取参数改为从query取:
interface IgetProductsRequest extends express.Request { readonly query: Readonly<{ gender?: string; category?: string; }>; }
3. 调整参数校验逻辑
仅当参数存在时才做合法性校验,没有传的参数直接跳过校验:
const getProducts = async ( req: IgetProductsRequest, res: IgetProductsResponse ) => { const category = req.query.category ? +req.query.category : undefined; const gender = req.query.gender ? +req.query.gender : undefined; ServerGlobal.getInstance().logger.info( `<getProducts>: Start processing request filtered by \ncategory ${category ?? '无'} and gender ${gender ?? '无'}` ); // 仅校验传入的分类参数 if (category !== undefined && !ServerGlobal.getInstance().isValidCategoryValue(category)) { ServerGlobal.getInstance().logger.error( `<getProducts>: Failed to get products because of invalid category filtered by category ${category} \nand gender ${gender}` ); res.status(400).send({ success: false, message: "Please provide valid category", }); return; } // 仅校验传入的性别参数 if (gender !== undefined && !ServerGlobal.getInstance().isValidGenderValue(gender)) { ServerGlobal.getInstance().logger.error( `<getProducts>: Failed to get products because of invalid gender filtered by category ${category} \n and gender ${gender}` ); res.status(400).send({ success: false, message: "Please provide valid gender", }); return; }
4. 动态拼接数据库查询条件
根据传入的参数动态生成查询条件,没有传的参数不作为过滤条件:
try { const query: Record<string, any> = {}; if (category !== undefined) query.category = category; if (gender !== undefined) query.gender = gender; const products = await ProductDB.find(query); // 后续返回逻辑保持不变即可 }
修改完成后三个不同参数的商品列表页就可以共用同一套控制器、Resolver、Service逻辑,不需要额外开发新的接口。
内容的提问来源于stack exchange,提问作者blablalbla3233
相关产品推荐
相关产品推荐

