# Markdown 模块
你可以使用标准Markdown语法标签,快捷地构造消息卡片内容,Markdown模块可用于渲染文本格式、图片、分割线等元素。本文介绍如何使用Markdown模块。
可使用Markdown标签的内容模块包括:
- 使用独立的Markdown模块,用一段Markdown标签构造包含格式化文本、图片、分割线的消息卡片内容。
- 将text对象的
tag
字段声明为hi_md
,使Markdown的格式化文本能嵌入多列文本布局、图片描述等使用场景
# 字段属性说明
参数 | 是否必须 | 类型 | 示例值 | 说明 |
---|---|---|---|---|
tag | 是 | String | markdown | 模块标签,固定值markdown。 |
content | 是 | String | **加粗** | 使用已支持的Markdown语法构造Markdown内容。 |
textAlign 待开发 | 否 | String | left | 设置文本内容的对齐方式,取值:left:左对齐 center:居中对齐 right:右对齐 默认值:left |
multiUrl | 否 | Struct | url对象 | 差异化跳转,仅在需要PC、移动端跳转不同链接使用 |
# 使用示例
[
...
{
"tag": "markdown",
"content": "普通文本\n标准emoji 😁😢🌞💼🏆❌✅\n*斜体*\n**粗体**\n~~删除线~~\n<u>下划线</u>\n[文字链接](https://www.feishu.cn)\n<font color=\"green\">这是一个绿色文本</font>\n<font color=\"red\">这是一个红色文本</font>\n<font color=\"grey\">这是一个灰色文本</font>\n<at open_id=\"ou_0f35****397e07de3f2\"></at>\n<at user_id=\"98643\"></at>\n<at email=\"zenglinhong@kanzhun.com\"></at>",
"textAlign": "left"
}
...
]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 样式示例
# 支持的语法
名称 | 语法 | 示例 | 支持的版本 | 可用范围 | 备注 |
---|---|---|---|---|---|
换行 | \n | 文本 换行 | 3.11 | Markdown模块,text对象的hi_md模式 | |
斜体 | *斜体* | 斜体 | 3.11 | Markdown模块,text对象的hi_md模式 | |
加粗 | **粗体** | 粗体 | 3.11 | Markdown模块,text对象的hi_md模式 | |
删除线 | ~~删除线~~ | 3.11 | Markdown模块,text对象的hi_md模式 | ||
下划线 | <u>下划线</u> | 下划线 | 3.11 | Markdown模块,text对象的hi_md模式 | |
超链接 | [标题](链接) [直书](https://zhishu.zhipin.com) | 直书 (opens new window) | 3.11 | Markdown模块,text对象的hi_md模式 | |
彩色文本 | <font color="green">这是一个绿色文本</font> <font color="red">这是一个红色文本</font> <font color="grey">这是一个灰色文本</font> | 这是一个绿色文本 这是一个红色文本 这是一个灰色文本 | 3.14 | Markdown模块,text对象的hi_md模式 | color属性为枚举值:green , red ,grey |
@指定人 | <at open_id="ou_0f3515*****97e07de3f2"></at> <at user_id="98**3"></at> <at email="zenglinhong@kanzhun.com"></at> | @人名 | 3.14 | Markdown模块,text对象的hi_md模式 | 属性只能够配置:open_id , user_id , email |
WARNING
彩色文本和@指定人语法出现在低版本时,会进行降级展示!!!
# 特殊字符转义
如果你要展示的字符命中以下字符,需要对字符进行转义才能保证正常展示。转义符号对照表如下:
- 使用斜线转义的特殊字符
特殊字符 转义符 描述 \ \\ 斜线 ` \` 反单引号 * \* 星号 _ \_ 下划线 { \{ 大括号左 } \} 大括号右 [ \[ 中括号左 ] \] 中括号右 ( \( 小括号左 ) \) 小括号右 # \# 井号 + \+ 加号 - \- 减号 . \. 点 ! \! 感叹号 ~ \~ 波浪线 > \> 大于号 < \< 小于号 - 使用HTML编码转义的特殊字符
特殊符号 转义符 描述 ` ` 半角空格,charCode = 160 ` `   半角空格,charCode = 8194 ` `   全角空格,charCode = 8195 & & 连接符 ' ' 单引号 " " 双引号
# SDK简化处理(java)
为简化您的使用,我们提供了服务端发送消息卡片markdown模块内容的文本转换工具类,示例如下
引入开放平台整体sdk依赖
<dependency>
<groupId>com.zhipin.cockatiel.common</groupId>
<artifactId>zhipin-cockatiel-common-openapi</artifactId>
<version>RELEASE</version>
</dependency>
1
2
3
4
5
2
3
4
5
java处理方式一
参照其中markdown模块的工具类方法MarkdownTextEscapeUtils.escapeString()
//全类型卡片拼接构造示例
@Test
public void testSendFullCard() throws Exception {
CompressCardContentBody contentBody = CompressCardContentBody.builder()
// header
.header(Header.builder()
.text(CardText.builder()
.content("普通文本")
.tag(TextEnum.PLAIN_TEXT.getTag())
.build())
.color(CardColorEnum.BLUE.getValue())
.build())
// cardLink
.cardLink(CardLink.builder()
.url("替换为您实际的内容")
.pcUrl("替换为您实际的内容")
.androidUrl("")
.iosUrl("替换为您实际的内容")
.build())
// globalConfig
.globalConfig(GlobalConfig.builder()
.forward(Boolean.FALSE)
.shareCard(Boolean.TRUE)
.build())
// modules
.modules(Lists.newArrayList(
// img
ImageModule.builder()
.tag(ModuleTagEnum.IMAGE.getTag())
.title(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("您的第一个图片模块")
.build())
.imgKey("替换为您实际的内容")
.alt(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("图片模块文本")
.build())
.preview(Boolean.TRUE)
.build(),
// split_line
BaseModule.builder()
.tag(ModuleTagEnum.SPLIT_LINE.getTag())
.build(),
// div text
DivModule.builder()
.tag(ModuleTagEnum.CONTENT.getTag())
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("内容模块——单文本")
.build())
.build(),
// markdown
MarkdownModule.builder()
.tag(ModuleTagEnum.MARKDOWN.getTag())
.content(MarkdownTextEscapeUtils.escapeString("markdown内容含有需展示的特殊符号-~[]{}~"))
.textAlign(TextAlignEnum.LEFT.getValue())
.multiUrl(CardLink.builder()
.url("替换为您实际的内容")
.pcUrl("替换为您实际的内容")
.androidUrl("")
.iosUrl("替换为您实际的内容")
.build())
.build(),
// div hi_md
DivModule.builder()
.tag(ModuleTagEnum.CONTENT.getTag())
.text(CardText.builder()
.tag(TextEnum.HI_MD.getTag())
.content(MarkdownTextEscapeUtils.escapeString("markdown内容含有需展示的特殊符号-~[]{}~"))
.build())
.build(),
// div 多文本
ImageDivModule.builder()
.tag(ModuleTagEnum.CONTENT.getTag())
.arrange(ArrangeEnum.BISECTED.getValue())
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("内容模块——单文本")
.build())
.fields(Lists.newArrayList(
CardField.builder()
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("内容模块——多文本1")
.build())
.needLayout(Boolean.TRUE)
.build(),
CardField.builder()
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("内容模块——多文本2")
.build())
.needLayout(Boolean.TRUE)
.build(),
CardField.builder()
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("内容模块——多文本3")
.build())
.needLayout(Boolean.TRUE)
.build()
))
.extra(CardImage.builder()
.tag(ModuleTagEnum.IMAGE.getTag())
.imgKey("替换为您实际的内容")
.alt(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("图片模块文本")
.build())
.preview(Boolean.TRUE)
.build())
.build(),
// action
ActionModule.builder()
.tag(ModuleTagEnum.ACTIONS.getTag())
.arrange(ArrangeEnum.BISECTED.getValue())
.actions(Lists.newArrayList(
ButtonAction.builder()
.type(ButtonTypeEnum.PRIMARY.getValue())
.tag(ActionEnum.BUTTON.getTag())
.needLayout(Boolean.TRUE)
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("图片模块文本")
.build())
.multiUrl(CardLink.builder()
.url("替换为您实际的内容")
.pcUrl("替换为您实际的内容")
.androidUrl("")
.iosUrl("替换为您实际的内容")
.build())
.callBacks(Lists.newArrayList(
CardCallBack.builder()
.key("click1")
.value("1")
.build(),
CardCallBack.builder()
.key("click2")
.value("2")
.build()
))
.confirm(CardConfirm.builder()
.title(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("弹窗标题")
.build())
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("弹窗内容")
.build())
.build())
.build(),
ListSelectorAction.builder()
.tag(ActionEnum.LIST_SELECTOR.getTag())
.needLayout(Boolean.TRUE)
.placeholder(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("下拉列表 默认文本")
.build())
.initialOption("joy")
.options(Lists.newArrayList(
CardOption.builder()
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("下拉选项文本1")
.build())
.value("joy")
.build(),
CardOption.builder()
.text(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("下拉选项文本2")
.build())
.value("tom")
.build()
))
.callBacks(Lists.newArrayList(
CardCallBack.builder()
.key("option1")
.value("1")
.build(),
CardCallBack.builder()
.key("option2")
.value("2")
.build()
))
.build()
))
.build(),
// note
NoteModule.builder()
.tag(ModuleTagEnum.NOTE.getTag())
.elements(Lists.newArrayList(
CardImage.builder()
.tag(ModuleTagEnum.IMAGE.getTag())
.imgKey("替换为您实际的内容")
.alt(CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("备注模块文本")
.build())
.preview(Boolean.TRUE)
.build(),
CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("备注文本1")
.build(),
CardText.builder()
.tag(TextEnum.PLAIN_TEXT.getTag())
.content("备注文本2")
.build()
))
.build()
))
.build();
String content = JSONObject.toJSONString(contentBody);
CreateMessageResp resp = openApiClient.im().message().create(CreateMessageReq.newBuilder()
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.content(content)
.msgType(MsgTypeEnum.MSG_TYPE_COMPRESSIVE_CARD)
.receiveId("替换为您实际的内容")
.uuid(UUID.randomUUID().toString())
.build())
.receiveIdType(CreateMessageReceiveIdTypeEnum.CHAT_ID)
.userIdType(UserIdTypeEnum.USER_ID)
.build());
String msgId = resp.getData().getMessageId();
}
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
java处理方式二
此方式为自行进行字符串拼接,content的内容需要经过markdown模块的工具类方法MarkdownTextEscapeUtils.escapeStringReEscape()处理后才能正常发送
@Test
public void testSendCard() throws Exception {
String content = "{\n" +
" \"modules\": [\n" +
" {\n" +
" \"tag\": \"div\",\n" +
" \"text\": {\n" +
" \"content\": \"" + MarkdownTextEscapeUtils.escapeStringReEscape("markdown内容含有需展示的特殊符号-~[]{}~") + "\" ," +
" \"tag\": \"hi_md\"\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"globalConfig\": {\n" +
" \"forward\": true\n" +
" }\n" +
"}";
CreateMessageResp resp = openApiClient.im().message().create(CreateMessageReq.newBuilder()
.userIdType(UserIdTypeEnum.USER_ID.getValue())
.receiveIdType(CreateMessageReceiveIdTypeEnum.USER_ID)
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.content(content)
.msgType(MsgTypeEnum.MSG_TYPE_COMPRESSIVE_CARD.getValue())
.receiveId("替换为您的实际内容")
.build())
.build());
}
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
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
java处理方式三
此方式为通过JSONObject类来进行拼接处理,在设置content时对内容执行MarkdownTextEscapeUtils.escapeString()
@Test
public void testSend5() throws Exception {
JSONObject card = new JSONObject();
JSONArray modules = new JSONArray();
card.put("modules", modules);
JSONObject m1 = new JSONObject();
modules.add(m1);
m1.put("tag", "div");
JSONObject m1Text = new JSONObject();
m1.put("text", m1Text);
m1Text.put("content", MarkdownTextEscapeUtils.escapeString("markdown内容含有需展示的特殊符号-~[]{}~"));
m1Text.put("tag", "hi_md");
JSONObject globalConfig = new JSONObject();
card.put("globalConfig", globalConfig);
globalConfig.put("forward", true);
CreateMessageResp resp = openApiClient.im().message().create(CreateMessageReq.newBuilder()
.userIdType(UserIdTypeEnum.USER_ID.getValue())
.receiveIdType(CreateMessageReceiveIdTypeEnum.USER_ID)
.createMessageReqBody(CreateMessageReqBody.newBuilder()
.content(card.toJSONString())
.msgType(MsgTypeEnum.MSG_TYPE_COMPRESSIVE_CARD.getValue())
.receiveId("替换为您的实际内容")
.build())
.build());
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Python语言简化处理支持
如您是使用python语言,因为目前我们平台暂未提供python语言的sdk,您在使用消息卡片markdown模块时可以参照上述java方法方式三,通过引入如下方法来进行内容文本的处理
markdown_chars = ["\\", "!", "#", "(", ")", "<", ">", "*", "+", "-", ".", "[", "]", "_", "`", "{", "}", "~"]
def escape_string(text, specified_chars=None):
escaped = filter_escapes(text)
if specified_chars is None:
specified_chars = markdown_chars
for markdown_char in specified_chars:
escaped = escaped.replace(markdown_char, "\\" + markdown_char)
return escaped
def filter_escapes(url):
return (url.replace("&", "&")
.replace(" ", " ")
.replace("\u00A0", " ")
.replace("\u2002", " ")
.replace("\u2003", " ")
.replace("'", "'")
.replace("\"", """))
##测试方法
##test_text = "~\u00A0&"
##print(escape_string(test_text))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22