first commit

This commit is contained in:
编码猿
2024-09-27 02:06:13 +08:00
commit 852d94fbb9
36760 changed files with 3274413 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('backend: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);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
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);
}

View File

@@ -0,0 +1,14 @@
module.exports={
mysqlConfig:{
host : 'localhost',
user : 'root',
password : 'root',
database : 'myblog'
},
ResponseResult: {
// 200 500 600
code: null,
message: null,
data: null,
}
}

View File

@@ -0,0 +1,37 @@
var mysql = require('mysql');
var config =require('../config')
class Mysql{
constructor(){
this.connection = mysql.createConnection(config.mysqlConfig);
//打开链接
this.connection.connect()
}
query(params){
return new Promise((resolve,reject)=>{
this.connection.query(params.sql,params.value,(error, results, fields)=>{
if(error){
resolve( this.error(error.message,error.code))
}else{
resolve(this.success(results))
}
})
})
}
//成功获取数据时
success(data=[],messages="请求成功"){
config.ResponseResult.code=200;
config.ResponseResult.message=messages;
config.ResponseResult.data=data;
return config.ResponseResult
}
//报错时
error(messages="请求失败",code="", data=[]){
config.ResponseResult.code=code;
config.ResponseResult.message=messages;
config.ResponseResult.data=data;
return config.ResponseResult
}
}
module.exports=new Mysql()

View File

@@ -0,0 +1,16 @@
{
"name": "backend",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node-dev ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"morgan": "~1.9.1",
"mysql": "^2.18.1"
}
}

View File

@@ -0,0 +1,16 @@
var express = require('express');
var router = express.Router();
var express =require('../mysql/index');
const mysql = require('../mysql/index');
/* GET home page. */
router.get('/', async (req, res, next)=> {
let resulit= await mysql.query({
sql:'SELECT * FROM `user`',
value:[]
})
res.json(resulit);
});
module.exports = router;

View File

@@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;

View File

@@ -0,0 +1,51 @@
{
"name": "backendv2",
"version": "0.1.0",
"private": true,
"scripts": {
"start": " concurrently \"npm run tsc\" \" npm run dev \" ",
"tsc": "tsc -w",
"dev": "cross-env NODE_ENV=dev node-dev -r tsconfig-paths/register dist/src/run/app.js",
"build": "cross-env NODE_ENV=prod pm2 start src/bin/www"
},
"dependencies": {
"@koa/cors": "^4.0.0",
"@types/kcors": "^2.2.6",
"@types/koa-json": "^2.0.20",
"@types/koa-logger": "^3.1.2",
"@types/koa-static": "^4.0.2",
"apidoc": "^1.0.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"debug": "^4.1.1",
"jsonwebtoken": "^9.0.0",
"kcors": "^2.2.2",
"koa": "^2.7.0",
"koa-bodyparser": "^4.2.1",
"koa-convert": "^1.2.0",
"koa-json": "^2.0.2",
"koa-log4": "^2.3.2",
"koa-logger": "^3.2.0",
"koa-multer": "^1.0.2",
"koa-onerror": "^4.1.0",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"md5": "^2.3.0",
"moment": "^2.29.4",
"mysql": "^2.18.1",
"reflect-metadata": "^0.1.13",
"routing-controllers": "^0.10.4",
"segment": "^0.1.3",
"tsconfig-paths": "^4.2.0",
"typedi": "^0.8.0",
"typeorm": "^0.3.16"
},
"devDependencies": {
"@types/jsonwebtoken": "^9.0.2",
"@types/koa": "^2.13.6",
"@types/koa-bodyparser": "^4.3.10",
"@types/koa-log4": "^2.3.3",
"@types/md5": "^2.3.2",
"cross-env": "^7.0.3"
}
}

View File

@@ -0,0 +1,58 @@
# POST http://127.0.0.1:3000/app/user/add HTTP/1.1
# content-type: application/json
# {
# "name": "bmy2",
# "pwd": "lb714500."
# }
# POST http://127.0.0.1:3000/app/user/login HTTP/1.1
# content-type: application/json
# {
# "name": "bmy2",
# "pwd": "lb714500."
# }
# POST http://127.0.0.1:3000/app/user/info HTTP/1.1
# content-type: application/json
# token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjozLCJ1c2VyX25hbWUiOiJibXkyIiwiaWF0IjoxNjg2NzU0MzIyfQ.ULXeAjdPNDwWAOi-0LC-WmiLKgHVtn3zrFQ8hR7FeRQ
# {}
# GET http://127.0.0.1:3000/app/article/label HTTP/1.1
# content-type: application/json
# {}
# GET http://127.0.0.1:3000/app/article/label HTTP/1.1
# content-type: application/json
# {
# }
# GET http://127.0.0.1:3000/app/article/Labeldetails HTTP/1.1
# content-type: application/json
# {
# "id":1
# }
# GET http://127.0.0.1:3000/app/article/Labeldetails?id=1 HTTP/1.1
# content-type: application/json
# {
# }
GET http://127.0.0.1:3000/app/article/Search?text="3" HTTP/1.1
content-type: application/json
{
}

View File

