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,83 @@
import { join } from 'path'
export default {
port: '3000',
staticPath: '../public',
jwtKey: "asdg364355#$%^&%$#!@",
aliyunOssConfig: {
accessKeyId: 'LTAIXlLtUBP2Cr8F',
accessKeySecret: 'B6i0KohY3yf0YGM6xsdqrXeGgFMifs',
},
routePrefix: {
app: '/app',
admin: '/admin',
apiPrefix: {
app: {
user: "/user",
article: "/article",
link: "/link"
},
admin: {
menu: "/menu",
lib: "/lib"
}
}
},
setPrefix: function(path: string): string {
let pathArr: string[] = path.split("/");
// @ts-ignore
return `${this.routePrefix[pathArr[0]]}${this.routePrefix.apiPrefix[pathArr[0]][pathArr[1]]}`
},
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}") ],
},
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' }
}
},
}

View File

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

View File

@@ -0,0 +1,80 @@
import { join } from 'path'
export default {
port: '80',
staticPath: '../public',
jwtKey: "asdg364355#$%^&%$#!@",
aliyunOssConfig: {
accessKeyId: 'LTAIXlLtUBP2Cr8F',
accessKeySecret: 'B6i0KohY3yf0YGM6xsdqrXeGgFMifs',
},
routePrefix: {
app: '/app',
admin: '/admin',
apiPrefix: {
app: {
user: "/user",
article: "/article",
link: "/link",
},
admin: {
menu: "/menu",
lib: "/lib"
}
}
},
setPrefix: function (path: string): string {
let pathArr: string[] = path.split("/");
// @ts-ignore
return `${this.routePrefix[pathArr[0]]}${this.routePrefix.apiPrefix[pathArr[0]][pathArr[1]]}`
},
orm: null,
mysql: {
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "",
database: "myblog",
synchronize: false,
logging: true,
entities: ["src/entity/**/*{.js,.ts}"],
},
cors: {
Origin: 'https://www.a.com',
Headers: 'token,data',
configCors: function () {
return {
"Access-Control-Allow-Origin": this.Origin,
"Access-Control-Allow-Headers": this.Headers
}
}
},
logConfig: {
appenders: {
access: {
type: 'console',
pattern: '-yyyy-MM-dd.log', //通过日期来生成文件
alwaysIncludePattern: true, //文件名始终以日期区分
encoding: "utf-8",
filename: join(__dirname, '../../logs/access.log') //生成文件路径和文件名
},
//系统日志
application: {
type: 'console',
pattern: '-yyyy-MM-dd.log', //通过日期来生成文件
alwaysIncludePattern: true, //文件名始终以日期区分
encoding: "utf-8",
filename: join(__dirname, '../../logs/application.log') //生成文件路径和文件名
},
out: {
type: 'console'
}
},
categories: {
default: { appenders: ['out'], level: 'info' },
access: { appenders: ['access'], level: 'info' },
application: { appenders: ['application'], level: 'WARN' }
}
},
}

View File

@@ -0,0 +1,26 @@
import { JsonController, Authorized, Body, HeaderParam, Get, Post, UseBefore, QueryParam} from 'routing-controllers';
import { RequestLog } from '@/middleware/requestLog'
import { Inject, Service } from 'typedi';
import { uploadOssHelper } from '@/utils/aliyunOss';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import config from '@/config'
@Service()
@JsonController(config.setPrefix("admin/lib"))
export class MenuController {
@Inject()
json!: JsonResult<any>;
@Get('/aliyunToken')
@UseBefore(RequestLog)
async getAliyunOssToken() {
let alyunHelper = new uploadOssHelper({
accessKeyId: config.aliyunOssConfig.accessKeyId,
accessKeySecret: config.aliyunOssConfig.accessKeySecret
})
return this.json.success(alyunHelper.createUploadParams());
}
}

View File

@@ -0,0 +1,34 @@
import { JsonController, Authorized, Body, HeaderParam, Get, Post, UseBefore, QueryParam} from 'routing-controllers';
import { RequestLog } from '@/middleware/requestLog'
import { Inject, Service } from 'typedi';
import { MenuServiceImpl } from '@/impl/MenuServiceImpl';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import config from '@/config'
import {addMenuParams } from "@/model/request/Menu";
@Service()
@JsonController(config.setPrefix("admin/menu"))
export class MenuController {
@Inject()
menuServiceImpl!: MenuServiceImpl;
@Inject()
json!: JsonResult<any>;
@Get('/list')
@UseBefore(RequestLog)
async MenuList() {
return this.menuServiceImpl.GetAllMenu();
}
@Post('/add')
@UseBefore(RequestLog)
@Authorized()
async MenuAdd(@Body() params: addMenuParams) {
return this.menuServiceImpl.addMenu(params);
}
}

