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}`;
}
}Postman请求
怎么样? 是不是好像有点样子了? 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这些概念, 不展开介绍了, 官方文档写的已经很详细了, 感兴趣可以自行前往.Documentation | NestJS - A progressive Node.js web frameworkdocs.nestjs.com
各位大神如果一定要纠结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
) { }
async save(user: User): Promise {
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 {
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官网.TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.typeorm.io
现在, 使用JS的你, 可以写前端页面, 也可以写后端逻辑, 还能进行数据存储. 作为一名JSer, 真开心.
2019, 重新出发, 从心出发
记得高考的时候, 就流传着一种说法:高考的魅力不在于如愿以偿,而在于阴差阳错.
活的愈久, 愈觉得很多结果是无法左右的. 能够随遇而安, 便是我力所能及最积极的事儿了.
因机缘巧合入职上海轻流, 工作已经四个月了, 学到了不少工作流程上的事情. 感谢2019年的阴差阳错能够让我遇到一群如此有趣的同事, 非常开心能够和你们共事.
我也在努力地成为1%全栈工程师, 争取能够用这些工具实现自己的一些小想法.顺便预祝我们公司的BPM产品[轻流]两周年快乐!!!