refactor: 重构优化

This commit is contained in:
xiaoxian521 2022-11-09 15:51:06 +08:00
parent 07b1d2c00a
commit 724e662a52
15 changed files with 2022 additions and 175 deletions

86
.gitignore vendored
View File

@ -1,4 +1,84 @@
node_modules
.DS_Store
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# Nuxt generate
dist
yarn.lock
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
# IDE
.idea
docs
.DS_Store

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 啝裳
Copyright (c) Lastest RealityBoy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,27 +1,34 @@
# 接口
<p align="center">
pure-admin官方后端
<br />
采用nodejs编写
</p>
## 快速启动
### 打开 `MySql`
来到项目的 `src/config/index.ts` 文件,查看第 `50` 行,将 `mysql` 的账号密码跟您的 `mysql` 保持一致
### 安装依赖
## 安装依赖
```
yarn install
pnpm install
```
## 项目启动
### 项目启动
采用 [nodemon](https://github.com/remy/nodemon) 运行项目,修改代码自动更新,无需重启
```
yarn dev
pnpm start
```
## Swagger文档访问地址
### `Swagger` 文档访问地址
http://localhost:3000
## 在swagger中添加token验证
① 先请求验证码接口拿到验证码info字段就是验证码
② 然后请求登录接口你可以在网页的Network中拿到登录成功后返回的token复制
③ 最后回到swagger点击右上角的绿色边框Authorize你会看到一个Value的输入框将复制的token前面加上Bearer 粘贴上去点确定即可Authorize
注意Bearer后面有一个空格哦
## 如何在 `Swagger` 中添加 `token` 验证
## 注意点
请先全局安装typescript、ts-node如安装请忽略
```
npm install -g typescript
npm install -g ts-node
```
① 在注册接口注册个账号,然后去请求登录接口,请求成功之后看下面的返回值 `accessToken`,复制这个 `token`
② 回到 `Swagger`,点击右上角的绿色边框 `Authorize`,您会看到一个 `Value` 的输入框,将复制的 `token` 前面加上 `Bearer ` 粘贴上去,点确定即可,注意需要在 `Bearer` 后面加个一个空格

12
nodemon.json Normal file
View File

@ -0,0 +1,12 @@
{
"restartable": "rs",
"ignore": [".git", "node_modules/", "dist/", "coverage/"],
"watch": ["src/"],
"execMap": {
"ts": "node -r ts-node/register"
},
"env": {
"NODE_ENV": "development"
},
"ext": "js,json,ts"
}

View File

@ -1,33 +1,32 @@
{
"name": "backend-ts",
"version": "1.0.0",
"description": "API接口",
"main": "index.js",
"name": "pure-admin-backend",
"version": "lastest",
"description": "pure-admin官方后端",
"scripts": {
"build": "tsc",
"dev": "ts-node ./src/server.ts",
"start": "nodemon ./dist/server.js",
"prod": "npm run build && npm run start",
"yarn:clean": "yarn cache clean"
"start": "nodemon --config nodemon.json src/server.ts"
},
"author": "xiaoxian521",
"license": "ISC",
"dependencies": {
"@types/express": "^4.17.9",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-swagger-generator": "^1.1.17",
"jsonwebtoken": "^8.5.1",
"mysql2": "^2.2.5",
"svg-captcha": "^1.4.0",
"winston": "^3.3.3"
},
"devDependencies": {
"body-parser": "^1.19.0",
"nodemon": "^1.19.4",
"open": "^7.3.0",
"tslint": "^5.20.1",
"typescript": "^3.9.7"
"@types/express": "^4.17.14",
"@types/formidable": "^2.0.5",
"@types/jsonwebtoken": "^8.5.9",
"@types/node": "^18.11.9",
"body-parser": "^1.20.1",
"dayjs": "^1.11.6",
"dotenv": "^16.0.3",
"esno": "^0.16.3",
"express": "^4.18.2",
"express-swagger-generator": "^1.1.17",
"formidable": "^2.0.1",
"jsonwebtoken": "^8.5.1",
"mysql2": "^2.3.3",
"nodemon": "^2.0.20",
"open": "^8.4.0",
"svg-captcha": "^1.4.0",
"ts-node": "^10.9.1",
"typescript": "^4.8.4",
"winston": "^3.8.2"
},
"repository": "git@github.com:xiaoxian521/vue-pure-admin.git"
"repository": "https://github.com/xiaoxian521/pure-admin-backend"
}

1736
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@ import * as express from "express";
import * as bodyParser from "body-parser";
class App {
public app: express.Application;
public app;
constructor() {
this.app = express();
this.config();

View File

@ -15,7 +15,7 @@ export default {
options: {
swaggerDefinition: {
info: {
description: "Pure-Admin官方接口",
description: "pure-admin官方后端",
title: "Swagger",
version: require("../../package.json").version,
},
@ -34,10 +34,13 @@ export default {
},
route: {
url: "./swagger-ui.html",
docs: "/swagger.json", //swagger文件 api
// swagger文件 api
docs: "/swagger.json",
},
basedir: __dirname, //app absolute path
files: ["../router/api/*.ts"], //Path to the API handle folder
// app absolute path
basedir: __dirname,
// path to the API handle folder
files: ["../router/api/*.ts"],
},
logs: {
level: process.env.LOG_LEVEL || "silly",

View File

@ -1,4 +1,4 @@
// 创建用户表
/** 创建用户表 */
const user =
"CREATE TABLE if not EXISTS users(id int PRIMARY key auto_increment,username varchar(32),password varchar(32),time DATETIME)";

View File

@ -1,20 +1,22 @@
import * as dayjs from "dayjs";
import * as mysql from "mysql2";
import secret from "../../config";
import * as jwt from "jsonwebtoken";
import { createHash } from "crypto";
import Logger from "../../loaders/logger";
import { Message } from "../../utils/enums";
import { Request, Response } from "express";
import { createMathExpr } from "svg-captcha";
// import { createMathExpr } from "svg-captcha";
import getFormatDate from "../../utils/date";
import { Code, Info } from "../../utils/infoEnum";
import { connection } from "../../utils/initMysql";
// import { formidable } from "formidable";
// let path = require("path");
export interface dataModel {
length: number;
}
/** 保存验证码 */
// let generateVerify: number;
// 保存验证码
let generateVerify: number;
/** 过期时间 单位:毫秒 默认 1分钟过期方便演示 */
let expiresIn = 60000;
/**
* @typedef Error
@ -26,11 +28,17 @@ let generateVerify: number;
* @property {[integer]} code
*/
// /**
// * @typedef Login
// * @property {string} username.required - 用户名 - eg: admin
// * @property {string} password.required - 密码 - eg: 123456
// * @property {integer} verify.required - 验证码
// */
/**
* @typedef Login
* @property {string} username.required - - eg: admin
* @property {string} password.required - - eg: 123456
* @property {integer} verify.required -
*/
/**
@ -48,18 +56,21 @@ let generateVerify: number;
*/
const login = async (req: Request, res: Response) => {
const { username, password, verify } = req.body;
// const { username, password, verify } = req.body;
// if (generateVerify !== verify) return res.json({
// code: Code.failCode,
// info: Info[0]
// success: false,
// data: {
// message: Message[0];
// }
// })
const { username, password } = req.body;
let sql: string =
"select * from users where username=" + "'" + username + "'";
connection.query(sql, async function (err, data: dataModel) {
connection.query(sql, async function (err, data: any) {
if (data.length == 0) {
await res.json({
code: Code.failCode,
info: Info[1],
success: false,
data: { message: Message[1] },
});
} else {
if (
@ -70,30 +81,57 @@ const login = async (req: Request, res: Response) => {
accountId: data[0].id,
},
secret.jwtSecret,
{ expiresIn: 20000 }
{ expiresIn }
);
await res.json({
code: Code.successCode,
info: Info[2],
expires: 20000,
name: username,
accessToken,
});
if (username === "admin") {
await res.json({
success: true,
data: {
message: Message[2],
username,
// 这里模拟角色,根据自己需求修改
roles: ["admin"],
accessToken,
// 这里模拟刷新token根据自己需求修改
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
expires: new Date(new Date()).getTime() + expiresIn,
},
});
} else {
await res.json({
success: true,
data: {
message: Message[2],
username,
// 这里模拟角色,根据自己需求修改
roles: ["common"],
accessToken,
// 这里模拟刷新token根据自己需求修改
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
expires: new Date(new Date()).getTime() + expiresIn,
},
});
}
} else {
await res.json({
code: Code.failCode,
info: Info[3],
success: false,
data: { message: Message[3] },
});
}
}
});
};
// /**
// * @typedef Register
// * @property {string} username.required - 用户名
// * @property {string} password.required - 密码
// * @property {integer} verify.required - 验证码
// */
/**
* @typedef Register
* @property {string} username.required - - eg: admin
* @property {string} password.required - - eg: 123456
* @property {integer} verify.required -
* @property {string} username.required -
* @property {string} password.required -
*/
/**
@ -111,24 +149,25 @@ const login = async (req: Request, res: Response) => {
*/
const register = async (req: Request, res: Response) => {
const { username, password, verify } = req.body;
if (generateVerify !== verify)
return res.json({
code: Code.failCode,
info: Info[0],
});
// const { username, password, verify } = req.body;
const { username, password } = req.body;
// if (generateVerify !== verify)
// return res.json({
// success: false,
// data: { message: Message[0] },
// });
if (password.length < 6)
return res.json({
code: Code.failCode,
info: Info[4],
success: false,
data: { message: Message[4] },
});
let sql: string =
"select * from users where username=" + "'" + username + "'";
connection.query(sql, async (err, data: dataModel) => {
connection.query(sql, async (err, data: any) => {
if (data.length > 0) {
await res.json({
code: Code.failCode,
info: Info[5],
success: false,
data: { message: Message[5] },
});
} else {
let time = await getFormatDate();
@ -151,8 +190,8 @@ const register = async (req: Request, res: Response) => {
Logger.error(err);
} else {
await res.json({
code: Code.successCode,
info: Info[6],
success: true,
data: { message: Message[6] },
});
}
});
@ -181,7 +220,7 @@ const updateList = async (req: Request, res: Response) => {
const { username } = req.body;
let payload = null;
try {
const authorizationHeader = req.get("Authorization");
const authorizationHeader = req.get("Authorization") as string;
const accessToken = authorizationHeader.substr("Bearer ".length);
payload = jwt.verify(accessToken, secret.jwtSecret);
} catch (error) {
@ -201,8 +240,8 @@ const updateList = async (req: Request, res: Response) => {
Logger.error(err);
} else {
await res.json({
code: Code.successCode,
info: Info[7],
success: true,
data: { message: Message[7] },
});
}
});
@ -230,7 +269,7 @@ const deleteList = async (req: Request, res: Response) => {
const { id } = req.params;
let payload = null;
try {
const authorizationHeader = req.get("Authorization");
const authorizationHeader = req.get("Authorization") as string;
const accessToken = authorizationHeader.substr("Bearer ".length);
payload = jwt.verify(accessToken, secret.jwtSecret);
} catch (error) {
@ -242,8 +281,8 @@ const deleteList = async (req: Request, res: Response) => {
console.log(err);
} else {
await res.json({
code: Code.successCode,
info: Info[8],
success: true,
data: { message: Message[8] },
});
}
});
@ -273,7 +312,7 @@ const searchPage = async (req: Request, res: Response) => {
const { page, size } = req.body;
let payload = null;
try {
const authorizationHeader = req.get("Authorization");
const authorizationHeader = req.get("Authorization") as string;
const accessToken = authorizationHeader.substr("Bearer ".length);
payload = jwt.verify(accessToken, secret.jwtSecret);
} catch (error) {
@ -286,8 +325,8 @@ const searchPage = async (req: Request, res: Response) => {
Logger.error(err);
} else {
await res.json({
code: Code.successCode,
info: data,
success: true,
data,
});
}
});
@ -316,7 +355,7 @@ const searchVague = async (req: Request, res: Response) => {
const { username } = req.body;
let payload = null;
try {
const authorizationHeader = req.get("Authorization");
const authorizationHeader = req.get("Authorization") as string;
const accessToken = authorizationHeader.substr("Bearer ".length);
payload = jwt.verify(accessToken, secret.jwtSecret);
} catch (error) {
@ -324,8 +363,8 @@ const searchVague = async (req: Request, res: Response) => {
}
if (username === "" || username === null)
return res.json({
code: Code.failCode,
info: Info[9],
success: false,
data: { message: Message[9] },
});
let sql: string = "select * from users";
sql += " WHERE username LIKE " + mysql.escape("%" + username + "%");
@ -335,32 +374,34 @@ const searchVague = async (req: Request, res: Response) => {
Logger.error(err);
} else {
await res.json({
code: Code.successCode,
info: data,
success: true,
data,
});
}
});
});
};
/**
* @route GET /captcha
* @summary
* @group captcha -
* @returns {object} 200
* @security JWT
*/
// const upload = async (req: Request, res: Response) => {};
const captcha = async (req: Request, res: Response) => {
const create = createMathExpr({
mathMin: 1,
mathMax: 4,
mathOperator: "+",
});
generateVerify = Number(create.text);
res.type("svg"); // 响应的类型
res.json({ code: Code.successCode, info: create.text, svg: create.data });
};
// /**
// * @route GET /captcha
// * @summary 图形验证码
// * @group captcha - 图形验证码
// * @returns {object} 200
// * @security JWT
// */
// const captcha = async (req: Request, res: Response) => {
// const create = createMathExpr({
// mathMin: 1,
// mathMax: 4,
// mathOperator: "+",
// });
// generateVerify = Number(create.text);
// res.type("svg"); // 响应的类型
// res.json({ success: true, data: { text: create.text, svg: create.data } });
// };
export {
login,
@ -369,5 +410,6 @@ export {
deleteList,
searchPage,
searchVague,
captcha,
// upload,
// captcha,
};

View File

@ -1,5 +1,5 @@
import app from "./app";
import * as open from "open";
// import * as open from "open";
import config from "./config";
import { user } from "./models/mysql";
import Logger from "./loaders/logger";
@ -16,7 +16,8 @@ import {
deleteList,
searchPage,
searchVague,
captcha,
// upload,
// captcha,
} from "./router/api/mysql";
app.post("/login", (req, res) => {
@ -43,9 +44,13 @@ app.post("/searchVague", (req, res) => {
searchVague(req, res);
});
app.get("/captcha", (req, res) => {
captcha(req, res);
});
// app.post("/upload", (req, res) => {
// upload(req, res);
// });
// app.get("/captcha", (req, res) => {
// captcha(req, res);
// });
app
.listen(config.port, () => {

View File

@ -1,11 +1,5 @@
// 状态码
export const enum Code {
failCode = -1,
successCode = 0,
}
// 返回信息
export enum Info {
/** 返回信息 */
export enum Message {
"请输入正确的验证码",
"账号尚未被注册",
"登录成功",

View File

@ -2,7 +2,7 @@ import * as mysql from "mysql2";
import mysqlConfig from "../config";
import Logger from "../loaders/logger";
//user数据库
/** user数据库 */
export const connection = mysql.createConnection(
Object.assign({ database: "user" }, mysqlConfig.mysql)
);

View File

@ -1,18 +1,16 @@
{
"compilerOptions": {
"target": "ESNEXT",
"module": "commonjs",
"moduleResolution": "node",
"pretty": true,
"sourceMap": true,
"target": "es6",
"outDir": "./dist",
"baseUrl": "./lib"
"outDir": "dist",
"allowSyntheticDefaultImports": true
},
"include": [
"src/**/*.ts", "src/router/api/user.js"
],
"include": ["src/**/*.ts", ],
"exclude": [
"node_modules",
"src/router/api/*.ts",
"dist"
]
}
}

View File

@ -1,29 +0,0 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {},
"rules": {
"interface-name": [
true,
"never-prefix"
],
"no-console": [
false
],
"semicolon": [
false
],
"quotemark": [
false
],
"object-literal-sor t-keys": [
false
],
"max-classes-per-file": [
false
]
},
"rulesDirectory": []
}