# KoaBoot.JS
**Repository Path**: JSshuai2015/koa-boot.-js
## Basic Information
- **Project Name**: KoaBoot.JS
- **Description**: 使用js的es7的装饰器语法糖基于koa封装模拟springboot风格制作的一个面向注解的web服务端框架
- **Primary Language**: JavaScript
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 1
- **Created**: 2020-09-07
- **Last Updated**: 2022-06-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
KoaBoot.js
基于Koa.js和原生js模仿springboot设计二次封装的服务端框架
⚠️KoaBoot.js正在开发中
# TODO:
- [x] 完成 基本层次的模仿与实现
- [x] 完善 Http 与 mysql 的装饰器
- [x] 完善面向对象编程开发体验
- [x] 自动扫描 Controller 导入路由
- [x] 完成 上传文件测试版本
- [x] 其他...
# Features:
- **面向注解与面向对象**: 层次更加的清晰以及编写服务端代码的阅读性更高
- **让 nodejs 平台上开发服务端更加规范化(虽然有 nest.js)**: 对新手上手服务端开发以及不懂 typescript 的前端 coder 更加友好
# Simple Usage:
Simple.js
```typescript
**/
/**
* Greated By xuanhei on 2020/9/4
**/
const {Api,Controller,PostMapping,GetMapping,DeleteMapping,PutMapping,FilePostMapping} = require('../Annotation/HttpAnnotion');
const IndexService = require("../Service/IndexService");
const {Init,Autowired} = require("../Annotation/InitAnnontion")
const ResultCode = require('../Utils/ResultCode');
/**
* 首页api
*/
@Api("/Article")
@Controller
@Init //增加这个注解给方法修改
class IndexController{
//自动实例化
@Autowired(IndexService)
indexService;
/**
* 增加文章
*/
@PostMapping("/addArticle")
addArticle(data,next){
return this.indexService.addTest(data);
}
/**
* 删除文章
*/
@DeleteMapping("/deleteArticle")
deleteArticle(data){
return this.indexService.deleteTest(data);
}
@PutMapping("/updateArticle")
updateArticle(data,next){
return this.indexService.updateArticle(data)
}
/**
* 查询单篇文章
*/
@GetMapping("/selectOneTest")
selectOneTest(data,next){
return this.indexService.selectOneTest(data)
}
/**
* 查询多篇文章
*/
@GetMapping("/selectArticle")
selectArticle(data,next){
return this.indexService.selectTest(data)
}
/**
* 上传文件
*/
@FilePostMapping("/upFile")
upFile(ctx,next){
return this.indexService.upFile(ctx,next);
}
}
```
run
```bash
git clone https://gitee.com/JSshuai2015/koa-boot.-js
cd koa-boot.-js
npm install
npm run dev
```
# 组成部分
- [Annotation](#Annotation): 注解修饰层,用于装配一些本项目需要预先封装好用以复用的事情
- [Config](#Config): 配置文件,存放文件上传路径以及 mysql 连接配置
- [Controller](#Controller): 控制器层,相应用户请求:决定使用什么视图,需要准备什么数据来显示
- [Server](#Server): 存放业务逻辑处理,也是一些关于数据库处理的操作,但不是直接和数据库打交道,他需要导入 Mapper 层,Mapper 层是直接对数据库打交道的,Server 主打数据输入和输出过程的处理
- [Mapper](#Mapper): Mapper 层,完成对数据库的 curd,并返回处理结果
- [Pojo](#Pojo): 实体层,暂未实现
- [Utils](#Utils): 封装的一些常用工具插件
- [KoaBootApplication.js](#KoaBootApplication): 启动入口
- 其他...: 等我后面更新吧。
# Annotation:
注解修饰层,用于装配一些本项目需要预先封装好用以复用的事情
# Config
配置文件,存放文件上传路径以及 mysql 连接配置
### Example
```typescript
/**
* Greated By xuanhei on 2020/9/5
**/
// 数据库配置
const config = {
port: 3000, // koa运行端口
database: {
host: "127.0.0.1",
user: "root",
password: "root",
database: "koadb", // 数据库名
},
};
module.exports = config;
```
# Controller
### 控制器
控制器层,相应用户请求:决定使用什么视图,需要准备什么数据来显示,示例代码:
```typescript
/**
* Greated By xuanhei on 2020/9/4
**/
const {
Api,
Controller,
PostMapping,
GetMapping,
DeleteMapping,
PutMapping,
FilePostMapping,
} = require("../Annotation/HttpAnnotion");
const IndexService = require("../Service/IndexService");
const { Init, Autowired } = require("../Annotation/InitAnnontion");
const ResultCode = require("../Utils/ResultCode");
/**
* 首页api
*/
@Api("/Article")
@Controller
@Init //增加这个注解给方法修改
class IndexController {
//自动实例化
@Autowired(IndexService)
indexService;
/**
* 增加文章
*/
@PostMapping("/addArticle")
addArticle(data, next) {
return this.indexService.addTest(data);
}
/**
* 删除文章
*/
@DeleteMapping("/deleteArticle")
deleteArticle(data) {
return this.indexService.deleteTest(data);
}
@PutMapping("/updateArticle")
updateArticle(data, next) {
return this.indexService.updateArticle(data);
}
/**
* 查询单篇文章
*/
@GetMapping("/selectOneTest")
selectOneTest(data, next) {
return this.indexService.selectOneTest(data);
}
/**
* 查询多篇文章
*/
@GetMapping("/selectArticle")
selectArticle(data, next) {
return this.indexService.selectTest(data);
}
/**
* 上传文件
*/
@FilePostMapping("/upFile")
upFile(ctx, next) {
return this.indexService.upFile(ctx, next);
}
}
```
# Server
### 服务层
存放业务逻辑处理,也是一些关于数据库处理的操作,但不是直接和数据库打交道,他需要导入 Mapper 层,Mapper 层是直接对数据库打交道的,Server 主打数据输入和输出过程的处理
```typescript
/**
* Greated By xuanhei on 2020/9/6
**/
const IndexMapper = require("../Mapper/IndexMapper");
const ResultCode = require("../Utils/ResultCode");
const { Init, Autowired } = require("../Annotation/InitAnnontion");
const { Service } = require("../Annotation/ServiceAnnontion");
const uploadimg = require("../Utils/FileUtil");
const { autobind } = require("core-decorators");
@Service
// @Init //增加这个注解给方法修改
class IndexService {
// @Autowired("../Mapper/IndexMapper")
indexMapper = new IndexMapper();
addTest(data) {
const that = this;
return async function () {
let SQLDATA = {};
try {
SQLDATA = await that.indexMapper.addTest(data);
} catch (e) {
console.log(e);
}
if (SQLDATA && SQLDATA === 1) {
return ResultCode.SUCCESS({
message: "插入成功",
});
}
return ResultCode.SUCCESS({
message: "插入失败",
});
};
}
deleteTest(id) {
const that = this;
return async function () {
let SQLDATA = {};
try {
SQLDATA = await that.indexMapper.deleteTest(id);
} catch (e) {
console.log(e);
}
if (SQLDATA && SQLDATA === 1) {
return ResultCode.SUCCESS({
message: "删除成功",
});
}
return ResultCode.SUCCESS({
message: "删除失败",
});
};
}
updateArticle(data) {
const that = this;
return async function () {
let SQLDATA = {};
try {
SQLDATA = await that.indexMapper.updateTest(data);
} catch (e) {
console.log(e);
}
if (SQLDATA && SQLDATA === 1) {
return ResultCode.SUCCESS({
message: "更改成功",
});
}
return ResultCode.SUCCESS({
message: "更改失败",
});
};
}
/**
* 查询单条数据
*/
selectOneTest(id) {
const that = this;
return async function () {
return ResultCode.SUCCESS({
data: that.indexMapper.selectOneTest(id),
message: "查询成功",
});
};
}
/**
* 查询多条数据
*/
selectTest() {
const that = this;
return async function () {
return ResultCode.SUCCESS({
data: that.indexMapper.selectTest(),
message: "查询成功",
});
};
}
/**
* 上传文件
*/
upFile(ctx, next) {
return async function () {
const imgUrl = uploadimg(ctx);
if (imgUrl) {
return ResultCode.SUCCESS({
data: imgUrl,
message: "文件上传成功",
});
} else {
return ResultCode.ERRO({
data: null,
message: "文件上传失败",
});
}
};
}
}
module.exports = IndexService;
```
# Mapper
### Mapper 层
Mapper 层,完成对数据库的 curd,并返回处理结果,此处简单封装了直接 sql 查询的注解,使用自定义占位符 :yourKey 形式,正则切割自动匹配传入对象的 key+value,具体自己去体验吧
```typescript
/**
* Greated By xuanhei on 2020/9/6
**/
const {
Mapper,
Insert,
Delete,
Update,
Select,
} = require("../Annotation/MapperAnnotion");
@Mapper
class IndexMapper {
/**
* 增加数据
*/
@Insert("insert into test set name=:name,age=:age")
addTest(obj) {}
/**
* 删除数据
*/
@Delete("DELETE FROM test WHERE id=:id")
deleteTest(id) {}
/**
* 删除数据
*/
@Update("UPDATE test SET name=:name,age=:age WHERE id=:id")
updateTest(data) {}
/**
* 查询多条数据
*/
@Select("select * from test where id=:id", 1) //0为默认返回数组 1为返回对象,默认可以不传
selectOneTest(id) {}
/**
* 查询多条数据
*/
@Select("select * from test")
selectTest() {}
}
module.exports = IndexMapper;
```
# Pojo
### 实体层,校验器以及数据库字段匹配和装配可在此层完成(暂未实现)
```typescript
//类似
@Init
class Test {
id = 0;
name = "";
age = 0;
}
```
# Utils
### 工具层,目前只有统一返回状态以及上传文件工具
```typescript
//工具类
const path = require("path");
const fs = require("fs");
function uploadimg(ctx, next) {
console.log(JSON.stringify(ctx.request, null, " "));
const fileName = ctx.request.files["file"]["name"];
const file = ctx.request.files["file"];
// 创建可读流
const render = fs.createReadStream(file.path);
let filePath = `${path.resolve(
__dirname,
"../FileStatic/images"
)}/${fileName}`;
const fileDir = path.join(__dirname, "../FileStatic/images");
if (!fs.existsSync(fileDir)) {
fs.mkdirSync(fileDir, (err) => {
console.log(err);
console.log("创建失败");
});
}
// 创建写入流
const upStream = fs.createWriteStream(filePath);
render.pipe(upStream);
return filePath;
}
module.exports = uploadimg;
```
```typescript
//返回类
module.exports = new (class ResultCode {
SUCCESS({ code = 200, message = "操作成功", data = "", state = true }) {
const Result = { code, message, data, state };
const response = {};
Object.keys(Result).forEach((key) => {
if (Result[key]) response[key] = Result[key];
});
return response;
}
ERRO({ code = 500, message = "操作失败", state = false }) {
const Result = { code, message, state };
const response = {};
Object.keys(Result).forEach((key) => {
if (Result[key]) response[key] = Result[key];
});
return response;
}
})();
```
# KoaBootApplication
### 启动入口
不需要说了吧
```typescript
```
# 构建指南
git clone to your PC...
# Maintainers
[@coder 猪](https://gitee.com/JSshuai2015).
# License
[Apache-2.0](LICENSE) © coderPig