提交 7b971e05 编写于 作者: Y yinpengxiao

项目初始化init

上级
/node_modules
package-lock.json
\ No newline at end of file
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../src/app.js');
var debug = require('debug')('demo:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
// app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app.callback());
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
console.log('端口:', process.env.PORT || 3000);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string' ?
'Pipe ' + port :
'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string' ?
'pipe ' + addr :
'port ' + addr.port;
debug('Listening on ' + bind);
}
\ No newline at end of file
{
"name": "koa2-test-api",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "node bin/www",
"dev": "./node_modules/.bin/nodemon bin/www",
"prd": "pm2 start bin/www",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"crypto-js": "^4.1.1",
"debug": "^4.1.1",
"ejs": "^3.1.6",
"jsonwebtoken": "^8.5.1",
"koa": "^2.7.0",
"koa-bodyparser": "^4.2.1",
"koa-convert": "^1.2.0",
"koa-json": "^2.0.2",
"koa-jwt": "^4.0.1",
"koa-logger": "^3.2.0",
"koa-onerror": "^4.1.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"koa-views": "^6.2.0",
"module-alias": "^2.2.2",
"mysql2": "^2.3.0",
"redis": "^3.1.2",
"require-directory": "^2.1.1",
"sequelize": "^6.6.5"
},
"devDependencies": {
"nodemon": "^1.19.1"
},
"_moduleAliases": {
"@models": "src"
}
}
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}
/*
* @Author: your name
* @Date: 2021-08-30 10:58:19
* @LastEditTime: 2021-09-03 11:36:19
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \koa2-test-api\app.js
*/
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
require('module-alias/register');
const InitManager = require('@models/core/init');
const catchError = require('@models/middleWares/exception');
app.use(catchError)
// error handler
onerror(app)
// middlewares
app.use(bodyparser({
enableTypes: ['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'ejs'
}))
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
InitManager.initCore(app);
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-09-03 09:15:37
* @LastEditTime: 2021-09-03 10:36:24
* @LastEditors: Please set LastEditors
* @Description: redis缓存
* @FilePath: \koa2-test-api\src\cache\_redis.js
*/
const redis = require('redis');
const REDIS = require('../config/config.js');
const redisClient = redis.createClient(REDIS.redis.port, REDIS.redis.host)
redisClient.on("error", function (error) {
if (error) {
console.error('redis错误:', error);
}
});
redisClient.on("connect", function (error) {
if (!error) {
console.error('redis链接设置成功');
}
});
/**
* redis设置
* @param {string} key 键
* @param {*} val 值
* @param {*} timeout 超时时间
*/
function set(key, val, timeout = 60 * 60) {
if (typeof val === 'object') {
val = JSON.stringify(val);
}
console.log('输出要设置的内容:', Buffer.from(val, 'utf-8'));
redisClient.set(key, Buffer.from(val, 'utf-8'));
redisClient.expire(key, timeout);
}
function get(key) {
return new Promise((resolve, reject) => {
redisClient.get(key, (err, val) => {
if (err) {
reject(err);
return
}
if (val == null) {
resolve(val);
return
}
try {
console.log('输出redis查询的内容:', JSON.parse(val));
resolve(JSON.parse(val))
} catch (error) {
resolve(val);
}
})
})
}
module.exports = {
get,
set
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 13:17:20
* @LastEditTime: 2021-09-03 10:21:19
* @LastEditors: Please set LastEditors
* @Description: 配置文件
* @FilePath: \koa2-test-api\src\config\config.js
*/
module.exports = {
environment: 'dev',
database: {
dbName: 'work_week_report',
host: 'localhost',
port: 3306,
user: 'root',
password: 'newpassword',
dialect: 'mysql',
logging: true,
pool: {
max: 5,
idle: 30000,
acquire: 60000,
}
},
security: {
secretKey: 'YpxXyy@#X[0-9a-Z]()',
expiresIn: 60 * 60
},
redis: {
port: 6379,
host: '127.0.0.1',
expiresIn: 60 * 60
}
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 14:23:54
* @LastEditTime: 2021-09-03 10:19:52
* @LastEditors: Please set LastEditors
* @Description: 数据库配置
* @FilePath: \koa2-test-api\src\config\db.js
*/
const Sequelize = require('sequelize');
const {
database
} = require('./config.js');
const conf = {
host: database.host,
dialect: database.dialect,
port: database.port,
logging: database.logging || true, //是否输出日志
pool: database.pool
}
// 数据库配置
const seq = new Sequelize(database.dbName, database.user, database.password, conf);
// 测试数据连接成功与否
seq
.authenticate()
.then(() => {
console.log(`${database.dialect}数据库链接成功.`);
})
.catch(err => {
console.error('${database.dialect}数据库链接失败:', err);
});
module.exports = {
seq
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 15:11:10
* @LastEditTime: 2021-09-03 11:49:55
* @LastEditors: Please set LastEditors
* @Description: 用户信息相关接口
* @FilePath: \koa2-test-api\src\controller\user.js
*/
const {
findUser,
createUser
} = require('../service/user.js');
async function login({
user_name,
password
}) {
if (!user_name) {
return {
msg: '用户名不能为空'
}
}
if (!password) {
return {
msg: '密码不能为空'
}
}
const result = await findUser({
user_name,
password
})
if (result.user_name) {
return result;
} else {
return {
msg: '用户名或者密码不正确'
}
}
}
async function registry({
user_name,
scope,
password
}) {
const existUser = await findUser({
user_name
})
console.log('查询用户是否存在:', existUser);
if (existUser.user_name) {
return {
msg: '用户名已经存在'
}
}
const result = await createUser({
user_name,
scope,
password
});
console.log('用户不存在,创建成功', result);
if (result.code == 200) {
return result;
} else {
return result;
}
}
module.exports = {
login,
registry
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 13:20:40
* @LastEditTime: 2021-09-03 11:51:52
* @LastEditors: Please set LastEditors
* @Description: 异常处理
* @FilePath: \koa2-test-api\src\core\http-exception.js
*/
class HttpException extends Error {
constructor(msg = '服务器异常', errorCode = 10000, code = 400) {
super()
this.errorCode = errorCode
this.code = code
this.msg = msg
}
}
class ParameterException extends HttpException {
constructor(msg, errorCode) {
super()
this.code = 400
this.msg = msg || '参数错误'
this.errorCode = errorCode || 10000
}
}
class NotFound extends HttpException {
constructor(msg, errorCode) {
super();
this.msg = msg || '资源未找到';
this.errorCode = errorCode || 10001;
this.code = 404;
}
}
class AuthFailed extends HttpException {
constructor(msg, errorCode) {
super();
this.msg = msg || '授权失败';
this.errorCode = errorCode || 10002;
this.code = 401;
}
}
class Forbidden extends HttpException {
constructor(msg, errorCode) {
super();
this.msg = msg || '禁止访问';
this.errorCode = errorCode || 10003;
this.code = 404;
}
}
class CreateUserFailed extends HttpException {
constructor(msg, errorCode) {
super();
this.msg = msg || '创建用户失败';
this.errorCode = errorCode || 10400;
this.code = 400;
}
}
class Success extends HttpException {
constructor(msg, errorCode) {
super();
this.msg = msg || '成功';
this.errorCode = errorCode || 200;
this.code = 200;
}
}
module.exports = {
HttpException,
ParameterException,
Success,
NotFound,
AuthFailed,
Forbidden,
CreateUserFailed
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-30 18:38:30
* @LastEditTime: 2021-09-03 08:16:50
* @LastEditors: Please set LastEditors
* @Description: 路由初始化
* @FilePath: \koa2-test-api\core\init.js
*/
const requireDirectory = require("require-directory");
const Router = require('koa-router');
const koaJwt = require('koa-jwt');
const {
security
} = require("../config/config.js");
class InitManager {
static initCore(app) {
InitManager.app = app;
InitManager.initLoadRouters();
InitManager.loadConfig();
InitManager.loadHttpException(); //加入全局的Exception
}
static initLoadRouters() {
const apiDirectory = `${process.cwd()}/src/routes/`;
const modules = requireDirectory(module, apiDirectory, {
visit: whenLoadModule
});
function whenLoadModule(obj) {
if (obj instanceof Router) {
InitManager.app.use(obj.routes())
InitManager.app.use(koaJwt({
secret: security.secretKey
}).unless({
path: [/^\/api\/users\/login/, /^\/api\/users\/register/]
}));
}
}
}
static loadConfig(path = '') {
const configPath = path || process.cwd() + '/src/config/config.js';
const config = require(configPath);
global.config = config;
}
static loadHttpException() {
const errors = require('./http-exception.js');
global.errs = errors;
}
}
module.exports = InitManager;
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 13:46:30
* @LastEditTime: 2021-09-03 09:04:39
* @LastEditors: Please set LastEditors
* @Description: 授权中间件
* @FilePath: \koa2-test-api\src\middleWares\auth.js
*/
const jwt = require('jsonwebtoken');
class Auth {
constructor() {
}
verToken(token) {
return new Promise((resolve, reject) => {
var userInfo = jwt.verify(token.split(' ')[1], global.config.security.secretKey);
console.log('ver获取用户信息:', userInfo);
resolve(userInfo);
}).catch(err => {
console.log('ver-fail:', err);
})
}
get m() {
return async (ctx, next) => {
const userToken = await this.verToken(ctx.request.header.authorization);
console.log('通过token获取用户信息:', userToken);
let errMsg = 'token不合法';
if (!userToken || !userToken.user_name) {
throw new global.errs.Forbidden(errMsg);
}
//将uid和scope挂载ctx中
ctx.body = userToken;
//console.log('学习:', ctx.body);
//现在走到这里token认证通过
await next();
}
}
}
module.exports = Auth;
\ No newline at end of file
/*
* @Author:尹鹏孝
* @Date: 2021-08-31 13:28:48
* @LastEditTime: 2021-09-03 08:14:57
* @LastEditors: Please set LastEditors
* @Description: 捕获异常生成返回的接口
* @FilePath: \koa2-test-api\src\middlewares\exception.js
*/
const catchError = async (ctx, next) => {
try {
await next();
} catch (error) {
if (error.errorCode) {
ctx.body = {
msg: error.msg,
errorCode: error.errorCode,
request: `${ctx.method} ${ctx.path}`
}
} else {
//对于未知的异常,采用特别处理
console.log(error.originalError);
if (error.originalError == 'JsonWebTokenError: invalid token') {
error.errorCode = 401;
ctx.body = {
errorCode: error.errorCode,
msg: 'token解析失效,请重新登录',
};
} else if (error.originalError == 'TokenExpiredError: jwt expired') {
error.errorCode = 401;
ctx.body = {
errorCode: error.errorCode,
msg: 'token失效,请重新登录',
};
} else {
ctx.body = {
msg: '未知异常,请联系管理员010-99999999',
};
}
}
}
}
module.exports = catchError
\ No newline at end of file
/*
* @Author: your name
* @Date: 2021-08-24 10:32:30
* @LastEditTime: 2021-08-31 14:39:21
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \sequelize\db\model\Foo.js
*/
const {
Sequelize
} = require('sequelize');
const {
seq
} = require("../config/db.js");
const {
STRING,
TEXT,
BOOLEAN,
INTEGER,
BIGINT,
FLOAT,
REAL,
DOUBLE,
DECIMAL,
DATE,
UUID
} = require("./type/index.js");
const Foo = seq.define('Foo', {
// 在这里定义模型属性
foo_name: {
type: STRING,
allowNull: false,
comment: "foo名称"
},
longTime: {
type: DATE,
// 这样,当前日期/时间将用于填充此列(在插入时)
defaultValue: Sequelize.NOW,
comment: "长时间"
},
uuid: {
type: UUID.type,
allowNull: false,
defaultValue: UUID.defaultValue, // 或 Sequelize.UUIDV1
comment: "不重复id-uuid"
},
}, {
// 这是其他模型参数
tableName: 'foo',
});
module.exports = {
Foo
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-24 10:05:31
* @LastEditTime: 2021-09-03 13:21:04
* @LastEditors: Please set LastEditors
* @Description: 用户模型
* @FilePath: \sequelize\db\model\User.js
*/
const {
seq
} = require("../config/db.js");
const {
STRING,
TEXT,
BOOLEAN,
INTEGER,
BIGINT,
FLOAT,
REAL,
DOUBLE,
DECIMAL,
DATE,
UUID
} = require("./type/index.js");
const User = seq.define('User', {
// 在这里定义模型属性
user_name: {
type: STRING,
allowNull: false,
validate: {
//is: /^[a-z]+$/i,
/* not: ['/^[a-z]+$/', "i"],
isEmail: true,
isUrl: true,
isIp: true,
isIPv4: true,
isIPv6: true,
isAlpha: true,
isAlphanumeric: true,
isNumeric: true,
isInt: true,
isFloat: true,
isDecimal: true,
isLowercase: true,
isUppercase: true,
notNull: false,
isNull: true,
notEmpty: true,
equals: 'yc',
contains: 'foo',
notIn: [
['a', 'b']
],
isIn: [
['a', 'b']
],
notContains: 'bar',
len: [2, 10],
isUUID: 4,
isDate: true,
isAfter: '2011-11-11',
isBefore: '2011-12-12',
max: 900,
min: 400,
isCreditCard: true,
isEvent(value) {
if (parseInt(value) % 2 !== 0) {
throw new Error('only even values are allowed !');
}
},
isIn: {
ags: [
['en'],
['zh']
],
msg: '必须为中文或者英文'
} */
}
},
password: {
type: STRING,
allowNull: false,
validate: {
is: /^[a-zA-Z0-9]{8,16}$/i
}
},
scope: {
type: INTEGER,
}
}, {
//追加固定表名称,之前是如果没有tableName时候是user
tableName: 'user',
//冻结表就是必须和表的字段一致freezeTableName,不允许省略
//freezeTableName: true,
//是否带有时间戳timestamps
//timestamps: true
});
module.exports = {
User
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 14:12:44
* @LastEditTime: 2021-08-31 14:12:45
* @LastEditors: Please set LastEditors
* @Description: sequelize数据类型
* @FilePath: \koa2-test-api\src\model\type\index.js
*/
const {
DataTypes,
Sequelize
} = require("sequelize"); // 导入内置数据类型
module.exports = {
STRING: DataTypes.STRING,
TEXT: DataTypes.TEXT, // TEXT
BOOLEAN: DataTypes.BOOLEAN,
INTEGER: DataTypes.INTEGER, // INTEGER
BIGINT: DataTypes.BIGINT, // BIGINT
FLOAT: DataTypes.FLOAT, // FLOAT
REAL: DataTypes.REAL, // REAL 仅 PostgreSQL.
DOUBLE: DataTypes.DOUBLE, // DOUBLE
DECIMAL: DataTypes.DECIMAL, // DECIMAL
DATE: DataTypes.DATE, //// DATETIME 适用于 mysql / sqlite, 带时区的TIMESTAMP 适用于 postgres
UUID: {
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4 // 或 Sequelize.UUIDV1
}
}
\ No newline at end of file
/*
* @Author: your name
* @Date: 2021-08-30 10:58:19
* @LastEditTime: 2021-08-31 09:56:28
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \koa2-test-api\routes\index.js
*/
const router = require('koa-router')()
router.get('/', async (ctx, next) => {
await ctx.render('index', {
title: '首页'
})
})
router.get('/string', async (ctx, next) => {
ctx.body = 'koa2 string'
})
router.get('/json', async (ctx, next) => {
ctx.body = {
title: 'koa2 json'
}
})
module.exports = router
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-30 10:58:19
* @LastEditTime: 2021-09-03 11:52:15
* @LastEditors: Please set LastEditors
* @Description: 用户接口
* @FilePath: \koa2-test-api\src\routes\api\users.js
*/
const {
login,
registry
} = require("../../controller/user.js");
const router = require('koa-router')()
const {
generateToken
} = require('../../utils/utils.js');
const auth = require("../../middleWares/auth.js");
router.prefix('/api/users')
router.post('/login', async (ctx, next) => {
const {
user_name,
password
} = ctx.request.body;
const result = await login({
user_name,
password
});
if (result.user_name) {
/**
* 生成token
*
* */
let token = generateToken(result.id, result.scope, result.user_name)
return ctx.body = new global.errs.Success(token);
} else {
return ctx.body = new global.errs.NotFound(result.msg);
}
})
//获取用户基本信息
router.get('/userInfo', new auth().m, async (ctx, next) => {
if (ctx.body.user_name) {
return ctx.body = new global.errs.Success(ctx.body);
}
return ctx.body = new global.errs.AuthFailed();
});
router.post('/register', async (ctx, next) => {
console.log('输出请求数据:', ctx.request.body);
const {
user_name,
password,
scope
} = ctx.request.body;
let newUser = await registry({
user_name,
password,
scope
});
console.log(newUser);
if (newUser.errorCode == 200) {
return ctx.body = new global.errs.Success(newUser);
} else {
return ctx.body = new global.errs.CreateUserFailed(newUser);
}
});
module.exports = router
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 15:01:10
* @LastEditTime: 2021-09-03 13:14:40
* @LastEditors: Please set LastEditors
* @Description: 查询用户
* @FilePath: \koa2-test-api\src\service\user.js
*/
const {
get,
set
} = require('../cache/_redis.js');
const {
User,
} = require('../model/User.js');
async function findUser({
user_name,
password
}) {
let user = {
attributes: ['user_name', 'id', 'scope', 'createdAt', 'updatedAt']
};
//通过用户名和密码查用户
if (password) {
user.where = {
password,
user_name
}
} else {
user.where = {
user_name: user_name || '',
}
}
//请求先去redis里面查询,如果有而且没过期就返回,不用再去数据库查询,如果过期就去数据库查询,然后再存储到redis中
let result = null;
result = await get(user_name);
console.log('在redis里面查询当前登录用户:', result);
if (result == null) {
result = await User.findOne(user);
if (result) {
result = result.dataValues;
//用户第一次登陆首查询后首先存储在redis中
console.log('查询结果', result);
set(result.user_name, JSON.stringify(result));
return result;
} else {
return {}
}
} else {
return result;
}
}
async function createUser({
user_name,
password,
scope
}) {
try {
console.log("创建函数:");
const user = await await User.create({
user_name,
password,
scope
});
console.log('创建用户是否成功', user);
return user
} catch (error) {
console.log('创建用户失败', error.errors[0].ValidationErrorItem);
return {
errorCode: '400',
msg: '密码不符合规则,请按规则输入'
}
}
}
module.exports = {
findUser,
createUser
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-09-03 09:13:19
* @LastEditTime: 2021-09-03 09:14:21
* @LastEditors: Please set LastEditors
* @Description: 区分环境
* @FilePath: \koa2-test-api\src\utils\env.js
*/
const ENV = process.env.NODE_ENV
module.exports = {
isDev: ENV === 'dev',
notDev: ENV !== 'dev',
isProd: ENV === 'production',
notProd: ENV !== 'production'
}
\ No newline at end of file
/*
* @Author: 尹鹏孝
* @Date: 2021-08-31 13:42:54
* @LastEditTime: 2021-09-02 18:34:24
* @LastEditors: Please set LastEditors
* @Description: 生成令牌
* @FilePath: \koa2-test-api\src\utils\utils.js
*/
const jwt = require("jsonwebtoken");
/**
*
* @param {number} uid 用户id
* @param {number} scope 用户区域
* @param {string} user_name 用户名
* @returns
*/
const generateToken = function (uid, scope, user_name) {
const {
secretKey,
expiresIn
} = global.config.security
//第一个参数为用户信息的js对象,第二个为用来生成token的key值,第三个为配置项
const token = jwt.sign({
uid,
scope,
user_name
}, secretKey, {
expiresIn
})
return token
}
module.exports = {
generateToken
}
\ No newline at end of file
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}
<!--
* @Author: your name
* @Date: 2021-08-30 10:58:19
* @LastEditTime: 2021-08-31 09:55:41
* @LastEditors: your name
* @Description: 首页改造
* @FilePath: \koa2-test-api\views\index.ejs
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
<%=title %>
</title>
</head>
<body>
<p>
<%=title%>
</p>
</body>
</html>
\ No newline at end of file
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册