Nestjs中如何实现User Entity到GetUserDto的无敏感字段数据转换
NestJS 中User Entity转GetUserDto排除敏感字段的最优实现方案
以下是两种生产环境常用的最优方案,可根据业务场景选择:
方案1:使用NestJS内置ClassSerializerInterceptor(最省事,适合全局统一处理场景)
该方案是NestJS官方推荐的标准处理方式,依赖class-transformer库,无需手动写转换逻辑:
- 第一步:给User实体的敏感字段添加
@Exclude()装饰器
import { Exclude } from 'class-transformer'; export class User{ name: string; username:string; @Exclude() password:string; @Exclude() salt:string; }
- 第二步:注册序列化拦截器
单路由生效示例:
import { ClassSerializerInterceptor, Controller, Get, UseInterceptors } from '@nestjs/common'; @Controller('user') export class UserController { @Get(':id') @UseInterceptors(ClassSerializerInterceptor) findOne(): User { // 直接返回查询得到的User实体实例即可,拦截器会自动排除@Exclude标记的字段 return userQueryResult; } }
全局生效只需在main.ts中添加配置:
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
注意:如果你的查询返回的是普通JS对象而非User类实例,需要先通过
plainToInstance(User, queryResult)转为实例后拦截器才会生效。
该方案优势是零额外转换代码,只要定义好实体的序列化规则就自动生效,适合大部分单序列化规则的场景。
方案2:使用class-transformer手动转换为DTO(最灵活,适合多DTO适配同个Entity的场景)
如果同一个User实体需要对应多个不同返回结构的DTO,不想把排除规则写死在Entity里,就用这个方案:
- 第一步:给GetUserDto的所有字段添加
@Expose()装饰器
import { Expose } from 'class-transformer'; export class GetUserDto{ @Expose() name: string; @Expose() username:string; }
- 第二步:在Service层或者Controller层执行转换,开启
excludeExtraneousValues配置就会自动排除DTO里未定义的字段:
import { plainToInstance } from 'class-transformer'; // user是你查询得到的User实体/普通查询结果对象 const getUserDto = plainToInstance(GetUserDto, user, { excludeExtraneousValues: true });
转换完成后getUserDto里只会保留name和username两个字段,password、salt都会被自动过滤。
该方案优势是完全和Entity解耦,不同DTO可以有不同的返回字段规则,适合复杂业务场景。
不推荐方案:手动映射
除非你的DTO字段只有1-2个,否则不要手动写赋值代码,字段多了之后维护成本极高,容易漏字段、写错字段。
内容的提问来源于stack exchange,提问作者Tiến Anh Dương
相关产品推荐
相关产品推荐