@@ -0,0 +1,76 @@
import { join } from "path";
export default{
port:'3000',
staticPath:'/public',
cors: {
Origin: '*',
Headers: 'token',
configCors: function () {
return {
"Access-Control-Allow-Origin": this.Origin,
"Access-Control-Allow-Headers": this.Headers
}
}
},
routePrefix: {
app: '/app',
admin: '/admin',
apiPrefix: {
app: {
user: "/user",
article:"/article"
},
admin: { }
}
},
orm: null,
jwtKey: "sdfgsdgfjhjf",
mysql: {
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "root",
database: "myblog",
synchronize: false,
logging: true,
entities: [ join(__dirname, "../entity/**/*{.js,.ts}") ],
},
logConfig: {
appenders: {
//系统日志
access: {
type: 'dateFile',
pattern: '_yyyy-MM-dd.log',
alwaysIncludePattern: true,
encoding: "utf-8",
category: "access",
filename: join(__dirname, '../../logs/access')
},
// 应用日志
application: {
type: 'dateFile',
pattern: '_yyyy-MM-dd.log',
alwaysIncludePattern: true,
encoding: "utf-8",
category: "application",
filename: join(__dirname, '../../logs/application')
},
out: {
type: 'console'
}
},
categories: {
default: { appenders: ['out'], level: 'info' },
access: { appenders: ['access'], level: 'info' },
application: { appenders: ['application'], level: 'WARN' }
},
},
setPrefix: function(path: string): string {
let pathArr: string[] = path.split("/");
// @ts-ignore
return `${this.routePrefix[pathArr[0]]}${this.routePrefix.apiPrefix[pathArr[0]][pathArr[1]]}`
},
}

View File

@@ -0,0 +1,34 @@
import dev from "./dev";
import pord from "./pord.";
import {Configuration} from "koa-log4";
import { DataSourceOptions, DataSource } from "typeorm";
export interface ConfigType {
port:string;
staticPath: string;
orm: DataSource;
jwtKey: string;
mysql: DataSourceOptions;
routePrefix: {
app: string;
admin: string;
apiPrefix: {
app: {
[key: string]: any
};
admin: {
[key: string]: any
}
}
},
cors: {
Origin: string;
Headers: string;
configCors: () => object;
},
setPrefix: (path: string) => string;
logConfig:Configuration;
}
export default process.env.NODE_ENV=="dev"?dev:pord

View File

@@ -0,0 +1,76 @@
import { join } from "path";
export default{
port:'80',
staticPath:'/public',
orm:null,
mysql: {
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "root",
database: "myblog",
synchronize: false,
logging: true,
entities: [ join(__dirname, "../entity/**/*{.js,.ts}") ],
},
routePrefix: {
app: '/app',
admin: '/admin',
apiPrefix: {
app: {
user: "/user"
},
admin: { }
}
},
cors: {
Origin: '*',
Headers: 'token',
configCors: function () {
return {
"Access-Control-Allow-Origin": this.Origin,
"Access-Control-Allow-Headers": this.Headers
}
}
},
logConfig: {
appenders: {
//系统日志
access: {
type: 'dateFile',
pattern: '_yyyy-MM-dd.log',
alwaysIncludePattern: true,
encoding: "utf-8",
category: "access",
filename: join(__dirname, '../../logs/access')
},
// 应用日志
application: {
type: 'dateFile',
pattern: '_yyyy-MM-dd.log',
alwaysIncludePattern: true,
encoding: "utf-8",
category: "application",
filename: join(__dirname, '../../logs/application')
},
out: {
type: 'console'
}
},
categories: {
default: { appenders: ['out'], level: 'info' },
access: { appenders: ['access'], level: 'info' },
application: { appenders: ['application'], level: 'WARN' }
},
},
jwtKey: "sdfgsdgfjhjf",
setPrefix: function(path: string): string {
let pathArr: string[] = path.split("/");
// @ts-ignore
return `${this.routePrefix[pathArr[0]]}${this.routePrefix.apiPrefix[pathArr[0]][pathArr[1]]}`
},
}

View File

@@ -0,0 +1,49 @@
import { JsonController, Authorized, Body, HeaderParam, Get, Post, UseBefore, QueryParam} from 'routing-controllers';
import { RequestLog } from '@/middledware/requestLog'
import { Inject, Service } from 'typedi';
import { ArticleServiceImpl } from '../../service/impl/ArticleServiceImpl';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import { User } from '@/m_res/user'
import config from '@/config/init'
@Service()
@JsonController(config.setPrefix("app/article"))
export class ArticleController {
@Inject()
articleServiceImpl!: ArticleServiceImpl;
@Inject()
json!: JsonResult<any>;
@Get('/label')
@UseBefore(RequestLog) //全部标签
async Articlelabel(){
return await this.articleServiceImpl.GetArticlelabel()
}
@Get('/Labeldetails')
@UseBefore(RequestLog) //标签 详情
async ArticleLabeldetails(@QueryParam("id") id: number){
return await this.articleServiceImpl.GetArticlelabeldetails(id)
}
@Get('/categories_list')
@UseBefore(RequestLog) //分类 全部
async GetCategoriesList() {
return await this.articleServiceImpl.GetCategoriesList();
}
@Get('/categories_info')
@UseBefore(RequestLog) //分类 详情
async GetArticgoriesListinfo(@QueryParam("id") id:number) {
return await this.articleServiceImpl.GetArticgoriesListinfo(id);
}
@Get('/Search')
@UseBefore(RequestLog) //分类 详情
async GetArticSearch(@QueryParam("text") text:string) {
return await this.articleServiceImpl.GetSearch(text);
}
}

