前言

Node作为一门后端语言,当然也可以连接数据库,为前端提供CURD接口

我们以mysql为例,自行安装mysql

TypeORM

TypeORM 是一个ORM框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript一起使用。 它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。

TypeORM作为TypeScript中最成熟的对象关系映射器,可以很好的与Nest框架集成使用。

安装依赖

npm install --save @nestjs/typeorm typeorm mysql2

新建数据库

CREATE DATABASE nanjiu
DEFAULT CHARACTER SET = 'utf8mb4';

新建一个nanjiu数据库

连接数据库

数据库建好之后,我们就可以使用typeorm来连接数据库并建立映射关系了

// dbConfig.ts
// 数据库配置
export function dbConfig() {
return {
type: 'mysql', // 数据库类型
host: '127.0.0.1', // 数据库地址
port: 3306, // 端口
username: 'root', // 用户名
password: '123456', // 密码
database: 'nanjiu', // 数据库名
entities: [__dirname + '/../**/*.entity{.ts,.js}'], // 实体类
synchronize: true, // 自动创建表
autoLoadEntities: true, // 自动加载实体类
} as DbConfig
}

需要在app.module.ts中进行注册

@Module({
imports: [
NanjiuModule, UserModule, InfoModule,
TypeOrmModule.forRoot(dbConfig() as any)
],
controllers: [AppController],
providers: [AppService],
})

定义实体

实体是一个映射到数据库表的类,使用@Entity装饰器来定义

// user.entry.ts
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity('user') // 表名
export class User { @PrimaryGeneratedColumn() // 自增主键
id: number; @Column() // 字段
name: string;
}

基本实体由列和关系组成,每个实体必须有一个主列。

每个实体都必须在连接配置中注册:

entities: [__dirname + '/../**/*.entity{.ts,.js}'], // 实体类

关联实体

实体定义后需要在module中导入并关联

@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService]
})

当你做完这一步之后你会发现数据库里已经根据你刚刚定义的实体建好了表

这是因为刚刚数据库配置那里开启了synchronize: true 自动创建表

CURD接口

数据库准备准备工作完成后,我们就可以来写接口了

controller控制器中定义接口path

// user.controller.ts
import { CreateUserDto } from './dto/create-user.dto';
export class UserController {
constructor(
private readonly userService: UserService,
) {} @Post('addUser')
create(@Body() createUserDto: CreateUserDto) {
// 添加用户
return this.userService.add(createUserDto);
}
}

新建DTO数据验证器

import { Injectable } from "@nestjs/common";
import { IsNotEmpty, IsString } from "class-validator"; // 引入验证器
@Injectable()
export class CreateUserDto {
@IsString({ message: '用户名必须是字符串'}) // 验证是否是字符串
@IsNotEmpty({ message: '用户名不能为空'}) // 验证是否为空
name: string; // 用户名
}

dto一般用来做参数验证

注册全局DTO验证管道

// main.ts
import { ValidationPipe } from '@nestjs/common'; app.useGlobalPipes(new ValidationPipe()) // 全局验证管道

service逻辑处理,入库操作

// user.service.ts
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { User } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm'; @Injectable()
export class UserService {
constructor(
// 使用 @InjectRepository(User) 注入实数据库实体
@InjectRepository(User)
private readonly userRepository: Repository<User>
) {} async add(createUserDto: CreateUserDto) {
// 添加用户,更多操作参考 TypeORM 文档
const res = await this.userRepository.save(createUserDto);
return res
}
}

调用接口

查看数据库

调用完接口,此时数据库中会新增一条数据

响应结果处理

从上面的响应结果来看并不规范,只是简单的返回了数据库查询结果,并且当系统发生异常错误时,如果我们没有手动处理异常,所有的异常都会进入到nest内置的异常处理层,它返回的信息格式如下:

{
"statusCode": 500,
"message": "Internal server error"
}

比如我们往user库中插入相同的name,但name设置了唯一性,所以这时会抛出错误,如果我们不处理返回给前端就是上面那种信息,这样前端同学看到就会很蒙,根本不知道为啥报错