View File

@@ -0,0 +1,100 @@
import { JsonController, Authorized, Body, HeaderParam, Get, Post, UseBefore, QueryParam} from 'routing-controllers';
import { RequestLog } from '@/middleware/requestLog'
import { Inject, Service } from 'typedi';
import { ArticleServiceImpl } from '@/impl/ArticleServiceImpl';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import { User } from '@/m_res/user'
import {CommentParams } from "@/model/request/Comment";
import config from '@/config'
import { Token } from '@/m_req/Token'
@Service()
@JsonController(config.setPrefix("app/article"))
export class ArticleController {
@Inject()
articleServiceImpl!: ArticleServiceImpl;
@Inject()
json!: JsonResult<any>;
/**
* @api {get} /app/user/info/:id info
* @apiDescription 获取用户的详细信息
* @apiName info
* @apiGroup user
* @apiParam {number} id 用户的id参数
*
* @apiSuccess {Object} data 用户数据存放在data内部
* @apiSuccess {Number} data.user_id 用户id
* @apiSuccess {String} data.user_name 用户名
* @apiSuccess {String} data.user_pwd 用户密码
* @apiSuccess {Number} data.user_phone 用户手机号
* @apiSuccess {String} data.user_img 用户头像
* @apiSuccess {String} data.user_addtime 注册时间
* @apiSuccessExample {json} 请求成功的返回:
* {
* "code" : 200,
* "msg" : "请求成功"
* "data" : {
* user_id: 1,
* user_name: "bmy",
* user_pwd: "714500",
* user_phone: 15056042604,
* user_img: "https://www.baidu.com/img/flexible/logo/pc/result@2.png",
* user_addtime: "2023-06-03T12:25:16.000Z"
* }
* }
* @apiErrorExample {json} 请求失败的返回
* {
* "code": 200,
* "msg" : "请求成功"
* "data": null
* }
* @apiSampleRequest http://127.0.0.1:3000/app/user/info
*/
@Get('/articleList')
@UseBefore(RequestLog)
async GetArticleList(@QueryParam("text") text: string) {
return await this.articleServiceImpl.GetArticleList(text);
}
@Get('/info')
@UseBefore(RequestLog)
async GetArticleInfo(@QueryParam("id") id: number) {
return await this.articleServiceImpl.GetArticleInfo(id);
}
@Get('/categories_list')
@UseBefore(RequestLog)
async GetCategoriesList() {
return await this.articleServiceImpl.GetCategoriesList();
}
@Get('/categories_info')
@UseBefore(RequestLog)
async GetCategoriesInfo(@QueryParam("id") id: number) {
return await this.articleServiceImpl.GetCategoriesInfo(id);
}
@Get('/search')
@UseBefore(RequestLog)
async Getsearch(@QueryParam("word") word: string) {
return await this.articleServiceImpl.GetSearch(word);
}
@Post('/push_comment')
@UseBefore(RequestLog)
@Authorized()
async PushComment(@Body() params: CommentParams,
@HeaderParam("token") token: Token) {
return await this.articleServiceImpl.pushComment(params, token);
}
}

View File

@@ -0,0 +1,28 @@
import { JsonController, Authorized, Body, HeaderParam, Get, Post, UseBefore, QueryParam} from 'routing-controllers';
import { RequestLog } from '@/middleware/requestLog'
import { Inject, Service } from 'typedi';
import { LinkServiceImpl } from '@/impl/LinkServiceImpl';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import { User } from '@/m_res/user'
import {CommentParams } from "@/model/request/Comment";
import config from '@/config'
import { Token } from '@/m_req/Token'
@Service()
@JsonController(config.setPrefix("app/link"))
export class ArticleController {
@Inject()
linkServiceImpl!: LinkServiceImpl;
@Inject()
json!: JsonResult<any>;
@Get('/list')
@UseBefore(RequestLog)
async LinkList() {
return this.linkServiceImpl.GetAllLink();
}
}

View File