View File

@@ -0,0 +1,49 @@
import { Authorized,HeaderParam,Get,JsonController,QueryParams,UseBefore,UseInterceptor,Post,Body} from "routing-controllers";
import { getOneUser ,addUser} from "../../model/request/User";
import { RequestLog } from "../../middledware/requestLog";
import { Service,Inject, } from "typedi";
import { UserServiceimpl } from "../../service/impl/userServiceimpl";
import { User } from "../../model/response/user";
import { JsonResponse } from "../../middledware/JsonResponse"
import { JsonResult ,msgList,res} from "../../utils/jsonResult";
import config from "@/config/init";
import {Token} from "@/m_req/request_Token";
@Service()
@JsonController(config.setPrefix("app/user"))
export class indexController{
@Inject()
UserServiceimpl!:UserServiceimpl;
@Inject()
jsonResult!:JsonResult<any>
// @Post('/info')
// @UseBefore(RequestLog)
// @Authorized()
// async getOneUser(@HeaderParam("token") token: Token): Promise<res<User | null>>{
// console.log("token: ", token);
// return await this.UserServiceimpl.GetOneUser(token.user_id);
// }
//用户添加
@Post('/add')
@UseBefore(RequestLog)
async add(@Body() params: addUser):Promise<res<null>> {
console.log("params",params)
return await this.UserServiceimpl.addUser(params);
}
//登录
@Post('/login')
@UseBefore(RequestLog)
async Login(@Body() params: addUser): Promise<res<User | null>> {
return await this.UserServiceimpl.Login(params);
}
}

View File

@@ -0,0 +1,72 @@
import { Article, } from '@/entity/Article';
import { Categories } from '@/entity/Categories';
import { Tag } from '@/entity/Tag';
import { Comment } from '@/entity/Comment';
import { User } from '@/entity/User';
import { Service, Inject } from 'typedi'
import { Like } from "typeorm"
import { Entity } from '@/utils/orm'
import { Segment } from '@/utils/segment'
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import { Article as ResArticle, comment as commentType, categories, Articlelabel, tag } from '@/m_res/Article';
@Service()
export class ArticleDao {
@Inject()
orm!: Entity
@Inject()
json!: JsonResult<any>;
@Inject()
segment!: Segment
//全部标签
async GetArticlelabelDao(): Promise<res<Array<tag | null>>> {
return this.json.success(await this.orm.get(Tag).find())
}
//标签 详情
async GetArticlelabeldetailsDao(id: number): Promise<res<Article[]>> {
console.log(111)
let res= await this.orm.get(Article).findBy({
tag_id: Like(`%${id}%`),
})
res.forEach(v => {
v.article_text = v.article_text.substr(0, 100)
})
return this.json.success(res)
}
// 分类 全部
async GetArticgoriesListDao(): Promise<res<Categories[]>> {
return this.json.success(await this.orm.get(Categories).find())
}
// 分类 详情
async GetArticgoriesListinfoDao(id: number): Promise<res<Article[]>> {
let ret= await this.orm.get(Article).findBy({
categories_id: Like(`%${id}%`),
})
ret.forEach(v => {
v.article_text = v.article_text.substr(0, 100)
})
return this.json.success(ret)
}
//搜索
async GetSearchDao(text:string): Promise<res<Article[]>> {
let sql: string = ""
this.segment.ik(text).forEach(v => {
sql += ` or article_title like '%${v.w}%'`
})
let res = await this.orm.repository(Article)
.where(sql.replace("or", ""))
.getMany()
return this.json.success(res)
}
}

View File

@@ -0,0 +1,97 @@
import { User ,selectUserField } from "../entity/User";
import { Entity } from "../utils/orm";
import { Service,Inject } from "typedi";
import manager, { DataSource } from "typeorm";
import config from "../config/init";
import { addUser, } from "@/m_req/User";
import { res,JsonResult ,msgList} from "@/utils/jsonResult";
import md5 from "md5";
import moment from "moment";
import { User as UserType } from "@/m_res/user";
import jsonwebtoken from "jsonwebtoken";
@Service()
export class UserDao{
@Inject()
entity!:Entity;
@Inject()
json!: JsonResult<any>;
async GetOneuser(id:number):Promise<res<UserType | null>>{
let data = <UserType> await this.entity.get(User).findOne({
select: selectUserField,
where: { user_id: id }
});
if (data) {
return this.json.success(data)
} else {
return this.json.success(null,msgList.NoFound)
}
}
async addUserDao(params: addUser): Promise<res<null>> {
let isHave = await this.entity.get(User).findOne({
where: { "user_name": params.name }
});
if (isHave != null) {
return this.json.success(null, msgList.UserNameExist)
} else {
await this.entity.source()
.insert()
.into(User)
.values([
{
user_name: params.name,
user_img: "https://c-ssl.dtstatic.com/uploads/item/202004/29/20200429154321_khaik.thumb.1000_0.jpg",
user_pwd: md5(params.pwd),
user_type: 0,
user_addtime: moment().valueOf()
},
])
.execute()
return this.json.success(null, msgList.addUserSuccess)
}
}
async LoginDao(params: addUser): Promise<res<UserType | null>> {
// const user = await this.entity.get(User).findOneBy({
// user_name: params.name,
// user_pwd: md5(params.pwd),
// })
const user = await this.entity.repository(User)
.where("user.user_name = :user_name", { user_name: params.name })
.andWhere('user.user_pwd = :user_pwd', { user_pwd: md5(params.pwd) })
.getOne()
if (user) {
var token = jsonwebtoken.sign({
user_id: user.user_id,
user_name: user.user_name
}, config.jwtKey);
return this.json.success(token)
} else {
return this.json.error(null,msgList.PasswordError)
}
}
async GetOneUser(id: number): Promise<res<UserType | null>> {
let data = <UserType>await this.entity.get(User).findOne({
select: selectUserField,
where: { user_id: id }
});
if (data) {
return this.json.success(data)
} else {
return this.json.success(null,msgList.NoFound)
}
}
}