所以我们要做的就是将响应格式化处理

在nest中,一般是在service中处理异常,如果有异常,直接抛出错误,由过滤器捕获,统一格式返回,如果成功,service把结果返回,controller直接return结果即可,由拦截器捕获,统一格式返回

失败:过滤器统一处理

成功:拦截器统一处理

异常拦截器

为了更加优雅地处理异常,我们可以创建一个异常过滤器,它主要用来捕获作为HttpException类实例的异常。

异常抛出封装:

// httpStatus.service.ts
import { Injectable, HttpException, HttpStatus, NestInterceptor } from '@nestjs/common' @Injectable()
export class HttpStatusError {
static fail(error, status = HttpStatus.BAD_REQUEST) {
throw new HttpException({statusCode: status, message: '请求失败', error}, status)
}
}

抛出异常:

// group.service.ts
// ...
import { HttpStatusError } from '../utils/httpStatus.service' @Injectable()
export class GroupService {
constructor(
@InjectRepository(Group)
private groupRepository: Repository<Group>,
@InjectRepository(Template)
private templateRepository: Repository<Template>,
) {}
// todo: 添加分组
async create(createGroupDto: CreateGroupDto) {
const data = this.groupRepository.create(createGroupDto);
const group = await this.groupRepository.findOne({ where: { name: createGroupDto.name } });
if (group) {
return HttpStatusError.fail('该分组已存在');
}
try {
const res = await this.groupRepository.save(data, { reload: true });
return res;
} catch (error) {
return HttpStatusError.fail(error);
}
}
}

异常拦截器封装:

import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common'; @Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest(); const status = exception.getStatus();
const exceptionRes: any = exception.getResponse();
const { error, message } = exceptionRes; const msgLog = {
status,
message,
error,
path: request.url,
timestamp: new Date().toLocaleString(),
}; response.status(status).json(msgLog);
}
}

使用:

 app.useGlobalFilters(new HttpExceptionFilter()); // 全局异常过滤器

请求:

这样报错信息就能够一目了然,简单实用的话可以直接抛出异常就可以,然后在抛出异常的地方给出详细信息。

全局响应拦截器

那成功的响应应该如何优雅地处理呢?

Interceptor拦截器

这里我们可以使用Interceptor拦截器,给成功响应按固定格式返回

import { Injectable, HttpException, HttpStatus, NestInterceptor, ExecutionContext,CallHandler } from '@nestjs/common'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators' @Injectable()
export class HttpStatusSuccess implements NestInterceptor{
intercept(context: ExecutionContext, next: CallHandler) :Observable<any> {
return next.handle().pipe(map(data => {
return {
statusCode: HttpStatus.OK,
message: '请求成功',
data
}
}))
}
}

使用:

 app.useGlobalInterceptors(new HttpStatusSuccess()); // 全局拦截器请求成功

请求:

【NestJS系列】连接数据库及优雅地处理响应的更多相关文章

  1. Spring系列 SpringMVC的请求与数据响应

    Spring系列 SpringMVC的请求与数据响应 SpringMVC的数据响应 数据响应的方式 y以下案例均部署在Tomcat上,使用浏览器来访问一个简单的success.jsp页面来实现 Suc ...

  2. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  3. React 系列 - 写出优雅的路由

    前言 自前端框架风靡以来,路由一词在前端的热度与日俱增,他是几乎所有前端框架的核心功能点.不同于后端,前端的路由往往需要表达更多的业务功能,例如与菜单耦合.与标题耦合.与"面包屑" ...

  4. 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

    本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...

  5. jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理

    ajax在得到请求响应后主要会做两个处理:获取响应数据和使用类型转化器转化数据 a.获取响应数据 获取响应数据是调用ajaxHandleResponses函数来处理. ajaxHandleRespon ...

  6. 【CSS3 入门教程系列】CSS3 Media Queries 实现响应式设计

    在 CSS2 中,你可以为不同的媒介设备(如屏幕.打印机)指定专用的样式表,而现在借助 CSS3 的 Media Queries 特性,可以更为有效的实现这个功能.你可以为媒介类型添加某些条件,检测设 ...

  7. 微信开发系列----02:实现POST请求响应

    继续昨天的,现在我们的微信测试成功了,可以开发实现微信的各种功能,今天主要实现微信的简单交互,比如发送语音,图片,文本等请求,网站服务器发送对应的响应. 项目GitHub地址:  https://gi ...

  8. Effective java 系列之更优雅的关闭资源-try-with-resources

    背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...

  9. struts系列:返回json格式的响应

    一.增加依赖库 // https://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin compile group: ' ...

  10. 程序员的自我修养系列(一):优雅的代码管理工具之GitHub

    1.导言 代码管理是程序员经常遇到一个问题,很多童鞋将代码保存到本地硬盘,此种方法管理混乱,也存在代码丢失的风险,且版本无法控制,因此养成良好的代码管理习惯是程序员的必修课.在众多代码管理工具中笔者在 ...

