Node项目不会代码分层怎么办?来看看网易大神怎么做

编者注:作者是网易高级前端@季含婷,当前负责网易供应商业务线前端开发以及接口管理平台建设工作,专注于中后台前端以及Node应用开发建设工作。

Node项目不会代码分层怎么办?来看看网易大神怎么做

一、背景

刚刚接触Node开发或者后端开发的同学,有时候虽然能跟着网上的例子能去写出一个Node应用,但是网上的大神们或者项目领导说你对你的代码分层了吗?

其实作为一个有追求的开发,自己也很想写出更健壮,更易维护性的大型项目,而不是网上demo级别的例子。

那么我们应该怎么做呢?

那这边就跟大家分享一下我们是如何通过代码分层,来提高项目的档次的。

二、分层方案

本文主要介绍项目中代码的分层结构,大致分为Dao、Model、Service、Controller层,这种分层模式在Java、Android和IOS都有被应用,下面我们看看在node中的应用。
项目配置
编程语言:NodeJS

数据库:mysql

第三方库:@tiger系列包+Sequelize

项目目录结构

2.1 Dao层

一般Dao层是用来和底层数据库通信,负责对数据库的增删改查。

在项目中用了第三方库Sequelize,它是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, SQLite 和 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 读取和复制等功能.

创建一个sequelize对象实例


2.2 Model层

Model即模型,常常和持久化的数据一一对应,Model承载的作用就是数据的抽象,描述了一个数据的定义,Model的实例就是一组组的数据。

抽取model基类:BaseModel
基类BaseModel包含一个model对象以及对应模型的CRUD操作,为继承它的子类提供数据库增删改查的操作方法

import { sequelize } from '../dao';

export class BaseModel {
    model: any;
    constructor(modelName: string, schema: any, option?: any) {
        this.model = sequelize.define(modelName, schema, option);
    }
    // 返回实例化的sequelize模型实例
    getModel() {
        return this.model;
    }
    // 多条查询
    findAll(option: any) {
        return this.model.findAll(option);
    }
    // 单条数据查询
    findOne(option: any) {
        return this.model.findOne(option);
    }
    // 更新方法
    update(values: any, option: any) {
        return this.model.update(values, option);
    }
    // 删除
    delete(option: any) {
        return this.model.destroy(option);
    }
    // 插入单个实体
    create(entity: any) {
        return this.model.create(entity);
    }
    // 批量插入实体集
    createBatch(entitys: any) {
        return this.model.bulkCreate(entitys);
    }
}

创建branch表映射model:BranchModel
BranchModel继承基类BaseModel,除了继承了BaseModel的CURD方法外,还可定义BranchModel自身需要的特殊方法。

import Sequelize from 'sequelize';
import { Service } from '@tiger/boot';

import { BaseModel } from './base.model';

@Service
export class BranchModel extends BaseModel {
    constructor() {
        super('branch', {
            id: { type: Sequelize.BIGINT, allowNull: false, autoIncrement: true, primaryKey: true },
            // 分支名
            branchName: { type: Sequelize.STRING(128), allowNull: false, defaultValue: '' },
            // 服务Id
            serviceId: { type: Sequelize.BIGINT, allowNull: false, defaultValue: 0 },
            // 分支描述
            description: { type: Sequelize.STRING(4096), allowNull: false, defaultValue: '' },
            // 分支创建人的邮箱
            createUser: { type: Sequelize.STRING(128), allowNull: false, defaultValue: '' },
            ...
        }, { 
            timestamps: false, 
            tableName: 'TB_YX_API_BRANCH' 
        });
        this.model = super.getModel();
        // 同步当前模型到数据库中
        this.model.sync();
    }
    // 特殊方法定义
    batchUpdate(){
        // ...
    }
}

2.3 Service层

Service的重点是在于提供服务,可以处理事务和业务逻辑。

创建BranchModel对应的service:BranchService
BranchService主要提供BranchModel的数据处理服务;一个Model最好有一个与之对应的service,这个service包含了业务需要对model处理的所有操作。

import { Service } from '@tiger/boot';

import { BranchModel } from '../../model/branch.model';
import { BranchInfoVO, BranchInfoParamsVO, CreateBranchInfoParamsVO, SetBranchStateParamsVO } from './vo/branch-info.vo';
import { OpenIdInfo } from '../shared/types';