View File

@@ -0,0 +1,33 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'article'
})
export class Article {
@PrimaryGeneratedColumn()
article_id!: number;
@Column()
article_user!: number;
@Column()
article_title!: string;
@Column()
article_time!: number;
@Column()
article_text!: string;
@Column()
article_backimg!: string;
@Column()
article_view!: number;
@Column()
categories_id!: string;
@Column()
tag_id!: string;
}

View File

@@ -0,0 +1,12 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'categories'
})
export class Categories {
@PrimaryGeneratedColumn()
categories_id!: number;
@Column()
categories_title!: string;
}

View File

@@ -0,0 +1,33 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'comment'
})
export class Comment {
@PrimaryGeneratedColumn()
comment_id!: number;
@Column()
comment_text!: string;
@Column()
comment_time!: number;
@Column()
comment_father_id!: number;
@Column()
article_id!: number;
// @Column()
// comment_reply_id!: number;
@Column()
user_id!: number;
@Column()
user_reply_id!: number;
@Column()
user_reply_name!: string;
}

View File

@@ -0,0 +1,12 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'tag'
})
export class Tag {
@PrimaryGeneratedColumn()
tag_id!: number;
@Column()
tag_title!: string;
}

View File

@@ -0,0 +1,35 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
import { Service,Inject } from "typedi";
@Service()
@Entity({ //表名不同时设置
name: 'user'
})
export class User {
@PrimaryGeneratedColumn() //主键
user_id!: number;
@Column()//列
user_name!: string;
@Column()
user_pwd!: string;
@Column()
user_type!: number;
@Column()
user_img!: string;
@Column()
user_addtime!: number;
}
export let selectUserField = {
user_id: true,
user_name:true,
user_img:true,
user_type: true,
user_addtime:true
}

View File

@@ -0,0 +1,19 @@
import { Interceptor,InterceptorInterface,Action } from "routing-controllers";
export class JsonResponse implements InterceptorInterface{
intercept(action: Action, content: any) {
if(content==null||content.length==0){
}else{
}
return content;
}
}

View File

@@ -0,0 +1,24 @@
import { KoaMiddlewareInterface } from 'routing-controllers';
import { Log } from '../utils/log';
import moment from 'moment';
export class RequestLog implements KoaMiddlewareInterface {
async use(context: any, next: (err?: any) => Promise<any>): Promise<any> {
const start = new Date().valueOf()
let nextAction = await next()
const ms = new Date().valueOf() - start
let message: string = `\n1 请求基本信息: ${context.request.method} ${ms}ms ${context.request.url} ${context.request.ip} ${moment().format('YYYY-MM-DD HH:mm:ss')}\n2 请求参数: ${JSON.stringify(
context.request.method == "GET"
? context.request.querystring
: context.request.body
)} \n3 请求头: ${JSON.stringify(context.request.header)} \n\n`;
console.log(message)
Log.ApplicationLogger().warn(message)
return nextAction
}
}

View File

@@ -0,0 +1,19 @@
import { IsString,MinLength,MaxLength,IsNotEmpty ,IsInt,maxLength} from "class-validator";
export class getOneUser{
@IsNotEmpty()
id!:number;
}
export class addUser {
@IsString({ message: "用户名必须字符串" })
@MinLength(3, { message: "用户名最少3个" })
@MaxLength(10, { message: "用户名最长10个" })
name!: string;
@IsString({ message: "密码必须字符串" })
@MinLength(6, { message: "密码最少6位" })
@MaxLength(20, { message: "密码最长20位" })
@IsNotEmpty({message: "密码不为空"})
pwd!: string;
}

View File

@@ -0,0 +1,5 @@
export interface Token {
user_id: number;
user_name: string;
iat: number
}

View File

