express 项目分层实践详解
前言
上次我们搭建了一个基本的express后台,但是这样的项目结构的可扩展性,维护性和代码复用性都不是很好,参照之前学习JavaWeb时候的四层架构设计,用分层的思想来对express进行一点小优化,进一步提高代码的可拓展性。本文的源代码在Github上,建议看着代码来看这篇文章。
1四(五)层结构概念
这个就简单说一下,所谓四层架构就是Model实体层,Dao层(数据访问层也就是从数据库中查数据),Service层(业务逻辑层,也就是处理好数据),Controller层(视图控制层,在前后端分离的情况下就是写接口响应前端请求)和前端的view(视图层),为啥要搞分层咧,说到底就是要解耦合,提高拓展性和维护性,写代码的时候,思路清晰一点,后面改代码的时候也知道要改哪边。
但是我们这次只是涉及后台的,视图层我们就不用管了,只需看前面的就行了。
2分层
首先看一下项目结构哈
│app.js │package.json │README.md │ ├─.idea ││express-project.iml ││misc.xml ││modules.xml ││vcs.xml ││watcherTasks.xml ││workspace.xml ││ │└─inspectionProfiles ├─bin │www │ ├─config │db.json │ ├─dao │BaseDao.js │UserDao.js │ ├─models │user.js │ ├─public │├─images │├─javascripts │└─stylesheets │style.css │ ├─routes │index.js │users.js │ ├─services │UserService.js │ ├─utils │db-util.js │ └─views error.jade index.jade layout.jade
按照分层思想,我们新建几个文件夹哈,首先是Model层的models文件夹,dao层的dao文件夹,service层的services文件夹,controller层的话就用原来的routes文件夹就可以了,为了方便,我加了一个全局配置的config文件夹和工具函数utils文件夹。具体项目如下,我们从最底层开始来一个一个来分析
2.1config
这个就放着各种配置文件,例如我的db.json里面就放了mongodb的端口号,数据库名那些,反正就是各种配置啦
2.2utils
这个就是有一些创建型的方法或者其他公共方法,像创建数据库连接池的方法我就放在这边的db-util里面了。
2.3models
实体层,针对mongodb来说,一个集合对应一个model,然后都是这样的形式啦。
constmongoose=require('mongoose'); const{mongoClient}=require('../utils/db-util'); //创建userSchema constuser=newmongoose.Schema({ name:String, id:String, },{versionKey:false}); /*model的参数1导出的模块名, 参数2创建的Schema, 参数2指定数据库中的集合的名字,若不加的,则抹默认取‘第一个参数s'的集合*/ letUser=mongoClient.model('User',user,'user'); module.exports=User;
2.4dao
创建完实体层,接下来就是dao层了,这边我封装了一个BaseDao,基本的数据库操作都有了,后面我们创建其他dao的时候就很舒服啦,直接继承一下BaseDao就好了。例如下面的这个UserDao:
letBaseDao=require('./BaseDao'); //导入对应的实体 letUser=require('../models/user'); classUserDaoextendsBaseDao{ constructor(){ super(User); } //如果有啥特殊需求的话,自己再重写方法咯 } module.exports=UserDao;
这样就写好了一个基本的dao了,增删改查这些他都从BaseDao中继承了,
2.5services
service层是业务逻辑层,这么写就看你项目的业务啦。我下面就简单些一个查询所有user数据的方法啦。
constUserDao=require('../dao/UserDao'); letuserDao=newUserDao(); classUserService{ asyncgetUserList(){ try{ //调用dao层查询数据 letuserList=awaituserDao.findAll(); returnuserList; }catch(err){ console.log(`getUserListerror-->${error}`); returnerror; } } } module.exports=UserService;
2.6routes
controller层,写接口用,这个写起来简单,就拿一下service层的数据返回就可以啦。
varexpress=require('express'); varrouter=express.Router(); constUserService=require('../services/UserService'); letuserService=newUserService(); /*GETuserslisting.*/ router.get('/',function(req,res,next){ userService.getUserList().then((data)=>{ res.json({ code:0, msg:'OK', data:data }) }); //res.send('respondwitharesource'); }); router.get('/login',(req,res,next)=>{ res.json({ code:0, msg:'OK', data:{result:true} }) }); module.exports=router;
然后这边的话,我有一个想法,就是想着每次多一个路由实例(controller)的时候,就要往app.js里面导入并引入,觉得这样controller多了的时候,app.js里面代码会很多,所以就想着把模块导入的代码移到routes文件夹里面的index.js里面来,app.js就引入个index就好啦。所以就有了下面index.js的代码。
varexpress=require('express'); varrouter=express.Router(); /*GEThomepage.*/ router.get('/',function(req,res,next){ res.render('index',{title:'Express'}); }); //user路由模块 //当我在user文件里面写一个'/login'的时候,前端访问就要访问'/user/login' router.use('/user',require('./users')); module.exports=router;
至此,全文就结束啦,对于express框架的分层实践如果有更好的建议或者我这样分层有啥问题的话,欢迎在在下方留言哈,大家一起学习一下。也希望大家多多支持毛票票。