init: 确认目录结构

This commit is contained in:
yoga 2022-07-30 19:04:25 +08:00
commit 73e3bc918b
18 changed files with 342 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
node_modules
/target/
# .env*
!.env.template
upload/*
log/*

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v16.16.0

13
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
"files.exclude": {
".{git}/": false
},
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true,
".*/": true
},
"files.associations": {},
"explorer.excludeGitIgnore": false
}

3
nodemon.json Normal file
View File

@ -0,0 +1,3 @@
{
}

27
package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "koa2-template",
"version": "1.0.0",
"description": "init a project with me",
"main": "index.js",
"scripts": {
"start": "pm2 start ./src/index.js",
"dev": "nodemon ./src/index.js",
"test": "node ./test/redis.test.js"
},
"author": "Hawkin",
"license": "MIT",
"dependencies": {
"bcryptjs": "^2.4.3",
"dotenv": "^16.0.0",
"jsonwebtoken": "^8.5.1",
"koa": "^2.13.4",
"koa-body": "^5.0.0",
"koa-parameter": "^3.0.1",
"koa-router": "^10.1.1",
"koa-static": "^5.0.0",
"pm2": "^5.2.0"
},
"devDependencies": {
"nodemon": "^2.0.16"
}
}

53
public/css/reset.css Normal file
View File

@ -0,0 +1,53 @@
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
text-decoration: none;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: "";
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/*清除浮动*/
.clearfix:before,
.clearfix:after {
content: "";
display: block;
visibility: hidden;
clear: both;
}
/*容器*/
.container {
margin: 10px auto 0px;
width: 95%;
}

24
readme.md Normal file
View File

@ -0,0 +1,24 @@
```bash
.
├── node_modules
├── public 静态资源
├── src
│ ├── index.js 项目入口文件
│ ├── app 业务应用
│ ├── config 业务配置
│ ├── routers 路由
│ ├── middlewares 中间件()
│ ├── controller 控制器(业务方法)
│ ├── services 数据库交互
│ ├── models (数据库)模型对象
│ ├── db 数据库连接对象
│ ├── constant 常数定义
│ ├── util 工具函数
│ └── views 渲染模板
├── test
│ ├── .example.http
│ └── redis.test.js
├── package.json
├── readme.md
└── readme.en.md
```

10
src/app/errorHandler.js Normal file
View File

@ -0,0 +1,10 @@
module.exports = (err, ctx) => {
let status;
switch (err.code) {
default:
status = 500;
}
ctx.status = status;
ctx.body = err;
// console.log(err)
};

35
src/app/index.js Normal file
View File

@ -0,0 +1,35 @@
const path = require("path");
const Koa = require("koa");
const KoaBody = require("koa-body");
const KoaStatic = require("koa-static");
const parameter = require("koa-parameter");
require("../config/env.config"); // 加载配置
const router = require("../routers"); // 加载路由
const { captureRouteOmit } = require("../middlewares/captureRouteOmit");
const errHandler = require("./errorHandler"); // 加载自定义异常
const app = new Koa();
app.use(
KoaBody({
multipart: true,
formidable: {
uploadDir: path.join(__dirname, "../../data/upload"),
keepExtensions: true,
},
parsedMethods: ["POST", "PUT", "PATCH", "DELETE"],
})
);
app.use(KoaStatic(path.join(__dirname, "../../public")));
app.use(parameter(app));
app.use(captureRouteOmit); // 兜底处理路由错误是否要考虑koa-parameter错误
app.use(router.routes()).use(router.allowedMethods());
// 统一的错误处理
app.on("error", errHandler); // 监听全局异常事件
module.exports = app;

1
src/config/.env Normal file
View File

@ -0,0 +1 @@
APP_PORT = 3000

31
src/config/.env.template Normal file
View File

