实战使用 NestJS 搭建一个 Admin 后台服务 - 03. DTO参数校验&swagger接口文档生成&swagger 接口文档导入 apifox

实战使用 NestJS 搭建一个 Admin 后台服务 - 01. 项目搭建、配置文件和路由

实战使用 NestJS 搭建一个 Admin 后台服务 - 02. typeorm 操作 mysql&基础 crud

一、DTO参数校验

  • 同样的先安装依赖
yarn add class-validator class-transformer
1、使用内置pipe 或者 自定义pipe
// src/pipe/validation.pipe.ts
import {
  ArgumentMetadata,
  Injectable,
  PipeTransform,
  BadRequestException,
} from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';
import { Logger } from '../utils/log4js';

@Injectable()
export class MyValidationPipe implements PipeTransform {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      // 如果没有传入验证规则,则不验证,直接返回数据
      return value;
    }
    // 将对象转换为 Class 来验证
    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      const msg = Object.values(errors[0].constraints)[0]; // 只需要取第一个错误信息并返回即可
      Logger.error(`Validation failed: ${msg}`);
      throw new BadRequestException(`Validation failed: ${msg}`);
    }
    return value;
  }

  private toValidate(metatype: any): boolean {
    const types: any[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}
2、修改dto
  • 修改 create-user.dto.ts 不过 CreateUserDto继承了 user.entity.ts 所以直接修改 user.entity.ts 较为方便
import { IsNotEmpty } from 'class-validator';
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class User {
  /** 每个实体必须至少有一个主列 */
  @PrimaryGeneratedColumn()
  id: number;

  /** @CreateDateColumn 是一个特殊列,自动为实体插入日期。无需设置此列,该值将自动设置。 */
  @CreateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'create_time',
    comment: '创建时间',
  })
  createTime: Date;

  /** @UpdateDateColumn 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。 */
  @UpdateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'update_time',
    comment: '更新时间',
  })
  updateTime: Date;

  @IsNotEmpty({
    message: '用户名不能为空',
  })
  @Column({ unique: true, nullable: true, comment: '用户名' })
  username: string;

  @IsNotEmpty({
    message: '邮箱不能为空',
  })
  @Column({ unique: true, nullable: true, comment: '邮箱' })
  email: string;

  @IsNotEmpty({
    message: '手机号不能为空',
  })
  @Column({ unique: true, nullable: true, comment: '手机号' })
  phone: string;

  @Column({ nullable: true, comment: '头像' })
  avatar: string;

  @IsNotEmpty({
    message: '密码不能为空',
  })
  @Column({ nullable: true, comment: '密码' })
  password: string;
}

3、全局使用 or 局部使用
  • 全局使用
  • exceptionFactory 做了一定转化,如下处理后,message 返回的是字符串,且是第一个验证错误
  • new ValidationPipe() 不对exceptionFactory 处理message 返回的是所有校验错误的字符串数组
// main.ts
import { BadRequestException, ValidationPipe } from '@nestjs/common';
/** 全局绑定验证管道 或者自定义 new MyValidationPipe() */
app.useGlobalPipes(
  new ValidationPipe({
    exceptionFactory: (errors) => {
      const firstError = errors[0];
      const message =
        firstError.constraints[Object.keys(firstError.constraints)[0]];
      return new BadRequestException(message);
    },
  }),
);
  • 局部使用, 在controller 层使用 users.controller.ts
@UsePipes(new ValidationPipe()) // 或者自定义 new MyValidationPipe()
@Post()
create(@Body() createUserDto: CreateUserDto) {
  return this.usersService.create(createUserDto);
}
4、效果展示
  • exceptionFactory 未转化

image.png

  • exceptionFactory 转化

image.png

二、swagger接口文档生成
yarn add @nestjs/swagger swagger-ui-express
  • 修改main.ts
const options = new DocumentBuilder()
  .setTitle('Cats example')
  .setDescription('The cats API description')
  .setVersion('1.0')
  .addTag('cats')
  .build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('doc', app, document); // 使用doc 不使用api 做一定区分

image.png

image.png

三、导入api fox
  • apifox 自行下载

image.png

image.png

image.png

image.png

  • 可以看到已经导入了,但body内相关参数并没有
  • 接下来进行swagger 装饰器文档编写

四、编写swagger 装饰器文档

1、修改user.entity.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty } from 'class-validator';
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class User {
  /** 每个实体必须至少有一个主列 */
  @PrimaryGeneratedColumn()
  id: number;

  /** @CreateDateColumn 是一个特殊列,自动为实体插入日期。无需设置此列,该值将自动设置。 */
  @CreateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'create_time',
    comment: '创建时间',
  })
  createTime: Date;

  /** @UpdateDateColumn 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。 */
  @UpdateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'update_time',
    comment: '更新时间',
  })
  updateTime: Date;

  @IsNotEmpty({
    message: '用户名不能为空',
  })
  @ApiProperty({ uniqueItems: true, description: '用户名' })
  @Column({ unique: true, nullable: true, comment: '用户名' })
  username: string;

  @IsNotEmpty({
    message: '邮箱不能为空',
  })
  @ApiProperty({ uniqueItems: true, description: '邮箱' })
  @Column({ unique: true, nullable: true, comment: '邮箱' })
  email: string;

  @IsNotEmpty({
    message: '手机号不能为空',
  })
  @ApiProperty({ uniqueItems: true, description: '手机号' })
  @Column({ unique: true, nullable: true, comment: '手机号' })
  phone: string;

  @ApiProperty({ description: '头像' })
  @Column({ nullable: true, comment: '头像' })
  avatar: string;

  @IsNotEmpty({
    message: '密码不能为空',
  })
  @ApiProperty({ description: '密码' })
  @Column({ nullable: true, comment: '密码' })
  password: string;
}
2、重复 三、导入api fox