@@ -0,0 +1,74 @@
import { JsonController, Authorized, Body, HeaderParam, Get, Post, UseBefore, UseInterceptor} from 'routing-controllers';
import { getOneUser, addUser } from '@/m_req/User'
import { RequestLog } from '@/middleware/requestLog'
import { Inject, Service } from 'typedi';
import { UserServiceImpl } from '@/impl/userServiceImpl';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import { User } from '@/m_res/user'
import { Token } from '@/m_req/Token'
import config from '@/config'
@Service()
@JsonController(config.setPrefix("app/user"))
export class UserController {
@Inject()
userServiceImpl!: UserServiceImpl;
@Inject()
json!: JsonResult<any>;
/**
* @api {get} /app/user/info/:id info
* @apiDescription 获取用户的详细信息
* @apiName info
* @apiGroup user
* @apiParam {number} id 用户的id参数
*
* @apiSuccess {Object} data 用户数据存放在data内部
* @apiSuccess {Number} data.user_id 用户id
* @apiSuccess {String} data.user_name 用户名
* @apiSuccess {Number} data.user_phone 用户手机号
* @apiSuccess {String} data.user_img 用户头像
* @apiSuccess {String} data.user_addtime 注册时间
* @apiSuccessExample {json} 请求成功的返回:
* {
* "code" : 200,
* "msg" : "请求成功"
* "data" : {
* user_id: 1,
* user_name: "bmy",
* user_phone: 15056042604,
* user_img: "https://www.baidu.com/img/flexible/logo/pc/result@2.png",
* user_addtime: "2023-06-03T12:25:16.000Z"
* }
* }
* @apiErrorExample {json} 请求失败的返回
* {
* "code": 200,
* "msg" : "请求成功"
* "data": null
* }
* @apiSampleRequest http://127.0.0.1:3000/app/user/info
*/
@Post('/info')
@UseBefore(RequestLog)
@Authorized()
async getOneUser(@HeaderParam("token") token: Token): Promise<res<User | null>>{
return await this.userServiceImpl.GetOneUser(token.user_id);
}
@Post('/add')
@UseBefore(RequestLog)
async add(@Body() params: addUser): Promise<res<null>> {
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,164 @@
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} from '@/m_res/Article';
import { CommentParams } from '@/model/request/Comment';
import { Token } from '@/m_req/Token'
import moment from 'moment';
@Service()
export class ArticleDao {
@Inject()
orm!: Entity
@Inject()
json!: JsonResult<any>;
@Inject()
segment!: Segment
async pushCommentDao(params: CommentParams, token: Token) {
let res = await this.orm.source()
.insert()
.into(Comment)
.values({
comment_text: params.comment_text,
comment_time: moment().valueOf(),
comment_father_id: params.comment_father_id,
article_id: params.article_id,
user_id: token.user_id,
user_reply_id: params.user_reply_id
})
.execute();
return this.json.success(null, msgList.pushMessageSuccess)
}
async GetArticleDao(text: string): Promise<res<Array<ResArticle>>> {
let res: ResArticle[] = []
if (text == undefined) {
res = <ResArticle[]>await this.orm.repository(Article).getMany();
} else {
res = <ResArticle[]><unknown>await this.orm.get(Article).findBy({
article_title: Like(`%${text}%`),
})
}
res.forEach(v => {
v.article_text = v.article_text.substr(0,100)
})
return this.json.success(res);
}
async GetArticleInfoDao(id: number): Promise<res<null>> {
let data = await this.orm.get(Article).findOne({ where: { article_id: id } })
if (data != null) {
let newData: ResArticle = <ResArticle><unknown>data
newData.categories_id = await this.orm.get(Categories).find({
where: (<string>data.categories_id).split(",").map(v => {
return { categories_id: Number(v) }
})
})
newData.tag_id = await this.orm.get(Tag).find({
where: (<string>data.tag_id).split(",").map(v => {
return { tag_id: Number(v) }
})
})
let comment = <commentType[]><unknown>await this.orm.get(Comment).find({
where: { article_id: id }
})
for (let i = 0; i < comment.length; i++) {
let me = await this.orm.get(User).findOne({
select: { user_name: true, user_img: true },
where: { user_id: comment[i].user_id }
})
let you = await this.orm.get(User).findOne({
select: { user_name: true },
where: { user_id: comment[i].user_reply_id }
})
if (me != null || you != null) {
for (const key in me) {
comment[i][key] = me[key]
}
for (const key in you) {
comment[i]["user_reply_name"] = you[key]
}
}
}
let leaveOne: commentType[] = [];
comment.forEach(v => {
if (v.comment_father_id == 0) {
v.comment_children = []
leaveOne.push(<commentType><unknown>v)
}
})
leaveOne.forEach(v => {
comment.forEach(j => {
if (v.comment_id == j.comment_father_id) {
// @ts-ignore
v.comment_children.push(j)
}
})
})
newData.article_comment = leaveOne;
return this.json.success(newData)
}
return this.json.error(null, "id不存在")
}
async GetCategoriesListDao(): Promise<res<categories[]>>{
return this.json.success(await this.orm.get(Categories).find({
order: {
categories_id: "DESC"
},
}))
}
async GetCategoriesInfoDao(id: number): Promise<res<ResArticle[]>>{
let res = await this.orm.get(Article).findBy({
categories_id: Like(`%${id}%`),
})
return this.json.success(res)
}
async SearchDao(word: string): Promise<res<ResArticle[]>>{
let sql: string = ""
this.segment.ik(word).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,27 @@
import { User, selectUserField } from '@/entity/User';
import { User as UserType } from '@/m_res/user'
import { Service, Inject } from 'typedi'
import { Entity } from '@/utils/orm'
import { addUser } from '@/model/request/User';
import moment from 'moment';
import md5 from 'md5';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import jsonwebtoken from 'jsonwebtoken'
import config from '@/config'
import { Link } from '@/entity/Link';
@Service()
export class LinkDao {
@Inject()
orm!: Entity
@Inject()
json!: JsonResult<any>;
async GetAllLink(): Promise<res<Link[]>> {
let res = await this.orm.repository(Link).getMany();
return this.json.success(res);
}
}

View File

@@ -0,0 +1,54 @@
import { Service, Inject } from 'typedi'
import { Entity } from '@/utils/orm'
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import { Menu } from '@/entity/Menu';
import { addMenuParams } from "@/model/request/Menu";
@Service()
export class MenuDao {
@Inject()
orm!: Entity
@Inject()
json!: JsonResult<any>;
async addMenuDao(params: addMenuParams): Promise<res<null>> {
let res = await this.orm.source()
.insert()
.into(Menu)
.values({
menu_text: params.text,
menu_icon: params.icon,
menu_href: params.path,
menu_type: params.type,
menu_father_id: params.father_id,
menu_status: 0
})
.execute();
return this.json.success(null, msgList.pushMessageSuccess)
}
async GetAllMenuDao(): Promise<res<Menu[]>> {
let res = await this.orm.repository(Menu).getMany();
let fa: Menu[] = []
res.forEach(v => {
if (v.menu_type == 1) {
fa.push(<Menu>v)
v.children = []
}
})
res.forEach(j => {
fa.forEach(v => {
if (j.menu_father_id == v.menu_id) {
v.children.push(<Menu>j)
}
})
})
return this.json.success(fa);
}
}

View File

@@ -0,0 +1,84 @@
import { User, selectUserField } from '@/entity/User';
import { User as UserType } from '@/m_res/user'
import { Service, Inject } from 'typedi'
import { Entity } from '@/utils/orm'
import { addUser } from '@/model/request/User';
import moment from 'moment';
import md5 from 'md5';
import { JsonResult, msgList, res } from '@/utils/jsonResult';
import jsonwebtoken from 'jsonwebtoken'
import config from '@/config'
@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 }
});
console.log("isHave: ", isHave);
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://upload.jianshu.io/users/upload_avatars/3136195/484e32c3504a.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/240/h/240",
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)
}
}
}

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,15 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'link'
})
export class Link {
@PrimaryGeneratedColumn()
link_id!: number;
@Column()
link_title!: string;
@Column()
link_url!: string;
}