@@ -0,0 +1,50 @@
export interface categories {
categories_id: number;
categories_title: string;
}
export interface tag {
tag_id: number;
tag_title: string;
}
export interface comment {
[key: string]: any;
comment_id: number;
comment_text: string;
comment_time: number;
comment_father_id: number;
article_id: number;
comment_reply_id: number;
user_id: number;
user_name: string;
user_img: string;
user_reply_id: number;
user_reply_name: string;
comment_children: comment[]
}
export interface Article {
article_id: number;
article_user: number;
article_title: string;
article_time: number;
article_text: string;
article_backimg: string;
article_view: number;
article_comment: comment[];
categories_id: categories[];
tag_id: tag[];
}
//标签
export interface Articlelabel{
article_id: number;
article_user: number;
article_title: string;
article_time: number;
article_text: string;
article_backimg: string;
article_view: number;
categories_id: string;
tag_id: string;
}

View File

@@ -0,0 +1,8 @@
export interface User {
user_id: number;
user_name: string;
user_pwd: string;
user_type: number;
user_img: string;
user_addtime: number;
}

View File

@@ -0,0 +1,39 @@
/*启动后端项目*/
import { init } from "@/run/init";
import { Controller, useKoaServer,useContainer } from "routing-controllers";
import { Container } from "typedi";
import { join } from "path";
import "reflect-metadata";
class App extends init {
app:typeof this.koa
constructor(){
super()
useContainer(Container)
this.app= useKoaServer(this.koa,{
cors:this.config.cors.configCors,
validation:true,
classTransformer:true,
controllers: [ `${join(__dirname, '../controller/**/*{.js,.ts}')}` ]
})
this.run()
}
run(){
this.app.listen(this.config.port, ()=>{
console.log( `
👏 博客后端接口 👏
👉 1:PC官网: http://127.0.0.1:${this.config.port}/
👉 2:Admin后台: xxxxx
`);
}) //支持回调参数
this.app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
}
}
new App();

View File

@@ -0,0 +1,53 @@
// @ts-ignore
//初始化项目插件
import Application from "koa";
import bodyparser from 'koa-bodyparser';
import json from 'koa-json';
import logger from 'koa-logger'; //请求日志
// @ts-ignore
import onerror from 'koa-onerror'
import staticPublic from 'koa-static';
import config from "../config/init";
import{ ConfigType } from '../config/init';
import { DataSource } from "typeorm";
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions";
export class init{
private plugin: Array<Application.Middleware<Application.DefaultState & { }, Application.DefaultContext & {}>> = [];
protected koa:Application =new Application()
protected config: ConfigType =<ConfigType><unknown>config;
protected orm!:DataSource;
constructor(){
this.initPlugin()
}
initPlugin(){
onerror(this.koa);
this.config.orm = new DataSource(<MysqlConnectionOptions>this.config.mysql)
this.config.orm.initialize()
this.plugin=[
bodyparser({
enableTypes:['json', 'form', 'text']
}),
json(),
logger(),
staticPublic(__dirname + config.staticPath),
// async (ctx, next) => {
// const start = new Date().valueOf()
// await next()
// const ms = new Date().valueOf() - start
// console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
// }
]
this.usePlugin()
}
usePlugin(){
//挂载插件数组到Koa内部
this.plugin.forEach(v=>{
this.koa.use(v)
})
}
}

View File

@@ -0,0 +1,16 @@
import { Article, categories,tag } from '@/m_res/Article'
import { res } from '@/utils/jsonResult';
import { Article as Articlein } from '@/entity/Article';
import {Categories} from '@/entity/Categories';
export interface ArticleService {
//标签
GetArticlelabel():Promise<res<Array<tag|null>>>
//标签详情
GetArticlelabeldetails(id:number):Promise<res<Articlein[]>>
//分类 全部
GetCategoriesList():Promise<res<Categories[]>>
//分类 详情
GetArticgoriesListinfo(id:number):Promise<res<Articlein[]>>
}

View File

@@ -0,0 +1,40 @@
import { ArticleService } from '@/service/ArticleServiceI'
import { ArticleDao } from '@/dao/ArticleDao'
import { Service, Inject } from 'typedi';
import { res } from '@/utils/jsonResult';
import { Article, categories ,Articlelabel,tag} from '@/m_res/Article'
import { Any } from 'typeorm';
import { Article as Articlein } from '@/entity/Article';
import { Categories } from '@/entity/Categories';
@Service()
export class ArticleServiceImpl implements ArticleService {
@Inject()
articleDao!: ArticleDao
//标签全部
async GetArticlelabel():Promise<res<Array<tag|null>>>{
return await this.articleDao.GetArticlelabelDao()
}
//标签 详情
async GetArticlelabeldetails(id:number):Promise<res<Articlein[]>>{
return await this.articleDao.GetArticlelabeldetailsDao(id)
}
//分类全部
async GetCategoriesList():Promise<res<Categories[]>>{
return await this.articleDao.GetArticgoriesListDao()
}
//分类 详情
async GetArticgoriesListinfo(id:number):Promise<res<Articlein[]>>{
return await this.articleDao.GetArticgoriesListinfoDao(id)
}
//搜索
async GetSearch(text:string):Promise<res<Articlein[]>>{
return await this.articleDao.GetSearchDao(text)
}
}

View File

