0%

用 typescript 生成 Swagger 文档

参考地址:https://wz2cool.github.io/2018/04/14/swagger-ts-doc-start/

apiModelProperty 装饰器

这个装饰器主要是为了生成 definitions 中的 model,我们看代码可看到如何描述一个 typescript 中的一个类。

1
2
3
4
5
6
7
8
9
10
11
12
import { apiModelProperty, DataType } from "swagger-ts-doc";

export class UpdateStudentDto {
@apiModelProperty(
DataType.STRING, // 类型
false, // 是否必填
"学生姓名" // 描述
)
public name: string;
@apiModelProperty(DataType.INTEGER, false, "学生年龄")
public age: number;
}

最后会生成与之对应的 swagger json 描述(这里我们不使用 yaml 语法,使用的 json 语法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"UpdateStudentDto": {
"type": "object",
"required": ["name", "age"],
"properties": {
"name": {
"type": "string",
"description": "学生姓名"
},
"age": {
"type": "integer",
"description": "学生年龄"
}
}
},

Request 参数

参考 swagger 文档:
https://swagger.io/docs/specification/describing-parameters/
https://swagger.io/docs/specification/describing-request-body/

  • RequestBody 类对应文档 requestBody
  • PathVariable 类对应文档 path parameters (in: path)
  • RequestParam 类对弈文档 query parameters (in: query)

Reponse

参考 swagger 文档:
https://swagger.io/docs/specification/describing-responses/
我们看一下定义多个返回相应

1
2
3
4
5
[
new Response(HttpStatusCode.OK, DataType.STRING, "ok"),
new Response(HttpStatusCode.INTERNAL_SERVER_ERROR, DataType.STRING, "内部错误"),
new Response(HttpStatusCode.NOT_FOUND, DataType.STRING, "学生未找到"),
],

registerRequestMapping 方法

这里就是我们要去生成 swagger 中 paths 节点调用的方法,这里我们举一个修改学生的一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 registerRequestMapping(
StudentApi, // tags 类似于把一些路由放到一个组里面
"/students/{id}", // 路由
RequestMethod.PUT,
[
new PathVariable("id", DataType.STRING, "学生ID"),
new RequestBody("student", DataType.OBJECT, UpdateStudentDto, "学生"),
],
[
new Response(HttpStatusCode.OK, DataType.STRING, "ok"),
new Response(HttpStatusCode.INTERNAL_SERVER_ERROR, DataType.STRING, "内部错误"),
new Response(HttpStatusCode.NOT_FOUND, DataType.STRING, "学生未找到"),
],
"修改学生"); // 对这个路由的描述
route.put("/:id", (req, res, next) => {
const input = req.body;
const id = req.params.id;
if (!id) {
res.status(HttpStatusCode.INTERNAL_SERVER_ERROR);
res.json("学生ID不能为空");
return;
}

if (lodash.findIndex(this.students, (x) => x.uuid === id) < 0) {
res.status(HttpStatusCode.NOT_FOUND);
res.json(`未能找到学生`);
return;
}

const student = new Student();
student.uuid = id;
student.name = input.name;
student.age = input.age;
this.modifyStudent(student);
res.json("ok");
});

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/bbc1fd72.html
版权声明:转载请注明出处!

自动生成日志

参考链接:https://juejin.im/post/5bd2debfe51d457abc710b57

Commitizen – 自动生成合格的 commit message

根据上述的描述,你是不是在感慨写个 commit message 好麻烦,这里介绍下 Commitizen – 能够根据提示自动生成符合规范的 commit message

安装

1
2
$ npm install -g commitizen
复制代码

在项目中使用

然后,在项目目录里,运行下面的命令,使其支持 AngularCommit message 格式。

1
2
$ commitizen init cz-conventional-changelog --save --save-exact
复制代码

commit

在提交的时候就可以使用 git cz 就可以根据提示,生成自动化的 commit message

validate-commit-msg 检查你的 commit-message 规范

Commitizen 可以帮助我们规范自己的 commit-message,但是在团队合作中,如何规范其他成员的 commit 规范呢?

可以使用 validate-commit-msg 来检查你的项目的 commit-message 是否符合格式

validate-commit-msg 安装

1
2
npm install --save-dev validate-commit-msg
复制代码

husky 安装

按照 validate-commit-msg 中 README 中写的,可以用 validate-commit-msg 作为一个 githook 来验证提交消息,并且推荐了 husky

This provides you a binary that you can use as a githook to validate the commit message. I recommend husky. You’ll want to make this part of the commit-msg githook, e.g. when using husky, add “commitmsg”: “validate-commit-msg” to your npm scripts in package.json.

执行

1
2
npm install husky --save-dev
复制代码

并且在 package.json 中的 scripts 字段中加入

1
2
"commitmsg": "validate-commit-msg"
复制代码

然后每次 git commit 之后,就会自动检查 commit message 是否合格。如果不合格,就会报错

1
2
3
4
husky > commit-msg (node v9.2.1)
INVALID COMMIT MSG: does not match "<type>(<scope>): <subject>" !
change
husky > commit-msg hook failed (add --no-verify to bypass)

生成 Change log

如果你的所有 commit 都符合 Angular 格式,那么发布新版本时, Change log 就可以用脚本自动生成。

生成的文档包括以下三个部分。

  • New features
  • Bug fixes
  • Breaking changes.

每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。

conventional-changelog 自动根据 commit 生成 change log

conventional-changelog 安装

1
npm install -g conventional-changelog-cli

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/320b027.html
版权声明:转载请注明出处!

node-coolq-robot

作者:草梅友仁

本项目基于 cq-robot、coolq-http-api、cq-websocket ,按照官方 SDK 风格重新封装了事件函数和 api 函数

项目特色

  1. 仿官方 SDK 风格,熟悉易语言版的很快就可以上手。

  2. 仿酷 Q 目录设计,可以像原生酷 Q 插件那样载入插件,也便于插件的开发

  3. 可以使用 JavaScript 和 TypeScript 进行开发,具有一定的跨平台性

项目目录

  • /src 源代码
    • /app 插件存放的位置
      • /com.example.demo 应用根目录
        • /data 应用数据存放目录
        • index.json/index.jsonc 插件配置项
        • index.ts/index.ts 插件入口文件
    • /conf
      • setting.json/setting.jsonc CQWebSocket 连接配置,用于和 coolq-http-api 建立连接
    • /utils 一些工具类
    • index.ts 项目运行入口
  • /dist 最终需要运行的文件

快速开始

  1. clone 本项目

    1
    git clone https://github.com/CaoMeiYouRen/node-coolq-robot.git
  2. 修改 src/conf/setting.jsonc 中的accessToken【重要】,其他参数可以默认(关于该配置,详见CoolQ HTTP API 配置

  3. 酷 Q 安装 coolq-http-api,修改 酷 Q Pro\data\app\io.github.richardchien.coolqhttpapi\config 下的相关配置,其中 access_token 与上方 accessToken 保持一致(关于该配置,详见CQWebSocketOption

  4. 酷 Q 启动 coolq-http-api,注意,如果修改 access_token 时插件已启用,请重载应用或重启酷 Q

  5. 执行 npm run build 生成 dist 文件

  6. 执行 dist/index.js,开发环境下可以使用 nodemon,生产环境可以使用 pm2 等

  7. 在控制台查看效果(如果出现 [WebSocket] 连接成功 即为成功)

  8. 演示效果

    image

image

安装插件

  1. 所有插件放在 src/app 目录下,新建一个由 appId 命名的文件夹(下称为应用根目录),入口文件必须为 index.js/index.ts(编译后均为 index.js),配置项为 index.json 或 index.jsonc【关于 jsonc 需要特别解释下,就是支持注释的 json,即 VScode 中的 JSON with Comments 格式】

  2. 应用所有数据需存放在 [appId]/data/ 目录下,以免给用户造成困扰

  3. 考虑到插件可能会有自己的 node_modules 依赖,将依赖也装在 项目根目录 下即可(注意,如果安装在项目根目录有问题,也可安装在 应用根目录 ,只不过 src 和 dist 目录下均需安装)

  4. 注意:最终执行的文件为 dist 目录下的内容,因此如果有除了 json/jsonc 格式以外的文件需要从 src 目录下复制,请修改 gulpfile.js 文件

插件开发

对于开发者,本人也提供了 demo,建议使用 TypeScript 进行开发,当然也支持用 JavaScript 开发

以下是一个空的 demo 示例,更详细内容请查看本项目的 src/app/下面的 demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class App extends CQApp {
constructor() {
super('com.example.demo', __dirname)
//每一个CQApp对象身上都挂载着一个属性:CQ,里面封装了所有api相关操作,是核心操作类,更多内容请直接查看注释
this.CQ.setDebug(false)//为了方便调试,本人提供了CQ.setDebug()方法来设置插件的运行环境,在debug模式下将不会执行具体的api操作,可以在不影响其他插件的情况下进行逻辑调试;同时也提供了CQ.getDebug()来获取当前的运行环境,开发者可以针对此做一些操作
this.isEnable = true//注意,只有isEnable为true的插件才会载入,可以将isEnable置为false不载入某插件
}
}
const app = new App()//类名可以随意
export { app }//导出模块的名称必须为app
/**
*仅在debug模式下执行,若不需要也可注释掉
*请注意,因为debug的内容在此处就会执行,因此是最先执行的内容!
*/
if (app.CQ.getDebug()) {
app.debug()
}
  1. 关于应用加载:符合以下条件之一的应用不会载入

    1. AppID 与其根文件夹名称不同
    2. CQ_API 版本不为 9
    3. HTTP_API 版本不为 4
    4. 应用未启用(isEnable=false)
  2. api 权限:在应用根目录的 index.json 中配置,对于没有权限的 api 调用不会执行

  3. 插件事件优先级:在应用根目录的 index.json 中配置,数值越低优先级越高,高优先级的可以截断消息。注意:本项目中并未对插件事件优先级做限制,而且也不限制优先级为 10000 时就不能截断消息,但为了与官方要求一致,建议不要使用 10000、20000、30000、40000、50000 以外的优先级,并且不得在优先级为 10000 时截断消息

  4. 日志:日志文件会在同级运行目录生成 log 文件夹。在 log 文件夹下有 app 和 debug 两个文件夹,分别是生产环境和开发环境的日志,会记录下 api 的调用和应用接收到的事件信息。当插件处于 debug 模式时,所有日志都在 debug 文件夹下;生产环境下,所有日志都在 app 目录下

项目依赖

node-cq-websocket : https://github.com/momocow/node-cq-websocket

coolq-http-api : https://github.com/richardchien/coolq-http-api

项目参考

JCQ-CoolQ : https://github.com/Meowya/JCQ-CoolQ

(本项目在开发中很大程度上借鉴了 JCQ 的思路,在此表示感谢)

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/5e4e9fe0.html
版权声明:转载请注明出处!

三分钟搭建一个 web 服务器

by 草梅友仁

项目地址https://github.com/CaoMeiYouRen/simple-web-server

上面的打不开可以访问这个地址https://gitee.com/caomeiyouren/simple-web-server

使用

新建一个目录,然后切换到该目录

运行以下命令即可,前提是已经安装了 git

1
2
3
4
git clone https://github.com/CaoMeiYouRen/simple-web-server.git
# github有点卡,如果上不去的话也可以换成下面这个链接
git clone https://gitee.com/caomeiyouren/simple-web-server.git
# 注意以上命令只要运行一个即可

然后继续运行

1
2
npm i #下载依赖
npm run server #运行脚本

运行后可通过 http://127.0.0.1:80 来访问

运行效果

image


如果不会使用 git 的也可以参考下面的文件目录自己建一个

文件目录

  • src/ 源代码
    • app.js web 服务脚本
    • public/ web 服务器根目录
      • index.html
  • package.json npm 包配置文件

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "simple-web-server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"server": "node ./src/app.js"
},
"author": "CaoMeiYouRen",
"license": "MIT",
"dependencies": {
"express": "^4.16.4"
}
}

app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var express = require("express");
var app = express();//使用express框架
var path = require("path");//这个是node.js自带的路径处理模块
/**
* app.use("/", express.static(path.join(__dirname, "public")));
* app.use("访问路径",express.static("要公开的目录"))
* 下面这段的意思是通过 域名/xxx 能够访问到 public/xxx 的内容
* 即将public目录作为静态目录公开
* path.join(__dirname, "public")能够获取到public的绝对目录
* 使用绝对目录作为根域名有一个好处就是能够保证找到这个目录,相对目录可能会出错
*/
app.use("/", express.static(path.join(__dirname, "public")));
var http = require("http");//导入http模块
app.get("/", (req, res) => {//当以get方式访问根目录时,返回index.html
res.sendFile(__dirname + "/public/index.html");
});
let port = 80;//脚本运行端口为80
http.createServer(app).listen(port, () => {
console.log("HTTP运行端口为 http://127.0.0.1:" + port);
});


index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="zh-CN">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>simple-web-server</title>
<style>

</style>
<script>

</script>
</head>

<body>
<h1>HelloWorld</h1>
</body>

</html>

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/fd373c4f.html
版权声明:转载请注明出处!

C#安装 MySQL 驱动以及实现简单的 MySQL 操作

by 草梅友仁

一、驱动下载

首先前往 MySql 官网下载驱动。下载地址:https://dev.mysql.com/downloads/connector/net/

img

注意驱动版本即可。注意:要下载.zip 版本,解压后会看到几个 dll,那个就是需要的驱动

img

最新的 8.0.16 版本驱动要求.net 版本在 4.5 以上,如果需要 4.0 版本的则需要 6.8.8 版本,选择 4.0 版本驱动即可

image

img

由于本人安装的 Visual Studio 2010 最高只支持.net4.0,因此只能使用旧版驱动。不管哪个版本,MySQL 的核心驱动都是 MySql.Data.dll,使用的时候只需要引入这个即可

image

二、驱动引入

  1. 新建一个项目,名称随意。

img

  1. 找到项目位置,在项目根目录下新建 lib 文件夹

image

  1. 将 MySql.Data.dll 复制到该目录下

image

  1. 回到 Visual Studio 2010 中,右键添加添加引用

    image

  2. 选择浏览,找到 MySql.Data.dll,选中并点击确定

img

三、连接数据库

  1. 新建一个 Database.cs 类,并引用 MySql.Data.MySqlClient 类。注意类名前添加 public,否则无法在其他类中调用这个类

image

  1. 写一个初始化方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Database
{
static MySqlConnection conn;//MySql连接
const String server = "localhost";//服务器地址
const String uid = "test";//用户名
const String pw = "123456";//密码
const String db = "test";//库名
/// <summary>
/// 初始化程序,连接数据库
/// </summary>
public static Boolean Init()
{
try
{
if (conn == null)
{
conn = new MySqlConnection("server=" + server + ";user id=" + uid + ";password=" + pw + ";database=" + db);
conn.Open();
Console.WriteLine("数据库连接成功");
}
return true;
}
catch (Exception e)//异常处理
{
Console.WriteLine("Exception caught: {0}", e);
return false;
}
}
}

​ 3. 在主程序中调用该方法,观察控制台是否有输出,如果显示“数据库连接成功”则表明数据库连接已成功,操作正确。

image

img

四、编写数据库操作辅助类

对数据库的操作有很多重复的内容,因此这些可以像初始化方法这样提取出来。

  1. 查询操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /// <summary>
    /// 查询操作,成功返回MySqlDataReader,具体的数据可以从该对象中获取;失败返回null
    /// </summary>
    public static MySqlDataReader Select(String sql)
    {
    try
    {
    Init();
    MySqlCommand command = new MySqlCommand(sql, conn);
    MySqlDataReader data = command.ExecuteReader();//这里返回从数据库获取的数据
    return data;
    }
    catch (Exception e)//注意了,对数据库的操作尤为要注意异常处理,因此直接写在这里即可
    {
    Console.WriteLine("Exception caught: {0}", e);
    return null;
    }
    }
  2. 增删改操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /// <summary>
    /// 执行一条sql指令,成功返回true,失败返回fasle
    /// 事实上
    /// </summary>
    public static Boolean DbOp(String sql)
    {
    try
    {
    Init();
    MySqlCommand command = new MySqlCommand(sql, conn);
    int result = command.ExecuteNonQuery();//这里返回的是受影响的数据条数,如果不为零则表明操作成功
    return result != 0;
    }
    catch (Exception e)
    {
    Console.WriteLine("Exception caught: {0}", e);
    return false;
    }
    }
  3. 实现字符串的转义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /// <summary>
    /// 转义字符串 例如 abc 转为 'abc'
    /// </summary>
    public static String Escape(Object str)
    {
    if (str.GetType() == "".GetType())
    {//是字符串的进行防注入
    return "'" + MySqlHelper.EscapeString(str.ToString()) + "'";//注意,MySQL中表示字符串时一定需要单引号或反引号
    }
    return str.ToString();
    }

五、实现简单的增删查改功能

  1. 数据表名称:user

    字段:id,类型 int;name,类型 text;pw,类型 text

    img

如果要用 sql 语句创建,可参考如下,也可以用可视化工具创建

1
2
3
4
5
CREATE TABLE IF NOT EXISTS `user`(
`id` INT AUTO_INCREMENT PRIMARY KEY,
`name` TEXT NOT NULL,
`pw` TEXT NOT NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. 在项目中新建一个 User.cs 类,内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;

namespace MySqlTest
{
class User
{
public int id;//编号
public String name;//用户名
public String pw;//密码
public User()
{
}
public User(MySqlDataReader data)
{
this.id = data.GetInt16("id");
this.name = data.GetString("name");
this.pw = data.GetString("pw");
}
public User(String name, String pw)//注册时需要创建无id的新用户
{
this.name = name;
this.pw = pw;
}
public User(int id, String name, String pw)
{
this.id = id;
this.name = name;
this.pw = pw;
}
}
}

  1. 实现 user 的查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 /// <summary>
/// 根据id查找指定用户
/// </summary>
public static User SelectUser(int id)
{
string sql = "SELECT * from user WHERE id = " + id;
MySqlDataReader data = Select(sql);//如果出现异常会返回null,需要注意!!
if (data != null && data.Read())
{
User user = new User(data);//由于上面已经在User的的构造函数中写了相关方法,所以这里直接调用即可
data.Close();
return user;
}
else
{
if (data != null) //如果不为空则需要关闭!
{
data.Close();
}
return null;
}
}

3.实现 user 的增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 /// <summary>
/// 创建新用户
/// </summary>
public static User AddUser(User user)
{
String sql = "INSERT into user(id,name,pw) values(0," + Escape(user.name) + "," + Escape(user.pw) + ")";
if (DbOp(sql))
{
return SelectUser(user.name);
}
else
{
return null;
}
}

4.实现 user 的更新

1
2
3
4
5
6
7
8
/// <summary>
/// 修改用户
/// </summary>
public static Boolean UpdateUser(User user)
{
String sql = "UPDATE user SET name = " + Escape(user.name) + ",pw = " + Escape(user.pw) + " WHERE id = " + user.id;
return DbOp(sql);
}

5.实现 user 的删除

1
2
3
4
5
6
7
8
/// <summary>
/// 删除用户
/// </summary>
public static Boolean DeleteUser(int id)
{
String sql = "DELETE from user WHERE id = " + id;
return DbOp(sql);
}

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/9925ae75.html
版权声明:转载请注明出处!