├── .gitignore ├── README.md ├── hello-world ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc.js ├── README.md ├── README.zh-CN.md ├── bootstrap.js ├── jest.config.js ├── jest.setup.js ├── package.json ├── src │ ├── config │ │ ├── config.default.ts │ │ ├── config.local.ts │ │ ├── config.unittest.ts │ │ └── plugin.ts │ ├── configuration.ts │ ├── controller │ │ ├── api.ts │ │ └── home.ts │ ├── interface.ts │ └── service │ │ └── user.ts ├── test │ └── controller │ │ ├── api.test.ts │ │ └── home.test.ts ├── tsconfig.json └── typings │ ├── app │ └── index.d.ts │ └── config │ ├── index.d.ts │ └── plugin.d.ts ├── message-board ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc.js ├── README.md ├── README.zh-CN.md ├── bootstrap.js ├── jest.config.js ├── jest.setup.js ├── package.json ├── src │ ├── config │ │ ├── config.default.ts │ │ ├── config.local.ts │ │ ├── config.unittest.ts │ │ └── plugin.ts │ ├── configuration.ts │ ├── controller │ │ ├── home.ts │ │ ├── message.ts │ │ └── user.ts │ ├── interface.ts │ ├── model │ │ ├── dao │ │ │ ├── message.ts │ │ │ └── user.ts │ │ ├── entity │ │ │ ├── message.ts │ │ │ └── user.ts │ │ └── service │ │ │ ├── message.ts │ │ │ ├── render.ts │ │ │ └── user.ts │ └── view │ │ ├── home.ejs │ │ ├── login.ejs │ │ └── register.ejs ├── test │ ├── controller │ │ ├── api.test.ts │ │ └── home.test.ts │ └── model │ │ └── dao │ │ ├── message.test.ts │ │ └── user.test.ts ├── tsconfig.json └── typings │ ├── app │ └── index.d.ts │ └── config │ ├── index.d.ts │ └── plugin.d.ts ├── package-lock.json └── todo-list ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc.js ├── README.md ├── README.zh-CN.md ├── bootstrap.js ├── jest.config.js ├── jest.setup.js ├── package.json ├── src ├── app │ ├── public │ │ └── index.html │ └── view │ │ └── home.ejs ├── config │ ├── config.default.ts │ ├── config.local.ts │ ├── config.unittest.ts │ └── plugin.ts ├── configuration.ts ├── controller │ ├── api.ts │ └── home.ts ├── interface.ts └── service │ ├── fileDB.ts │ ├── render.ts │ └── user.ts ├── test └── controller │ ├── api.test.ts │ └── home.test.ts ├── tsconfig.json └── typings ├── app └── index.d.ts └── config ├── index.d.ts └── plugin.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # midwayjs-tutorial 2 | 3 | - web 基础 4 | - TODO list 网站 5 | - web static 6 | - midway init 创建脚手架项目 7 | - 使用 ejs 等模板编写前端页面 8 | - 将 todo list 存储在文件 9 | - 留言板 10 | - 留言板页面 11 | - 使用 midway + mysql + sql 语句编写增删改查 12 | - 单元测试 13 | - 聊天室 14 | - websocket 15 | - blog 16 | - 一体化研发 17 | - 使用 mysql + orm 编写增删改查接口 18 | - 展示列表页(分页) 19 | - 文章页 20 | - 后台文章 list 页 (分页) 21 | - 后台文章编辑页 (markdown) 22 | - 中后台 23 | - sso 登录系统 24 | - 设计用户表 25 | - 登录页面编写 26 | - 鉴权中间件 27 | - 302 跳转验证会跳 28 | - 假期管理后台 29 | - 设计员工表 30 | - 建立员工权限体系 31 | - schedule 定时添加员工 32 | - 员工申请页 33 | - TL 审批页 34 | - 搭建系统 35 | - 设计信息流首页 36 | - 楼层搭建设计 37 | - 搭建配置后台 38 | - RabbitMq 推送广告 39 | - Serverless 40 | - Hello world 41 | - 普通项目 42 | - 部署博客 43 | - 聚合部署 44 | -------------------------------------------------------------------------------- /hello-world/.editorconfig: -------------------------------------------------------------------------------- 1 | # 🎨 editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true -------------------------------------------------------------------------------- /hello-world/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/mwts/", 3 | "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"], 4 | "env": { 5 | "jest": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | package-lock.json 6 | yarn.lock 7 | coverage/ 8 | dist/ 9 | .idea/ 10 | run/ 11 | .DS_Store 12 | *.sw* 13 | *.un~ 14 | .tsbuildinfo 15 | .tsbuildinfo.* 16 | -------------------------------------------------------------------------------- /hello-world/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('mwts/.prettierrc.json') 3 | } 4 | -------------------------------------------------------------------------------- /hello-world/README.md: -------------------------------------------------------------------------------- 1 | # my-midway-project 2 | 3 | ## QuickStart 4 | 5 | 6 | 7 | see [midway docs][midway] for more detail. 8 | 9 | ### Development 10 | 11 | ```bash 12 | $ npm i 13 | $ npm run dev 14 | $ open http://localhost:7001/ 15 | ``` 16 | 17 | ### Deploy 18 | 19 | ```bash 20 | $ npm start 21 | $ npm stop 22 | ``` 23 | 24 | ### npm scripts 25 | 26 | - Use `npm run lint` to check code style. 27 | - Use `npm test` to run unit test. 28 | 29 | 30 | [midway]: https://midwayjs.org 31 | -------------------------------------------------------------------------------- /hello-world/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # my-midway-project 2 | 3 | ## 快速入门 4 | 5 | 6 | 7 | 如需进一步了解,参见 [midway 文档][midway]。 8 | 9 | ### 本地开发 10 | 11 | ```bash 12 | $ npm i 13 | $ npm run dev 14 | $ open http://localhost:7001/ 15 | ``` 16 | 17 | ### 部署 18 | 19 | ```bash 20 | $ npm start 21 | $ npm stop 22 | ``` 23 | 24 | ### 内置指令 25 | 26 | - 使用 `npm run lint` 来做代码风格检查。 27 | - 使用 `npm test` 来执行单元测试。 28 | 29 | 30 | [midway]: https://midwayjs.org 31 | -------------------------------------------------------------------------------- /hello-world/bootstrap.js: -------------------------------------------------------------------------------- 1 | const WebFramework = require('@midwayjs/web').Framework; 2 | const web = new WebFramework().configure({ 3 | port: 7001, 4 | }); 5 | 6 | const { Bootstrap } = require('@midwayjs/bootstrap'); 7 | Bootstrap.load(web).run(); 8 | -------------------------------------------------------------------------------- /hello-world/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testPathIgnorePatterns: ['/test/fixtures'], 5 | coveragePathIgnorePatterns: ['/test/'], 6 | setupFilesAfterEnv: ['./jest.setup.js'] 7 | }; 8 | -------------------------------------------------------------------------------- /hello-world/jest.setup.js: -------------------------------------------------------------------------------- 1 | jest.setTimeout(30000); 2 | -------------------------------------------------------------------------------- /hello-world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-midway-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "dependencies": { 7 | "@midwayjs/bootstrap": "^2.3.0", 8 | "@midwayjs/core": "^2.3.0", 9 | "@midwayjs/web": "^2.3.0", 10 | "@midwayjs/decorator": "^2.3.0", 11 | "egg": "^2.0.0", 12 | "egg-scripts": "^2.10.0" 13 | }, 14 | "devDependencies": { 15 | "@midwayjs/cli": "^1.0.0", 16 | "@midwayjs/egg-ts-helper": "^1.0.1", 17 | "@midwayjs/luckyeye": "^1.0.0", 18 | "@midwayjs/mock": "^2.3.0", 19 | "@types/jest": "^26.0.10", 20 | "@types/node": "14", 21 | "cross-env": "^6.0.0", 22 | "mwts": "^1.0.5", 23 | "jest": "^26.4.0", 24 | "ts-jest": "^26.2.0", 25 | "typescript": "^4.0.0" 26 | }, 27 | "engines": { 28 | "node": ">=12.0.0" 29 | }, 30 | "scripts": { 31 | "start": "egg-scripts start --daemon --title=my-midway-project --framework=@midwayjs/web", 32 | "stop": "egg-scripts stop --title=my-midway-project", 33 | "start_build": "npm run build && cross-env NODE_ENV=development midway-bin dev", 34 | "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", 35 | "test": "midway-bin test --ts", 36 | "cov": "midway-bin cov --ts", 37 | "lint": "mwts check", 38 | "lint:fix": "mwts fix", 39 | "ci": "npm run cov", 40 | "build": "midway-bin build -c", 41 | "check": "luckyeye" 42 | }, 43 | "midway-bin-clean": [ 44 | ".vscode/.tsbuildinfo", 45 | "dist" 46 | ], 47 | "midway-luckyeye": { 48 | "packages": [ 49 | "midway_v2" 50 | ] 51 | }, 52 | "repository": { 53 | "type": "git", 54 | "url": "" 55 | }, 56 | "author": "", 57 | "license": "MIT" 58 | } 59 | -------------------------------------------------------------------------------- /hello-world/src/config/config.default.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; 2 | 3 | export type DefaultConfig = PowerPartial; 4 | 5 | export default (appInfo: EggAppInfo) => { 6 | const config = {} as DefaultConfig; 7 | 8 | // use for cookie sign key, should change to your own and keep security 9 | config.keys = appInfo.name + '_1626800829121_6518'; 10 | 11 | // add your config here 12 | config.middleware = []; 13 | 14 | config.midwayFeature = { 15 | // true 代表使用 midway logger 16 | // false 或者为空代表使用 egg-logger 17 | replaceEggLogger: true, 18 | }; 19 | 20 | // config.security = { 21 | // csrf: false, 22 | // }; 23 | 24 | return config; 25 | }; 26 | -------------------------------------------------------------------------------- /hello-world/src/config/config.local.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里加入这段是因为 egg 默认的安全策略,在 post 请求的时候如果不传递 token 会返回 403 3 | * 由于大部分新手用户不太了解这个机制,所以在本地和单测环境做了默认处理 4 | * 请注意,线上环境依旧会有该错误,需要手动开启 5 | * 如果想了解更多细节,请访问 https://eggjs.org/zh-cn/core/security.html#安全威胁-csrf-的防范 6 | */ 7 | export const security = { 8 | csrf: false, 9 | }; 10 | -------------------------------------------------------------------------------- /hello-world/src/config/config.unittest.ts: -------------------------------------------------------------------------------- 1 | export const security = { 2 | csrf: false, 3 | }; 4 | -------------------------------------------------------------------------------- /hello-world/src/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | export default { 3 | logrotator: false, // disable when use @midwayjs/logger 4 | static: false, 5 | } as EggPlugin; 6 | -------------------------------------------------------------------------------- /hello-world/src/configuration.ts: -------------------------------------------------------------------------------- 1 | import { App, Configuration } from '@midwayjs/decorator'; 2 | import { ILifeCycle } from '@midwayjs/core'; 3 | import { Application } from 'egg'; 4 | import { join } from 'path'; 5 | 6 | @Configuration({ 7 | importConfigs: [join(__dirname, './config')], 8 | conflictCheck: true, 9 | }) 10 | export class ContainerLifeCycle implements ILifeCycle { 11 | @App() 12 | app: Application; 13 | 14 | async onReady() {} 15 | } 16 | -------------------------------------------------------------------------------- /hello-world/src/controller/api.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Controller, Post, Provide, Query } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { IGetUserResponse } from '../interface'; 4 | import { UserService } from '../service/user'; 5 | 6 | @Provide() 7 | @Controller('/api') 8 | export class APIController { 9 | @Inject() 10 | ctx: Context; 11 | 12 | @Inject() 13 | userService: UserService; 14 | 15 | @Post('/get_user') 16 | async getUser(@Query() uid: string): Promise { 17 | const user = await this.userService.getUser({ uid }); 18 | return { success: true, message: 'OK', data: user }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /hello-world/src/controller/home.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Provide } from '@midwayjs/decorator'; 2 | 3 | @Provide() 4 | @Controller('/') 5 | export class HomeController { 6 | @Get('/') 7 | async home() { 8 | return 'Hello Bilibili!'; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /hello-world/src/interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description User-Service parameters 3 | */ 4 | export interface IUserOptions { 5 | uid: string; 6 | } 7 | 8 | export interface IGetUserResponse { 9 | success: boolean; 10 | message: string; 11 | data: IUserOptions; 12 | } 13 | -------------------------------------------------------------------------------- /hello-world/src/service/user.ts: -------------------------------------------------------------------------------- 1 | import { Provide } from '@midwayjs/decorator'; 2 | import { IUserOptions } from '../interface'; 3 | 4 | @Provide() 5 | export class UserService { 6 | async getUser(options: IUserOptions) { 7 | return { 8 | uid: options.uid, 9 | username: 'mockedName', 10 | phone: '12345678901', 11 | email: 'xxx.xxx@xxx.com', 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /hello-world/test/controller/api.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from "@midwayjs/mock"; 2 | import { Framework } from "@midwayjs/web"; 3 | import { Application } from "egg"; 4 | 5 | describe("test/controller/api.test.ts", () => { 6 | let app: Application; 7 | 8 | beforeAll(async () => { 9 | // create app 10 | app = await createApp(); 11 | }); 12 | 13 | afterAll(async () => { 14 | await close(app); 15 | }); 16 | 17 | it("should POST /api/get_user", async () => { 18 | // make request 19 | const result = await createHttpRequest(app) 20 | .post("/api/get_user") 21 | .query({ uid: 123 }); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.body.message).toBe("OK"); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /hello-world/test/controller/home.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from '@midwayjs/mock'; 2 | import { Framework } from '@midwayjs/web'; 3 | import { Application } from 'egg'; 4 | import * as assert from 'assert'; 5 | 6 | describe('test/controller/home.test.ts', () => { 7 | 8 | let app: Application; 9 | 10 | beforeAll(async () => { 11 | // create app 12 | app = await createApp(); 13 | }); 14 | 15 | afterAll(async () => { 16 | await close(app); 17 | }); 18 | 19 | it('should GET /', async () => { 20 | // make request 21 | const result = await createHttpRequest(app).get('/'); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.text).toBe('Hello Midwayjs!'); 26 | 27 | // or use assert 28 | assert.deepStrictEqual(result.status, 200); 29 | assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /hello-world/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "inlineSourceMap":true, 10 | "noImplicitThis": true, 11 | "noUnusedLocals": true, 12 | "stripInternal": true, 13 | "skipLibCheck": false, 14 | "pretty": true, 15 | "declaration": true, 16 | "typeRoots": [ "./typings", "./node_modules/@types"], 17 | "outDir": "dist" 18 | }, 19 | "exclude": [ 20 | "dist", 21 | "node_modules", 22 | "test" 23 | ] 24 | } -------------------------------------------------------------------------------- /hello-world/typings/app/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | export * from 'egg'; 6 | export as namespace Egg; -------------------------------------------------------------------------------- /hello-world/typings/config/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'midway-schedule'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | onerror?: EggPluginItem; 22 | session?: EggPluginItem; 23 | i18n?: EggPluginItem; 24 | watcher?: EggPluginItem; 25 | multipart?: EggPluginItem; 26 | security?: EggPluginItem; 27 | development?: EggPluginItem; 28 | logrotator?: EggPluginItem; 29 | schedule?: EggPluginItem; 30 | static?: EggPluginItem; 31 | jsonp?: EggPluginItem; 32 | view?: EggPluginItem; 33 | schedulePlus?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /hello-world/typings/config/plugin.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'midway-schedule'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | onerror?: EggPluginItem; 22 | session?: EggPluginItem; 23 | i18n?: EggPluginItem; 24 | watcher?: EggPluginItem; 25 | multipart?: EggPluginItem; 26 | security?: EggPluginItem; 27 | development?: EggPluginItem; 28 | logrotator?: EggPluginItem; 29 | schedule?: EggPluginItem; 30 | static?: EggPluginItem; 31 | jsonp?: EggPluginItem; 32 | view?: EggPluginItem; 33 | schedulePlus?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /message-board/.editorconfig: -------------------------------------------------------------------------------- 1 | # 🎨 editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true -------------------------------------------------------------------------------- /message-board/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/mwts/", 3 | "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"], 4 | "env": { 5 | "jest": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /message-board/.gitignore: -------------------------------------------------------------------------------- 1 | cache 2 | logs/ 3 | npm-debug.log 4 | yarn-error.log 5 | node_modules/ 6 | package-lock.json 7 | yarn.lock 8 | coverage/ 9 | dist/ 10 | .idea/ 11 | run/ 12 | .DS_Store 13 | *.sw* 14 | *.un~ 15 | .tsbuildinfo 16 | .tsbuildinfo.* 17 | 18 | -------------------------------------------------------------------------------- /message-board/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('mwts/.prettierrc.json') 3 | } 4 | -------------------------------------------------------------------------------- /message-board/README.md: -------------------------------------------------------------------------------- 1 | # my-midway-project 2 | 3 | ## QuickStart 4 | 5 | 6 | 7 | see [midway docs][midway] for more detail. 8 | 9 | ### Development 10 | 11 | ```bash 12 | $ npm i 13 | $ npm run dev 14 | $ open http://localhost:7001/ 15 | ``` 16 | 17 | ### Deploy 18 | 19 | ```bash 20 | $ npm start 21 | $ npm stop 22 | ``` 23 | 24 | ### npm scripts 25 | 26 | - Use `npm run lint` to check code style. 27 | - Use `npm test` to run unit test. 28 | 29 | 30 | [midway]: https://midwayjs.org 31 | -------------------------------------------------------------------------------- /message-board/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # my-midway-project 2 | 3 | ## 快速入门 4 | 5 | 6 | 7 | 如需进一步了解,参见 [midway 文档][midway]。 8 | 9 | ### 本地开发 10 | 11 | ```bash 12 | $ npm i 13 | $ npm run dev 14 | $ open http://localhost:7001/ 15 | ``` 16 | 17 | ### 部署 18 | 19 | ```bash 20 | $ npm start 21 | $ npm stop 22 | ``` 23 | 24 | ### 内置指令 25 | 26 | - 使用 `npm run lint` 来做代码风格检查。 27 | - 使用 `npm test` 来执行单元测试。 28 | 29 | 30 | [midway]: https://midwayjs.org 31 | -------------------------------------------------------------------------------- /message-board/bootstrap.js: -------------------------------------------------------------------------------- 1 | const WebFramework = require('@midwayjs/web').Framework; 2 | const web = new WebFramework().configure({ 3 | port: 7001, 4 | }); 5 | 6 | const { Bootstrap } = require('@midwayjs/bootstrap'); 7 | Bootstrap.load(web).run(); 8 | -------------------------------------------------------------------------------- /message-board/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testPathIgnorePatterns: ['/test/fixtures'], 5 | coveragePathIgnorePatterns: ['/test/'], 6 | setupFilesAfterEnv: ['./jest.setup.js'] 7 | }; 8 | -------------------------------------------------------------------------------- /message-board/jest.setup.js: -------------------------------------------------------------------------------- 1 | jest.setTimeout(30000); 2 | -------------------------------------------------------------------------------- /message-board/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-midway-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "dependencies": { 7 | "@midwayjs/bootstrap": "^2.3.0", 8 | "@midwayjs/core": "^2.3.0", 9 | "@midwayjs/web": "^2.3.0", 10 | "@midwayjs/decorator": "^2.3.0", 11 | "@midwayjs/orm": "^2.13.4", 12 | "egg": "^2.0.0", 13 | "egg-scripts": "^2.10.0", 14 | "mysql2": "^2.3.3", 15 | "typeorm": "^0.2.41" 16 | }, 17 | "devDependencies": { 18 | "@midwayjs/cli": "^1.0.0", 19 | "@midwayjs/egg-ts-helper": "^1.0.1", 20 | "@midwayjs/luckyeye": "^1.0.0", 21 | "@midwayjs/mock": "^2.3.0", 22 | "@types/jest": "^26.0.24", 23 | "@types/node": "14", 24 | "cross-env": "^6.0.0", 25 | "jest": "^26.4.0", 26 | "mwts": "^1.0.5", 27 | "ts-jest": "^26.2.0", 28 | "typescript": "^4.0.0" 29 | }, 30 | "engines": { 31 | "node": ">=12.0.0" 32 | }, 33 | "scripts": { 34 | "start": "egg-scripts start --daemon --title=my-midway-project --framework=@midwayjs/web", 35 | "stop": "egg-scripts stop --title=my-midway-project", 36 | "start_build": "npm run build && cross-env NODE_ENV=development midway-bin dev", 37 | "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", 38 | "test": "midway-bin test --ts", 39 | "cov": "midway-bin cov --ts", 40 | "lint": "mwts check", 41 | "lint:fix": "mwts fix", 42 | "ci": "npm run cov", 43 | "build": "midway-bin build -c", 44 | "check": "luckyeye" 45 | }, 46 | "midway-bin-clean": [ 47 | ".vscode/.tsbuildinfo", 48 | "dist" 49 | ], 50 | "midway-luckyeye": { 51 | "packages": [ 52 | "midway_v2" 53 | ] 54 | }, 55 | "repository": { 56 | "type": "git", 57 | "url": "" 58 | }, 59 | "author": "", 60 | "license": "MIT" 61 | } 62 | -------------------------------------------------------------------------------- /message-board/src/config/config.default.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; 2 | 3 | export type DefaultConfig = PowerPartial; 4 | 5 | export default (appInfo: EggAppInfo) => { 6 | const config = {} as DefaultConfig; 7 | 8 | // use for cookie sign key, should change to your own and keep security 9 | config.keys = appInfo.name + '_1633873124084_1912'; 10 | 11 | // add your config here 12 | config.middleware = []; 13 | 14 | config.midwayFeature = { 15 | // true 代表使用 midway logger 16 | // false 或者为空代表使用 egg-logger 17 | replaceEggLogger: true, 18 | }; 19 | 20 | // config.security = { 21 | // csrf: false, 22 | // }; 23 | 24 | config.orm = { 25 | type: 'mysql', 26 | host: '127.0.0.1', 27 | port: 3306, 28 | username: 'root', 29 | password: '', 30 | database: 'message_board', 31 | synchronize: true, // 如果第一次使用,不存在表,有同步的需求可以写 true 32 | logging: true, 33 | } 34 | 35 | return config; 36 | }; 37 | -------------------------------------------------------------------------------- /message-board/src/config/config.local.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里加入这段是因为 egg 默认的安全策略,在 post 请求的时候如果不传递 token 会返回 403 3 | * 由于大部分新手用户不太了解这个机制,所以在本地和单测环境做了默认处理 4 | * 请注意,线上环境依旧会有该错误,需要手动开启 5 | * 如果想了解更多细节,请访问 https://eggjs.org/zh-cn/core/security.html#安全威胁-csrf-的防范 6 | */ 7 | export const security = { 8 | csrf: false, 9 | }; 10 | -------------------------------------------------------------------------------- /message-board/src/config/config.unittest.ts: -------------------------------------------------------------------------------- 1 | export const security = { 2 | csrf: false, 3 | }; 4 | -------------------------------------------------------------------------------- /message-board/src/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | export default { 3 | logrotator: false, // disable when use @midwayjs/logger 4 | static: false, 5 | } as EggPlugin; 6 | -------------------------------------------------------------------------------- /message-board/src/configuration.ts: -------------------------------------------------------------------------------- 1 | import { App, Configuration } from '@midwayjs/decorator'; 2 | import { ILifeCycle } from '@midwayjs/core'; 3 | import { Application } from 'egg'; 4 | import { join } from 'path'; 5 | import * as orm from '@midwayjs/orm'; 6 | 7 | @Configuration({ 8 | imports: [ 9 | orm, 10 | ], 11 | importConfigs: [join(__dirname, './config')], 12 | conflictCheck: true, 13 | }) 14 | export class ContainerLifeCycle implements ILifeCycle { 15 | @App() 16 | app: Application; 17 | 18 | async onReady() { } 19 | } 20 | -------------------------------------------------------------------------------- /message-board/src/controller/home.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject, Provide } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { MessageService } from '../model/service/message'; 4 | import { RenderService } from '../model/service/render'; 5 | 6 | @Provide() 7 | @Controller('/') 8 | export class HomeController { 9 | @Inject() 10 | renderService: RenderService; 11 | 12 | @Inject() 13 | messageService: MessageService; 14 | 15 | @Inject() 16 | ctx: Context; 17 | 18 | @Get('/') 19 | async home() { 20 | const text = this.ctx.cookies.get('my_session_data'); 21 | let cookies = null; 22 | if (text) { 23 | cookies = JSON.parse(text); 24 | } 25 | 26 | const msgList = await this.messageService.list(); 27 | return this.renderService.render('home', { cookies, msgList }); 28 | } 29 | 30 | @Get('/register') 31 | async register() { 32 | return this.renderService.render('register', {}); 33 | } 34 | 35 | @Get('/login') 36 | async login() { 37 | return this.renderService.render('login', {}); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /message-board/src/controller/message.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Controller, Post, Get, Provide } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { MessageService } from '../model/service/message'; 4 | 5 | @Provide() 6 | @Controller('/message') 7 | export class MessageController { 8 | @Inject() 9 | ctx: Context; 10 | 11 | @Inject() 12 | messageService: MessageService; 13 | 14 | @Get('/') 15 | async list(): Promise { 16 | const list = await this.messageService.list(); 17 | return list; 18 | } 19 | 20 | @Post('/') 21 | async post(): Promise { 22 | // TODO 23 | const cookieText = this.ctx.cookies.get('my_session_data'); 24 | let cookies = null; 25 | if (cookieText) { 26 | cookies = JSON.parse(cookieText); 27 | } 28 | 29 | // TODO 判断用户是否登录,未登录不能发送留言 30 | 31 | const { text } = this.ctx.request.body; 32 | console.log(cookies.username, text); 33 | this.messageService.post(cookies.username, text); 34 | 35 | this.ctx.redirect('/'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /message-board/src/controller/user.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Controller, Post, Get, Provide } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { IGetUserResponse } from '../interface'; 4 | import { UserService } from '../model/service/user'; 5 | 6 | @Provide() 7 | @Controller('/user') 8 | export class UserController { 9 | @Inject() 10 | ctx: Context; 11 | 12 | @Inject() 13 | userService: UserService; 14 | 15 | @Post('/register') 16 | async register(): Promise { 17 | const { username, password } = this.ctx.request.body; 18 | if (!username || !password) { 19 | this.ctx.status = 500; 20 | return { success: false, message: '参数错误' }; 21 | } 22 | const user = await this.userService.register(username, password); 23 | this.ctx.redirect('/login'); 24 | return { success: true, message: 'OK', data: user }; 25 | } 26 | 27 | @Post('/login') 28 | async login(): Promise { 29 | const { username, password } = this.ctx.request.body; 30 | const success = await this.userService.login(username, password); 31 | if (success) { 32 | // 成功登录 33 | this.ctx.cookies.set('my_session_data', JSON.stringify({ username })) 34 | this.ctx.redirect('/'); 35 | return; 36 | } else { 37 | // 登录失败 38 | // TODO 密码错误三次禁止登录 39 | this.ctx.status = 403; 40 | } 41 | } 42 | 43 | @Get('/logout') // /user/logout 44 | async logout() { 45 | this.ctx.cookies.set('my_session_data', '') 46 | this.ctx.redirect('/'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /message-board/src/interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description User-Service parameters 3 | */ 4 | export interface IUserOptions { 5 | uid: string; 6 | } 7 | 8 | export interface IGetUserResponse { 9 | success: boolean; 10 | message: string; 11 | data?: any; 12 | } 13 | -------------------------------------------------------------------------------- /message-board/src/model/dao/message.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; 2 | import { InjectEntityModel } from '@midwayjs/orm'; 3 | import { Repository } from 'typeorm'; 4 | import { Message } from '../entity/message'; 5 | 6 | export interface IUser { 7 | id: number; 8 | username: string; 9 | password: string; 10 | } 11 | 12 | @Scope(ScopeEnum.Singleton) 13 | @Provide() 14 | export class MessageDao { 15 | @InjectEntityModel(Message) 16 | message: Repository; 17 | 18 | // 查询 (列表) 19 | async list() { 20 | return this.message.find(); 21 | } 22 | 23 | // 查询 (根据id) 24 | async getById(id: number) { 25 | // return this.message.findByIds([id]); 26 | return this.message.findOne({ id }); 27 | } 28 | // 查询 (根据用户) 29 | // 查询 (根据内容) 30 | 31 | // 新增 32 | async add(username: string, text: string) { 33 | // create a entity object 34 | const msg = new Message(); 35 | msg.username = username; 36 | msg.text = text; 37 | 38 | // save entity 39 | const result = await this.message.save(msg); 40 | 41 | // save success 42 | console.log('msg id = ', result.id); 43 | return msg; 44 | } 45 | 46 | // 修改 47 | async updateById(id: number, text: string) { 48 | return this.message.update({ id }, { text }); 49 | } 50 | 51 | // 删除 52 | async deleteById(id: number) { 53 | return this.message.delete({ id }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /message-board/src/model/dao/user.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; 2 | import { InjectEntityModel } from '@midwayjs/orm'; 3 | import { Repository } from 'typeorm'; 4 | import { User } from '../entity/user'; 5 | 6 | export interface IUser { 7 | id: number; 8 | username: string; 9 | password: string; 10 | } 11 | 12 | @Scope(ScopeEnum.Singleton) 13 | @Provide() 14 | export class UserDao { 15 | @InjectEntityModel(User) 16 | userModel: Repository; 17 | 18 | async list() { 19 | return this.userModel.find(); 20 | } 21 | 22 | async add(username: string, password: string) { 23 | // create a entity object 24 | const user = new User(); 25 | user.username = username; 26 | user.password = password; 27 | 28 | // save entity 29 | const userResult = await this.userModel.save(user); 30 | 31 | // save success 32 | console.log('user id = ', userResult.id); 33 | return user; 34 | } 35 | 36 | async findByUsername(username: string) { 37 | const user = await this.userModel.findOne({ 38 | username, 39 | }); 40 | if (user) { 41 | return user; 42 | } 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /message-board/src/model/entity/message.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, PrimaryGeneratedColumn } from 'typeorm'; 3 | 4 | @EntityModel('message') 5 | export class Message { 6 | @PrimaryGeneratedColumn() 7 | id: number; 8 | 9 | @Column({ 10 | length: 32, 11 | }) 12 | username: string; 13 | 14 | @Column({ 15 | length: 140, 16 | }) 17 | text: string; 18 | } 19 | -------------------------------------------------------------------------------- /message-board/src/model/entity/user.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, PrimaryGeneratedColumn } from 'typeorm'; 3 | 4 | @EntityModel('user') 5 | export class User { 6 | @PrimaryGeneratedColumn() 7 | id: number; 8 | 9 | @Column({ 10 | length: 32, 11 | }) 12 | username: string; 13 | 14 | @Column({ 15 | length: 32, 16 | }) 17 | password: string; 18 | } 19 | -------------------------------------------------------------------------------- /message-board/src/model/service/message.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Inject } from '@midwayjs/decorator'; 2 | import { MessageDao } from '../dao/message'; 3 | import { UserDao } from '../dao/user'; 4 | 5 | @Provide() 6 | export class MessageService { 7 | @Inject() 8 | messageDao: MessageDao; 9 | 10 | @Inject() 11 | userDao: UserDao; 12 | 13 | // 查询留言列表 14 | async list() { 15 | return this.messageDao.list(); 16 | } 17 | 18 | // 发送留言 19 | async post(username: string, text: string) { 20 | return this.messageDao.add(username, text); 21 | } 22 | 23 | async update(username: string, text: string) { 24 | const user = await this.userDao.findByUsername(username); 25 | return this.messageDao.updateById(user.id, text); 26 | } 27 | 28 | async deleteById(id: number) { 29 | return this.messageDao.deleteById(id); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /message-board/src/model/service/render.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; 2 | import { renderFile } from 'ejs'; 3 | import { join } from 'path'; 4 | 5 | @Scope(ScopeEnum.Singleton) 6 | @Provide() 7 | export class RenderService { 8 | 9 | async render(file: string, locals: any) { 10 | return renderFile(join(__dirname, `../../view/${file}.ejs`), locals); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /message-board/src/model/service/user.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Inject } from '@midwayjs/decorator'; 2 | import { UserDao } from '../dao/user'; 3 | 4 | @Provide() 5 | export class UserService { 6 | @Inject() 7 | userDao: UserDao; 8 | 9 | // 将用户数据插入数据库 10 | async register(username: string, password: string) { 11 | return await this.userDao.add(username, password); 12 | } 13 | 14 | // 检查用户密码是否与数据库中匹配 15 | async login(username: string, password: string) { 16 | const user = await this.userDao.findByUsername(username); 17 | if (user && user.password === password) { 18 | return true; 19 | } 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /message-board/src/view/home.ejs: -------------------------------------------------------------------------------- 1 | 2 |
3 | <% if (cookies) { %> 4 | 欢迎你, <%= cookies.username %>! 登出 5 | 6 | 7 | 8 |

留言列表

9 |
    10 | <% msgList.forEach(function({ username, text }){ %> 11 |
  • <%= username %>: <%= text %>
  • 12 | <% }); %> 13 |
14 | 15 | 16 |

发留言

17 |
18 | 19 | 20 |
21 | 22 | <% } else { %> 23 | 请登录 24 | <% } %> 25 |
26 | -------------------------------------------------------------------------------- /message-board/src/view/login.ejs: -------------------------------------------------------------------------------- 1 |

