fix: replace new line symbol to <br/> in exported markdown (#265)
This commit is contained in:
parent
226c20e0c9
commit
396fa2f6ae
|
@ -1,4 +1,4 @@
|
||||||
package com.databasir.core.render.markdown;
|
package com.databasir.core.domain.document.generator.markdown;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ public class MarkdownBuilder {
|
||||||
// build rows
|
// build rows
|
||||||
for (List<String> row : rows) {
|
for (List<String> row : rows) {
|
||||||
builder.append("| ");
|
builder.append("| ");
|
||||||
for (String column : row) {
|
for (String data : row) {
|
||||||
builder.append(column).append(" | ");
|
builder.append(convertNewLineToBr(data)).append(" | ");
|
||||||
}
|
}
|
||||||
builder.append(LINE);
|
builder.append(LINE);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,17 @@ public class MarkdownBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String convertNewLineToBr(String content) {
|
||||||
|
if (content == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return content
|
||||||
|
.replace("\r\n", "<br/>")
|
||||||
|
.replace("\n", "<br/>");
|
||||||
|
}
|
||||||
|
|
||||||
public String build() {
|
public String build() {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
package com.databasir.core.domain.document.generator;
|
package com.databasir.core.domain.document.generator.markdown;
|
||||||
|
|
||||||
import com.alibaba.excel.util.StringUtils;
|
import com.alibaba.excel.util.StringUtils;
|
||||||
import com.databasir.common.SystemException;
|
import com.databasir.common.SystemException;
|
||||||
import com.databasir.core.domain.document.data.DatabaseDocumentResponse;
|
import com.databasir.core.domain.document.data.DatabaseDocumentResponse;
|
||||||
import com.databasir.core.domain.document.data.DocumentTemplatePropertiesResponse;
|
import com.databasir.core.domain.document.data.DocumentTemplatePropertiesResponse;
|
||||||
import com.databasir.core.domain.document.data.TableDocumentResponse;
|
import com.databasir.core.domain.document.data.TableDocumentResponse;
|
||||||
|
import com.databasir.core.domain.document.generator.DocumentFileGenerator;
|
||||||
|
import com.databasir.core.domain.document.generator.DocumentFileType;
|
||||||
import com.databasir.core.domain.document.service.DocumentTemplateService;
|
import com.databasir.core.domain.document.service.DocumentTemplateService;
|
||||||
import com.databasir.core.render.markdown.MarkdownBuilder;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -82,10 +83,23 @@ public class MarkdownDocumentFileGenerator implements DocumentFileGenerator {
|
||||||
// table document build
|
// table document build
|
||||||
doc.getTables().forEach(table -> {
|
doc.getTables().forEach(table -> {
|
||||||
if (StringUtils.isNotBlank(table.getComment())) {
|
if (StringUtils.isNotBlank(table.getComment())) {
|
||||||
builder.secondTitle(table.getName() + " /\\*" + table.getComment() + "\\*/");
|
String convertedComment = table.getComment()
|
||||||
|
.replace("\r\n", " ")
|
||||||
|
.replace("\n", " ");
|
||||||
|
String comment;
|
||||||
|
if (convertedComment.length() > 30) {
|
||||||
|
comment = convertedComment.substring(0, 30) + "...";
|
||||||
|
} else {
|
||||||
|
comment = convertedComment;
|
||||||
|
}
|
||||||
|
builder.secondTitle(table.getName() + " /\\*" + comment + "\\*/");
|
||||||
} else {
|
} else {
|
||||||
builder.secondTitle(table.getName());
|
builder.secondTitle(table.getName());
|
||||||
}
|
}
|
||||||
|
builder.secondTitle(table.getName());
|
||||||
|
if (StringUtils.isNotBlank(table.getComment())) {
|
||||||
|
builder.blockquotes(table.getComment());
|
||||||
|
}
|
||||||
columnBuild(builder, table, columnTitleMap);
|
columnBuild(builder, table, columnTitleMap);
|
||||||
indexBuild(builder, table, indexTitleMap);
|
indexBuild(builder, table, indexTitleMap);
|
||||||
foreignKeyBuild(builder, table, foreignKeyTitleMap);
|
foreignKeyBuild(builder, table, foreignKeyTitleMap);
|
|
@ -3,13 +3,9 @@ package com.databasir.core;
|
||||||
import com.databasir.core.meta.data.DatabaseMeta;
|
import com.databasir.core.meta.data.DatabaseMeta;
|
||||||
import com.databasir.core.meta.provider.MetaProviders;
|
import com.databasir.core.meta.provider.MetaProviders;
|
||||||
import com.databasir.core.meta.provider.condition.Condition;
|
import com.databasir.core.meta.provider.condition.Condition;
|
||||||
import com.databasir.core.render.Render;
|
|
||||||
import com.databasir.core.render.RenderConfig;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -41,14 +37,6 @@ public class Databasir {
|
||||||
.select(connection, condition);
|
.select(connection, condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderAsMarkdown(DatabaseMeta meta, OutputStream out) throws IOException {
|
|
||||||
renderAsMarkdown(new RenderConfig(), meta, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void renderAsMarkdown(RenderConfig config, DatabaseMeta meta, OutputStream stream) throws IOException {
|
|
||||||
Render.markdownRender(config).rendering(meta, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Databasir of() {
|
public static Databasir of() {
|
||||||
return of(new DatabasirConfig());
|
return of(new DatabasirConfig());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package com.databasir.core.render;
|
|
||||||
|
|
||||||
import com.databasir.core.meta.data.DatabaseMeta;
|
|
||||||
import com.databasir.core.render.markdown.MarkdownTemplateRender;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public interface Render {
|
|
||||||
|
|
||||||
void rendering(DatabaseMeta meta, OutputStream outputStream) throws IOException;
|
|
||||||
|
|
||||||
static Render markdownRender(RenderConfig configuration) {
|
|
||||||
return new MarkdownTemplateRender(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package com.databasir.core.render;
|
|
||||||
|
|
||||||
import com.databasir.core.meta.data.ColumnMeta;
|
|
||||||
import com.databasir.core.meta.data.IndexMeta;
|
|
||||||
import com.databasir.core.meta.data.TriggerMeta;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class RenderConfig {
|
|
||||||
|
|
||||||
private Boolean renderTables = true;
|
|
||||||
|
|
||||||
private Boolean renderColumns = true;
|
|
||||||
|
|
||||||
private Boolean renderIndexes = true;
|
|
||||||
|
|
||||||
private Boolean renderTriggers = true;
|
|
||||||
|
|
||||||
private LinkedHashMap<String, Function<ColumnMeta, String>> columnTitleAndValueMapping =
|
|
||||||
columnTitleAndValueMapping();
|
|
||||||
|
|
||||||
private LinkedHashMap<String, Function<IndexMeta, String>> indexTitleAndValueMapping =
|
|
||||||
indexTitleAndValueMapping();
|
|
||||||
|
|
||||||
private LinkedHashMap<String, Function<TriggerMeta, String>> triggerTitleAndValueMapping =
|
|
||||||
triggerTitleAndValueMapping();
|
|
||||||
|
|
||||||
protected LinkedHashMap<String, Function<ColumnMeta, String>> columnTitleAndValueMapping() {
|
|
||||||
LinkedHashMap<String, Function<ColumnMeta, String>> mapping = new LinkedHashMap<>();
|
|
||||||
mapping.put("Name", ColumnMeta::getName);
|
|
||||||
mapping.put("Type", column -> {
|
|
||||||
String type;
|
|
||||||
if (column.getDecimalDigits() == null || column.getDecimalDigits().equals(0)) {
|
|
||||||
type = column.getType()
|
|
||||||
+ "(" + column.getSize().toString() + ")";
|
|
||||||
} else {
|
|
||||||
type = column.getType()
|
|
||||||
+ "(" + column.getSize().toString() + ", " + column.getDecimalDigits().toString() + ")";
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
});
|
|
||||||
return mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected LinkedHashMap<String, Function<IndexMeta, String>> indexTitleAndValueMapping() {
|
|
||||||
LinkedHashMap<String, Function<IndexMeta, String>> mapping = new LinkedHashMap<>();
|
|
||||||
mapping.put("Name", IndexMeta::getName);
|
|
||||||
mapping.put("IsUnique", index -> index.getIsUniqueKey() ? "YES" : "");
|
|
||||||
mapping.put("Columns", index -> String.join(", ", index.getColumnNames()));
|
|
||||||
return mapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected LinkedHashMap<String, Function<TriggerMeta, String>> triggerTitleAndValueMapping() {
|
|
||||||
LinkedHashMap<String, Function<TriggerMeta, String>> mapping = new LinkedHashMap<>();
|
|
||||||
mapping.put("Name", TriggerMeta::getName);
|
|
||||||
mapping.put("Timing", trigger -> trigger.getTiming() + " " + trigger.getManipulation());
|
|
||||||
mapping.put("Statement", trigger -> trigger.getStatement().replace("\n", " ")
|
|
||||||
.replace("\r", " "));
|
|
||||||
mapping.put("Create At", TriggerMeta::getCreateAt);
|
|
||||||
return mapping;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
package com.databasir.core.render.markdown;
|
|
||||||
|
|
||||||
import com.databasir.core.meta.data.DatabaseMeta;
|
|
||||||
import com.databasir.core.meta.data.TableMeta;
|
|
||||||
import com.databasir.core.render.Render;
|
|
||||||
import com.databasir.core.render.RenderConfig;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class MarkdownRender implements Render {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final RenderConfig config;
|
|
||||||
|
|
||||||
protected MarkdownRender(RenderConfig config) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MarkdownRender of(RenderConfig config) {
|
|
||||||
return new MarkdownRender(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rendering(DatabaseMeta meta,
|
|
||||||
OutputStream outputStream) throws IOException {
|
|
||||||
MarkdownBuilder contentBuilder = MarkdownBuilder.builder();
|
|
||||||
contentBuilder.primaryTitle(meta.getDatabaseName());
|
|
||||||
if (config.getRenderTables()) {
|
|
||||||
for (TableMeta table : meta.getTables()) {
|
|
||||||
buildTableName(contentBuilder, table);
|
|
||||||
if (config.getRenderColumns()) {
|
|
||||||
buildColumns(contentBuilder, table);
|
|
||||||
}
|
|
||||||
if (config.getRenderIndexes()) {
|
|
||||||
buildIndexes(contentBuilder, table);
|
|
||||||
}
|
|
||||||
if (config.getRenderTriggers()) {
|
|
||||||
buildTriggers(contentBuilder, table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputStream.write(contentBuilder.build().getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildTableName(MarkdownBuilder contentBuilder, TableMeta table) {
|
|
||||||
String tableName;
|
|
||||||
if (table.getComment().isEmpty()) {
|
|
||||||
tableName = table.getName();
|
|
||||||
} else {
|
|
||||||
tableName = table.getName() + "(" + table.getComment() + ")";
|
|
||||||
}
|
|
||||||
contentBuilder.secondTitle(tableName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildColumns(MarkdownBuilder contentBuilder, TableMeta table) {
|
|
||||||
contentBuilder.unorderedList(Collections.singletonList("columns"));
|
|
||||||
List<List<String>> allColumnRows = table.getColumns()
|
|
||||||
.stream()
|
|
||||||
.map(column -> config.getColumnTitleAndValueMapping()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.map(mapping -> mapping.apply(column))
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
contentBuilder.table(tableTitles(), allColumnRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildIndexes(MarkdownBuilder contentBuilder, TableMeta table) {
|
|
||||||
contentBuilder.unorderedList(Collections.singletonList("indexes"));
|
|
||||||
List<List<String>> allIndexRows = table.getIndexes().stream()
|
|
||||||
.map(index -> config.getIndexTitleAndValueMapping()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.map(mapping -> mapping.apply(index))
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
contentBuilder.table(indexTitles(), allIndexRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildTriggers(MarkdownBuilder contentBuilder, TableMeta table) {
|
|
||||||
if (table.getTriggers() == null || table.getTriggers().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
contentBuilder.unorderedList(Collections.singletonList("triggers"));
|
|
||||||
List<List<String>> allRows = table.getTriggers().stream()
|
|
||||||
.map(trigger -> config.getTriggerTitleAndValueMapping()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.map(mapping -> mapping.apply(trigger))
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
contentBuilder.table(triggerTitles(), allRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> tableTitles() {
|
|
||||||
return new ArrayList<>(config.getColumnTitleAndValueMapping().keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> indexTitles() {
|
|
||||||
return new ArrayList<>(config.getIndexTitleAndValueMapping().keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> triggerTitles() {
|
|
||||||
return new ArrayList<>(config.getTriggerTitleAndValueMapping().keySet());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package com.databasir.core.render.markdown;
|
|
||||||
|
|
||||||
import com.databasir.core.meta.data.DatabaseMeta;
|
|
||||||
import com.databasir.core.render.Render;
|
|
||||||
import com.databasir.core.render.RenderConfig;
|
|
||||||
import freemarker.template.Configuration;
|
|
||||||
import freemarker.template.Template;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import freemarker.template.TemplateExceptionHandler;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* use freemarker template to render markdown
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class MarkdownTemplateRender implements Render {
|
|
||||||
|
|
||||||
private final RenderConfig renderConfig;
|
|
||||||
|
|
||||||
private String templatePath = "template/render/markdown/markdown.ftlh";
|
|
||||||
|
|
||||||
public MarkdownTemplateRender(RenderConfig config, String templatePath) {
|
|
||||||
this(config);
|
|
||||||
this.templatePath = templatePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rendering(DatabaseMeta meta, OutputStream outputStream) throws IOException {
|
|
||||||
doRendering(meta, outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doRendering(DatabaseMeta meta, OutputStream outputStream) throws IOException {
|
|
||||||
Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
|
|
||||||
cfg.setClassForTemplateLoading(getClass(), "/");
|
|
||||||
cfg.setDefaultEncoding("UTF-8");
|
|
||||||
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
|
||||||
cfg.setLogTemplateExceptions(false);
|
|
||||||
cfg.setWrapUncheckedExceptions(true);
|
|
||||||
cfg.setFallbackOnNullLoopVariable(false);
|
|
||||||
|
|
||||||
Map<String, Object> root = new HashMap<>();
|
|
||||||
root.put("meta", meta);
|
|
||||||
root.put("config", renderConfig);
|
|
||||||
Template template = cfg.getTemplate(templatePath);
|
|
||||||
try {
|
|
||||||
template.process(root, new OutputStreamWriter(outputStream));
|
|
||||||
} catch (TemplateException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
# ${meta.databaseName}
|
|
||||||
| | |
|
|
||||||
| --------------- | ---- |
|
|
||||||
| Database name | |
|
|
||||||
| Product name | |
|
|
||||||
| Product version | |
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
| | name | type | comment |
|
|
||||||
| ---- | --------------- | ------ | ------ |
|
|
||||||
<#list meta.tables as table>
|
|
||||||
| ${table_index+1} | [${table.name}](#${table.name}) | ${table.type} | ${table.comment!'N/A'} |
|
|
||||||
</#list>
|
|
||||||
|
|
||||||
<#if config.renderTables>
|
|
||||||
<#list meta.tables as table>
|
|
||||||
## ${table.name}
|
|
||||||
<#if config.renderColumns>
|
|
||||||
### Columns
|
|
||||||
|
|
||||||
| | name | type | primary Key | nullable | auto increment| default | comment |
|
|
||||||
| --- | ---- | ---- | ----------- | -------- | ------------- | ------- | ------- |
|
|
||||||
<#list table.columns as column>
|
|
||||||
| ${column_index+1} | ${column.name} | ${column.type} | ${column.isPrimaryKey?then('YES','NO')} | ${column.nullable } | ${column.autoIncrement} | ${column.defaultValue!'NULL'} | ${column.comment!''} |
|
|
||||||
</#list>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#if config.renderIndexes>
|
|
||||||
### Indexes
|
|
||||||
|
|
||||||
| | name | unique | columns |
|
|
||||||
| --- | ---- | ------ | ------- |
|
|
||||||
<#list table.indexes as index>
|
|
||||||
| ${index_index+1} | ${index.name} | ${index.isUniqueKey?then('YES', 'NO')} | ${index.columnNames?join(', ')} |
|
|
||||||
</#list>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
<#if config.renderTriggers>
|
|
||||||
### Triggers
|
|
||||||
|
|
||||||
| | name | timing | statement | created |
|
|
||||||
| --- | ---- | ------ | --------- | ------- |
|
|
||||||
<#list table.triggers as trigger>
|
|
||||||
| ${trigger_index} | ${trigger.name} | ${trigger.timing + " " + trigger.manipulation } | ${trigger.statement?replace("\n", "<br>")?replace("\r", " ")} | ${trigger.createAt} |
|
|
||||||
</#list>
|
|
||||||
</#if>
|
|
||||||
|
|
||||||
</#list>
|
|
||||||
</#if>
|
|
Loading…
Reference in New Issue