2

Markdown

相信现在应该没有人没听过markdown,如果你没听过,你该反思下,如果你没用过,建议你从现在开始尝试。markdown是一种基于文本的描述语言,什么意思呢,通俗的讲就是你只要靠键盘就能完成文章的排版,并且可读性很高,Markdown因为其超级简单的语法(十分钟就能入门),能够摆脱万恶的鼠标,友好的编辑界限,灵活的扩展性等特点迅速在开发人员间流行起来,成为文档编写首选工具,github的README文档默认使用markdown。

markdown主要是用来写文档,在word的时代,写文档对于开发人员就是折磨,“文档十分钟,排版一小时”是很常见的,不仅如此排出来往往还是一坨狗屎,有了markdown之后,情况就变了,你只需用md描述你的格式,具体排版就交给工具。

在写文档上,md描述的是文档的格式,但作为一门这么优秀的描述语言,可不仅仅能描述格式这么简单。

Markdown绘制流程图

我们怎么描述一个流程?用自然语言描述就是“A提交到B,B审批后流转到C,C审批后流程结束”,用流程编排工具就是在界面上拖拽各种节点将每个节点按照流程流转规则连接,用程序描述就是后台需要将流程信息结构化存储,并且借助流程引擎驱动流程。既然markdown是描述语言,能不能用markdown来描述流程,肯定是可以的,我们拍脑袋想一个语法:

A->B
B->C
C->END

这样是不是描述好了,不用任何工具只需一个记事本我们就描述好了一个流程,如果有程序能够基于这个规则驱动流程是不是就可以用markdown描述流程了,你可能觉得实际流程还有很多信息markdown无法描述,但仅考虑流程图不考虑业务实现上,完全是可以用md描述清楚的,并且有人实现了,mermaid就是一个用md来绘制各种图的项目,点击这里可以体验下用markdown绘制流程图,绘制UML等,下面这个UML图就是通过该工具进行绘制

语法如下:

sequenceDiagram
    participant AbapRepository
    participant BasicRepository
    participant JCoFunctionTemplate
    participant MetaDataStorage
    AbapRepository ->> BasicRepository : getFunction
    BasicRepository ->> MetaDataStorage :loadFunctionTemplate
    MetaDataStorage -->> BasicRepository :JCoFunctionTemplate
    BasicRepository ->> JCoFunctionTemplate :getFunction
    JCoFunctionTemplate -->> BasicRepository:new AbapFunction(this);
    BasicRepository --> AbapRepository:JCoFunction

介绍md绘制流程图目的不是告诉有一个工具可以用md绘制流程图,而且想告诉你,md是描述语言,不是文档语言,不是专门用来写文档的,任何需要描述的活动都可以用md实现,一旦你意识到了这个,事情就有趣了。

描述语言和模板语言

在jsp中,我们可以在html中插入java代码,运行时会执行java代码,最终完成完整的html渲染,这个就是一种模板语言。模板语言负责将数据和内容进行整合完成最终的渲染。java中较流行的模板语言有freemarker,velocity,jsp等,模板语言一个问题就是太偏技术,对非开发人员很不友好,对开发人员也不友好,写起来很别扭,如果md能够模板语言结合就完美,什么意思呢,通过md提供数据,结合模板进行渲染。下面就通过一个具体的项目说明这个过程。

用Markdown创建表

在sql中,我们可以通过下面语句创建表:


-- Create table
create table MX_USER
(
    ID VARCHAR(100),
    NAME VARCHAR(100),
    EMAIL VARCHAR(100)
);

-- Add comments to the table
comment on table MX_USER
is '用户表';

-- Add comments to the columns
comment on column MX_USER.ID
is '主键';
comment on column MX_USER.NAME
is '姓名';
comment on column MX_USER.EMAIL
is '邮箱';

-- Create primary, unique and foreign key constraints
alter table MX_USER
add constraint MX_USER_PK primary key (ID);

-- Create/Recreate indexes
create unique idx_name on (NAME,EMAIL);

以上sql完成了几件事

  • 创建表
  • 对表进行备注
  • 对字段进行备注
  • 创建主键约束
  • 创建索引

如果要创建新的表就拷贝上面的sql稍加修改就行。

你会不会觉得这样巨麻烦,反正我是觉得很麻烦,我想要的方式是这样的