@@ -0,0 +1,37 @@
import { User } from "../../entity/User";
import { userService } from "../userService";
import { Service,Inject } from "typedi";
import { UserDao } from "../../dao/UserDao";
import {res} from "../../utils/jsonResult";
import { addUser } from "@/m_req/User";
import { User as UserType} from "@/m_res/user";
@Service()
export class UserServiceimpl implements userService{
@Inject()
UserDao!:UserDao;
GetAlluser(): User[] {
throw new Error("Method not implemented.");
}
async GetOneuser(id:number): Promise<res<User | null>> {
console.log("cccccc",id)
return await this.UserDao.GetOneuser(id)
}
//用户添加
async addUser(params: addUser): Promise<res<null>> {
return await this.UserDao.addUserDao(params);
}
//登录查询
async Login(params: addUser): Promise<res<UserType | null>> {
return await this.UserDao.LoginDao(params);
}
//token查询
async GetOneUser(id: number): Promise<res<UserType | null>> {
return await this.UserDao.GetOneUser(id);
}
}

View File

@@ -0,0 +1,11 @@
import { User } from "../entity/User";
import { addUser } from '@/m_req/User'
import { res } from "@/utils/jsonResult";
import { User as UserType } from "@/m_res/user";
export interface userService {
GetAlluser():Array<User>
GetOneuser(id:number):Promise<res<User | null>>
addUser(params: addUser): Promise<res<null>>;
Login(params: addUser): Promise<res<UserType | null>>;
GetOneUser(id: number): Promise<res<UserType | null>>;
}

View File

@@ -0,0 +1,27 @@
import { Action } from 'routing-controllers';
import JsonwebToken, { VerifyErrors, JwtPayload } from 'jsonwebtoken'
import config from '@/config/init'
import { JsonResult, msgList } from '@/utils/jsonResult';
/**
* Token检验的装饰器代码实现
*/
export class AuthorizationChecker {
json: JsonResult<null> = new JsonResult
async check(action: Action, roles: string[]): Promise<boolean> {
if (action.request.headers.hasOwnProperty("token")) {
const token = action.request.headers['token'];
return new Promise<boolean>((success: (value: boolean | PromiseLike<boolean>) => void) => {
JsonwebToken.verify( token, config.jwtKey, (err: VerifyErrors | null, decoded: JwtPayload | undefined | string) =>{
if(err){
throw this.json.error(null,msgList.DecodedTokenError)
}else{
action.request.headers['token'] = decoded
success(true)
}
});
})
}
throw this.json.error(null,msgList.NoFoundToken)
}
}

View File

@@ -0,0 +1,81 @@
import { Inject, Service } from 'typedi';
export enum codeList {
Success = 200,
Error = 500,
NoFound = 404
}
export enum msgList {
Success = "请求成功",
Error = "请求成功",
NoFound = "未找到用户",
SystemError = "系统错误",
DeleteSuccess = "删除成功",
NoFoundToken = "缺少token",
DecodedTokenError = "解密token失败",
PasswordError = "用户密码错误,请检查",
UserNameExist = "用户名已存在,请改名",
addUserSuccess = "注册成功",
}
export interface res<T> {
code: number;
msg: string;
data: T;
}
@Service()
export class JsonResult<T> {
// 状态码
private _code!: number;
// 错误的中文信息
private _msg!: string;
// 接口数据
private _data!: T;
public get code(): number {
return this._code;
}
public set code(value: number) {
this._code = value;
}
public get msg(): string {
return this._msg;
}
public set msg(value: string) {
this._msg = value;
}
public get data(): T {
return this._data;
}
public set data(value: T) {
this._data = value;
}
success<U extends T>(data: U, msg?: string, code?: number ) {
this.code = code || codeList.Success;
this.msg = msg || msgList.Success;
this.data = data;
return {
code: this.code,
msg: this.msg,
data: this.data,
}
}
error<U extends T>(data: U, msg?: string, code?: number) {
this.code = code || codeList.Error;
this.msg = msg || msgList.SystemError;
this.data = data;
return {
code: this.code,
msg: this.msg,
data: this.data,
}
}
}

View File

@@ -0,0 +1,20 @@
import log4 from "koa-log4";
import config from "../config/init";
log4.configure(config.logConfig)
export class Log {
/**
* 系统级日志
*/
public static AccessLogger() {
return log4.koaLogger(log4.getLogger('access'), { level: 'auto' });
}
/**
* 应用级别的日志
* @constructor
*/
public static ApplicationLogger() {
return log4.getLogger('application')
}
}

View File

@@ -0,0 +1,35 @@
import { DataSource, EntityTarget, ObjectLiteral, QueryRunner, Repository, SelectQueryBuilder } from "typeorm";
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions";
import config from '../config/init';
import { Service } from "typedi";
@Service()
export class Entity{
getid<T extends ObjectLiteral>(entity:EntityTarget<T>):Repository<T>{
return(<DataSource><unknown>config.orm).getRepository(entity)
}
// 使用 存储库 查询
get<T extends ObjectLiteral>(entity: EntityTarget<T>): Repository<T> {
return (<DataSource><unknown>config.orm).getRepository(entity)
}
// 基于 实体管理器 创建 QueryBuilder
manager<T extends ObjectLiteral>(entity: EntityTarget<T> | any): SelectQueryBuilder<T> {
return (<DataSource><unknown>config.orm).manager.createQueryBuilder(entity,entity.name.toLowerCase())
}
// 基于 数据源 创建 QueryBuilder
source(queryRunner?: QueryRunner): SelectQueryBuilder<any> {
return (<DataSource><unknown>config.orm).createQueryBuilder(queryRunner)
}
// 基于 存储库 使用 QueryBuilder
repository<T extends ObjectLiteral>(entity: EntityTarget<T> | any): SelectQueryBuilder<ObjectLiteral> {
return (<DataSource><unknown>config.orm).getRepository(entity).createQueryBuilder(entity.name.toLowerCase())
}
}

