├── .gitignore
├── .idea
├── express-restfulAPI.iml
├── misc.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── .vcmrc
├── .vscode
└── launch.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── app
├── apidoc
│ ├── api
│ │ ├── article.js
│ │ ├── category.js
│ │ ├── upload.js
│ │ └── user.js
│ └── define
│ │ ├── article.js
│ │ ├── category.js
│ │ ├── common.js
│ │ ├── upload.js
│ │ └── user.js
├── controllers
│ ├── article.js
│ ├── base.js
│ ├── category.js
│ ├── index.js
│ ├── test.js
│ └── users.js
├── middlewares
│ ├── index.js
│ ├── log.js
│ ├── not-find.js
│ ├── res-extend.js
│ └── verify-token.js
├── models
│ ├── article.js
│ ├── category.js
│ ├── index.js
│ ├── right.js
│ ├── role.js
│ └── users.js
├── myutil
│ ├── authentication.js
│ ├── crypto.js
│ ├── format.js
│ ├── index.js
│ ├── params-handler.js
│ ├── response-handler.js
│ ├── return.js
│ └── upload.js
├── public
│ └── default
│ │ └── defaultlogo.png
├── routes
│ ├── article.js
│ ├── category.js
│ ├── index.js
│ └── user.js
└── services
│ ├── article.js
│ ├── base.js
│ ├── category.js
│ ├── index.js
│ └── users.js
├── build
├── create-admin.js
├── index.js
├── public
│ └── upload
│ │ └── images
│ │ └── defaultlogo.png
└── server.js
├── config
├── development.json
├── enum.js
├── error-message.js
├── error-system.js
├── index.js
├── log4js.json
├── log4js.pro.json
├── pagesize.js
├── production.json
├── right.js
├── role-right.js
├── router.js
├── settings.js
├── settings.pro.js
└── success-message.js
├── package.json
├── server.js
└── test
└── http
└── user.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 | # Dependency directories
23 | node_modules/
24 |
25 | # vscode setting
26 | .vscode
27 |
28 | app/public/upload/
29 | app/public/apidoc/
30 |
31 | # Output of 'npm pack'
32 | *.tgz
33 |
34 | # log4js
35 | logs
36 |
37 | package-lock.json
--------------------------------------------------------------------------------
/.idea/express-restfulAPI.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | exports
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | true
66 | DEFINITION_ORDER
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | 1524559432624
152 |
153 |
154 | 1524559432624
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 | file://$PROJECT_DIR$/api/routes/todoListRoutes.js
201 | 6
202 |
203 |
204 |
205 | file://$PROJECT_DIR$/app/middlewares/error-handler.js
206 | 3
207 |
208 |
209 |
210 |
211 | file://$PROJECT_DIR$/app/middlewares/error-handler.js
212 | 4
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
--------------------------------------------------------------------------------
/.vcmrc:
--------------------------------------------------------------------------------
1 | {
2 | "helpMessage": "\nPlease fix your commit message (and consider using https://www.npmjs.com/package/commitizen)\n",
3 | "types": [
4 | "feat",
5 | "fix",
6 | "docs",
7 | "style",
8 | "refactor",
9 | "perf",
10 | "test",
11 | "chore",
12 | "revert"
13 | ],
14 | "warnOnFail": false,
15 | "autoFix": false
16 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "attach",
10 | <<<<<<< HEAD
11 | "name": "Attach to node",
12 | =======
13 | "name": "Attach",
14 | "runtimeExecutable": "nodemon",
15 | >>>>>>> master
16 | "port": 9229,
17 | "restart": true,
18 | "skipFiles": [
19 | "${workspaceFolder}/node_modules/**/*.js"
20 | ]
21 | }
22 | ]
23 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # [1.0.0](https://github.com/morehao/express-restfulApi/compare/v0.0.2...v1.0.0) (2018-09-12)
3 |
4 |
5 | ### Bug Fixes
6 |
7 | * **category:** category中controller命名修改 ([8c16c3b](https://github.com/morehao/express-restfulApi/commit/8c16c3b))
8 | * **users:** 用户列表接口修复,populate为空数组 ([9d3ec42](https://github.com/morehao/express-restfulApi/commit/9d3ec42))
9 |
10 |
11 | ### Features
12 |
13 | * **article:** 上传接口,获取文件的信息 ([8d2a95f](https://github.com/morehao/express-restfulApi/commit/8d2a95f))
14 | * **article:** 文章的增、改、列表接口 ([09e8e08](https://github.com/morehao/express-restfulApi/commit/09e8e08))
15 | * **article:** 新增upload接口,还未实现接口的内部逻辑 ([aacb78b](https://github.com/morehao/express-restfulApi/commit/aacb78b))
16 | * **article:** 新增文章接口 ([e5b61a6](https://github.com/morehao/express-restfulApi/commit/e5b61a6))
17 | * **article-category:** 增加文章类别的修改和列表接口 ([9ec1810](https://github.com/morehao/express-restfulApi/commit/9ec1810))
18 | * **article-category:** 文章分类,建表和创建的接口 ([35d0b59](https://github.com/morehao/express-restfulApi/commit/35d0b59))
19 | * **base-service:** baseservice增加findById,家、公司都可搬砖 ([89808cb](https://github.com/morehao/express-restfulApi/commit/89808cb))
20 | * **logs:** 优化日志,格式化日志的保存与输出 ([a909324](https://github.com/morehao/express-restfulApi/commit/a909324))
21 | * **upload:** 上传图片到七牛云 ([ea89b23](https://github.com/morehao/express-restfulApi/commit/ea89b23))
22 | * **validator:** 添加validator校验 ([c5bda27](https://github.com/morehao/express-restfulApi/commit/c5bda27))
23 |
24 |
25 |
26 |
27 | ## [0.0.2](https://github.com/morehao/express-restfulApi/compare/v0.0.1...v0.0.2) (2018-07-10)
28 |
29 |
30 | ### Bug Fixes
31 |
32 | * **files:** 删除一些无用的文件 ([885b012](https://github.com/morehao/express-restfulApi/commit/885b012))
33 | * **package-lock:** 修复github提示的hoek版本过低问题 ([bc57a40](https://github.com/morehao/express-restfulApi/commit/bc57a40))
34 | * **token:** 修复中间件检测不到token过期的问题 ([11f2657](https://github.com/morehao/express-restfulApi/commit/11f2657))
35 |
36 |
37 | ### Features
38 |
39 | * **build:** 初始化创建管理员用户 ([497f904](https://github.com/morehao/express-restfulApi/commit/497f904))
40 | * **changelog:** 新增commit提交日志 ([cca17a2](https://github.com/morehao/express-restfulApi/commit/cca17a2))
41 | * **cros:** 设置跨域访问 ([744cdd7](https://github.com/morehao/express-restfulApi/commit/744cdd7))
42 | * **data-return:** 对返回的数据进行格式化处理 ([762ef76](https://github.com/morehao/express-restfulApi/commit/762ef76))
43 | * **error-handler:** 通过中间件对错误进行统一处理 ([96fb203](https://github.com/morehao/express-restfulApi/commit/96fb203))
44 | * **list:** 分页处理,增加总数据数目dataCount ([f8d7c68](https://github.com/morehao/express-restfulApi/commit/f8d7c68))
45 | * **log4js:** 请求日志console到命令行终端工具 ([db27a8f](https://github.com/morehao/express-restfulApi/commit/db27a8f))
46 | * **log4js:** 通过log4js记录程序日志 ([d131947](https://github.com/morehao/express-restfulApi/commit/d131947))
47 | * **mocha-test:** 利用mocha测试框架编写单元测试 ([7baa7e4](https://github.com/morehao/express-restfulApi/commit/7baa7e4))
48 | * **package-lock:** 删除package-lock.json,重新生成该文件 ([e21aa6d](https://github.com/morehao/express-restfulApi/commit/e21aa6d))
49 | * **role-right:** 权限管理model文件 ([91223ec](https://github.com/morehao/express-restfulApi/commit/91223ec))
50 | * **study-async:** 新增node改写回调函数的学习 ([dfd2ccc](https://github.com/morehao/express-restfulApi/commit/dfd2ccc))
51 | * **token:** JWT实现token机制 ([bcbefae](https://github.com/morehao/express-restfulApi/commit/bcbefae))
52 | * **user-login:** 新增用户登录接口 ([0fb860d](https://github.com/morehao/express-restfulApi/commit/0fb860d))
53 | * **users:** 用户管理的增删改查基本接口 ([54b534d](https://github.com/morehao/express-restfulApi/commit/54b534d))
54 |
55 |
56 | ### Performance Improvements
57 |
58 | * **middlewares:** 优化中间件注册和使用 ([1667338](https://github.com/morehao/express-restfulApi/commit/1667338))
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 morehao
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # express-blog
2 | 在express框架下的学习与摸索,如果可能,最终希望形成一个博客系统
3 | 1、restfulAPI的实现
4 | 2、实现MVC模式
5 | 3、res添加属性,对返回的数据格式化为统一的标准
6 | 4、对错误进行通过中间件进行统一处理
7 | 5、用户管理的简单增删改查接口
8 | 6、用户列表查询的封装处理
9 | 7、npm run build 初始化创建管理员用户
10 | 8、读出数据的二次处理(填充)
11 | 9、学习使用vscode调试程序
12 | 10、使用JWT实现token认证
13 | 11、使用log4js管理日志
14 | 12、使用mocha框架编写测试代码
15 | 13、设置跨域访问
16 | 14、优化日志,格式化日志信息,但仍需修改
17 | 15、 后来添加的东西忘记记录了。。。。。
18 | 参考资料:
19 | [restful api](https://www.codementor.io/olatundegaruba/nodejs-restful-apis-in-10-minutes-q0sgsfhbd)
20 | [log4js](https://juejin.im/post/5b7d0e20f265da43231f00d4)
21 |
22 | 命令说明:
23 | ``` shell
24 | # 安装依赖
25 | npm install
26 | # 开发模式启动程序
27 | npm run dev
28 | # 生产模式启动程序
29 | npm run start
30 | # 生成接口文档
31 | npm run apidoc
32 | # 生成提交日志
33 | npm run changelog
34 | # 运行测试代码
35 | npm run test
36 | # 初始化构建,生成admin账号
37 | npm run build
38 | ```
39 | 注:执行`npm run apidoc`后启动程序,开发环境下访问`localhost:4000/apidoc`即可查看接口文档。
40 |
--------------------------------------------------------------------------------
/app/apidoc/api/article.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | * @api {POST} /article 新增文章
4 | * @apiName create an article
5 | * @apiGroup Article
6 | * @apiDescription 新增文章的接口
7 | * @apiUse headerParams
8 | * @apiUse articleParams
9 | * @apiUse articleCreareResponse
10 | * @apiErrorExample {json} Error-Response:
11 | * {
12 | * status: 200,
13 | * errorCode: 20401,
14 | * errorMsg: '该文章已经存在'
15 | * }
16 | */
17 |
18 | /**
19 | * @api {PUT} /article/:_id 文章更新
20 | * @apiName update an article
21 | * @apiGroup Article
22 | * @apiDescription 文章更新的接口
23 | * @apiUse headerParams
24 | * @apiParam {String} _id 文章的id
25 | * @apiUse articleParamsOptional
26 | * @apiSuccessExample Success-Response:
27 | {
28 | "status": 200,
29 | "errorCode": 0,
30 | "data": "文章修改成功!"
31 | }
32 | * @apiUse articleNotFind
33 | */
34 |
35 | /**
36 | * @api {GET} /article/:_id 文章详情
37 | * @apiName view an article
38 | * @apiGroup Article
39 | * @apiDescription 文章详情的接口
40 | * @apiUse headerParams
41 | * @apiParam {String} _id 文章的id
42 | * @apiUse articleResponse
43 | * @apiUse articleNotFind
44 | */
45 |
46 | /**
47 | * @api {GET} /article 文章列表
48 | * @apiName get articleList
49 | * @apiGroup Article
50 | * @apiDescription 文章列表的接口
51 | * @apiUse headerParams
52 | * @apiUse listParams
53 | * @apiUse articleParamsOptional
54 | * @apiUse articleListResponse
55 | * @apiUse articleNotFind
56 | */
57 |
--------------------------------------------------------------------------------
/app/apidoc/api/category.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | * @api {POST} /category 新增文章类别
4 | * @apiName create a category
5 | * @apiGroup Category
6 | * @apiDescription 新增文章类别的接口
7 | * @apiUse headerParams
8 | * @apiUse categoryParams
9 | * @apiUse categoryCreateResponse
10 | * @apiErrorExample {json} Error-Response:
11 | * {
12 | * status: 200,
13 | * errorCode: 20301,
14 | * errorMsg: '该分类已经存在'
15 | * }
16 | */
17 |
18 | /**
19 | * @api {PUT} /category/:_id 文章类别更新
20 | * @apiName update a category
21 | * @apiGroup Category
22 | * @apiDescription 文章类别更新的接口
23 | * @apiUse headerParams
24 | * @apiParam {String} _id 文章类别的id
25 | * @apiParam {String} name 可选,文章类别的名称
26 | * @apiUse categoryResponse
27 | * @apiUse categoryNotFind
28 | */
29 |
30 | /**
31 | * @api {GET} /category/:_id 文章类别详情
32 | * @apiName view a category
33 | * @apiGroup Category
34 | * @apiDescription 文章类别详情的接口
35 | * @apiUse headerParams
36 | * @apiParam {String} _id 文章类别的id
37 | * @apiUse categoryResponse
38 | * @apiUse categoryNotFind
39 | */
40 |
41 | /**
42 | * @api {GET} /category/:_id 文章类别列表
43 | * @apiName get categoryList
44 | * @apiGroup Category
45 | * @apiDescription 文章类别列表的接口
46 | * @apiUse headerParams
47 | * @apiUse listParams
48 | * @apiParam {String} name 可选,文章类别的名称
49 | * @apiUse categoryListResponse
50 | * @apiUse categoryNotFind
51 | */
52 |
--------------------------------------------------------------------------------
/app/apidoc/api/upload.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | * @api {POST} /upload 图片上传
4 | * @apiName upload
5 | * @apiGroup Upload
6 | * @apiDescription 图片上传的接口,form-data方式
7 | * @apiUse headerParams
8 | * @apiParam {File} file 上传的图片文件
9 | * @apiSuccessExample Success-Response:
10 | {
11 | "status": 200,
12 | "errorCode": 0,
13 | "data": [
14 | {
15 | "imageUrl": "127.0.0.1:4000/upload/0c990080-cbab-11e8-b47c-83c45848f87a.jpg",
16 | "imageName": "0c990080-cbab-11e8-b47c-83c45848f87a.jpg",
17 | "resource": "server"
18 | }
19 | ]
20 | }
21 | */
22 |
--------------------------------------------------------------------------------
/app/apidoc/api/user.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | * @api {POST} /user 新增用户
4 | * @apiDescription 用户新增的接口
5 | * @apiName create a user
6 | * @apiGroup User
7 | * @apiUse userParams
8 | * @apiUse userResponse
9 | * @apiErrorExample {json} Error-Response:
10 | * {
11 | * status: 200,
12 | * errorCode: 20100,
13 | * errorMsg: '该用户已经存在'
14 | * }
15 | */
16 |
17 | /**
18 | * @api {DELETE} /user/:_id 删除用户
19 | * @apiDescription 用户删除的接口
20 | * @apiName delete a user
21 | * @apiGroup User
22 | * @apiUse headerParams
23 | * @apiParam {String} _id 用户的id
24 | * @apiSuccessExample Success-Response:
25 | * {
26 | * errorCode: 0,
27 | * status: 200,
28 | * data: "用户删除成功!"
29 | * }
30 | * @apiUse userNotFind
31 | */
32 |
33 | /**
34 | * @api {PUT} /user/:_id 更新用户
35 | * @apiDescription 更新用户信息的接口
36 | * @apiName update a user
37 | * @apiGroup User
38 | * @apiUse headerParams
39 | * @apiParam {String} _id 用户的id
40 | * @apiUse userParamsOptional
41 | * @apiSuccessExample Success-Response:
42 | * {
43 | * errorCode: 0,
44 | * status: 200,
45 | * data: "用户信息更新成功!"
46 | * }
47 | * @apiUse userNotFind
48 | */
49 |
50 | /**
51 | * @api {POST} /user/:_id 用户详情
52 | * @apiDescription 用户详情的接口
53 | * @apiName view a user
54 | * @apiGroup User
55 | * @apiUse headerParams
56 | * @apiParam {String} _id 用户的id
57 | * @apiUse userResponse
58 | * @apiUse userNotFind
59 | */
60 |
61 | /**
62 | * @api {GET} /user 用户列表
63 | * @apiDescription 查看用户列表的接口
64 | * @apiName get userList
65 | * @apiGroup User
66 | * @apiUse headerParams
67 | * @apiUse listParams
68 | * @apiUse userParamsOptional
69 | * @apiUse userListResponse
70 | * @apiUse userNotFind
71 | */
72 |
73 | /**
74 | * @api {POST} /users/login 用户登录
75 | * @apiDescription 用户登录的接口
76 | * @apiName user login
77 | * @apiGroup User
78 | * @apiParam {String} name 用户名
79 | * @apiParam {String} password 密码
80 | * @apiSuccessExample Success-Response:
81 | {
82 | "status": 200,
83 | "errorCode": 0,
84 | "data": {
85 | "_id": "5bbc59366501713374220caa",
86 | "intruction": "这个人很懒,什么都有没留下、、、",
87 | "logo": "/upload/images/defaultlogo.png",
88 | "role": "ordinary users",
89 | "name": "morehao",
90 | "nickName": "毛浩先生",
91 | "age": 24,
92 | "sex": "male",
93 | "company": "太原科技大学",
94 | "website": "morehao.com",
95 | "createdAt": "2018-10-09 15:31:02",
96 | "updatedAt": "2018-10-09 15:31:02",
97 | "__v": 0,
98 | "reSex": "男",
99 | "lastLogin": "暂无登录记录",
100 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1YmJjNTkzNjY1MDE3MTMzNzQyMjBjYWEiLCJpYXQiOjE1MzkwNzAzNjksImV4cCI6MTUzOTE1Njc2OX0.NkluX_5Z7NhcE_azAa16Jtqh3YBnbzXO2MecYKD0exs"
101 | }
102 | }
103 | * @apiUse userNotFind
104 | */
105 |
--------------------------------------------------------------------------------
/app/apidoc/define/article.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | @apiDefine articleParams
4 | @apiParam {String} title 文章标题
5 | @apiParam {String} content 文章内容
6 | @apiParam {String} type 文章格式,可选值为['markdown', 'html']
7 | */
8 |
9 | /**
10 | @apiDefine articleParamsOptional
11 | @apiParam {String} title 可选,文章标题
12 | @apiParam {String} type 可选,文章格式,可选值为['markdown', 'html']
13 | */
14 |
15 | /**
16 | * @apiDefine articleCreareResponse
17 | * @apiSuccessExample Success-Response:
18 | {
19 | "status": 200,
20 | "errorCode": 0,
21 | "data": {
22 | "countInfo": {
23 | "commentCount": 0,
24 | "visitCount": 0,
25 | "collectCount": 0,
26 | "likeCount": 0
27 | },
28 | "top": false,
29 | "good": false,
30 | "deleted": false,
31 | "_id": "5bbc77aded51c71df03f3ba9",
32 | "title": "标题1",
33 | "content": "内容1",
34 | "categoryId": "5bbc6241dbaf531fac21b662",
35 | "authorId": "5bbc59366501713374220caa",
36 | "createAt": "2018-10-09T09:41:01.086Z",
37 | "updateAt": "2018-10-09T09:41:01.087Z",
38 | "__v": 0
39 | }
40 | }
41 | */
42 |
43 | /**
44 | * @apiDefine articleResponse
45 | * @apiSuccessExample Success-Response:
46 | {
47 | "status": 200,
48 | "errorCode": 0,
49 | "data": {
50 | "countInfo": {
51 | "commentCount": 0,
52 | "visitCount": 0,
53 | "collectCount": 0,
54 | "likeCount": 0
55 | },
56 | "top": false,
57 | "good": false,
58 | "deleted": false,
59 | "_id": "5bbc77aded51c71df03f3ba9",
60 | "title": "标题",
61 | "content": "内容1",
62 | "categoryId": {
63 | "_id": "5bbc6241dbaf531fac21b662",
64 | "name": "类别1",
65 | "userId": "5bbc59366501713374220caa",
66 | "createdAt": "2018-10-09 16:09:37",
67 | "updatedAt": "2018-10-09 16:09:37",
68 | "__v": 0,
69 | "id": "5bbc6241dbaf531fac21b662"
70 | },
71 | "authorId": {
72 | "intruction": "这个人很懒,什么都有没留下、、、",
73 | "logo": "/upload/images/defaultlogo.png",
74 | "role": "ordinary users",
75 | "_id": "5bbc59366501713374220caa",
76 | "name": "morehao",
77 | "nickName": "毛浩先生",
78 | "age": 24,
79 | "sex": "male",
80 | "company": "太原科技大学",
81 | "website": "morehao.com",
82 | "createdAt": "2018-10-09 15:31:02",
83 | "updatedAt": "2018-10-09 15:31:02",
84 | "__v": 0,
85 | "lastLogin": "2018-10-09 17:48:43",
86 | "id": "5bbc59366501713374220caa"
87 | },
88 | "createAt": "2018-10-09T09:41:01.086Z",
89 | "updateAt": "2018-10-09T09:41:01.087Z",
90 | "__v": 0
91 | }
92 | }
93 | */
94 |
95 | /**
96 | * @apiDefine articleListResponse
97 | * @apiSuccessExample Success-Response:
98 | {
99 | "status": 200,
100 | "errorCode": 0,
101 | "data": {
102 | "dataCount": 1,
103 | "list": [
104 | {
105 | "_id": "5bbc77aded51c71df03f3ba9",
106 | "countInfo": {
107 | "commentCount": 0,
108 | "visitCount": 0,
109 | "collectCount": 0,
110 | "likeCount": 0
111 | },
112 | "top": false,
113 | "good": false,
114 | "deleted": false,
115 | "title": "标题",
116 | "content": "内容1",
117 | "categoryId": {
118 | "_id": "5bbc6241dbaf531fac21b662",
119 | "name": "类别1",
120 | "userId": "5bbc59366501713374220caa",
121 | "createdAt": "2018-10-09T08:09:37.986Z",
122 | "updatedAt": "2018-10-09T08:09:37.000Z",
123 | "__v": 0
124 | },
125 | "authorId": {
126 | "_id": "5bbc59366501713374220caa",
127 | "intruction": "这个人很懒,什么都有没留下、、、",
128 | "logo": "/upload/images/defaultlogo.png",
129 | "role": "ordinary users",
130 | "name": "morehao",
131 | "nickName": "毛浩先生",
132 | "age": 24,
133 | "sex": "male",
134 | "company": "太原科技大学",
135 | "website": "morehao.com",
136 | "createdAt": "2018-10-09T07:31:02.362Z",
137 | "updatedAt": "2018-10-09T07:31:02.000Z",
138 | "__v": 0
139 | },
140 | "createAt": "2018-10-09T09:41:01.086Z",
141 | "updateAt": "2018-10-09T09:41:01.087Z",
142 | "__v": 0
143 | }
144 | ]
145 | }
146 | }
147 | */
148 |
149 | /**
150 | * @apiDefine articleNotFind
151 | * @apiErrorExample {json} Error-Response:
152 | * {
153 | * status: 200,
154 | * errorCode: 20402,
155 | * errorMsg: '该文章不存在'
156 | * }
157 | */
158 |
--------------------------------------------------------------------------------
/app/apidoc/define/category.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | @apiDefine categoryParams
4 | @apiParam {String} name 文章类别名称
5 | */
6 |
7 | /**
8 | * @apiDefine categoryCreateResponse
9 | * @apiSuccessExample Success-Response:
10 | {
11 | "status": 200,
12 | "errorCode": 0,
13 | "data": {
14 | "_id": "5bbc5fbe2e22a330ccad507a",
15 | "name": "类别",
16 | "userId": "5bbc59366501713374220caa",
17 | "createdAt": "2018-10-09 15:58:54",
18 | "updatedAt": "2018-10-09 15:58:54",
19 | "__v": 0,
20 | "id": "5bbc5fbe2e22a330ccad507a"
21 | }
22 | }
23 | */
24 |
25 | /**
26 | * @apiDefine categoryResponse
27 | * @apiSuccessExample Success-Response:
28 | {
29 | "status": 200,
30 | "errorCode": 0,
31 | "data": {
32 | "_id": "5bbc6241dbaf531fac21b662",
33 | "name": "类别1",
34 | "userId": {
35 | "intruction": "这个人很懒,什么都有没留下、、、",
36 | "logo": "/upload/images/defaultlogo.png",
37 | "role": "ordinary users",
38 | "_id": "5bbc59366501713374220caa",
39 | "name": "morehao",
40 | "nickName": "毛浩先生",
41 | "age": 24,
42 | "sex": "male",
43 | "company": "太原科技大学",
44 | "website": "morehao.com",
45 | "createdAt": "2018-10-09 15:31:02",
46 | "updatedAt": "2018-10-09 15:31:02",
47 | "__v": 0,
48 | "lastLogin": "2018-10-09 16:56:54",
49 | "id": "5bbc59366501713374220caa"
50 | },
51 | "createdAt": "2018-10-09 16:09:37",
52 | "updatedAt": "2018-10-09 16:09:37",
53 | "__v": 0,
54 | "id": "5bbc6241dbaf531fac21b662"
55 | }
56 | }
57 | */
58 |
59 | /**
60 | * @apiDefine categoryListResponse
61 | * @apiSuccessExample Success-Response:
62 | {
63 | "status": 200,
64 | "errorCode": 0,
65 | "data": {
66 | "dataCount": 2,
67 | "list": [
68 | {
69 | "_id": "5bbc5fbe2e22a330ccad507a",
70 | "name": "类别",
71 | "userId": {
72 | "_id": "5bbc59366501713374220caa",
73 | "intruction": "这个人很懒,什么都有没留下、、、",
74 | "logo": "/upload/images/defaultlogo.png",
75 | "role": "ordinary users",
76 | "name": "morehao",
77 | "nickName": "毛浩先生",
78 | "age": 24,
79 | "sex": "male",
80 | "company": "太原科技大学",
81 | "website": "morehao.com",
82 | "createdAt": "2018-10-09T07:31:02.362Z",
83 | "updatedAt": "2018-10-09T07:31:02.000Z",
84 | "__v": 0
85 | },
86 | "createdAt": "2018-10-09T07:58:54.940Z",
87 | "updatedAt": "2018-10-09T07:58:54.000Z",
88 | "__v": 0
89 | }
90 | ]
91 | }
92 | }
93 | */
94 |
95 | /**
96 | * @apiDefine categoryNotFind
97 | * @apiErrorExample {json} Error-Response:
98 | * {
99 | * status: 200,
100 | * errorCode: 20302,
101 | * errorMsg: '该分类不存在'
102 | * }
103 | */
104 |
--------------------------------------------------------------------------------
/app/apidoc/define/common.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | * @apiDefine headerParams
4 | * @apiHeader {String} token 用户登录后返回的token令牌
5 | */
6 | /**
7 | * @apiDefine listParams
8 | * @apiParam {Number} page 可选,列表数据页码
9 | * @apiParam {Number} pagesize 可选,一页展示的数据条数
10 | */
11 |
--------------------------------------------------------------------------------
/app/apidoc/define/upload.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/morehao/express-blog/46c9903e72d2a32e481b5a50c9c847fb11e43ca4/app/apidoc/define/upload.js
--------------------------------------------------------------------------------
/app/apidoc/define/user.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /**
3 | * @apiDefine userParams
4 | * @apiParam {String} name 用户名
5 | * @apiParam {Number} age 年龄
6 | * @apiParam {String} nickName 昵称
7 | * @apiParam {Enum} sex 性别
8 | * @apiParam {String} company 学校或者公司
9 | * @apiParam {String} website 个人网站
10 | * @apiParam {String} instruction 个人简介
11 | * @apiParam {String} role 用户角色
12 | */
13 |
14 | /**
15 | * @apiDefine userParamsOptional
16 | * @apiParam {String} name 可选,用户名
17 | * @apiParam {Number} age 可选,年龄
18 | * @apiParam {String} nickName 可选,昵称
19 | * @apiParam {Enum} sex 可选,性别
20 | * @apiParam {String} company 可选,学校或者公司
21 | * @apiParam {String} website 可选,个人网站
22 | * @apiParam {String} instruction 可选,个人简介
23 | * @apiParam {String} role 可选,用户角色
24 | */
25 |
26 | /**
27 | * @apiDefine userResponse
28 | * @apiSuccessExample Success-Response:
29 | {
30 | "status": 200,
31 | "errorCode": 0,
32 | "data": {
33 | "intruction": "这个人很懒,什么都有没留下、、、",
34 | "logo": "/upload/images/defaultlogo.png",
35 | "role": "ordinary users",
36 | "_id": "5bbc59366501713374220caa",
37 | "name": "morehao",
38 | "nickName": "毛浩先生",
39 | "age": 24,
40 | "sex": "male",
41 | "company": "太原科技大学",
42 | "website": "morehao.com",
43 | "createdAt": "2018-10-09 15:31:02",
44 | "updatedAt": "2018-10-09 15:31:02",
45 | "__v": 0,
46 | "lastLogin": "2018-10-09 15:31:02",
47 | "id": "5bbc59366501713374220caa",
48 | "reSex": "男"
49 | }
50 | }
51 | */
52 |
53 | /**
54 | * @apiDefine userListResponse
55 | * @apiSuccessExample Success-Response:
56 | {
57 | "status": 200,
58 | "errorCode": 0,
59 | "data": {
60 | "dataCount": 1,
61 | "list": [
62 | {
63 | "_id": "5bbc59366501713374220caa",
64 | "intruction": "这个人很懒,什么都有没留下、、、",
65 | "logo": "/upload/images/defaultlogo.png",
66 | "role": "ordinary users",
67 | "name": "morehao",
68 | "nickName": "毛浩先生",
69 | "age": 24,
70 | "sex": "male",
71 | "company": "太原科技大学",
72 | "website": "morehao.com",
73 | "createdAt": "2018-10-09 15:31:02",
74 | "updatedAt": "2018-10-09 15:31:02",
75 | "__v": 0,
76 | "reSex": "男",
77 | "lastLogin": "暂无登录记录"
78 | }
79 | ]
80 | }
81 | }
82 | */
83 | /**
84 | * @apiDefine userNotFind
85 | * @apiErrorExample {json} Error-Response:
86 | * {
87 | * status: 200,
88 | * errorCode: 20101,
89 | * errorMsg: '该用户不存在!'
90 | * }
91 | */
92 |
--------------------------------------------------------------------------------
/app/controllers/article.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const uuidv1 = require('uuid/v1')
3 | const path = require('path')
4 | const Services = require('../services')
5 | const {auth, resHandler, paramsHandler, validator, upload} = require('../myutil')
6 | const {pageConfig, settings} = require('../../config')
7 | class ArticleController {
8 | async create (req, res) {
9 | try {
10 | if (validator.isEmpty(req.body.title, {ignore_whitespace: true})) {
11 | const errorMsg = 'TITLE_IS_EMPTY'
12 | throw errorMsg
13 | }
14 | if (validator.isEmpty(req.body.content, {ignore_whitespace: true})) {
15 | const errorMsg = 'CONTENT_IS_EMPTY'
16 | throw errorMsg
17 | }
18 | const userInfo = auth.verifyToken(req.headers.token)
19 | req.body.authorId = userInfo.userId
20 | const result = await Services.article.addArticle(req.body)
21 | res.sendOk(result)
22 | } catch (error) {
23 | const errorRes = resHandler.getErrorRes(error)
24 | res.sendErr(errorRes)
25 | }
26 | }
27 | async update (req, res) {
28 | try {
29 | const result = await Services.article.editById(req.params._id, req.body)
30 | res.sendOk(result)
31 | } catch (error) {
32 | res.sendErr(error)
33 | }
34 | }
35 | async upload (req, res) {
36 | try {
37 | const fileInfo = await upload.getFileInfo(req)
38 | let tasks = []
39 | let result
40 | if (!settings.qiniuConfig.accessKey) {
41 | let saveRes = []
42 | for (let item in fileInfo.files) {
43 | const uid = uuidv1()
44 | const filePath = fileInfo.files[item].path
45 | const fileName = uid + path.extname(fileInfo.files[item].name).toLowerCase()
46 | const target = path.join(settings.upload.savePath, fileName)
47 | saveRes.push(await Services.article.saveFile(filePath, target, fileName))
48 | }
49 | result = saveRes.map(item => {
50 | let obj = {
51 | imageUrl: `${settings.website}${settings.upload.showPath}${item}`,
52 | imageName: item,
53 | resource: 'server'
54 | }
55 | return obj
56 | })
57 | } else {
58 | for (let item in fileInfo.files) {
59 | const uid = uuidv1()
60 | const filePath = fileInfo.files[item].path
61 | const fileName = uid + path.extname(fileInfo.files[item].name).toLowerCase()
62 | tasks.push(Services.article.qiniuUpload(filePath, fileName))
63 | }
64 | const qiniuRes = await Promise.all(tasks)
65 | result = qiniuRes.map(item => {
66 | let obj = {
67 | imageUrl: `${settings.qiniuConfig.originUrl}${item.key}`,
68 | imageName: item.key,
69 | resource: 'qiniu'
70 | }
71 | return obj
72 | })
73 | }
74 | res.sendOk(result)
75 | } catch (error) {
76 | res.sendErr(error)
77 | }
78 | }
79 | async detail (req, res) {
80 | try {
81 | const result = await Services.article.getArticleById(req.params._id)
82 | res.sendOk(result)
83 | } catch (error) {
84 | const errorRes = resHandler.getErrorRes(error)
85 | res.sendErr(errorRes)
86 | }
87 | }
88 | async list (req, res) {
89 | try {
90 | // 翻页参数处理
91 | const offset = paramsHandler.offsetFormat(req.query, pageConfig.article)
92 | console.log(req.query)
93 | const queryObj = {
94 | condition: req.query,
95 | skipCount: offset.skipCount,
96 | pagesize: offset.pagesize,
97 | sortRule: offset.sortRule,
98 | populate: [{path: 'authorId', select: '-password'}, {path: 'categoryId'}]
99 | }
100 | const result = await Services.article.getArticleList(queryObj)
101 | res.sendOk(result)
102 | } catch (error) {
103 | const errorRes = resHandler.getErrorRes(error)
104 | res.sendErr(errorRes)
105 | }
106 | }
107 | }
108 | module.exports = new ArticleController()
109 |
--------------------------------------------------------------------------------
/app/controllers/base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mdb = require('../models')
3 |
4 | class BaseController {
5 | constructor (modelName) {
6 | this.modelName = modelName
7 | this.name = 'aaaa'
8 | }
9 | async test () {
10 | console.log('this.name', this.name)
11 | const result = await mdb[this.modelName].find()
12 | return result
13 | }
14 | }
15 | module.exports = BaseController
16 |
--------------------------------------------------------------------------------
/app/controllers/category.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const Services = require('../services')
3 | const {auth, resHandler, paramsHandler, validator} = require('../myutil')
4 | const {pageConfig} = require('../../config')
5 |
6 | class CategoryController {
7 | async create (req, res) {
8 | try {
9 | if (validator.isEmpty(req.body.name, {ignore_whitespace: true})) {
10 | const errorMsg = 'CATEGORYNAME_IS_EMPTY'
11 | throw errorMsg
12 | }
13 | const userInfo = auth.verifyToken(req.headers.token)
14 | req.body.userId = userInfo.userId
15 | const result = await Services.category.addCategory(req.body)
16 | res.sendOk(result)
17 | } catch (error) {
18 | const errorRes = resHandler.getErrorRes(error)
19 | res.sendErr(errorRes)
20 | }
21 | }
22 |
23 | async update (req, res) {
24 | try {
25 | const result = await Services.category.editById(req.params._id, req.body)
26 | res.sendOk(result)
27 | } catch (error) {
28 | const errorRes = resHandler.getErrorRes(error)
29 | res.sendErr(errorRes)
30 | }
31 | }
32 |
33 | async detail (req, res) {
34 | try {
35 | const result = await Services.category.getCategoryById(req.params._id)
36 | res.sendOk(result)
37 | } catch (error) {
38 | const errorRes = resHandler.getErrorRes(error)
39 | res.sendErr(errorRes)
40 | }
41 | }
42 |
43 | async list (req, res) {
44 | try {
45 | // 翻页参数处理
46 | const offset = paramsHandler.offsetFormat(req.query, pageConfig.users)
47 | const queryObj = {
48 | condition: req.query,
49 | skipCount: offset.skipCount,
50 | pagesize: offset.pagesize,
51 | sortRule: offset.sortRule,
52 | populate: [{path: 'userId', select: '-password'}]
53 | }
54 | const result = await Services.category.getCategoryList(queryObj)
55 | res.sendOk(result)
56 | } catch (error) {
57 | // const errorRes = resHandler.getErrorRes(error)
58 | // res.sendErr(errorRes)
59 | res.sendErr(error)
60 | }
61 | }
62 | }
63 | module.exports = new CategoryController()
64 |
--------------------------------------------------------------------------------
/app/controllers/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const controllers = {}
3 | controllers.users = require('./users')
4 | controllers.category = require('./category')
5 | controllers.article = require('./article')
6 | controllers.test = require('./test')
7 |
8 | module.exports = controllers
9 |
--------------------------------------------------------------------------------
/app/controllers/test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // const uuid = require('uuid/v1')
3 | const BaseController = require('./base')
4 | class TestController extends BaseController {
5 | constructor (modelName) {
6 | super(modelName)
7 | this.modelName = 'User'
8 | this.testResponse = this.testResponse.bind(this)
9 | }
10 |
11 | async testResponse (req, res) {
12 | try {
13 | const result = await super.test()
14 | res.send({data: result})
15 | } catch (error) {
16 | res.sendErr(error)
17 | }
18 | }
19 | }
20 | module.exports = new TestController()
21 |
--------------------------------------------------------------------------------
/app/controllers/users.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const Services = require('../services')
3 | const {auth, format, resHandler, paramsHandler} = require('../myutil')
4 | const {pageConfig} = require('../../config')
5 |
6 | class UsersController {
7 | async create (req, res) {
8 | try {
9 | const result = await Services.users.addUser(req.body)
10 | res.sendOk(result)
11 | } catch (error) {
12 | const errorRes = resHandler.getErrorRes(error)
13 | res.sendErr(errorRes)
14 | }
15 | }
16 | async destroy (req, res) {
17 | try {
18 | const result = await Services.users.destroy(req.params._id)
19 | res.sendOk(result)
20 | } catch (error) {
21 | const errorRes = resHandler.getErrorRes(error)
22 | res.sendErr(errorRes)
23 | }
24 | }
25 | async update (req, res) {
26 | try {
27 | const params = req.body
28 | params._id = req.params._id
29 | const result = await Services.users.update(req.body)
30 | res.sendOk(result)
31 | } catch (error) {
32 | const errorRes = resHandler.getErrorRes(error)
33 | res.sendErr(errorRes)
34 | }
35 | }
36 | async list (req, res) {
37 | try {
38 | // 翻页参数处理
39 | const offset = paramsHandler.offsetFormat(req.query, pageConfig.users)
40 | const queryObj = {
41 | condition: req.query,
42 | skipCount: offset.skipCount,
43 | pagesize: offset.pagesize,
44 | sortRule: offset.sortRule,
45 | populate: []
46 | }
47 | const userList = await Services.users.getUserList(queryObj)
48 | userList.list = userList.list.map(data => {
49 | return format.user(data)
50 | })
51 | res.sendOk(userList)
52 | } catch (error) {
53 | const errorRes = resHandler.getErrorRes(error)
54 | res.sendErr(errorRes)
55 | }
56 | // const modelObj = {
57 | // user: mdbs.User
58 | // }
59 | // const result = await modelObj[req.query.modelName].find()
60 | // const result = await mdbs.User.find({
61 | // $or: [
62 | // {name: {$regex: 'admin', $options: 'i'}},
63 | // {name: {$regex: 'test001', $options: 'i'}}
64 | // ]
65 | // })
66 | }
67 | async detail (req, res) {
68 | try {
69 | const result = await Services.users.detail(req.params._id)
70 | res.sendOk(result)
71 | } catch (error) {
72 | const errorRes = resHandler.getErrorRes(error)
73 | res.sendErr(errorRes)
74 | }
75 | }
76 | async login (req, res) {
77 | try {
78 | const result = await Services.users.login(req.body)
79 | result.token = auth.createToken(result._id)
80 | res.sendOk(result)
81 | } catch (error) {
82 | const errorRes = resHandler.getErrorRes(error)
83 | res.sendErr(errorRes)
84 | }
85 | }
86 | async test (req, res) {
87 | const result = await Services.users.test(req.body.name)
88 | res.sendOk(result)
89 | }
90 | }
91 | module.exports = new UsersController()
92 |
--------------------------------------------------------------------------------
/app/middlewares/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const middleware = {}
3 |
4 | middleware.resExtend = require('./res-extend')
5 | middleware.verifyToken = require('./verify-token')
6 | middleware.notFind = require('./not-find')
7 | middleware.log = require('./log.js')
8 |
9 | module.exports = middleware
10 |
--------------------------------------------------------------------------------
/app/middlewares/log.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const uuidv4 = require('uuid/v4')
3 | module.exports = (req, res, next) => {
4 | const headers = req.headers
5 | if (!headers.traceId) {
6 | headers.traceId = uuidv4()
7 | }
8 | const traceId = headers.traceId
9 | logger.info(`traceId:${traceId}`)
10 | next()
11 | }
12 |
--------------------------------------------------------------------------------
/app/middlewares/not-find.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // 404错误处理中间件
3 | const {resHandler} = require('../myutil')
4 |
5 | module.exports = (req, res, next) => {
6 | const errorRes = resHandler.getErrorRes('NOT_FIND_ROUTE')
7 | res.sendErr(errorRes)
8 | }
9 |
--------------------------------------------------------------------------------
/app/middlewares/res-extend.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = (req, res, next) => {
3 | res.sendOk = (data) => {
4 | const rst = {
5 | status: 200,
6 | errorCode: 0,
7 | data: data
8 | }
9 | logger.info(`traceId:${req.headers.traceId}`)
10 | logger.info(`method: [${req.method}] req-url: ${req.url}`)
11 | logger.info(`req-query:${JSON.stringify(req.query)}`)
12 | logger.info(`req-params:${JSON.stringify(req.params)}`)
13 | if (req.url !== '/user/login') {
14 | logger.info(`req-body:${JSON.stringify(req.body)}`)
15 | }
16 | logger.info(`sendOk:${JSON.stringify(data)}`)
17 | res.send(rst)
18 | }
19 | res.sendErr = (errorInfo) => {
20 | logger.info(`traceId:${req.headers.traceId}`)
21 | logger.error(`method: [${req.method}] req-url: ${req.url}`)
22 | logger.error(`req-query:${JSON.stringify(req.query)}`)
23 | logger.error(`req-params:${JSON.stringify(req.params)}`)
24 | logger.error(`req-body:${JSON.stringify(req.body)}`)
25 | logger.error(`sendErr:${JSON.stringify(errorInfo)}`)
26 | res.send(errorInfo)
27 | }
28 | next()
29 | }
30 |
--------------------------------------------------------------------------------
/app/middlewares/verify-token.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const {auth, resHandler} = require('../myutil')
3 |
4 | module.exports = (req, res, next) => {
5 | const headers = req.headers
6 | if (!headers.token) {
7 | const errorRes = resHandler.getErrorRes('TOKEN_IS_MISSING')
8 | res.sendErr(errorRes)
9 | return
10 | }
11 | try {
12 | auth.verifyToken(headers.token)
13 | next()
14 | } catch (error) {
15 | const errorRes = resHandler.getErrorMsg(error)
16 | res.sendErr(errorRes)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/models/article.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mongoose = require('mongoose')
3 | const Schema = mongoose.Schema
4 | const ObjectId = Schema.ObjectId
5 | const ArticleSchema = new Schema({
6 | title: { type: String },
7 | content: { type: String },
8 | authorId: { type: ObjectId, ref: 'Users', index: true },
9 | top: { type: Boolean, default: false, index: true }, // 置顶文章
10 | good: { type: Boolean, default: false }, // 精华文章
11 | createAt: { type: Date, default: Date.now, index: true },
12 | updateAt: { type: Date, default: Date.now },
13 | countInfo: {
14 | commentCount: {type: Number, default: 0},
15 | visitCount: {type: Number, default: 0},
16 | collectCount: {type: Number, default: 0},
17 | likeCount: {type: Number, default: 0}
18 | },
19 | contentType: { type: String, enum: ['html', 'markdown'] },
20 | categoryId: { type: ObjectId, ref: 'Categorys' },
21 | deleted: { type: Boolean, default: false }
22 | })
23 |
24 | module.exports = mongoose.model('Articles', ArticleSchema)
25 |
--------------------------------------------------------------------------------
/app/models/category.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mongoose = require('mongoose')
3 | const moment = require('moment')
4 | const Schema = mongoose.Schema
5 | const ObjectId = Schema.ObjectId
6 | const CategorySchema = new Schema({
7 | userId: {type: ObjectId, ref: 'Users'},
8 | name: {type: String, required: 'name is required'},
9 | createdAt: {
10 | type: Date,
11 | default: Date.now
12 | },
13 | updatedAt: {
14 | type: Date,
15 | default: Date.now
16 | }
17 | }, {
18 | timestamps: {
19 | createdAt: 'createdAt',
20 | updatedAt: 'updatedAt'
21 | }
22 | })
23 |
24 | CategorySchema.set('toJSON', { getters: true, virtuals: true })
25 | CategorySchema.set('toObject', { getters: true, virtuals: true })
26 |
27 | CategorySchema.path('createdAt').get(function (v) {
28 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
29 | })
30 | CategorySchema.path('updatedAt').get(function (v) {
31 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
32 | })
33 |
34 | module.exports = mongoose.model('Categorys', CategorySchema)
35 |
--------------------------------------------------------------------------------
/app/models/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const mdbs = {}
4 | mdbs.User = require('./users')
5 | mdbs.Role = require('./role')
6 | mdbs.Right = require('./right')
7 | mdbs.Article = require('./article')
8 | mdbs.ArticleCategory = require('./category')
9 |
10 | module.exports = mdbs
11 |
--------------------------------------------------------------------------------
/app/models/right.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mongoose = require('mongoose')
3 | const moment = require('moment')
4 | const Schema = mongoose.Schema
5 | const RightSchema = new Schema({
6 | rightNameEN: { type: String, required: 'name is required' },
7 | rightNameCN: { type: String, required: 'name is required' },
8 | description: { type: String, default: '该权限尚无描述' },
9 | router: [
10 | {
11 | type: String,
12 | ref: 'Routers'
13 | }
14 | ],
15 | createdAt: {
16 | type: Date,
17 | default: Date.now
18 | },
19 | updatedAt: {
20 | type: Date,
21 | default: Date.now
22 | }
23 | }, {
24 | timestamps: {
25 | createdAt: 'createdAt',
26 | updatedAt: 'updatedAt'
27 | }
28 | })
29 |
30 | RightSchema.set('toJSON', { getters: true, virtuals: true })
31 | RightSchema.set('toObject', { getters: true, virtuals: true })
32 |
33 | RightSchema.path('createdAt').get(function (v) {
34 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
35 | })
36 | RightSchema.path('updatedAt').get(function (v) {
37 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
38 | })
39 |
40 | module.exports = mongoose.model('Rights', RightSchema)
41 |
--------------------------------------------------------------------------------
/app/models/role.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mongoose = require('mongoose')
3 | const moment = require('moment')
4 | const Schema = mongoose.Schema
5 | const RoleSchema = new Schema({
6 | roleNameEN: { type: String, required: 'name is required' },
7 | roleNameCN: { type: String, required: 'name is required' },
8 | description: { type: String, default: '该角色尚无描述' },
9 | right: [
10 | {
11 | type: String,
12 | ref: 'Rights'
13 | }
14 | ],
15 | createdAt: {
16 | type: Date,
17 | default: Date.now
18 | },
19 | updatedAt: {
20 | type: Date,
21 | default: Date.now
22 | }
23 | }, {
24 | timestamps: {
25 | createdAt: 'createdAt',
26 | updatedAt: 'updatedAt'
27 | }
28 | })
29 |
30 | RoleSchema.set('toJSON', { getters: true, virtuals: true })
31 | RoleSchema.set('toObject', { getters: true, virtuals: true })
32 |
33 | RoleSchema.path('createdAt').get(function (v) {
34 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
35 | })
36 | RoleSchema.path('updatedAt').get(function (v) {
37 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
38 | })
39 |
40 | module.exports = mongoose.model('Roles', RoleSchema)
41 |
--------------------------------------------------------------------------------
/app/models/users.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mongoose = require('mongoose')
3 | const moment = require('moment')
4 | const Schema = mongoose.Schema
5 | const UserSchema = new Schema({
6 | name: { type: String, required: 'name is required' },
7 | nickName: { type: String },
8 | password: { type: String },
9 | age: {type: Number, min: 18, max: 95},
10 | sex: { type: String, enum: ['male', 'female', 'unknow'] },
11 | company: String, // 大学或者公司
12 | website: String, // 个人网站
13 | intruction: { type: String, default: '这个人很懒,什么都有没留下、、、' },
14 | logo: { type: String, default: '/upload/images/defaultlogo.png' },
15 | role: {type: String, default: 'ordinary users'},
16 | lastLogin: Date,
17 | createdAt: {
18 | type: Date,
19 | default: Date.now
20 | },
21 | updatedAt: {
22 | type: Date,
23 | default: Date.now
24 | }
25 | }, {
26 | timestamps: {
27 | createdAt: 'createdAt',
28 | updatedAt: 'updatedAt'
29 | }
30 | })
31 |
32 | UserSchema.set('toJSON', { getters: true, virtuals: true })
33 | UserSchema.set('toObject', { getters: true, virtuals: true })
34 |
35 | UserSchema.path('lastLogin').get(function (v) {
36 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
37 | })
38 | UserSchema.path('createdAt').get(function (v) {
39 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
40 | })
41 | UserSchema.path('updatedAt').get(function (v) {
42 | return moment(v).format('YYYY-MM-DD HH:mm:ss')
43 | })
44 |
45 | UserSchema.statics = {
46 | findAge: async function (age) {
47 | const findRes = await this.find({age: age})
48 | return findRes
49 | }
50 | }
51 |
52 | module.exports = mongoose.model('Users', UserSchema)
53 |
--------------------------------------------------------------------------------
/app/myutil/authentication.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const jwt = require('jsonwebtoken')
3 | const {settings} = require('../../config')
4 |
5 | module.exports = {
6 | createToken (uuid) {
7 | const token = jwt.sign(
8 | {userId: uuid},
9 | settings.jwtSecret,
10 | {expiresIn: 3600 * 24}
11 | )
12 | return token
13 | },
14 | verifyToken (token) {
15 | const result = jwt.verify(token, settings.jwtSecret)
16 | return result
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/myutil/crypto.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const crypto = require('crypto')
3 |
4 | module.exports = {
5 | // 密码加密
6 | encrypted (password, saltKey) {
7 | const cipher = crypto.createCipher('bf', saltKey)
8 | let newPsd = ''
9 | newPsd += cipher.update(password, 'utf8', 'hex')
10 | newPsd += cipher.final('hex')
11 | return newPsd
12 | },
13 | // 密码解密
14 | decrypted (password, saltKey) {
15 | const decipher = crypto.createDecipher('bf', saltKey)
16 | let oldPsd = ''
17 | oldPsd += decipher.update(password, 'hex', 'utf8')
18 | oldPsd += decipher.final('utf8')
19 | return oldPsd
20 | },
21 | // 密码对比
22 | checkPasswd (inputPasswd, userPasswd) {
23 | let result
24 | if (inputPasswd === userPasswd) {
25 | result = true
26 | } else {
27 | result = false
28 | }
29 | return result
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/myutil/format.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const enums = require('../../config/enum')
4 | const moment = require('moment')
5 |
6 | module.exports = {
7 | formatDate (date) {
8 | let result
9 | if (!date) {
10 | result = ''
11 | } else {
12 | result = moment(date).format('YYYY-MM-DD HH:mm:ss')
13 | }
14 | return result
15 | },
16 | user (data) {
17 | if (data.sex) {
18 | data.reSex = enums.user[data.sex]
19 | }
20 | delete data.password
21 | data.createdAt = this.formatDate(data.createdAt)
22 | data.updatedAt = this.formatDate(data.updatedAt)
23 | if (data.lastLogin) {
24 | data.lastLogin = this.formatDate(data.lastLogin)
25 | } else {
26 | data.lastLogin = '暂无登录记录'
27 | }
28 | return data
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/myutil/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const myutil = {}
3 |
4 | myutil.crypto = require('./crypto')
5 | myutil.paramsHandler = require('./params-handler')
6 | myutil.resHandler = require('./response-handler')
7 | myutil.format = require('./format')
8 | myutil.auth = require('./authentication')
9 | myutil.validator = require('validator')
10 | myutil.upload = require('./upload')
11 |
12 | module.exports = myutil
13 |
--------------------------------------------------------------------------------
/app/myutil/params-handler.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | offsetFormat: (params, defaultLimt) => {
4 | let result = {}
5 | const pagesize = (params.pagesize !== undefined) ? parseInt(params.pagesize) : parseInt(defaultLimt)
6 | const currentPage = (params.page !== undefined) ? params.page : 1
7 | const sortRule = (params.sortRule !== undefined) ? parseInt(params.sortRule) : parseInt(-1)
8 | result.skipCount = (currentPage - 1) * pagesize
9 | result.pagesize = pagesize
10 | result.sortRule = sortRule
11 | return result
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/myutil/response-handler.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const {errorMsg, successMsg, errorSystem} = require('../../config')
4 |
5 | module.exports = {
6 | getSuccessMsg (succMsg) {
7 | const successRes = successMsg[succMsg] ? successMsg[succMsg] : successMsg['OPTION_SUCCESS']
8 | return successRes
9 | },
10 | getErrorMsg (error) {
11 | const errorMessage = error.message ? error.message : 'serverError'
12 | const finalError = errorSystem[errorMessage] ? errorSystem[errorMessage] : 'SERVER_ERROR'
13 | const result = errorMsg[finalError]
14 | return result
15 | },
16 | getErrorRes (error) {
17 | const result = errorMsg[error] ? errorMsg[error] : errorMsg['SERVER_ERROR']
18 | return result
19 | },
20 | getModelError (model) {
21 | const result = errorSystem[model] ? errorSystem[model] : 'SERVER_ERROR'
22 | return result
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/myutil/return.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const configs = require('../../config')
3 |
4 | module.exports = {
5 | // 成功提示的返回
6 | returnSuccess: (successMsg) => {
7 | const result = {
8 | status: 200,
9 | errorCode: 0,
10 | successMsg: configs.successMsg[successMsg]
11 | }
12 | return result
13 | },
14 | // 错误提示的返回
15 | returnError: (errMsg) => {
16 | const result = {
17 | status: 200,
18 | errorCode: configs.errorMsg[errMsg].errorCode,
19 | errorMsg: configs.errorMsg[errMsg].errorMsg
20 | }
21 | return result
22 | },
23 | // 正常数据的返回
24 | returnOk: (data) => {
25 | const result = {
26 | status: 200,
27 | errorCode: 0,
28 | data: data
29 | }
30 | return result
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/myutil/upload.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const formidable = require('formidable')
3 |
4 | module.exports = {
5 | getFileInfo (req) {
6 | return new Promise(function (resolve, reject) {
7 | const form = new formidable.IncomingForm()
8 | form.multiples = true
9 | form.parse(req, function (err, fields, files) {
10 | if (err) return reject(err)
11 | resolve({fileds: fields, files: files})
12 | })
13 | })
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/public/default/defaultlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/morehao/express-blog/46c9903e72d2a32e481b5a50c9c847fb11e43ca4/app/public/default/defaultlogo.png
--------------------------------------------------------------------------------
/app/routes/article.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Controllers = require('../controllers')
4 |
5 | module.exports = (app) => {
6 | app.route('/article')
7 | .post(Controllers.article.create)
8 | .get(Controllers.article.list)
9 | app.route('/article/:_id')
10 | .get(Controllers.article.detail)
11 | .put(Controllers.article.update)
12 | }
13 |
--------------------------------------------------------------------------------
/app/routes/category.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Controllers = require('../controllers')
4 |
5 | module.exports = (app) => {
6 | app.route('/category')
7 | .post(Controllers.category.create)
8 | .get(Controllers.category.list)
9 | app.route('/category/:_id')
10 | .get(Controllers.category.detail)
11 | .put(Controllers.category.update)
12 | }
13 |
--------------------------------------------------------------------------------
/app/routes/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Controllers = require('../controllers')
4 | const middleware = require('../middlewares')
5 | const middlewaresArr = [middleware.verifyToken, middleware.log]
6 |
7 | module.exports = (app) => {
8 | app.use(middleware.resExtend)
9 | app.post('/users/test', Controllers.users.test)
10 | app.post('/user/login', Controllers.users.login)
11 | app.post('/user', Controllers.users.create)
12 | app.use(middlewaresArr)
13 | require('./user')(app)
14 | require('./category')(app)
15 | require('./article')(app)
16 | app.route('/upload')
17 | .post(Controllers.article.upload)
18 | app.route('/test')
19 | .post(Controllers.test.testResponse)
20 |
21 | // app.post(Controllers.test.test)
22 |
23 | app.use('/test1', Controllers.test.test)
24 | }
25 |
--------------------------------------------------------------------------------
/app/routes/user.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Controllers = require('../controllers')
4 |
5 | module.exports = (app) => {
6 | app.route('/user')
7 | .get(Controllers.users.list)
8 | app.route('/user/:_id')
9 | .get(Controllers.users.detail)
10 | .put(Controllers.users.update)
11 | .delete(Controllers.users.destroy)
12 | }
13 |
--------------------------------------------------------------------------------
/app/services/article.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const qiniu = require('qiniu')
3 | const fs = require('fs')
4 | const BaseService = require('./base')
5 | const mdb = require('../models')
6 | const {resHandler} = require('../myutil')
7 | const {settings} = require('../../config')
8 |
9 | class ArticleService extends BaseService {
10 | constructor (model) {
11 | super(model)
12 | this.model = 'Article'
13 | }
14 | async addArticle (params) {
15 | try {
16 | const query = {
17 | title: params.title,
18 | authorId: params.authorId
19 | }
20 | const findRes = await super.findOne(query)
21 | if (findRes) {
22 | const errorMsg = 'ARTICLE_HAS_EXITS'
23 | throw errorMsg
24 | }
25 | const result = await super.save(params)
26 | return result
27 | } catch (error) {
28 | throw error
29 | }
30 | }
31 | async editById (id, params) {
32 | try {
33 | const findRes = await super.findById(id)
34 | if (!findRes) {
35 | const errorMsg = 'ARTICLE_NOT_EXITS'
36 | throw errorMsg
37 | }
38 | await super.updateById(id, params)
39 | const result = resHandler.getSuccessMsg('ARTICLE_UPDATE_SUCCESS')
40 | return result
41 | } catch (error) {
42 | throw error
43 | }
44 | }
45 | async getArticleList (params) {
46 | try {
47 | const result = await super.list(params)
48 | return result
49 | } catch (error) {
50 | throw error
51 | }
52 | }
53 | async getArticleById (id) {
54 | try {
55 | const result = await mdb.Article.findById(id)
56 | .populate([{path: 'authorId', select: '-password'}, {path: 'categoryId'}])
57 | if (!result) {
58 | const errorMsg = 'ARTICLE_NOT_EXITS'
59 | throw errorMsg
60 | }
61 | return result
62 | } catch (error) {
63 | throw error
64 | }
65 | }
66 | async qiniuUpload (localFile, key) {
67 | try {
68 | const {accessKey, secretKey, bucket} = settings.qiniuConfig
69 | const mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
70 | const putPolicy = new qiniu.rs.PutPolicy({scope: bucket})
71 | const uploadToken = putPolicy.uploadToken(mac)
72 | const config = new qiniu.conf.Config()
73 | config.zone = qiniu.zone.Zone_z1
74 | const formUploader = new qiniu.form_up.FormUploader(config)
75 | const putExtra = new qiniu.form_up.PutExtra()
76 | return new Promise(function (resolve, reject) {
77 | formUploader.putFile(uploadToken, key, localFile, putExtra, function (respErr, respBody, respInfo) {
78 | if (respErr) return reject(respErr)
79 | if (respInfo.statusCode === 200) return resolve(respBody)
80 | reject(new Error('上传失败:statusCode !== 200'))
81 | })
82 | })
83 | } catch (error) {
84 | throw error
85 | }
86 | }
87 |
88 | async saveFile (filePath, target, fileName) {
89 | try {
90 | const readStream = fs.createReadStream(filePath)
91 | const writeStream = fs.createWriteStream(target)
92 | readStream.pipe(writeStream)
93 | return fileName
94 | } catch (error) {
95 | throw error
96 | }
97 | }
98 | }
99 | module.exports = new ArticleService()
100 |
--------------------------------------------------------------------------------
/app/services/base.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const mdb = require('../models')
3 | const {resHandler} = require('../myutil')
4 | class BaseService {
5 | constructor (model) {
6 | this.model = model
7 | this.adventures = null // 相当于select,选择返回的属性
8 | }
9 | async findOne (params) {
10 | try {
11 | const result = await mdb[this.model].findOne(params, this.adventures, {lean: true})
12 | return result
13 | } catch (error) {
14 | const modelErrorMsg = resHandler.getModelError(this.model)
15 | throw modelErrorMsg
16 | }
17 | }
18 | async findById (id) {
19 | try {
20 | const result = await mdb[this.model].findById(id, {lean: true})
21 | return result
22 | } catch (error) {
23 | const modelErrorMsg = resHandler.getModelError(this.model)
24 | throw modelErrorMsg
25 | }
26 | }
27 | async save (params) {
28 | try {
29 | const result = await mdb[this.model].create(params)
30 | return result
31 | } catch (error) {
32 | const modelErrorMsg = resHandler.getModelError(this.model)
33 | throw modelErrorMsg
34 | }
35 | }
36 | async updateById (id, params) {
37 | try {
38 | const result = await mdb[this.model].update({_id: id}, {$set: params})
39 | return result
40 | } catch (error) {
41 | const modelErrorMsg = resHandler.getModelError(this.model)
42 | throw modelErrorMsg
43 | }
44 | }
45 | async list (params) {
46 | try {
47 | const query = mdb[this.model]
48 | .find(params.condition, this.adventures, {lean: true})
49 | .populate(params.populate)
50 | .skip(params.skipCount)
51 | .limit(params.pagesize)
52 | .sort({createdAt: Number(params.sortRule)})
53 | // if (params.populate) {
54 | // query.populate = params.populate
55 | // }
56 | const dataCount = await mdb[this.model].countDocuments()
57 | const list = await query
58 | return {
59 | dataCount: dataCount,
60 | list: list
61 | }
62 | } catch (error) {
63 | // const modelErrorMsg = resHandler.getModelError(this.model)
64 | // throw modelErrorMsg
65 | throw error
66 | }
67 | }
68 | async getUserByName (name) {
69 | const query = mdb[this.model].findOne({name: name}, this.adventures, {blen: true})
70 | if (this.model === 'User') {
71 | query.select('-password')
72 | }
73 | const result = await query
74 | return result
75 | }
76 | }
77 |
78 | module.exports = BaseService
79 |
--------------------------------------------------------------------------------
/app/services/category.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const BaseService = require('./base')
3 | const mdb = require('../models')
4 | const {resHandler} = require('../myutil')
5 |
6 | class CategoryService extends BaseService {
7 | constructor (model) {
8 | super(model)
9 | this.model = 'ArticleCategory'
10 | }
11 |
12 | async addCategory (data) {
13 | try {
14 | const query = {
15 | userId: data.userId,
16 | name: data.name
17 | }
18 | const findRes = await super.findOne(query)
19 | if (findRes) {
20 | const errorMsg = 'CATEGORY_HAS_EXITS'
21 | throw errorMsg
22 | }
23 | const result = await mdb.ArticleCategory.create(data)
24 | return result
25 | } catch (error) {
26 | throw error
27 | }
28 | }
29 |
30 | async editById (id, params) {
31 | try {
32 | const findRes = await super.findById(id)
33 | if (!findRes) {
34 | const errorMsg = 'CATEGORY_NOT_EXITS'
35 | throw errorMsg
36 | }
37 | await super.updateById(id, params)
38 | const result = resHandler.getSuccessMsg('CATEGORY_UPDATE_SUCCESS')
39 | return result
40 | } catch (error) {
41 | throw error
42 | }
43 | }
44 |
45 | async getCategoryById (id) {
46 | try {
47 | const result = await mdb.ArticleCategory.findById(id)
48 | .populate([{path: 'userId', select: '-password'}])
49 | if (!result) {
50 | const errorMsg = 'CATEGORY_NOT_EXITS'
51 | throw errorMsg
52 | }
53 | return result
54 | } catch (error) {
55 | throw error
56 | }
57 | }
58 |
59 | async getCategoryList (params) {
60 | try {
61 | const result = await super.list(params)
62 | return result
63 | } catch (error) {
64 | throw error
65 | }
66 | }
67 | }
68 | module.exports = new CategoryService()
69 |
--------------------------------------------------------------------------------
/app/services/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const Services = {}
3 |
4 | Services.users = require('./users')
5 | Services.category = require('./category')
6 | Services.article = require('./article')
7 |
8 | module.exports = Services
9 |
--------------------------------------------------------------------------------
/app/services/users.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const BaseService = require('./base')
3 | const mdb = require('../models')
4 | const {crypto, format, resHandler} = require('../myutil')
5 | const {settings} = require('../../config')
6 | class UserService extends BaseService {
7 | constructor (model) {
8 | super(model)
9 | this.model = 'User'
10 | }
11 | async addUser (data) {
12 | try {
13 | const findRes = await mdb.User.findOne({name: data.name})
14 | if (findRes) {
15 | const errorMsg = 'USER_HAS_EXITS'
16 | throw errorMsg
17 | }
18 | data.password = crypto.encrypted(data.password, settings.saltKey)
19 | const result = await mdb.User.create(data)
20 | return format.user(result.toObject())
21 | } catch (error) {
22 | throw error
23 | }
24 | }
25 | async getUserByName (name) {
26 | try {
27 | const user = await mdb.User.findOne({name: name}, null, {lean: true})
28 | return user
29 | } catch (error) {
30 | const errorMsg = 'SERVER_ERROR'
31 | throw errorMsg
32 | }
33 | }
34 | async getUserById (id) {
35 | try {
36 | const user = await mdb.User.findById(id)
37 | return user
38 | } catch (error) {
39 | const errorMsg = 'SERVER_ERROR'
40 | throw errorMsg
41 | }
42 | }
43 | async destroy (params) {
44 | try {
45 | const findRes = await mdb.User.findById(params)
46 | if (!findRes) {
47 | const errorMsg = 'USER_NOT_EXITS'
48 | throw errorMsg
49 | }
50 | await mdb.User.remove({_id: params})
51 | const result = resHandler.getSuccessMsg('USER_DELETE_SUCCESS')
52 | return result
53 | } catch (error) {
54 | throw error
55 | }
56 | }
57 | async update (params) {
58 | try {
59 | await mdb.User.findById(params._id)
60 | await mdb.User.update({_id: params._id}, {$set: params})
61 | const result = resHandler.getSuccessMsg('USER_UPDATE_SUCCESS')
62 | return result
63 | } catch (error) {
64 | const errorMsg = 'USER_UPDATE_FAILED'
65 | throw errorMsg
66 | }
67 | }
68 | async getUserList (params) {
69 | try {
70 | const result = super.list(params)
71 | return result
72 | } catch (error) {
73 | throw error
74 | }
75 | }
76 | async detail (params) {
77 | try {
78 | const findRes = await mdb.User.findById(params)
79 | const result = format.user(findRes.toObject())
80 | return result
81 | } catch (error) {
82 | const errorMsg = 'USER_NOT_EXITS'
83 | throw errorMsg
84 | }
85 | }
86 | async login (params) {
87 | try {
88 | const findRes = await mdb.User.findOne({name: params.name}, null, {lean: true})
89 | if (!findRes) {
90 | const errorMsg = 'USER_NOT_EXITS'
91 | throw errorMsg
92 | }
93 | const inputPasswd = crypto.encrypted(params.password, settings.saltKey)
94 | const equal = await crypto.checkPasswd(inputPasswd, findRes.password)
95 | if (!equal) {
96 | const errorMsg = 'USER_PASSWORD_WRONG'
97 | throw errorMsg
98 | }
99 | const result = format.user(findRes)
100 | return result
101 | } catch (error) {
102 | const errorMsg = 'USER_LOGIN_FAILED'
103 | throw errorMsg
104 | }
105 | }
106 | async test (params) {
107 | this.body = 2
108 | const result = super.getUserByName(params)
109 | return result
110 | }
111 | }
112 |
113 | module.exports = new UserService()
114 |
--------------------------------------------------------------------------------
/build/create-admin.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const mdbs = require('../app/models')
4 | const myutil = require('../app/myutil')
5 |
6 | module.exports = async (name, password, saltKey, role) => {
7 | try {
8 | const findRes = await mdbs.User.findOne({name: name})
9 | if (findRes) {
10 | console.log('admin用户已经存在,请勿重复添加')
11 | return 'admin用户已经存在,请勿重复添加'
12 | } else {
13 | const newPwd = myutil.crypto.encrypted(password, saltKey)
14 | mdbs.User.create({
15 | name: name,
16 | nickname: name,
17 | sex: 'male',
18 | password: newPwd,
19 | role: role
20 | })
21 | console.log('admin用户添加成功')
22 | return 'admin用户添加成功'
23 | }
24 | } catch (error) {
25 | console.log('添加admin用户的操作存在错误')
26 | return '添加admin用户的操作存在错误'
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/build/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const initObj = {}
3 |
4 | initObj.createAdmin = require('./create-admin')
5 |
6 | module.exports = initObj
7 |
--------------------------------------------------------------------------------
/build/public/upload/images/defaultlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/morehao/express-blog/46c9903e72d2a32e481b5a50c9c847fb11e43ca4/build/public/upload/images/defaultlogo.png
--------------------------------------------------------------------------------
/build/server.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const express = require('express')
3 | const path = require('path')
4 | const app = express()
5 | const mongoose = require('mongoose')
6 | const bodyParser = require('body-parser')
7 |
8 | app.use(express.static(path.join(__dirname, 'public')))
9 |
10 | const {settings} = require('../config')
11 |
12 | const inits = require('./index')
13 |
14 | // 连接数据库
15 | mongoose.Promise = global.Promise // 将mongoose自身的promise替代为ES6promise
16 | mongoose.connect(settings.dbConfig.URL)
17 |
18 | app.use(bodyParser.urlencoded({ extended: true }))
19 | app.use(bodyParser.json())
20 |
21 | app.listen(settings.port)
22 | console.log('express-blog server started on: ' + settings.port)
23 |
24 | inits.createAdmin(settings.adminConfig.name, settings.adminConfig.password, settings.saltKey, settings.adminConfig.role)
25 |
26 | module.exports = app
27 |
--------------------------------------------------------------------------------
/config/development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Customer": {
3 | "settings": "settings",
4 | "log4js": "log4js"
5 | }
6 | }
--------------------------------------------------------------------------------
/config/enum.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | user: {
4 | male: '男'
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/config/error-message.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | /*
3 | 所有接口的status均为200;
4 | errorCode规则:当errorCode为0时表示接口访问成功并且无抛错;不为零时,errorCode共计五位,
5 | 第一位表示错误级别,1开头的为系统级别错误,2开头为系统功能模块对应的错误,其中,第二三位
6 | 表示功能模块编号,第四五位表示具体错误编号。
7 | */
8 | module.exports = {
9 | // 系统级别错误
10 | NOT_FIND_ROUTE: {
11 | status: 200,
12 | errorCode: 10000,
13 | errorMsg: '访问的路由不存在'
14 | },
15 | SERVER_ERROR: {
16 | status: 200,
17 | errorCode: 10001,
18 | errorMsg: '服务器开小差去了'
19 | },
20 | LIST_QUERY_FAILDE: {
21 | status: 200,
22 | errorCode: 10002,
23 | errorMsg: '列表查询失败'
24 | },
25 | // token认证模块错误
26 | TOKEN_IS_MISSING: {
27 | status: 200,
28 | errorCode: 20000,
29 | errorMsg: 'token缺失'
30 | },
31 | TOKEN_IS_INVALID: {
32 | status: 200,
33 | errorCode: 20001,
34 | errorMsg: 'token无效'
35 | },
36 | TOKEN_HAS_EXPIRED: {
37 | status: 200,
38 | errorCode: 20002,
39 | errorMsg: 'token已经过期'
40 | },
41 | // 用户管理模块错误
42 | USER_HAS_EXITS: {
43 | status: 200,
44 | errorCode: 20100,
45 | errorMsg: '该用户已经存在'
46 | },
47 | USER_NOT_EXITS: {
48 | status: 200,
49 | errorCode: 20101,
50 | errorMsg: '该用户不存在'
51 | },
52 | USER_PASSWORD_WRONG: {
53 | status: 200,
54 | errorCode: 20102,
55 | errorMsg: '用户密码错误'
56 | },
57 | USER_LOGIN_FAILED: {
58 | status: 200,
59 | errorCode: 20103,
60 | errorMsg: '用户登录失败'
61 | },
62 | USER_ADD_FAILED: {
63 | status: 200,
64 | errorCode: 20104,
65 | errorMsg: '用户创建失败'
66 | },
67 | USER_DELETE_FAILED: {
68 | status: 200,
69 | errorCode: 20105,
70 | errorMsg: '用户删除失败'
71 | },
72 | USER_UPDATE_FAILED: {
73 | status: 200,
74 | errorCode: 20106,
75 | errorMsg: '用户更新失败'
76 | },
77 | USER_QUERY_FAILED: {
78 | status: 200,
79 | errorCode: 20107,
80 | errorMsg: '用户查询失败'
81 | },
82 | USERLIST_FIND_FAILDE: {
83 | status: 200,
84 | errorCode: 20108,
85 | errorMsg: '用户列表查询失败'
86 | },
87 | // 路由管理模块错误
88 | ROUTER_HAS_EXITS: {
89 | status: 200,
90 | errorCode: 20200,
91 | errorMsg: '该路由已经存在'
92 | },
93 | ROUTER_NOT_EXITS: {
94 | status: 200,
95 | errorCode: 20201,
96 | errorMsg: '该路由不存在'
97 | },
98 | CATEGORY_HAS_EXITS: {
99 | status: 200,
100 | errorCode: 20301,
101 | errorMsg: '该分类已经存在'
102 | },
103 | CATEGORY_NOT_EXITS: {
104 | status: 200,
105 | errorCode: 20302,
106 | errorMsg: '该分类不存在'
107 | },
108 | CATEGORYNAME_IS_EMPTY: {
109 | status: 200,
110 | errorCode: 20303,
111 | errorMsg: '文章类别的名字不能为空'
112 | },
113 | ARTICLE_HAS_EXITS: {
114 | status: 200,
115 | errorCode: 20401,
116 | errorMsg: '该文章已经存在'
117 | },
118 | ARTICLE_NOT_EXITS: {
119 | status: 200,
120 | errorCode: 20402,
121 | errorMsg: '该文章不存在'
122 | },
123 | TITLE_IS_EMPTY: {
124 | status: 200,
125 | errorCode: 20403,
126 | errorMsg: '文章标题不能为空'
127 | },
128 | CONTENT_IS_EMPTY: {
129 | status: 200,
130 | errorCode: 20404,
131 | errorMsg: '文章内容不能为空'
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/config/error-system.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | 'invalid token': 'TOKEN_IS_INVALID',
5 | 'jwt expired': 'TOKEN_HAS_EXPIRED',
6 | serverError: 'SERVER_ERROR',
7 | User: 'USERLIST_FIND_FAILED'
8 | }
9 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const config = require('config')
3 |
4 | const settings = config.get('Customer.settings')
5 | const log4js = config.get('Customer.log4js')
6 |
7 | const configs = {}
8 |
9 | configs.settings = require(`./${settings}`)
10 | configs.logConfig = require(`./${log4js}`)
11 | // configs.settings = require('./settings')
12 | configs.errorMsg = require('./error-message')
13 | configs.successMsg = require('./success-message')
14 | configs.errorSystem = require('./error-system')
15 | configs.pageConfig = require('./pagesize')
16 | configs.enum = require('./enum')
17 | configs.router = require('./router.js')
18 | configs.right = require('./right')
19 |
20 | module.exports = configs
21 |
--------------------------------------------------------------------------------
/config/log4js.json:
--------------------------------------------------------------------------------
1 | {
2 | "appenders": {
3 | "request": {
4 | "type": "console",
5 | "filename": "./logs/access",
6 | "pattern": "-yyyy-MM-dd.log",
7 | "alwaysIncludePattern": true,
8 | "category": "http"
9 | },
10 | "application": {
11 | "type": "DateFile",
12 | "filename": "./logs/application",
13 | "pattern": "-yyyy-MM-dd.log",
14 | "alwaysIncludePattern": true
15 | },
16 | "err": {
17 | "type": "stderr",
18 | "filename": "./logs/errors",
19 | "pattern": "-yyyy-MM-dd.log",
20 | "alwaysIncludePattern": true
21 | }
22 | },
23 | "categories": {
24 | "default": { "appenders": ["application", "request"], "level": "info" }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/config/log4js.pro.json:
--------------------------------------------------------------------------------
1 | {
2 | "appenders": {
3 | "request": {
4 | "type": "DateFile",
5 | "filename": "./logs/access",
6 | "pattern": "-yyyy-MM-dd.log",
7 | "alwaysIncludePattern": true,
8 | "category": "http"
9 | },
10 | "application": {
11 | "type": "DateFile",
12 | "filename": "./logs/application",
13 | "pattern": "-yyyy-MM-dd.log",
14 | "alwaysIncludePattern": true
15 | },
16 | "errorFile": {
17 | "type": "DateFile",
18 | "filename": "./logs/errors",
19 | "pattern": "-yyyy-MM-dd.log",
20 | "alwaysIncludePattern": true
21 | },
22 | "errors": {
23 | "type": "logLevelFilter",
24 | "level": "ERROR",
25 | "appender": "errorFile"
26 | }
27 | },
28 | "categories": {
29 | "default": { "appenders": ["application", "request"], "level": "info" },
30 | "error": { "appenders": ["errors"], "level": "error" }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/config/pagesize.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | users: 10,
5 | category: 10,
6 | article: 10
7 | }
8 |
--------------------------------------------------------------------------------
/config/production.json:
--------------------------------------------------------------------------------
1 | {
2 | "Customer": {
3 | "settings": "settings.pro",
4 | "log4js": "log4js.pro"
5 | }
6 | }
--------------------------------------------------------------------------------
/config/right.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // 系统权限
3 | const {users} = require('./router.js')
4 | module.exports = {
5 | userAdd: [users.add],
6 | userDelete: [users.delete],
7 | userEdit: [users.edit],
8 | userView: [users.view],
9 | userList: [users.viewList],
10 | userLogin: [users.login],
11 | userAll: [users.add, users.delete, users.edit, users.view, users.viewList, users.login]
12 | }
13 |
--------------------------------------------------------------------------------
/config/role-right.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // 角色与权限关联关系
3 | const {right} = require('./right')
4 | module.exports = {
5 | root: [right.userAll], // 超级管理员
6 | admin: [right.userLogin, right.userView, right.userList], // 普通管理员
7 | normal: [right.userLogin, right.userEdit, right.userView] // 普通用户
8 | }
9 |
--------------------------------------------------------------------------------
/config/router.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // 当请求方式为GET和DELETE时,isParams的值,1代表请求的url中有数组对象,0代表没有,默认为0
3 | // 已注册的路由
4 | module.exports = {
5 | users: {
6 | add: {
7 | routerNameCN: '创建用户',
8 | routerNmaeEN: 'add user',
9 | router: '/users',
10 | method: 'POST',
11 | isParams: 0
12 | },
13 | delete: {
14 | routerNameCN: '删除用户',
15 | routerNmaeEN: 'delete user',
16 | router: '/users',
17 | method: 'DELETE',
18 | isParams: 1
19 | },
20 | edit: {
21 | routerNameCN: '编辑用户',
22 | routerNmaeEN: 'edit user',
23 | router: '/users',
24 | method: 'PUT',
25 | isParams: 1
26 | },
27 | view: {
28 | routerNameCN: '查看单个用户',
29 | routerNmaeEN: 'view user',
30 | router: '/users',
31 | method: 'GET',
32 | isParams: 1
33 | },
34 | viewList: {
35 | routerNameCN: '查看用户列表',
36 | routerNmaeEN: 'view user list',
37 | router: '/users',
38 | method: 'GET',
39 | isParams: 0
40 | },
41 | login: {
42 | routerNameCN: '用户登录',
43 | routerNmaeEN: 'user login',
44 | router: '/users',
45 | method: 'POST',
46 | isParams: 0
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/config/settings.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | // 密码盐
5 | saltKey: 'express_frame',
6 | // jwt实现token认证的secret
7 | jwtSecret: 'express_jwt',
8 | port: process.env.PORT || 4000,
9 | website: '127.0.0.1:4000',
10 | // mongodb数据库配置
11 | dbConfig: {
12 | URL: 'mongodb://127.0.0.1:27017/express-blog',
13 | DB: 'express-blog',
14 | HOST: '127.0.0.1',
15 | PORT: 27017,
16 | USERNAME: 'morehao',
17 | PASSWORD: 'morehao'
18 | },
19 | mongooseDebug: true,
20 | adminConfig: {
21 | name: 'admin',
22 | password: '123456',
23 | role: 'ordinary users'
24 | },
25 | qiniuConfig: {
26 | accessKey: '',
27 | secretKey: '',
28 | bucket: 'express-blog',
29 | originUrl: ''
30 | },
31 | upload: {
32 | savePath: 'app/public/upload',
33 | showPath: '/upload/'
34 | }
35 | // redis数据库配置
36 | }
37 |
--------------------------------------------------------------------------------
/config/settings.pro.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | module.exports = {
4 | // 密码盐
5 | saltKey: 'express_frame',
6 | // jwt实现token认证的secret
7 | jwtSecret: 'express_jwt',
8 | port: process.env.PORT || 5000,
9 | website: '127.0.0.1:4000',
10 | // mongodb数据库配置
11 | dbConfig: {
12 | URL: 'mongodb://127.0.0.1:27017/express-blog',
13 | DB: 'express-blog',
14 | HOST: '127.0.0.1',
15 | PORT: 27017,
16 | USERNAME: 'morehao',
17 | PASSWORD: 'morehao'
18 | },
19 | mongooseDebug: false,
20 | adminConfig: {
21 | name: 'admin',
22 | password: '123456',
23 | role: 'ordinary users'
24 | },
25 | qiniuConfig: {
26 | accessKey: '',
27 | secretKey: '',
28 | bucket: 'express-blog',
29 | originUrl: ''
30 | },
31 | upload: {
32 | savePath: 'app/public/upload',
33 | showPath: '/upload/'
34 | }
35 | // redis数据库配置
36 | }
37 |
--------------------------------------------------------------------------------
/config/success-message.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | USER_UPDATE_SUCCESS: '用户信息更新成功!',
4 | USER_DELETE_SUCCESS: '用户删除成功!',
5 | OPTION_SUCCESS: '操作成功!',
6 | ROUTER_DELETE_SUCCESS: '路由删除成功!',
7 | ROUTER_UPDATE_SUCCESS: '路由更新成功!',
8 | CATEGORY_UPDATE_SUCCESS: '文章类别修改成功!',
9 | ARTICLE_UPDATE_SUCCESS: '文章修改成功!'
10 | }
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "express-blog",
3 | "version": "1.0.0",
4 | "description": "express-blog",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "cross-env NODE_ENV=development nodemon --inspect server.js",
8 | "start": "cross-env NODE_ENV=production node server.js",
9 | "build": "node ./build/server.js",
10 | "test": "mocha test/**/*.js",
11 | "standard": "standard",
12 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
13 | "apidoc": "apidoc -i app/apidoc/ -o app/public/apidoc/"
14 | },
15 | "author": "morehao",
16 | "license": "MIT",
17 | "pre-commit": [
18 | "standard"
19 | ],
20 | "apidoc": {
21 | "name": "express-blog接口文档",
22 | "title": "express-blog接口文档",
23 | "version": "0.1.0"
24 | },
25 | "devDependencies": {
26 | "bluebird": "^3.5.1",
27 | "config": "^2.0.1",
28 | "cors": "^2.8.4",
29 | "cross-env": "^5.2.0",
30 | "eslint": "^4.19.1",
31 | "formidable": "^1.2.1",
32 | "mocha": "^5.2.0",
33 | "multer": "^1.3.1",
34 | "nodemon": "^1.17.3",
35 | "pre-commit": "^1.2.2",
36 | "qiniu": "^7.2.1",
37 | "standard": "^11.0.1",
38 | "supertest": "^3.1.0",
39 | "uuid": "^3.3.2",
40 | "validator": "^10.7.1"
41 | },
42 | "standard": {
43 | "globals": [
44 | "describe",
45 | "it",
46 | "logger"
47 | ]
48 | },
49 | "dependencies": {
50 | "amqplib": "^0.5.2",
51 | "body-parser": "^1.18.2",
52 | "debug": "^3.1.0",
53 | "express": "^4.16.3",
54 | "jsonwebtoken": "^8.2.2",
55 | "lodash": "^4.17.10",
56 | "log4js": "^2.8.0",
57 | "moment": "^2.22.1",
58 | "mongoose": "^5.0.17"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const express = require('express')
3 | const path = require('path')
4 | const app = express()
5 | const mongoose = require('mongoose')
6 | const bodyParser = require('body-parser')
7 | const cors = require('cors')
8 | const log4js = require('log4js')
9 |
10 | const {logConfig, settings} = require('./config')
11 | // const myutil = require('./app/myutil')
12 |
13 | const routes = require('./app/routes') // 引入路由
14 | // 日志配置
15 | log4js.configure(logConfig)
16 | let logger = log4js.getLogger()
17 | global.logger = logger
18 |
19 | // 配置静态文件
20 | app.use(express.static(path.join(__dirname, 'app/public')))
21 | // 配置apidoc
22 | app.use('/apidoc', express.static(path.join(__dirname, 'app/public/apidoc/')))
23 |
24 | // 连接数据库
25 | // 将mongoose自身的promise替代为ES6的promise
26 | mongoose.Promise = global.Promise
27 | // MongoDB升级到4.0之后,需要加useNewUrlParser参数和useCreateIndex参数
28 | mongoose.connect(settings.dbConfig.URL, { useNewUrlParser: true, useCreateIndex: true })
29 | mongoose.set('debug', settings.mongooseDebug)
30 |
31 | // 请求体解析中间件
32 | app.use(bodyParser.urlencoded({ extended: true }))
33 | app.use(bodyParser.json())
34 |
35 | // // 对res的扩展
36 | // app.use(myutil.resExtend)
37 |
38 | // 跨域配置
39 | app.use(cors())
40 |
41 | // 注册路由
42 | routes(app)
43 | app.listen(settings.port)
44 | logger.info(`start:port is ${settings.port}`)
45 |
46 | module.exports = app
47 |
--------------------------------------------------------------------------------
/test/http/user.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const request = require('supertest')
4 | const assert = require('assert')
5 | const app = require('../../server')
6 |
7 | describe('test express-frame http request', () => {
8 | let server = app.listen(9000)
9 | describe('test user module', () => {
10 | let createUser = {
11 | name: 'test009',
12 | password: '123456'
13 | }
14 | it('test /users (post) create ', async () => {
15 | let response = await request(server)
16 | .post('/users')
17 | .send(createUser)
18 | .set('Accept', 'application/json')
19 | .expect(200)
20 | assert.deepEqual(0, response.body.errorCode)
21 | })
22 | })
23 | })
24 |
--------------------------------------------------------------------------------