image.png

image.png

下一篇

本篇完成了参数校验的相关工作,下篇将进行jwt 的逻辑编写

<think>好的,我现在需要帮助用户了解SpringBoot与Vue前后端分离开发的最佳实践和总结。首先,我得回忆一下相关的知识,确保信息准确。用户提到了参考引用里的内容,里面提到SpringBoot基于Spring4.0,简化配置,解决依赖问题。而用户现在想了解的是前后端分离的最佳实践,特别是SpringBoot和Vue的结合。 首先,我应该考虑前后端分离的基本概念,明确前后端的职责划分。前端负责展示和交互,后端处理数据和业务逻辑。接下来需要讨论技术选型,比如SpringBoot的版本,Vue的生态系统,可能还需要提到相关的工具,比如Webpack、Axios等。 然后是接口设计规范,RESTful API的重要性,使用Swagger文档化。这里需要注意如何设计统一的响应格式和状态码,这样前后端协作会更顺畅。 接着是开发流程,可能需要涉及并行开发、Mock数据的使用,以及接口联调阶段的问题。跨域问题是一个常见的坑,需要配置CORS或者使用代理解决。 安全性方面,JWT认证和HTTPS是必须提到的,同时参数校验和防SQL注入也不能忽视。 部署优化方面,前端可以用Nginx做静态资源服务器,后端用Jenkins自动化部署,性能监控工具如Spring Boot Actuator也是关键点。 协作规范部分,Git分支管理和代码审查是团队协作的基础,文档维护同样重要。测试方面,单元测试和自动化测试确保代码质量。 最后,常见问题如跨域、路由配置、性能优化需要给出解决方案。可能还需要补充一些实际案例或者具体配置示例,让用户更容易理解。 需要确保回答结构清晰,分点列出,每个部分都有具体的建议和实践方法。同时,要引用用户提供的参考内容,比如SpringBoot简化配置的优点,结合到最佳实践中。还要注意使用正确的中文表达,避免技术术语错误,比如正确使用“JWT”而不是“JWT令牌”重复。最后生成相关问题,帮助用户进一步探索。</think># SpringBoot与Vue前后端分离开发实践总结 ## 一、技术架构设计 1. **职责划分** - 前端(Vue):负责UI渲染、路由管理、用户交互,通过$axios$发送HTTP请求 - 后端(SpringBoot):处理业务逻辑、数据持久化,提供RESTful API接口[^1] 2. **技术选型建议** ```markdown - SpringBoot 2.7.x + Spring Security + MyBatis Plus - Vue3 + Vue Router + Pinia + Axios - 构建工具:Maven/Gradle + Webpack/Vite ``` ## 二、接口规范设计 1. **RESTful API设计** - 使用HTTP状态码:$200(成功)/201(创建)/400(参数错误)/401(未认证)/403(无权限)$ - 统一响应格式: ```json { "code": 200, "data": {}, "message": "操作成功" } ``` 2. **接口文档管理** - SpringBoot集成$Swagger3$自动生成API文档 - 配置示例: ```java @Bean public OpenAPI customOpenAPI() { return new OpenAPI().info(new Info().title("仓库管理系统")); } ``` ## 三、开发协作流程 1. **并行开发模式** - 使用$Mock.js$模拟后端接口 - 接口定义先行:提前约定DTO字段和接口规范 2. **跨域解决方案** ```java // SpringBoot配置类 @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*"); } }; } ``` ## 四、安全防护实践 1. **认证授权机制** - JWT令牌认证流程: $$流程图$$ 用户登录 → 颁发Token → 前端存储 → 请求携带 → 后端验证 2. **安全防护措施** - 使用$Spring Security$配置权限控制 - SQL注入防护:MyBatis Plus自动预编译 - XSS防护:前端$vue-dompurify$过滤 ## 五、部署优化方案 | 模块 | 优化方案 | 工具选择 | |------------|-----------------------------|--------------------| | 前端部署 | Nginx静态资源服务+CDN加速 | Webpack代码分割 | | 后端部署 | Docker容器化+Jenkins自动化 | JMeter压力测试 | | 监控运维 | Spring Boot Admin健康监控 | Prometheus+Granafa | ## 六、常见问题解决方案 1. **跨域问题** - 开发环境:配置vue.config.js代理 ```javascript devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } ``` 2. **路由冲突** - 前端配置history模式路由 - Nginx添加重定向规则: ```nginx location / { try_files $uri $uri/ /index.html; } ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值