View File

@@ -0,0 +1,16 @@
//@ts-ignore
import segment from 'segment'
import { Service, Inject } from 'typedi'
@Service()
export class Segment {
seg: segment;
constructor() {
this.seg = new segment()
this.seg.useDefault();
}
ik(text: string): { w: string, p: number }[] {
return this.seg.doSegment(text)
}
}

View File

@@ -0,0 +1,88 @@
{
"compilerOptions": {
"target": "ES2015",
"lib": [
"esnext",
"dom"
],
"module": "commonjs",
"baseUrl": "./",
"outDir": "./dist/",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"strict": true,
"skipLibCheck": true,
"paths": {
"@/*": [
"src/*",
"dist/src*",
],
"@/config/*": [
"src/config/*",
"dist/src/config/*",
],
"@/controller/*": [
"src/controller/*",
"dist/src/controller/*",
],
"@/c_admin/*": [
"src/controller/admin/*",
"dist/src/controller/admin/*",
],
"@/c_app/*": [
"src/controller/app/*",
"dist/src/controller/app/*"
],
"@/dao/*": [
"src/dao/*",
"dist/src/dao/*"
],
"@/entity/*": [
"src/entity/*",
"dist/src/entity/*"
],
"@/middledware/*": [
"src/middledware/*",
"dist/src/middledware/*"
],
"@/model/*": [
"src/model/*",
"dist/src/model/*"
],
"@/m_req/*": [
"src/model/request/*",
"dist/src/model/request/*"
],
"@/m_res/*": [
"src/model/response/*",
"dist/src/model/response/*"
],
"@/plugins/*": [
"src/plugins/*",
"dist/src/plugins/*"
],
"@/public/*": [
"src/public/*",
"dist/src/public/*"
],
"@/run/*": [
"src/run/*",
"dist/src/run/*"
],
"@/service/*": [
"src/service/*",
"dist/service/*"
],
"@/impl/*": [
"src/service/impl/*",
"dist/src/service/impl/*"
],
"@/utils/*": [
"src/utils/*",
"dist/src/utils/*"
],
}
}
}

View File

@@ -0,0 +1,44 @@
插件
cross-env 环境变量插件
routing-controllers
kcors
npm install class-validator --save 参数检查效验 需要与reflect-metadata 搭配
koa-log4 日志插件
moment 时间插件
TypeORM 数据库
typrdi 调class库
tsconfig-paths 插件 使用类型别名时使用
md5 加密插件
网址
https://blog.csdn.net/pzy_666/article/details/123369193 禁用eslint / ts相关检查
笔记
path.join() 拼接字符串需引用 path (onde.js 自带)
routing-controllers
useContainer 注入
controller 调 service 调 dao 调 entity

View File

@@ -0,0 +1,13 @@
{
"name": "typescript",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "typescript",
"version": "1.0.0",
"license": "ISC"
}
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "typescript",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "concurrently \"npm run watch\" \"npm run start\" ",
"start": "node dist/qwe.js",
"watch":"tsc -w"
},
"keywords": [],
"author": "",
"license": "ISC"
}

View File

