Nest+TypeORM助你成为1%全栈工程师
Nest+TypeORM助你成为1%全栈工程师
1%全栈工程师
在技术圈子里, 一个人若是自称全栈, 往往会遇到以下两种情况.
如果前端自称全栈, 那么请回答:
- 如何实现LRU缓存机制?
- MySQL的数据如何恢复到任意时间点?
- 使用Redis有哪些好处?
- 存储过程与触发器的区别?
- JVM垃圾收集器有哪些?谈谈优劣势比较?
如果后端自称全栈, 那么请回答:
- 元素浮动有哪些缺陷?
- 如何用纯CSS实现一个三角形?
- 如何实现寄生组合继承?
- 谈谈JS的事件循环?
- AMD与CMD的区别是什么?
为了避免被dis, 本篇文章的目标设定为成为1%全栈工程师. 我就会1%, 这些题我答不上来不是很正常么?
通识技能
作为前端你可能不了解分布式、乐观锁悲观锁、 数据存储等细节; 作为后端你可能不了解JS的特性、 CSS3属性、 浏览器兼容. 但是有一些技能是通识性技能.
- 关系型数据库有主键、外键的概念知道吧?
- 数据库基本操作CRUD知道吧?
- 继承的概念知道吧?
- 数据库标识往往用id, 且通常是自增知道吧?
- 网页应用数据都是从[前端→后端→数据库→前端]知道吧?
- ...
本文默认你已经掌握了这些学生时代就讲过的知识. 前端所谓的全栈, 就是用JS实现后端. 这些通识认知是最基本的要求.
Nest
我作为一个切图仔, 既不会Java那一套, 也不会C#那一套. 日常工作我也只用JS. 我能写后端吗?
能! 使用Nest, 可以让你傻瓜式开发服务端.
只需三步, 就可以让你的服务端跑起来.
第一步: 安装环境
npm i -g @nestjs/cli
第二步: 初始化项目
nest new project-name
第三步: 安装依赖包并运行
npm install
npm run start
发送Get请求
很常规的操作吧? 现在我们看下初始化项目中代码都有啥.
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
我相信这两段代码并不需要我额外的解释, 你一看就明白发生了什么并且能够预判请求会发生什么.
Postman请求不过别小看这两段代码, 他体现了最基本的编程思想, 将控制器与数据处理相分离.
可能看到这里各位前端工程师会有疑惑: 不对啊, 我平时看到的请求没那么简单粗暴啊, 以用户模块为例, 怎么着也得是getUser?id=1这样的, 你这啥都没的, 太糙了吧.
No problem! 改造下控制器代码
发送带参数的Get请求
@Controller('user')
export class AppController {
@Get('getUser')
getUser(@Query() query): string {
return `查找到用户编号为:${query.id}`;
}
}
怎么样? 是不是好像有点样子了? Nest最神奇的地方就是代码一看就懂. 需要我告诉你这段代码怎么接收参数怎么设置路由么? 如果需要的话, 我可以给你介绍一些口碑不错的眼科医院. .♪(^∀^●)ノ
发送Post请求
最后写一个Post请求来结束Nest部分的内容吧.
@Controller('user')
export class AppController {
@Post('login')
userLogin(@Body() user: { account: string, password: string }): string {
if (user.account === 'admin' && user.password === '12345') {
return '登陆成功';
} else {
return '登陆失败';
}
}
}
可以说, 如果学生时代你写过JSP的作业, 你就会写Nest. 顺便一提, Nest是支持typescript的, 书写体验非常棒. 更重要的是, 其作者受到Angular的启发, 语法和Angular非常像, 同样有module, pipe, providers这些概念, 不展开介绍了, 官方文档写的已经很详细了, 感兴趣可以自行前往.
各位大神如果一定要纠结Node的性能、并发等问题. 请注意, 我只是一个1%全栈工程师, 要啥自行车呢?
TypeORM
我就是个切图仔, 数据库查询语句我只知道一个select * from table. 可我就是想搞数据库. 有办法吗?
有! TypeORM就非常适合咱们这种没什么本事野心还贼大的菜b.
对象关系映射(Object Relational Mapping), 简称ORM. 简单地来说, 就是数据库中表与表的关系, 和实体类的关系非常像, 可以写好实体然后映射过去. 话不多说, 开门见山.
在前文Nest项目的基础上继续安装依赖. 数据库我用的是mysql, 如果是其他数据库请参考文末TypeORM官网.
npm install @nestjs/typeorm --save
npm install mysql --save
npm install typeorm --save
声明实体类
user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
account: string;
@Column()
password: string;
@CreateDateColumn()
createTime: Date;
@UpdateDateColumn()
updateTime: Date;
}
user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>
) { }
async save(user: User): Promise<User> {
return this.userRepository.save(user);
}
}
user.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';
@Controller('user')
export class UserController {
constructor(
private readonly service: UserService
) { }
@Post('save')
async save(@Body() dto: User): Promise<any> {
let message = '';
await this.service.save(dto).then(() => {
message = '注册成功';
}).catch(e => {
message = '注册失败';
});
return message;
}
}
user.module.ts
@Module({
imports: [TypeOrmModule.forFeature([User])], // 引入实体类
providers: [UserService], // 为服务提供注册商
controllers: [UserController], // 控制器
})
export class UserModule { }
配置ORM
app.module.ts
@Module({
imports: [
UserModule,
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '12345',
database: 'demo', // 自己提前建好数据库, 无需建表
entities: ['src/**/**.entity{.ts,.js}'], // 实体存放的目录, 目前只能靠文件后缀识别
synchronize: true, // 项目一运行就根据实体自动创建表结构
}),
]
})
export class AppModule { }
简单地分析下, 看代码盲猜结果: 数据请求进入控制器(UserController), 解析请求数据并调用service进行数据存储, 返回响应. 代码看上去好像是这么运行的, 那我们来验证一下.
先开启服务, 直接npm start. 此时观察我们的数据库可以发现, user表已经自己创建好了.
接下来我们尝试发送请求
前往数据库查看
这里有要你写SQL语句么? 没有. 但是你的确实现了从前端到后端到数据库操作的流程. 既然在这里我们用到了save方法.
this.userRepository.save(user);
想必你肯定猜到TypeORM提供了delete、find方法等. 本文不负责API搬运, 只介绍基本概念和初始化操作, 属于科普向文章. 更多细节请查看TypeORM官网.
现在, 使用JS的你, 可以写前端页面, 也可以写后端逻辑, 还能进行数据存储. 作为一名JSer, 真开心.
2019, 重新出发, 从心出发
记得高考的时候, 就流传着一种说法:高考的魅力不在于如愿以偿,而在于阴差阳错.
活的愈久, 愈觉得很多结果是无法左右的. 能够随遇而安, 便是我力所能及最积极的事儿了.
因机缘巧合入职上海轻流, 工作已经四个月了, 学到了不少工作流程上的事情. 感谢2019年的阴差阳错能够让我遇到一群如此有趣的同事, 非常开心能够和你们共事.
我也在努力地成为1%全栈工程师, 争取能够用这些工具实现自己的一些小想法.顺便预祝我们公司的BPM产品[轻流]两周年快乐!!!