@ -0,0 +1,31 @@
APP_PORT = 3000
MYSQL_DIALECT = mysql
MYSQL_HOST =
MYSQL_PORT = 3306
MYSQL_DBNAME =
MYSQL_USER =
MYSQL_PASSWD =
MARIA_DIALECT = mariadb
MARIA_HOST =
MARIA_PORT = 3306
MARIA_DBNAME =
MARIA_USER =
MARIA_PASSWD =
MONGO_DIALECT = mongodb
MONGO_HOST =
MONGO_PORT = 21017
MONGO_DBNAME =
MONGO_USER =
MONGO_PASSWD =
REDIS_DIALECT = redis
REDIS_HOST =
REDIS_PORT = 6379
REDIS_DBNAME =
REDIS_USER =
REDIS_PASSWD =
JWT_SECRET =

3
src/config/env.config.js Normal file
View File

@ -0,0 +1,3 @@
const { config } = require("dotenv");
config({ path: "./src/config/.env" });

87
src/constant/errorType.js Normal file
View File

@ -0,0 +1,87 @@
module.exports = {
userFormateError: {
code: '10001',
message: '用户名或密码为空',
result: '',
},
userAlreadyExited: {
code: '10002',
message: '用户已经存在',
result: '',
},
userRegisterError: {
code: '10003',
message: '用户注册错误',
result: '',
},
userDoesNotExist: {
code: '10004',
message: '用户不存在',
result: '',
},
userLoginError: {
code: '10005',
message: '用户登录失败',
result: '',
},
invalidPassword: {
code: '10006',
message: '密码不匹配',
result: '',
},
tokenExpiredError: {
code: '10101',
message: 'token已过期',
result: '',
},
invalidToken: {
code: '10102',
message: '无效的token',
result: '',
},
hasNotAdminPermission: {
code: '10103',
message: '没有管理员权限',
result: '',
},
fileUploadError: {
code: '10201',
message: '商品图片上传失败',
result: '',
},
unSupportedFileType: {
code: '10202',
message: '不支持的文件格式',
result: '',
},
goodsFormatError: {
code: '10203',
message: '商品参数格式错误',
result: '',
},
publishGoodsError: {
code: '10204',
message: '发布商品失败',
result: '',
},
invalidGoodsID: {
code: '10205',
message: '无效的商品id',
result: '',
},
cartFormatError: {
code: '10301',
message: '购物车数据格式错误',
result: '',
},
addrFormatError: {
code: '10401',
message: '地址数据格式错误',
result: '',
},
orderFormatError: {
code: '10501',
message: '订单数据格式错误',
result: '',
},
}

7
src/index.js Normal file
View File

@ -0,0 +1,7 @@
const app = require("./app");
const { APP_PORT } = process.env;
app.listen(APP_PORT ?? 3000, () => {
console.log(`server is running on http://localhost:${APP_PORT ?? 3000}`);
});

View File

@ -0,0 +1,17 @@
async function captureRouteOmit(ctx, next) {
try {
await next();
if (!ctx.body) {
// 没有资源
ctx.status = 404;
ctx.body = { message: "Not Found." };
}
} catch (e) {
// 如果后面的代码报错 返回500(泛服务器错误)
ctx.status = 500;
ctx.body = { message: "Server Error." };
// 记录错误日志
}
}
module.exports = { captureRouteOmit };

14
src/routers/index.js Normal file
View File

@ -0,0 +1,14 @@
const fs = require("fs");
const Router = require("koa-router");
const router = new Router();
// 自动载入同级目录中所有文件里的router
fs.readdirSync(__dirname).forEach((file) => {
if (file !== "index.js") {
let r = require("./" + file);
router.use(r.routes());
}
});
module.exports = router;

8
test/.http Normal file
View File

@ -0,0 +1,8 @@
GET http://localhost:3000/ HTTP/1.1
###
POST http://localhost:3000/ HTTP/1.1
Content-Type: application/json; charset=utf-8
{}

0
test/.rest Normal file
View File