重构后端,完善获取资源/下载列表、博客列表接口
This commit is contained in:
22
Server/src/APIs/GetBlogList.ts
Normal file
22
Server/src/APIs/GetBlogList.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { API } from "../Plugs/API/API";
|
||||
import ServerStdResponse from "../ServerStdResponse";
|
||||
import MySQLConnection from '../Plugs/MySQLConnection'
|
||||
|
||||
// 获取博客列表
|
||||
class GetBlogList extends API {
|
||||
constructor() {
|
||||
super('GET', '/blogList');
|
||||
}
|
||||
private defaultAccessLevel = 6;
|
||||
|
||||
public async onRequset(data: any, res: any) {
|
||||
let blogListRes = await MySQLConnection.execute('SELECT uuid, title, description, publish_time from blog WHERE access_level > ? ORDER BY publish_time DESC',[this.defaultAccessLevel]);
|
||||
if(!blogListRes){
|
||||
this.logger.error('查询时数据库发生错误');
|
||||
return res.json(ServerStdResponse.SERVER_ERROR);
|
||||
}
|
||||
return res.json({...ServerStdResponse.OK, data: blogListRes});
|
||||
}
|
||||
}
|
||||
|
||||
export default GetBlogList;
|
||||
29
Server/src/APIs/GetResourceList.ts
Normal file
29
Server/src/APIs/GetResourceList.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { API } from "../Plugs/API/API";
|
||||
import ServerStdResponse from "../ServerStdResponse";
|
||||
import MySQLConnection from '../Plugs/MySQLConnection'
|
||||
|
||||
// 获取资源列表
|
||||
class GetResourceList extends API {
|
||||
constructor() {
|
||||
super('GET', '/resourceList');
|
||||
}
|
||||
private typeList = ['resource', 'download']
|
||||
|
||||
public async onRequset(data: any, res: any) {
|
||||
let { type } = data;
|
||||
if(!type){
|
||||
return res.json(ServerStdResponse.PARAMS_MISSING);
|
||||
}
|
||||
if(!this.typeList.includes(type)){
|
||||
return res.json(ServerStdResponse.INVALID_PARAMS);
|
||||
}
|
||||
let resourceListRes = await MySQLConnection.execute('SELECT * from resource WHERE type = ? ORDER BY recommand ASC',[type]);
|
||||
if(!resourceListRes){
|
||||
this.logger.error('查询时数据库发生错误');
|
||||
return res.json(ServerStdResponse.SERVER_ERROR);
|
||||
}
|
||||
return res.json({...ServerStdResponse.OK, data: resourceListRes});
|
||||
}
|
||||
}
|
||||
|
||||
export default GetResourceList;
|
||||
16
Server/src/APIs/GetTest.ts
Normal file
16
Server/src/APIs/GetTest.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { API } from "../Plugs/API/API";
|
||||
import ServerStdResponse from "../ServerStdResponse";
|
||||
import MySQLConnection from '../Plugs/MySQLConnection'
|
||||
|
||||
// 测试接口
|
||||
class GetTest extends API {
|
||||
constructor() {
|
||||
super('GET', '/test');
|
||||
}
|
||||
|
||||
public async onRequset(data: any, res: any) {
|
||||
res.json(ServerStdResponse.OK);
|
||||
}
|
||||
}
|
||||
|
||||
export default GetTest;
|
||||
16
Server/src/Plugs/API/API.ts
Normal file
16
Server/src/Plugs/API/API.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import Logger from "../Logger";
|
||||
|
||||
abstract class API {
|
||||
|
||||
protected logger: Logger;
|
||||
public middlewareFunc: Function[] = [];
|
||||
constructor(public method: string, public uri: string, ...func: any) {
|
||||
this.logger = new Logger('API][' + method + '][' + uri);
|
||||
this.middlewareFunc.push(...func);
|
||||
}
|
||||
|
||||
// to override
|
||||
public abstract onRequset(data: any, res: any): void;
|
||||
}
|
||||
|
||||
export { API };
|
||||
53
Server/src/Plugs/API/APILoader.ts
Normal file
53
Server/src/Plugs/API/APILoader.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import express, { NextFunction, Request, Response } from "express";
|
||||
import cors from "cors";
|
||||
import Logger from "../Logger";
|
||||
import { API } from "./API";
|
||||
import ServerStdResponse from "../../ServerStdResponse";
|
||||
class APILoader {
|
||||
private app = express();
|
||||
private logger = new Logger('APILoader');
|
||||
constructor(private port?: number) {
|
||||
this.logger.info('API服务加载中...');
|
||||
this.app.use(express.json({ limit: '50mb' }));
|
||||
this.app.use(express.urlencoded({ extended: true }));
|
||||
this.app.use(cors({
|
||||
origin: ['http://localhost:5173', 'http://note.ctbu.net.cn', 'http://124.223.5.195:23501'],
|
||||
methods: ['GET', 'POST'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization', 'Access-Control-Allow-Origin', ''],
|
||||
}));
|
||||
}
|
||||
|
||||
add(api: { new(): API }) {
|
||||
const instance = new api();
|
||||
for (let func of instance.middlewareFunc) {
|
||||
this.app[instance.method.toLowerCase() as keyof express.Application](instance.uri, (req: Request, res: Response, next: NextFunction) => {
|
||||
func(req, res, next);
|
||||
});
|
||||
this.logger.info(`[${instance.method}][${instance.uri}] 已启用中间件[${func.name}]`);
|
||||
}
|
||||
|
||||
this.app[instance.method.toLowerCase() as keyof express.Application](instance.uri, (req: Request, res: Response) => {
|
||||
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
|
||||
this.logger.info(`[${instance.method}][${instance.uri}] 被请求[${(ip as string).replace('::ffff:', '')}]`);
|
||||
const data = Object.assign({}, req.query, req.body);
|
||||
instance.onRequset(data, res);
|
||||
});
|
||||
this.logger.info(`[${instance.method}][${instance.uri}] 加载成功`);
|
||||
}
|
||||
|
||||
start(port?: number) {
|
||||
if (this.port == undefined && port == undefined)
|
||||
throw new Error('未指定API端口')
|
||||
this.app.use((req: Request, res: Response) => {
|
||||
this.logger.info(`[${req.method}][${req.url.split('?')[0]}] 该API不存在`);
|
||||
res.json(ServerStdResponse.API_NOT_FOUND)
|
||||
})
|
||||
this.app.listen(port || this.port, () => {
|
||||
this.logger.info(`已全部加载完成,API服务开放在端口:${port || this.port}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
APILoader,
|
||||
}
|
||||
40
Server/src/Plugs/Logger.ts
Normal file
40
Server/src/Plugs/Logger.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
class Logger {
|
||||
constructor(private namespace: string) {
|
||||
}
|
||||
|
||||
private getTime(): string {
|
||||
return new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
||||
}
|
||||
|
||||
public info(info: string, ...args: any): void {
|
||||
args = args.map((arg: any) => {
|
||||
if (typeof arg === 'object') {
|
||||
return JSON.stringify(arg);
|
||||
}
|
||||
return arg;
|
||||
})
|
||||
console.log(`[${this.getTime()}][INFO][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
|
||||
}
|
||||
|
||||
public warn(info: string, ...args: any): void {
|
||||
args = args.map((arg: any) => {
|
||||
if (typeof arg === 'object') {
|
||||
return JSON.stringify(arg);
|
||||
}
|
||||
return arg;
|
||||
})
|
||||
console.log(`[${this.getTime()}][WARN][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
|
||||
}
|
||||
|
||||
public error(info: string, ...args: any): void {
|
||||
args = args.map((arg: any) => {
|
||||
if (typeof arg === 'object') {
|
||||
return JSON.stringify(arg);
|
||||
}
|
||||
return arg;
|
||||
})
|
||||
console.log(`[${this.getTime()}][ERROR][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
export default Logger;
|
||||
17
Server/src/Plugs/Middleware/Auth.ts
Normal file
17
Server/src/Plugs/Middleware/Auth.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import config from "../../config";
|
||||
import ServerStdResponse from "../../ServerStdResponse";
|
||||
import Logger from "../Logger";
|
||||
const logger = new Logger("Auth");
|
||||
const Auth = (req: Request, res: Response, next: NextFunction) => {
|
||||
let token = req.headers.authorization;
|
||||
if (token === config.authToken || token == config.adminToken) {
|
||||
next();
|
||||
} else {
|
||||
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
|
||||
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求鉴权不通过[${token}][${ip}]`);
|
||||
res.json(ServerStdResponse.AUTH_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
export default Auth;
|
||||
17
Server/src/Plugs/Middleware/AuthAdmin.ts
Normal file
17
Server/src/Plugs/Middleware/AuthAdmin.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import config from "../../config";
|
||||
import ServerStdResponse from "../../ServerStdResponse";
|
||||
import Logger from "../Logger";
|
||||
const logger = new Logger("AuthAdmin");
|
||||
const AuthAdmin = (req: Request, res: Response, next: NextFunction) => {
|
||||
let token = req.headers.authorization;
|
||||
if (token === config.adminToken) {
|
||||
next();
|
||||
} else {
|
||||
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
|
||||
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求鉴权不通过[${token}][${ip}]`);
|
||||
res.json(ServerStdResponse.AUTH_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthAdmin;
|
||||
9
Server/src/Plugs/Middleware/Unbind.ts
Normal file
9
Server/src/Plugs/Middleware/Unbind.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import Logger from "../Logger";
|
||||
const logger = new Logger("Unbind");
|
||||
const Unbind = (req: Request, res: Response, next: NextFunction) => {
|
||||
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
|
||||
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求了未绑定的接口[${ip}]`);
|
||||
}
|
||||
|
||||
export default Unbind;
|
||||
77
Server/src/Plugs/MySQLConnection.ts
Normal file
77
Server/src/Plugs/MySQLConnection.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
// MYSQL数据库连接池
|
||||
// 版本:v0.1
|
||||
import mysql from "mysql2/promise";
|
||||
import Logger from "./Logger";
|
||||
import config from "../config";
|
||||
|
||||
class MySQLConnectPool {
|
||||
private pool: any;
|
||||
private logger = new Logger('MySQLConnection');
|
||||
|
||||
constructor() {
|
||||
this.pool = this.createConnectPool();
|
||||
this.logger.info("[MySQL] 数据库连接池已创建")
|
||||
setTimeout(async () => {
|
||||
let res = await this.testConnection();
|
||||
if (res)
|
||||
this.logger.info("[MySQL] 数据库测试成功")
|
||||
else
|
||||
this.logger.error("[MySQL] 数据库测试失败")
|
||||
}, 10);
|
||||
}
|
||||
|
||||
// 内部函数,无需手动调用
|
||||
createConnectPool() {
|
||||
return mysql.createPool({
|
||||
host: config.mysql.host,
|
||||
database: config.mysql.database,
|
||||
user: config.mysql.user,
|
||||
password: config.mysql.password,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0
|
||||
})
|
||||
}
|
||||
|
||||
// 内部函数,无需手动调用
|
||||
async testConnection() {
|
||||
try {
|
||||
let res = await this.execute("SELECT 1 + 1 As result");
|
||||
if (res[0].result == 2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
} catch (error) {
|
||||
this.logger.error(`[MySQL] 数据库测试发生了错误:` + error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 执行SQL语句
|
||||
async execute(sql: string, values?: any[], database?: string) {
|
||||
let connection: any;
|
||||
try {
|
||||
connection = await this.pool.getConnection();
|
||||
|
||||
// 如果指定了数据库,则更改当前连接的数据库
|
||||
if (database) {
|
||||
await connection.changeUser({ database });
|
||||
}
|
||||
|
||||
let [rows, fields] = await connection.execute(sql, values);
|
||||
return rows;
|
||||
} catch (error) {
|
||||
this.logger.error("[MySQL] 数据库发生错误:" + error, '\n##', sql, '\n##', JSON.stringify(values));
|
||||
return undefined;
|
||||
} finally {
|
||||
if (database)
|
||||
await connection.changeUser({ database: config.mysql.database });// 恢复默认数据库
|
||||
if (connection)
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let MySQLConnection = new MySQLConnectPool();
|
||||
export default MySQLConnection;
|
||||
31
Server/src/Server/Server.ts
Normal file
31
Server/src/Server/Server.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import Logger from "../Plugs/Logger";
|
||||
import { APILoader } from "../Plugs/API/APILoader";
|
||||
import config from "../config";
|
||||
|
||||
import GetTest from "../APIs/GetTest";
|
||||
import GetResourceList from "../APIs/GetResourceList";
|
||||
import GetBlogList from "../APIs/GetBlogList";
|
||||
|
||||
class Server {
|
||||
private logger = new Logger('Server');
|
||||
public static instance: Server;
|
||||
private apiLoader = new APILoader();
|
||||
|
||||
constructor() {
|
||||
Server.instance = this;
|
||||
}
|
||||
|
||||
public async start() {
|
||||
// 加载前台API
|
||||
this.apiLoader.add(GetTest);
|
||||
this.apiLoader.add(GetResourceList);
|
||||
this.apiLoader.add(GetBlogList);
|
||||
|
||||
this.apiLoader.start(config.apiPort);
|
||||
}
|
||||
}
|
||||
|
||||
let _Server = new Server();
|
||||
export {
|
||||
_Server as server,
|
||||
}
|
||||
52
Server/src/ServerStdResponse.ts
Normal file
52
Server/src/ServerStdResponse.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
const ServerStdResponse = {
|
||||
OK: {
|
||||
code: 0,
|
||||
message: 'OK'
|
||||
},
|
||||
PARAMS_MISSING: {
|
||||
code: -1,
|
||||
message: 'Parameters missing'
|
||||
},
|
||||
INVALID_PARAMS: {
|
||||
code: -2,
|
||||
message: 'Invalid parameters'
|
||||
},
|
||||
INVALID_TOKEN: {
|
||||
code: -3,
|
||||
message: 'Invalid token'
|
||||
},
|
||||
SERVER_ERROR: {
|
||||
code: -4,
|
||||
message: 'Server error'
|
||||
},
|
||||
API_NOT_FOUND: {
|
||||
code: -5,
|
||||
message: 'API not found'
|
||||
},
|
||||
AUTH_ERROR: {
|
||||
code: -6,
|
||||
message: 'Authentication error'
|
||||
},
|
||||
IDENTIFY_FAILED: {
|
||||
code: -7,
|
||||
message: 'Identify failed'
|
||||
},
|
||||
GOODS: {
|
||||
NOTFOUND: {
|
||||
code: -4001,
|
||||
message: 'Goods not found'
|
||||
}
|
||||
},
|
||||
ORDER: {
|
||||
NOTFOUND: {
|
||||
code: -5001,
|
||||
message: 'Order not found'
|
||||
},
|
||||
ALREADY_CANCEL: {
|
||||
code: -5002,
|
||||
message: 'Order already canceled'
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export default ServerStdResponse;
|
||||
15
Server/src/config.ts
Normal file
15
Server/src/config.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
const config = {
|
||||
mysql: {
|
||||
host: 'localhost',
|
||||
// host:'server.tonesc.cn',
|
||||
database: 'tonecn',
|
||||
user: 'root',
|
||||
password: 'Shi15023847146'
|
||||
// password: '245565'
|
||||
},
|
||||
authToken: '17e50223f4a545ec9e36ebf08e2f71bb',
|
||||
adminToken: '3a6f71412f9e48b9bbbd056aa7eb5467',
|
||||
apiPort: 23500,
|
||||
} as const;
|
||||
|
||||
export default config;
|
||||
11
Server/src/index.ts
Normal file
11
Server/src/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import Logger from "./Plugs/Logger";
|
||||
let logger = new Logger("Server");
|
||||
logger.info('服务正启动...');
|
||||
import { server } from "./Server/Server";
|
||||
async function main() {
|
||||
server.start();
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
logger.error(err);
|
||||
});
|
||||
Reference in New Issue
Block a user