@Service
export class BranchService {
    constructor(
        private branchModel: BranchModel
    ) {
    }
    async getBranchList(serviceId: number): Promise {
        const result = await this.branchModel.findAll({
            where: {
                serviceId: serviceId
            },
            order: [['deleteFlag', 'ASC'], ['updateTime', 'DESC']]
        });
        return result;
    }

    async createBranch(param: CreateBranchInfoParamsVO, user: OpenIdInfo): Promise {
        const values = {
            ...param,
            createUser: user.email,
            createTime: Date.now()
        };
        const result = await this.branchModel.create(values);
        return result;
    }

    async updateBranch(param: BranchInfoParamsVO, user: OpenIdInfo): Promise {
        const values = {
            branchName: param.branchName,
            description: param.description,
            updateUser: user.email,
            updateTime: Date.now()
        };
        const result = await this.branchModel.update(values, { where: { id: param.id } });
        return result;
    }
}

创建controller对应的service:BranchManageService
BranchManageService提供与controller对应的服务,主要做业务逻辑处理。一个controller最好有一个与之对应的service,这个service包含有controller调度的所有操作。

import { Service } from '@tiger/boot';

import { BranchService } from './branch.service';
import { BranchApiDetailQueryVO, ServiceBranchInfoListVO } from './vo/branch-info.vo';

@Service
export class BranchManageService {
    constructor(
        private branchService: BranchService
    ) {
    }
    // 批量查询分支信息
    async queryBranch(branchList: BranchApiDetailQueryVO[]): Promise {
        const serviceIdList: number[] = branchList.map(item => Number(item.serviceId)),
            branchIdList: number[] = branchList.map(item => item.branchId),
            result: ServiceBranchInfoListVO[] = [],
            servicePromise = this.branchService.batchQueryServiceInfo(serviceIdList),
            branchPromise = this.branchService.batchQueryBranchInfo(branchIdList),
            res = await Promise.all([servicePromise, branchPromise]),
            [serviceInfos, branchInfos] = res;
        if (serviceInfos.length > 0) {
            serviceInfos.forEach((service: any) => {
                const item: ServiceBranchInfoListVO = {
                    serviceId: service.id,
                    cmdbServiceId: service.cmdbServiceId,
                    cmdbServiceName: service.cmdbServiceName,
                    cmdbProductName: service.cmdbProductName,
                    branchList: branchInfos.filter((branch: any) => branch.serviceId === service.id)
                };
                result.push(item);
            });
        }
        return result;
    }
    ...

2.4 Controller

根据具体的业务场景,可以创建其他服务;
Controller层
controller是控制中心,所有的指令,调度都从这里发出去。与service交互,只负责调用服务,不负责业务逻辑处理。

创建controller:BranchController

import { RestController, RequestMapping,  PostMapping } from '@tiger/boot';
import { Boom } from '@tiger/error';
import { AppConfig, RequestContext, AjaxResult } from '@tiger/core';
import { isNullOrUndefined } from 'util';

import { BranchManageService } from './branch-manage.service';
import {  ServiceBranchInfoListVO, BatchQueryBranchVO } from './vo/branch-info.vo';

@RestController
@RequestMapping(`${AppConfig.contextPath}${AppConfig.xhrPrefix}`, [])
export class BranchController {
    constructor(
        private service: BranchManageService
    ) { }
    /** 批量查询分支信息 */
    @PostMapping('/branch/queryBranch.json')
    async queryBranch(ctx: RequestContext>) {
        // 参数校验
        if (isNullOrUndefined(ctx.request.body)) {
             throw Boom.notFound('参数错误');
        }
        const result = await this.service.queryBranch(ctx.request.body.branchList);
        ctx.body = AjaxResult.success(result);
    }
}

三、总结

这种分层结构不仅仅是为了使代码看上去清晰,更像是我们对一个系统的拆解和组装,降低代码的耦合度,提高代码的可扩展性。它可以让你在遇到代码交接的情况下减少提刀砍人的可能性,可以让多人协作开发更容易。

你可能感兴趣的:(Node项目不会代码分层怎么办?来看看网易大神怎么做)