# mx_user

``text
用户表
``

列名|类型|备注|默认值
---|---|---|---
*id|varchar(100)|主键|-
name|varchar(100)|姓名|-
email|varchar(100)|邮箱|-


### idx_name
- name
- email

我自己定了一些规则:

  • #表示创建新表
  • text备注表示对表进行备注
  • 列信息放在表格里,表格列分别为,列名,类型,备注,默认值,除了列名和类型是必须,其他都是可选。
  • 主键列列明前面加*号
  • 索引用###表示,索引列用-表示

方案如下:

  • 解析markdown,获取结构化数据
  • 结合velocity模板生成最终的sql

commonmark-java是一个解析markdown的java库,借助commonmark可以完成对markdown的解析,这里不对具体解析过程进行讲解,源码已经上传至github,可以点击这里获取源码,解析后获取到结构化数据,结合velocity模板生成sql,目前支持oracle和mysql两个数据库,两个数据库模板如下:

oracle
-- Create table
#foreach($item in $items)
create table $item.name.toUpperCase()
(
#foreach($column in $item.columns)
    #set($s = "#if($foreach.count != $item.columns.size()),#end")
    #set($s1 = "#if($column.defaultValue) default $column.defaultValue#end")
    $column.name.toUpperCase() $column.type.toUpperCase()$s1$s
#end
);
    #if($item.comment)

-- Add comments to the table
comment on table $item.name.toUpperCase()
is '$item.comment';
    #end

-- Add comments to the columns
#foreach($column in $item.columns)
comment on column $item.name.toUpperCase().$column.name.toUpperCase()
is '$column.comment';
#end

-- Create primary, unique and foreign key constraints
alter table $item.name.toUpperCase()
add constraint $item.name.toUpperCase()_PK primary key ($util.joinUpper($item.keys));

-- Create/Recreate indexes
#foreach($index in $item.indexs)
create unique $index.name on ($util.joinUpper($index.columns));
#end
#end
mysql

#foreach($item in $items)

create table $item.name
(
#foreach($column in $item.columns)
    #set($spliter = "#if($foreach.count != $item.columns.size()),#end")
    #set($defaultValue = "#if($column.defaultValue) default $column.defaultValue#end")
    #set($comment = "#if($column.comment) comment '$column.comment'#end")
    $column.name $column.type.toUpperCase()$defaultValue$comment$spliter
#end
);
#if($item.comment)

-- Add comments to the table
ALTER TABLE $item.name COMMENT '$item.comment';
#end

-- Create primary
alter table $item.name add primary key ($util.join($item.keys));

-- Create indexes
#foreach($index in $item.indexs)
create index $index.name on ${item.name}($util.join($index.columns));
#end
#end

为了使工具更加好用,默认从剪贴板里读取markdown文件,生成后除了输出控制台外,还将内容放入剪贴板,在源码bin目录下已经生成了一个客户端sqlmd.jar,你只需将符合上面规则的markdown复制到剪贴板,然后运行该客户端,即可得到最终的sql,命令如下

java -jar sqlmd.jar [oracle|mysql]

默认生成oracle的脚本,你可以在命令后面加上mysql指定mysql

借助commonmark我们可以很方便完成对markdown的解析,再结合velocity就可以达到我们想要的效果,用很低的成本就完成了一件很cool的事。

写在最后

除了sql,我们还能做什么事,打开了这个潘多拉之盒,我们能做的事取决于我们的想象,我在之前的文章自动化单元测试的构想中里提过,希望能够借助markdown编写测试用例,当时拍脑袋想了一个语法

# [config]

- casecount:100
- level:10

# [object]MpaasUser


# [class]MpaasQuery

## eq
- position:first
- rand:0%
- times:1-100

> field
- type:string
- value:rand/static
- valueType:raw/normal

能够实现吗?完全可以的。再发散下思维,还能干什么事?我最终的目的就是想用markdown构建整个系统的基础框架,包括前端,后段,数据库,测试用例,这个想法最早来源于借助docsify完成倚天的文档,我发现,我只要写markdown就能完成一个很酷,很漂亮的文档库,整个文档库我只花了一周就完成,而且还是业余时间,那为什么不能用markdown来完成完整系统的构建呢?

参考


DQuery
300 声望93 粉丝

幸福是奋斗出来的