随机推荐

  1. C#中BitConverter.ToUInt16、BitConverter.ToUInt32原理与用法详解

    一.基础知识 a.1字节=8位(1Byte=8bit)   二进制表示:11111111   十进制表示:255 计算机内部约定用多少字节来规范数值,比如红绿蓝三色在计算机中只分配了一个字节,一个字节 ...

  2. 基于.NetCore+React单点登录系统

    对于有多个应用系统的企业来说,每一个应用系统都有自己的用户体系,这就造成用户在切换不同应用系统时,就要多次输入账号密码,导致体验非常不好,也造成使用上非常不便. 针对这个问题,我们就可以采用单点登录的 ...

  3. vue 一键导出数据为excel文件并附带样式 十分简单

    自入行以来我就一直疑惑一个问题,导出excel为什么总是搞的很复杂,包括网上的教程,屎里淘金,非常耗费精力.今天刚好业务需要,整理一个简单明了的由vue前端导出的版本出来. 开始: #1.添加xlsx ...

  4. Java的标识符、关键字、 常量、变量、数据类型、 数据类型转换、字符ASCII码表(基础语法的学习)

    一.Java的关键字和标识符 关键字 1.定义: 在Java程序中,已经定义好的被预先使用的一些特殊的单词称为关键字,一共有50个关键字(48+2个保留字),关键字都是小写的英文单词 2.关键字的分类 ...

  5. Bash 编程

    原文:https://seankross.com/the-unix-workbench/bash-programming.html[1] 数学 创建math.sh: #!/usr/bin/env ba ...

  6. 慢 SQL 优化之索引的作用是什么?

    前言 本文针对 MySQL 数据库的 InnoDB 存储引擎,介绍其中索引的实现以及索引在慢 SQL 优化中的作用. 本文主要讨论不同场景下索引生效与失效的原因. 慢SQL与索引的关系 慢SQL优化原 ...

  7. 解决QRCODE生成的二维码微信长按不识别问题

    问题描述 QRcode 生成二维码,展示到页面,微信打开,长按二维码没反应.而直接放二维码图片上去可以识别. 问题原因 手机兼容问题qrcode在页面生成二维码时,会生成一个canvas标签和一个im ...

  8. MyBatis体系笔记

    MyBatis 什么是MyBatis MyBatis是优秀的持久层框架 MyBatis使用XML将SQL与程序解耦,便于维护 MyBatis学习简单,执行高效,是JDBC的延伸 1.MyBatis开发 ...

  9. 前端Vue加载中页面动画弹跳动画loading

    前端Vue加载中页面动画弹跳动画loading, 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin?id=13091 效果图如下: 使用方法 ...

  10. 让AI支持游戏制作流程:从游戏设计到发布一个完整的生态系统

    目录 引言 随着游戏产业的快速发展,人工智能(AI)技术在游戏开发中的应用越来越广泛.游戏设计人员可以通过利用AI技术来自动化游戏中的某些流程,提高游戏制作的效率,降低开发成本,同时还可以创造出更加具 ...