View File

@@ -0,0 +1,29 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'menu'
})
export class Menu {
@PrimaryGeneratedColumn()
menu_id!: number;
@Column()
menu_text!: string;
@Column()
menu_icon!: string;
@Column()
menu_href!: string;
@Column()
menu_type!: number;
@Column()
menu_father_id!: number;
@Column()
menu_status!: number;
children!: Menu[]
}

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,33 @@
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity({
name: 'user'
})
export class User {
// [key: string]: any;
@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,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,8 @@
import { IsString, MinLength, MaxLength, IsNotEmpty } from 'class-validator'
export interface CommentParams {
comment_text: string;
comment_father_id: number;
article_id: number;
user_reply_id: number;
}

View File

@@ -0,0 +1,7 @@
export interface addMenuParams {
icon: string;
text: string;
path: string;
type: number;
number;number;
}

View File

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

View File

@@ -0,0 +1,18 @@
import { IsString, MinLength, MaxLength, IsNotEmpty } 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,39 @@
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[];
}

View File

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

View File

@@ -0,0 +1,47 @@
/**
* 启动我们的后端项目
*/
import "reflect-metadata";
import { Init } from './init'
import { useKoaServer,useContainer, Action } from 'routing-controllers';
import { join } from 'path';
import { Container } from 'typedi';
import { AuthorizationChecker } from '@/utils/authorizationChecker';
class App extends Init {
app: typeof this.koa;
authorizationChecker: AuthorizationChecker = new AuthorizationChecker();
constructor() {
super()
useContainer(Container);
this.app = useKoaServer(this.koa, {
authorizationChecker: this.authorizationChecker.check.bind(this.authorizationChecker),
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,51 @@
/**
* 初始化项目插件的配置
*/
import Application from 'koa'
import bodyparser from 'koa-bodyparser'
import json from 'koa-json'
import logger from 'koa-logger'
import staticPublic from 'koa-static'
// @ts-ignore
import onerror from 'koa-onerror'
import config, { ConfigType } from '@/config'
import { DataSource } from "typeorm";
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions";
import { join } from 'path';
export class Init {
// 存放我们koa框架用到的所有插件
private plugin: Array<Application.Middleware<Application.DefaultState & { }, Application.DefaultContext & {}>> = []
protected koa: Application = new Application();
protected config: ConfigType = <ConfigType><unknown>config;
constructor() {
this.initPlugin()
}
initPlugin() {
onerror(this.koa)
// 初始化 typeorm 的连接,并保存到全局变量 orm 中
this.config.orm = new DataSource(<MysqlConnectionOptions>this.config.mysql)
this.config.orm.initialize()
// koa 的插件数据
this.plugin = [
bodyparser({
enableTypes:['json', 'form', 'text']
}),
json(),
// logger((str, args) => {
// console.log("str: ", str);
// console.log("args: ", args);
// }),
staticPublic(join(__dirname,config.staticPath))
]
this.plugin.forEach(v => this.koa.use(v))
}
}

View File

@@ -0,0 +1,13 @@
import { Article, categories } from '@/m_res/Article'
import { res } from '@/utils/jsonResult';
import {CommentParams } from "@/model/request/Comment";
import { Token } from '@/m_req/Token'
export interface ArticleService {
GetArticleList(text: string): Promise<res<Array<Article>>>;
GetArticleInfo(id: number): Promise<res<null>>;
GetCategoriesList(): Promise<res<categories[]>>;
GetCategoriesInfo(id: number): Promise<res<Article[]>>;
GetSearch(word: string): Promise<res<Article[]>>
pushComment(params: CommentParams, token: Token): Promise<res<string>>
}

View File

@@ -0,0 +1,7 @@
import { Link } from '@/entity/Link'
import { res } from '@/utils/jsonResult';
export interface LinkService {
GetAllLink(): Promise<res<Array<Link>>>;
}

View File

@@ -0,0 +1,9 @@
import { Menu } from '@/entity/Menu'
import { res } from '@/utils/jsonResult';
import {addMenuParams } from "@/model/request/Menu";
export interface MenuService {
GetAllMenu(): Promise<res<Array<Menu>>>;
addMenu(params: addMenuParams): Promise<res<null>>;
}

View File

@@ -0,0 +1,39 @@
import { ArticleService } from '@/service/ArticleService'
import { ArticleDao } from '@/dao/ArticleDao'
import { Service, Inject } from 'typedi';
import { res } from '@/utils/jsonResult';
import { Article, categories } from '@/m_res/Article'
import { CommentParams } from '@/model/request/Comment';
import { Token } from '@/m_req/Token'
@Service()
export class ArticleServiceImpl implements ArticleService {
@Inject()
articleDao!: ArticleDao
async pushComment(params: CommentParams, token: Token): Promise<res<string>> {
return await this.articleDao.pushCommentDao(params, token);
}
async GetArticleList(text: string): Promise<res<Array<Article>>> {
return await this.articleDao.GetArticleDao(text);
}
async GetArticleInfo(id: number): Promise<res<null>> {
return await this.articleDao.GetArticleInfoDao(id);
}
async GetCategoriesList(): Promise<res<categories[]>>{
return await this.articleDao.GetCategoriesListDao();
}
async GetCategoriesInfo(id: number): Promise<res<Article[]>>{
return await this.articleDao.GetCategoriesInfoDao(id);
}
async GetSearch(word: string): Promise<res<Article[]>> {
return await this.articleDao.SearchDao(word);
}
}

View File

@@ -0,0 +1,17 @@
import { Service, Inject } from 'typedi';
import { res } from '@/utils/jsonResult';
import { LinkService } from '../LinkService';
import { Link } from '@/entity/Link';
import { LinkDao } from '@/dao/LinkDao';
@Service()
export class LinkServiceImpl implements LinkService {
@Inject()
linkDao!: LinkDao
async GetAllLink(): Promise<res<Link[]>> {
return this.linkDao.GetAllLink();
}
}

View File

@@ -0,0 +1,22 @@
import { Service, Inject } from 'typedi';
import { res } from '@/utils/jsonResult';
import { MenuService } from '../MenuService';
import { Menu } from '@/entity/Menu';
import { MenuDao } from '@/dao/MenuDao';
import {addMenuParams } from "@/model/request/Menu";
@Service()
export class MenuServiceImpl implements MenuService {
@Inject()
menuDao!: MenuDao
async GetAllMenu(): Promise<res<Menu[]>> {
return this.menuDao.GetAllMenuDao();
}
async addMenu(params: addMenuParams): Promise<res<null>> {
return this.menuDao.addMenuDao(params);
}
}

View File

@@ -0,0 +1,31 @@
import { User } from '@/m_res/user'
import { UserService } from '@/service/userService'
import { UserDao } from '@/dao/UserDao'
import { Service, Inject } from 'typedi';
import { addUser } from '@/model/request/User';
import { res } from '@/utils/jsonResult';
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<UserType | null>> {
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);
}
}

View File

@@ -0,0 +1,11 @@
import { User } from '@/m_res/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<UserType | null>>;
addUser(params: addUser): Promise<res<null>>;
Login(params: addUser): Promise<res<UserType | null>>;
}

View File

@@ -0,0 +1,53 @@
import crypto from "crypto-js";
export class uploadOssHelper {
accessKeyId: string = "";
accessKeySecret: string = "";
timeout: number;
maxSize: number;
constructor(options: {
accessKeyId: string,
accessKeySecret: string,
timeout?: number,
maxSize?: number
}) {
this.accessKeyId = options.accessKeyId;
this.accessKeySecret = options.accessKeySecret;
// 限制参数的生效时间,单位为小时,默认值为1。
this.timeout = options.timeout || 1;
// 限制上传文件的大小,单位为MB,默认值为10。
this.maxSize = options.maxSize || 10;
}
createUploadParams() {
const policy = this.getPolicyBase64();
const signature = this.signature(policy);
return {
OSSAccessKeyId: this.accessKeyId,
policy: policy,
Signature: signature,
};
}
getPolicyBase64() {
let date = new Date();
// 设置policy过期时间。
date.setHours(date.getHours() + this.timeout);
let srcT = date.toISOString();
const policyText = {
expiration: srcT,
conditions: [
// 限制上传文件大小。
["content-length-range", 0, this.maxSize * 1024 * 1024],
],
};
const buffer = new Buffer(JSON.stringify(policyText));
return buffer.toString("base64");
}
signature(policy: string) {
return crypto.enc.Base64.stringify(
crypto.HmacSHA1(policy, this.accessKeySecret)
);
}
}

View File

@@ -0,0 +1,27 @@
import { Action } from 'routing-controllers';
import JsonwebToken, { VerifyErrors, JwtPayload } from 'jsonwebtoken'
import config from '@/config'
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,82 @@
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 = "注册成功",
pushMessageSuccess = "发布成功",
}
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,22 @@
import log4 from 'koa-log4'
import config from '@/config'
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,26 @@
import { EntityTarget, ObjectLiteral, DataSource, Repository, EntityManager, QueryRunner, SelectQueryBuilder } from "typeorm";
import config from '@/config'
import { Service } from 'typedi'
@Service()
export class 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)
}
}