@@ -0,0 +1,305 @@
// enum Direction {
// Up = "UP",
// Down = "DOWN",
// Left = "LEFT",
// Right = "RIGHT",
// }
// console.log(Direction.Up)
// interface objTBase{
// id:number;
// name:string
// }
// interface objType extends objTBase{
// test :[];
// }
// let obj:objType ={
// id:1,
// name:"222",
// test:[]
// }
// interface responseBase<T>{
// data:T
// }
// interface SearchFunc {
// (source: string, subString: string): boolean; //定义函数约束
// }
// let mySearch: SearchFunc;
// mySearch = function(source: string, subString: string) {
// let result = source.search(subString);
// return false
// }
// interface ioi {
// (name:string,id:number):string
// }
// let dd:ioi=(d )=>{
// return ""
// }
// dd("585",5)
// interface StringArray {
// da: string,
// va: string;
// }
// let myArray: StringArray;
// myArray ={da:"55",va:"656"}
// let myStr: string = myArray["da"];
// console.log(myStr)
// interface NumberDictionary {
// [index:string]: number;
// id: number; // 可以,length是number类型
// name: number // 错误,`name`的类型与索引类型返回值的类型不匹配
// }
// let ss:NumberDictionary={
// id:1,
// name:2,
// 1:1,
// ddd:1,
// }
// class Animal {
// name: string;
// }
// class Dog {
// breed: string;
// }
// // 错误:使用数值型的字符串索引,有时会得到完全不同的Animal!
// interface NotOkay {
// [x: string]: Animal;
// [x: string]: Dog;
// }
// interface Shape {
// color: string;
// }
// interface Square extends Shape {
// sideLength: number;
// }
// let square = <Square>{};
// square.color = "blue";
// interface Counter {
// (start: number): string;
// interval: number;
// reset(): void;
// }
// function getCounter(): Counter {
// let counter = <Counter> function (start: number) { };
// counter.interval = 123;
// counter.reset = function () { };
// return counter;
// }
// let c = getCounter();
// c(10);
// c.reset();
// c.interval = 5.0;
// abstract class Animal {
// abstract makeSound(): void;
// move(): void {
// console.log('roaming the earch...');
// }
// }
// let myAdd = function(x:number, y:number):number { return x + y; };
// myAdd(1,2)
// let deck = {
// suits: ["hearts", "spades", "clubs", "diamonds"],
// cards: Array(52),
// createCardPicker: function() {
// return ()=> {
// let pickedCard = Math.floor(Math.random() * 52);
// let pickedSuit = Math.floor(pickedCard / 13);
// return {suit: this.suits[pickedSuit], card: pickedCard % 13};
// }
// }
// }
// let cardPicker = deck.createCardPicker();
// let pickedCard = cardPicker();
// alert("card: " + pickedCard.card + " of " + pickedCard.suit);
// interface UIElement {
// addClickListener(onclick: (s: number, e: number) => void): void;
// }
// let dd:UIElement={
// addClickListener:((s)=>{
// s(1,1)
// })
// }
// function ss<T>(ss:T):T{
// return ss}
// let dd:(ss:string):string= ss
// function identity<T>(arg: T[]): T[] {
// return arg;
// }
// identity<string|Number>(["11,","111",1])
// interface GenericIdentityFn<T> {
// (arg: T): T;
// }
// function identity<T>(arg: T): T {
// return arg;
// }
// identity(1)
// let myIdentity: GenericIdentityFn<number>
// myIdentity=function(a){
// return 1
// }
// // myIdentity(1)
// interface Lengthwise {
// length: number;
// }
// function loggingIdentity<T extends Lengthwise>(arg: T): T {
// console.log(arg.length); // Now we know it has a .length property, so no more error
// return arg;
// }
// loggingIdentity({ff:20length: 10});
// class BeeKeeper {
// hasMask!: boolean;
// }
// class ZooKeeper {
// nametag!: string;
// }
// class Animal {
// numLegs!: number;
// }
// class Bee extends Animal {
// keeper!: BeeKeeper;
// }
// class Lion extends Animal {
// keeper!: ZooKeeper;
// }
// function createInstance<A extends Animal>(c: new () => A): A {
// return new c();
// }
// createInstance(Lion).keeper.nametag; // typechecks!
// createInstance(Bee).keeper.hasMask; // typechecks!
// function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
// return names.map(n => o[n]);
// }
// interface Person {
// name: string;
// age: number;
// }
// let person: Person = {
// name: 'Jarid',
// age: 35
// };
// let strings: string[] = pluck(person, ['name']); // ok, string[]
// let ss:number=1
// console.log(ss)
// type Easing = "ease-in" | "ease-out" | "ease-in-out";
// class UIElement {
// animate(dx: number, dy: number, easing: Easing) {
// if (easing === "ease-in") {
// // ...
// }
// else if (easing === "ease-out") {
// }
// else if (easing === "ease-in-out") {
// }
// else {
// // error! should not pass null or undefined.
// }
// }
// }
// let button = new UIElement();
// button.animate(0, 0, "ease-in");
// button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here
// interface Square {
// kind: "square";
// size: number;
// }
// interface Rectangle {
// kind: "rectangle";
// width: number;
// height: number;
// }
// interface Circle {
// kind: "circle";
// radius: number;
// }
// type Shape = Square | Rectangle | Circle;
// function area(s:Shape) {
// switch (s.kind) {
// case "square": return s.size * s.size;
// case "rectangle": return s.height * s.width;
// case "circle": return Math.PI * s.radius ** 2;
// }
// }
// interface Square{
// kind: "circle";
// }
// let ss:Square={
// kind:"circle",
// }
// area(ss)
// interface Map1<T> {
// [key: string]: T;
// }
// let keys: keyof Map1<number>; // string
// let value: Map1<number>['foo']; // number
// type Pick1<T, K extends keyof T> = {
// [P in K]: T[P];
// }
// type Record1<K extends string, T> = {
// [P in K]: T;
// }

View File

@@ -0,0 +1,3 @@
console.log(11);
var ddd = 11;
console.log(11);

View File

@@ -0,0 +1,40 @@
// console.log(11)
// let ddd:number=11
// console.log(11)
// function color(value:string) {
// console.log("value",value);
// return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
// console.log("target",target)
// console.log("propertyKey",propertyKey)
// console.log("descriptor",descriptor)
// }
// }
// class utils{
// @color("你好")
// getNamea(){
// }
// }
function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
}
}
@classDecorator
class Greeter {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
var dd=new Greeter("world")
console.log(dd.hello);

View File

@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES5",
"lib": [
"esnext",
"dom"
],
"module": "commonjs",
"baseUrl": "./",
"outDir": "./dist/",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true,
"strict": true,
"skipLibCheck": true,
}
}