用户登录

2 | 3 |
4 | 用户名
5 | 密码
6 | 7 | 注册 8 |
9 | -------------------------------------------------------------------------------- /message-board/src/view/register.ejs: -------------------------------------------------------------------------------- 1 |

注册用户

2 | 3 |
4 | 用户名
5 | 密码
6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /message-board/test/controller/api.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from "@midwayjs/mock"; 2 | import { Framework } from "@midwayjs/web"; 3 | import { Application } from "egg"; 4 | 5 | describe("test/controller/api.test.ts", () => { 6 | let app: Application; 7 | 8 | beforeAll(async () => { 9 | // create app 10 | app = await createApp(); 11 | }); 12 | 13 | afterAll(async () => { 14 | await close(app); 15 | }); 16 | 17 | it("should POST /api/get_user", async () => { 18 | // make request 19 | const result = await createHttpRequest(app) 20 | .post("/api/get_user") 21 | .query({ uid: 123 }); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.body.message).toBe("OK"); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /message-board/test/controller/home.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from '@midwayjs/mock'; 2 | import { Framework } from '@midwayjs/web'; 3 | import { Application } from 'egg'; 4 | import * as assert from 'assert'; 5 | 6 | describe('test/controller/home.test.ts', () => { 7 | 8 | let app: Application; 9 | 10 | beforeAll(async () => { 11 | // create app 12 | app = await createApp(); 13 | }); 14 | 15 | afterAll(async () => { 16 | await close(app); 17 | }); 18 | 19 | it('should GET /', async () => { 20 | // make request 21 | const result = await createHttpRequest(app).get('/'); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.text).toBe('Hello Midwayjs!'); 26 | 27 | // or use assert 28 | assert.deepStrictEqual(result.status, 200); 29 | assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /message-board/test/model/dao/message.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close } from '@midwayjs/mock'; 2 | import { Framework } from '@midwayjs/web'; 3 | import * as assert from 'assert'; 4 | import { MessageDao } from '../../../src/model/dao/message'; 5 | 6 | describe('MessageDao', () => { 7 | it('#list', async () => { 8 | // create app 9 | const app = await createApp(); 10 | // 根据依赖注入 class 获取实例 11 | const messageDao = await app.getApplicationContext().getAsync(MessageDao); 12 | 13 | const res = await messageDao.list(); 14 | assert(res.length); 15 | 16 | // close app 17 | await close(app); 18 | }); 19 | 20 | it('#add & #delete', async () => { 21 | // create app 22 | const app = await createApp(); 23 | 24 | // 根据依赖注入 class 获取实例 25 | const messageDao = await app.getApplicationContext().getAsync(MessageDao); 26 | 27 | const text = 'nihao, a a a !' 28 | const res = await messageDao.add('lellansin', text); 29 | 30 | const list = await messageDao.list() 31 | const lastItem = list[list.length - 1]; 32 | assert.deepStrictEqual(res, lastItem); 33 | assert.strictEqual(res.text, text); 34 | assert.strictEqual(lastItem.text, text); 35 | 36 | await messageDao.deleteById(res.id); 37 | 38 | const res2 = await messageDao.getById(res.id); 39 | assert(!res2); 40 | 41 | // close app 42 | await close(app); 43 | }); 44 | 45 | it('#add & #update', async () => { 46 | // create app 47 | const app = await createApp(); 48 | 49 | // 根据依赖注入 class 获取实例 50 | const messageDao = await app.getApplicationContext().getAsync(MessageDao); 51 | 52 | const text = 'nihao, update test!' 53 | const res = await messageDao.add('lellansin', text); 54 | 55 | 56 | const updateText = 'update to this' 57 | await messageDao.updateById(res.id, updateText); 58 | 59 | const res2 = await messageDao.getById(res.id); 60 | assert.strictEqual(res2.text, updateText); 61 | 62 | await messageDao.deleteById(res2.id); 63 | 64 | // close app 65 | await close(app); 66 | }); 67 | }); -------------------------------------------------------------------------------- /message-board/test/model/dao/user.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close } from '@midwayjs/mock'; 2 | import { Framework } from '@midwayjs/web'; 3 | import * as assert from 'assert'; 4 | import { UserDao } from '../../../src/model/dao/user'; 5 | 6 | describe('UserDao', () => { 7 | it('#list', async () => { 8 | // create app 9 | const app = await createApp(); 10 | // 根据依赖注入 class 获取实例 11 | const userDao = await app.getApplicationContext().getAsync(UserDao); 12 | 13 | const res = await userDao.list(); 14 | assert.strictEqual(JSON.stringify(res), JSON.stringify([ 15 | { id: 1, username: 'lellansin1234', password: '123456' }, 16 | { id: 2, username: 'lellansin', password: '123456' }, 17 | { id: 3, username: 'alan', password: '123456' } 18 | ])) 19 | 20 | // close app 21 | await close(app); 22 | }); 23 | 24 | it('#findByUsername', async () => { 25 | // create app 26 | const app = await createApp(); 27 | 28 | // 根据依赖注入 class 获取实例 29 | const userDao = await app.getApplicationContext().getAsync(UserDao); 30 | 31 | const res = await userDao.findByUsername('lellansin'); 32 | assert.strictEqual(res.id, 2); 33 | 34 | // close app 35 | await close(app); 36 | }); 37 | }); -------------------------------------------------------------------------------- /message-board/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "inlineSourceMap":true, 10 | "noImplicitThis": true, 11 | "noUnusedLocals": true, 12 | "stripInternal": true, 13 | "skipLibCheck": false, 14 | "pretty": true, 15 | "declaration": true, 16 | "typeRoots": [ "./typings", "./node_modules/@types"], 17 | "outDir": "dist" 18 | }, 19 | "exclude": [ 20 | "dist", 21 | "node_modules", 22 | "test" 23 | ] 24 | } -------------------------------------------------------------------------------- /message-board/typings/app/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | export * from 'egg'; 6 | export as namespace Egg; -------------------------------------------------------------------------------- /message-board/typings/config/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'midway-schedule'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | 'onerror'?: EggPluginItem; 22 | 'session'?: EggPluginItem; 23 | 'i18n'?: EggPluginItem; 24 | 'watcher'?: EggPluginItem; 25 | 'multipart'?: EggPluginItem; 26 | 'security'?: EggPluginItem; 27 | 'development'?: EggPluginItem; 28 | 'logrotator'?: EggPluginItem; 29 | 'schedule'?: EggPluginItem; 30 | 'static'?: EggPluginItem; 31 | 'jsonp'?: EggPluginItem; 32 | 'view'?: EggPluginItem; 33 | 'schedulePlus'?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /message-board/typings/config/plugin.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'midway-schedule'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | 'onerror'?: EggPluginItem; 22 | 'session'?: EggPluginItem; 23 | 'i18n'?: EggPluginItem; 24 | 'watcher'?: EggPluginItem; 25 | 'multipart'?: EggPluginItem; 26 | 'security'?: EggPluginItem; 27 | 'development'?: EggPluginItem; 28 | 'logrotator'?: EggPluginItem; 29 | 'schedule'?: EggPluginItem; 30 | 'static'?: EggPluginItem; 31 | 'jsonp'?: EggPluginItem; 32 | 'view'?: EggPluginItem; 33 | 'schedulePlus'?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "@types/ejs": { 6 | "version": "3.1.0", 7 | "resolved": "https://registry.nlark.com/@types/ejs/download/@types/ejs-3.1.0.tgz?cache=0&sync_timestamp=1629707318863&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fejs%2Fdownload%2F%40types%2Fejs-3.1.0.tgz", 8 | "integrity": "sha1-q4EJIIEGtedk5abJKyuhxiW3MCA=", 9 | "dev": true 10 | }, 11 | "ansi-styles": { 12 | "version": "3.2.1", 13 | "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-3.2.1.tgz", 14 | "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", 15 | "requires": { 16 | "color-convert": "^1.9.0" 17 | } 18 | }, 19 | "async": { 20 | "version": "0.9.2", 21 | "resolved": "https://registry.nlark.com/async/download/async-0.9.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fasync%2Fdownload%2Fasync-0.9.2.tgz", 22 | "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" 23 | }, 24 | "balanced-match": { 25 | "version": "1.0.2", 26 | "resolved": "https://registry.nlark.com/balanced-match/download/balanced-match-1.0.2.tgz", 27 | "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=" 28 | }, 29 | "brace-expansion": { 30 | "version": "1.1.11", 31 | "resolved": "https://registry.nlark.com/brace-expansion/download/brace-expansion-1.1.11.tgz", 32 | "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", 33 | "requires": { 34 | "balanced-match": "^1.0.0", 35 | "concat-map": "0.0.1" 36 | } 37 | }, 38 | "chalk": { 39 | "version": "2.4.2", 40 | "resolved": "https://registry.nlark.com/chalk/download/chalk-2.4.2.tgz", 41 | "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", 42 | "requires": { 43 | "ansi-styles": "^3.2.1", 44 | "escape-string-regexp": "^1.0.5", 45 | "supports-color": "^5.3.0" 46 | } 47 | }, 48 | "color-convert": { 49 | "version": "1.9.3", 50 | "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", 51 | "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", 52 | "requires": { 53 | "color-name": "1.1.3" 54 | } 55 | }, 56 | "color-name": { 57 | "version": "1.1.3", 58 | "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", 59 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 60 | }, 61 | "concat-map": { 62 | "version": "0.0.1", 63 | "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", 64 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 65 | }, 66 | "ejs": { 67 | "version": "3.1.6", 68 | "resolved": "https://registry.nlark.com/ejs/download/ejs-3.1.6.tgz", 69 | "integrity": "sha1-W/0KBol0O7UmizVQzO7rvBcCgio=", 70 | "requires": { 71 | "jake": "^10.6.1" 72 | } 73 | }, 74 | "escape-string-regexp": { 75 | "version": "1.0.5", 76 | "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", 77 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 78 | }, 79 | "filelist": { 80 | "version": "1.0.2", 81 | "resolved": "https://registry.npm.taobao.org/filelist/download/filelist-1.0.2.tgz", 82 | "integrity": "sha1-gCAvIUYtTRwuIUEZsYB8G8A4Dls=", 83 | "requires": { 84 | "minimatch": "^3.0.4" 85 | } 86 | }, 87 | "has-flag": { 88 | "version": "3.0.0", 89 | "resolved": "https://registry.nlark.com/has-flag/download/has-flag-3.0.0.tgz", 90 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 91 | }, 92 | "jake": { 93 | "version": "10.8.2", 94 | "resolved": "https://registry.npm.taobao.org/jake/download/jake-10.8.2.tgz", 95 | "integrity": "sha1-68nehVgWCmbYLQ6txqLlj7xQCns=", 96 | "requires": { 97 | "async": "0.9.x", 98 | "chalk": "^2.4.2", 99 | "filelist": "^1.0.1", 100 | "minimatch": "^3.0.4" 101 | } 102 | }, 103 | "minimatch": { 104 | "version": "3.0.4", 105 | "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", 106 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", 107 | "requires": { 108 | "brace-expansion": "^1.1.7" 109 | } 110 | }, 111 | "supports-color": { 112 | "version": "5.5.0", 113 | "resolved": "https://registry.nlark.com/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1626703342506&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz", 114 | "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", 115 | "requires": { 116 | "has-flag": "^3.0.0" 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /todo-list/.editorconfig: -------------------------------------------------------------------------------- 1 | # 🎨 editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true -------------------------------------------------------------------------------- /todo-list/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/mwts/", 3 | "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"], 4 | "env": { 5 | "jest": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /todo-list/.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | package-lock.json 6 | yarn.lock 7 | coverage/ 8 | dist/ 9 | .idea/ 10 | run/ 11 | .DS_Store 12 | *.sw* 13 | *.un~ 14 | .tsbuildinfo 15 | .tsbuildinfo.* 16 | cache 17 | -------------------------------------------------------------------------------- /todo-list/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('mwts/.prettierrc.json') 3 | } 4 | -------------------------------------------------------------------------------- /todo-list/README.md: -------------------------------------------------------------------------------- 1 | # my-midway-project 2 | 3 | ## QuickStart 4 | 5 | 6 | 7 | see [midway docs][midway] for more detail. 8 | 9 | ### Development 10 | 11 | ```bash 12 | $ npm i 13 | $ npm run dev 14 | $ open http://localhost:7001/ 15 | ``` 16 | 17 | ### Deploy 18 | 19 | ```bash 20 | $ npm start 21 | $ npm stop 22 | ``` 23 | 24 | ### npm scripts 25 | 26 | - Use `npm run lint` to check code style. 27 | - Use `npm test` to run unit test. 28 | 29 | [midway]: https://midwayjs.org 30 | 31 | ## Static 插件 32 | 33 | Midway.js 框架 -> egg.js 框架 -> koa.js 框架 (middleware) 34 | 35 | ### egg 体系下的默认规约 36 | 37 | src/config/plugin 插件开关 38 | src/config/config.${环境} 具体环境的(包括插件)配置 39 | 40 | ### 插件配置 41 | 42 | 插件目录/config/ 下面能找到插件的配置 43 | -------------------------------------------------------------------------------- /todo-list/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # my-midway-project 2 | 3 | ## 快速入门 4 | 5 | 6 | 7 | 如需进一步了解,参见 [midway 文档][midway]。 8 | 9 | ### 本地开发 10 | 11 | ```bash 12 | $ npm i 13 | $ npm run dev 14 | $ open http://localhost:7001/ 15 | ``` 16 | 17 | ### 部署 18 | 19 | ```bash 20 | $ npm start 21 | $ npm stop 22 | ``` 23 | 24 | ### 内置指令 25 | 26 | - 使用 `npm run lint` 来做代码风格检查。 27 | - 使用 `npm test` 来执行单元测试。 28 | 29 | 30 | [midway]: https://midwayjs.org 31 | -------------------------------------------------------------------------------- /todo-list/bootstrap.js: -------------------------------------------------------------------------------- 1 | const WebFramework = require('@midwayjs/web').Framework; 2 | const web = new WebFramework().configure({ 3 | port: 7001, 4 | }); 5 | 6 | const { Bootstrap } = require('@midwayjs/bootstrap'); 7 | Bootstrap.load(web).run(); 8 | -------------------------------------------------------------------------------- /todo-list/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testPathIgnorePatterns: ['/test/fixtures'], 5 | coveragePathIgnorePatterns: ['/test/'], 6 | setupFilesAfterEnv: ['./jest.setup.js'] 7 | }; 8 | -------------------------------------------------------------------------------- /todo-list/jest.setup.js: -------------------------------------------------------------------------------- 1 | jest.setTimeout(30000); 2 | -------------------------------------------------------------------------------- /todo-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-midway-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "dependencies": { 7 | "@midwayjs/bootstrap": "^2.3.0", 8 | "@midwayjs/core": "^2.3.0", 9 | "@midwayjs/decorator": "^2.3.0", 10 | "@midwayjs/web": "^2.3.0", 11 | "egg": "^2.0.0", 12 | "egg-scripts": "^2.10.0", 13 | "ejs": "^3.1.6" 14 | }, 15 | "devDependencies": { 16 | "@midwayjs/cli": "^1.0.0", 17 | "@midwayjs/egg-ts-helper": "^1.0.1", 18 | "@midwayjs/luckyeye": "^1.0.0", 19 | "@midwayjs/mock": "^2.3.0", 20 | "@types/ejs": "^3.1.0", 21 | "@types/jest": "^26.0.10", 22 | "@types/node": "14", 23 | "cross-env": "^6.0.0", 24 | "jest": "^26.4.0", 25 | "mwts": "^1.0.5", 26 | "ts-jest": "^26.2.0", 27 | "typescript": "^4.0.0" 28 | }, 29 | "engines": { 30 | "node": ">=12.0.0" 31 | }, 32 | "scripts": { 33 | "start": "egg-scripts start --daemon --title=my-midway-project --framework=@midwayjs/web", 34 | "stop": "egg-scripts stop --title=my-midway-project", 35 | "start_build": "npm run build && cross-env NODE_ENV=development midway-bin dev", 36 | "dev": "cross-env ets && cross-env NODE_ENV=local midway-bin dev --ts", 37 | "test": "midway-bin test --ts", 38 | "cov": "midway-bin cov --ts", 39 | "lint": "mwts check", 40 | "lint:fix": "mwts fix", 41 | "ci": "npm run cov", 42 | "build": "midway-bin build -c", 43 | "check": "luckyeye" 44 | }, 45 | "midway-bin-clean": [ 46 | ".vscode/.tsbuildinfo", 47 | "dist" 48 | ], 49 | "midway-luckyeye": { 50 | "packages": [ 51 | "midway_v2" 52 | ] 53 | }, 54 | "repository": { 55 | "type": "git", 56 | "url": "" 57 | }, 58 | "author": "", 59 | "license": "MIT" 60 | } 61 | -------------------------------------------------------------------------------- /todo-list/src/app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 前端渲染 3 | 4 |
5 | 6 |
7 | 8 |
    9 | 10 |
11 | 12 | 107 | -------------------------------------------------------------------------------- /todo-list/src/app/view/home.ejs: -------------------------------------------------------------------------------- 1 | EJS 模板渲染 (file) 2 | 3 |
4 | 5 |
6 | 7 |
    8 | <% list.forEach(function(item) { %> 9 |
  • 10 | <%= item %> 11 | 12 | 删除 13 |
  • 14 | <% }) %> 15 |
16 | 17 | 59 | -------------------------------------------------------------------------------- /todo-list/src/config/config.default.ts: -------------------------------------------------------------------------------- 1 | import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg'; 2 | import { join } from 'path'; 3 | 4 | export type DefaultConfig = PowerPartial; 5 | 6 | export default (appInfo: EggAppInfo) => { 7 | const config = {} as DefaultConfig; 8 | 9 | // use for cookie sign key, should change to your own and keep security 10 | config.keys = appInfo.name + '_1627836302225_3059'; 11 | 12 | // add your config here 13 | config.middleware = []; 14 | 15 | config.midwayFeature = { 16 | // true 代表使用 midway logger 17 | // false 或者为空代表使用 egg-logger 18 | replaceEggLogger: true, 19 | }; 20 | 21 | // config.security = { 22 | // csrf: false, 23 | // }; 24 | 25 | config.static = { 26 | prefix: '/', 27 | dir: join(appInfo.baseDir, 'app/public'), 28 | // dirs: [ dir1, dir2 ] or [ dir1, { prefix: '/static2', dir: dir2 } ], 29 | // support lazy load 30 | // dynamic: true, 31 | // preload: false, 32 | // buffer: false, 33 | // maxFiles: 1000, 34 | }; 35 | 36 | return config; 37 | }; 38 | -------------------------------------------------------------------------------- /todo-list/src/config/config.local.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里加入这段是因为 egg 默认的安全策略,在 post 请求的时候如果不传递 token 会返回 403 3 | * 由于大部分新手用户不太了解这个机制,所以在本地和单测环境做了默认处理 4 | * 请注意,线上环境依旧会有该错误,需要手动开启 5 | * 如果想了解更多细节,请访问 https://eggjs.org/zh-cn/core/security.html#安全威胁-csrf-的防范 6 | */ 7 | export const security = { 8 | csrf: false, 9 | }; 10 | -------------------------------------------------------------------------------- /todo-list/src/config/config.unittest.ts: -------------------------------------------------------------------------------- 1 | export const security = { 2 | csrf: false, 3 | }; 4 | -------------------------------------------------------------------------------- /todo-list/src/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | export default { 3 | logrotator: false, // disable when use @midwayjs/logger 4 | static: true, 5 | } as EggPlugin; 6 | -------------------------------------------------------------------------------- /todo-list/src/configuration.ts: -------------------------------------------------------------------------------- 1 | import { App, Configuration } from '@midwayjs/decorator'; 2 | import { ILifeCycle } from '@midwayjs/core'; 3 | import { Application } from 'egg'; 4 | import { join } from 'path'; 5 | 6 | @Configuration({ 7 | importConfigs: [join(__dirname, './config')], 8 | conflictCheck: true, 9 | }) 10 | export class ContainerLifeCycle implements ILifeCycle { 11 | @App() 12 | app: Application; 13 | 14 | async onReady() {} 15 | } 16 | -------------------------------------------------------------------------------- /todo-list/src/controller/api.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Controller, Post, Get, Put, Del, Provide, Query } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { IGetUserResponse } from '../interface'; 4 | import { UserService } from '../service/user'; 5 | import { TodolistService } from '../service/fileDB'; 6 | 7 | @Provide() 8 | @Controller('/api') 9 | export class APIController { 10 | @Inject('ctx') 11 | ctx: Context; 12 | 13 | @Inject('TodolistService') 14 | db: TodolistService; 15 | 16 | @Inject() 17 | userService: UserService; 18 | 19 | @Post('/get_user') 20 | async getUser(@Query() uid: string): Promise { 21 | const user = await this.userService.getUser({ uid }); 22 | return { success: true, message: 'OK', data: user }; 23 | } 24 | 25 | // POST /api/todo 26 | @Post('/todo') 27 | async addTodo() { 28 | const { text } = this.ctx.request.body; 29 | await this.db.add(text); 30 | 31 | // 跳转到直出的 HTML 页面 32 | this.ctx.redirect('/'); 33 | return 'ok'; 34 | } 35 | 36 | // GET /api/todo 37 | @Get('/todo') 38 | async getTodo() { 39 | return await this.db.list(); 40 | } 41 | 42 | // DELETE /api/todo 43 | // curl localhost:6001/apis/todo/1234 -> id: 1234 44 | @Del('/todo/:id') 45 | async deleteTodo() { 46 | const { id } = this.ctx.params; 47 | await this.db.del(Number(id)); 48 | } 49 | 50 | // PUT /api/todo 51 | @Put('/todo/:id') 52 | async putTodo() { 53 | const { id } = this.ctx.params; 54 | const { text } = this.ctx.request.body; 55 | await this.db.update(Number(id), text); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /todo-list/src/controller/home.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Provide, Inject } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; // egg 中 ctx 的定义 3 | // import * as DB from '../service/fileDB'; 4 | import { RenderService } from '../service/render'; 5 | 6 | @Provide() 7 | @Controller('/') 8 | export class HomeController { 9 | @Inject('ctx') // 将 ctx 注入到当前 controller 类中 10 | ctx: Context; 11 | 12 | @Inject('TodolistService') 13 | db; 14 | 15 | @Inject() 16 | renderService: RenderService; 17 | 18 | // GET / 19 | @Get('/') 20 | async home() { 21 | // 告诉浏览器,当前返回的是 HTML 页面(而不是纯文本) 22 | this.ctx.type = 'html'; 23 | const todoList = this.db.list(); 24 | return this.renderService.render({ 25 | list: todoList, 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /todo-list/src/interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description User-Service parameters 3 | */ 4 | export interface IUserOptions { 5 | uid: string; 6 | } 7 | 8 | export interface IGetUserResponse { 9 | success: boolean; 10 | message: string; 11 | data: IUserOptions; 12 | } 13 | -------------------------------------------------------------------------------- /todo-list/src/service/fileDB.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; 2 | import { writeFile, readFile, existsSync } from 'fs'; 3 | 4 | export interface ITodo { 5 | id: number; 6 | text: string; 7 | } 8 | 9 | @Scope(ScopeEnum.Singleton) 10 | @Provide('TodolistService') 11 | export class TodolistService { 12 | private todoList: ITodo[] = []; 13 | 14 | async list() { 15 | if (existsSync('./cache')) { 16 | const buffer = await new Promise((resolve, reject) => readFile('./cache', 17 | (err, data) => { 18 | if (err) { 19 | return reject(err); 20 | } 21 | resolve(data); 22 | })); 23 | this.todoList = JSON.parse(buffer.toString()); 24 | } 25 | return this.todoList; 26 | } 27 | 28 | async add(text: string) { 29 | const list = await this.list(); 30 | list.push({ 31 | id: await this.incrId(), 32 | text 33 | }); 34 | await this.flushCache(list); 35 | } 36 | 37 | async del(id: number) { 38 | const list = await this.list(); 39 | const idx = list.findIndex((item) => item.id === id); 40 | list.splice(idx, 1) 41 | await this.flushCache(list); 42 | } 43 | 44 | async update(id: number, newText: string) { 45 | const list = await this.list(); 46 | const idx = list.findIndex((item) => item.id === id); 47 | if (id) { 48 | list[idx].text = newText; 49 | await this.flushCache(list); 50 | } 51 | } 52 | 53 | private async incrId() { 54 | const list = await this.list(); 55 | let maxId = 0; 56 | for (const { id } of list) { 57 | if (id > maxId) { 58 | maxId = id; 59 | } 60 | } 61 | return maxId + 1; 62 | } 63 | 64 | private flushCache(list: ITodo[]) { 65 | return new Promise((resolve, reject) => 66 | writeFile('./cache', JSON.stringify(list), (err) => { 67 | if (err) { 68 | return reject(err); 69 | } 70 | resolve(null); 71 | }) 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /todo-list/src/service/render.ts: -------------------------------------------------------------------------------- 1 | import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; 2 | import { renderFile } from 'ejs'; 3 | import { join } from 'path'; 4 | 5 | @Scope(ScopeEnum.Singleton) 6 | @Provide() 7 | export class RenderService { 8 | 9 | async render(locals) { 10 | return renderFile(join(__dirname, '../app/view/home.ejs'), locals); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /todo-list/src/service/user.ts: -------------------------------------------------------------------------------- 1 | import { Provide } from '@midwayjs/decorator'; 2 | import { IUserOptions } from '../interface'; 3 | 4 | @Provide() 5 | export class UserService { 6 | async getUser(options: IUserOptions) { 7 | return { 8 | uid: options.uid, 9 | username: 'mockedName', 10 | phone: '12345678901', 11 | email: 'xxx.xxx@xxx.com', 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /todo-list/test/controller/api.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from "@midwayjs/mock"; 2 | import { Framework } from "@midwayjs/web"; 3 | import { Application } from "egg"; 4 | 5 | describe("test/controller/api.test.ts", () => { 6 | let app: Application; 7 | 8 | beforeAll(async () => { 9 | // create app 10 | app = await createApp(); 11 | }); 12 | 13 | afterAll(async () => { 14 | await close(app); 15 | }); 16 | 17 | it("should POST /api/get_user", async () => { 18 | // make request 19 | const result = await createHttpRequest(app) 20 | .post("/api/get_user") 21 | .query({ uid: 123 }); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.body.message).toBe("OK"); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /todo-list/test/controller/home.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from '@midwayjs/mock'; 2 | import { Framework } from '@midwayjs/web'; 3 | import { Application } from 'egg'; 4 | import * as assert from 'assert'; 5 | 6 | describe('test/controller/home.test.ts', () => { 7 | 8 | let app: Application; 9 | 10 | beforeAll(async () => { 11 | // create app 12 | app = await createApp(); 13 | }); 14 | 15 | afterAll(async () => { 16 | await close(app); 17 | }); 18 | 19 | it('should GET /', async () => { 20 | // make request 21 | const result = await createHttpRequest(app).get('/'); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.text).toBe('Hello Midwayjs!'); 26 | 27 | // or use assert 28 | assert.deepStrictEqual(result.status, 200); 29 | assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /todo-list/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "inlineSourceMap":true, 10 | "noImplicitThis": true, 11 | "noUnusedLocals": true, 12 | "stripInternal": true, 13 | "skipLibCheck": false, 14 | "pretty": true, 15 | "declaration": true, 16 | "typeRoots": [ "./typings", "./node_modules/@types"], 17 | "outDir": "dist" 18 | }, 19 | "exclude": [ 20 | "dist", 21 | "node_modules", 22 | "test" 23 | ] 24 | } -------------------------------------------------------------------------------- /todo-list/typings/app/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | export * from 'egg'; 6 | export as namespace Egg; -------------------------------------------------------------------------------- /todo-list/typings/config/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'midway-schedule'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | onerror?: EggPluginItem; 22 | session?: EggPluginItem; 23 | i18n?: EggPluginItem; 24 | watcher?: EggPluginItem; 25 | multipart?: EggPluginItem; 26 | security?: EggPluginItem; 27 | development?: EggPluginItem; 28 | logrotator?: EggPluginItem; 29 | schedule?: EggPluginItem; 30 | static?: EggPluginItem; 31 | jsonp?: EggPluginItem; 32 | view?: EggPluginItem; 33 | schedulePlus?: EggPluginItem; 34 | } 35 | } -------------------------------------------------------------------------------- /todo-list/typings/config/plugin.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import 'midway-schedule'; 18 | import { EggPluginItem } from 'egg'; 19 | declare module 'egg' { 20 | interface EggPlugin { 21 | onerror?: EggPluginItem; 22 | session?: EggPluginItem; 23 | i18n?: EggPluginItem; 24 | watcher?: EggPluginItem; 25 | multipart?: EggPluginItem; 26 | security?: EggPluginItem; 27 | development?: EggPluginItem; 28 | logrotator?: EggPluginItem; 29 | schedule?: EggPluginItem; 30 | static?: EggPluginItem; 31 | jsonp?: EggPluginItem; 32 | view?: EggPluginItem; 33 | schedulePlus?: EggPluginItem; 34 | } 35 | } --------------------------------------------------------------------------------