mirror of
https://github.com/vran-dev/databasir.git
synced 2025-08-28 18:43:14 +08:00
feat: use plantuml to export er diagram
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package com.databasir.core.domain.document.data;
|
||||
|
||||
import com.databasir.core.domain.document.generator.DocumentFileType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DocumentFileTypeResponse {
|
||||
|
||||
private String name;
|
||||
|
||||
private String fileExtension;
|
||||
|
||||
private DocumentFileType type;
|
||||
|
||||
}
|
@@ -7,7 +7,15 @@ import lombok.Getter;
|
||||
@Getter
|
||||
public enum DocumentFileType {
|
||||
|
||||
MARKDOWN("md"), EXCEL("xlsx");
|
||||
MARKDOWN("md", "Markdown"),
|
||||
|
||||
PLANT_UML_ER_SVG("svg", "UML SVG"),
|
||||
|
||||
PLANT_UML_ER_PNG("png", "UML PNG"),
|
||||
;
|
||||
|
||||
private String fileExtension;
|
||||
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
@@ -1,22 +0,0 @@
|
||||
package com.databasir.core.domain.document.generator;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
@Component
|
||||
public class ExcelDocumentFileGenerator implements DocumentFileGenerator {
|
||||
|
||||
@Override
|
||||
public boolean support(DocumentFileType type) {
|
||||
return type == DocumentFileType.EXCEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DocumentFileGenerateContext context, OutputStream outputStream) {
|
||||
|
||||
}
|
||||
|
||||
private void buildTableWithSheet() {
|
||||
}
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
package com.databasir.core.domain.document.generator.plantuml;
|
||||
|
||||
import com.databasir.common.SystemException;
|
||||
import com.databasir.core.domain.document.data.DatabaseDocumentResponse;
|
||||
import com.databasir.core.domain.document.data.TableDocumentResponse;
|
||||
import com.databasir.core.domain.document.generator.DocumentFileGenerator;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.SourceStringReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public abstract class BasePlantUmlFileGenerator implements DocumentFileGenerator {
|
||||
|
||||
public static final String LINE = "\r\n";
|
||||
|
||||
@Override
|
||||
public void generate(DocumentFileGenerateContext context, OutputStream outputStream) {
|
||||
String dsl = new ErDsl(context).toDsl();
|
||||
try {
|
||||
new SourceStringReader(dsl).outputImage(outputStream, fileFormatOption());
|
||||
} catch (IOException e) {
|
||||
log.error("export plantuml error", e);
|
||||
throw new SystemException("System error");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract FileFormatOption fileFormatOption();
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ErDsl {
|
||||
|
||||
private final DocumentFileGenerateContext context;
|
||||
|
||||
private Set<String> foreignKeyRelations = new HashSet<>(16);
|
||||
|
||||
public String toDsl() {
|
||||
DatabaseDocumentResponse databaseDocument = context.getDatabaseDocument();
|
||||
StringBuilder dslBuilder = new StringBuilder(1024);
|
||||
dslBuilder.append("@startuml").append(LINE);
|
||||
|
||||
// configuration
|
||||
dslBuilder.append("' hide the spot").append(LINE);
|
||||
dslBuilder.append("hide circle").append(LINE);
|
||||
|
||||
// entities
|
||||
String entities = databaseDocument.getTables()
|
||||
.stream()
|
||||
.map(table -> toErDsl(table))
|
||||
.collect(Collectors.joining(LINE));
|
||||
dslBuilder.append(entities);
|
||||
|
||||
// relation
|
||||
dslBuilder.append(LINE);
|
||||
String relations = foreignKeyRelations.stream()
|
||||
.collect(Collectors.joining(LINE));
|
||||
dslBuilder.append(relations);
|
||||
dslBuilder.append(LINE);
|
||||
|
||||
dslBuilder.append("@enduml");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("------------------------------");
|
||||
log.debug(dslBuilder.toString());
|
||||
log.debug("------------------------------");
|
||||
}
|
||||
return dslBuilder.toString();
|
||||
}
|
||||
|
||||
private String toErDsl(TableDocumentResponse table) {
|
||||
StringBuilder dslBuilder = new StringBuilder(1024);
|
||||
dslBuilder.append("entity ").append(table.getName())
|
||||
.append(" {");
|
||||
table.getColumns()
|
||||
.stream()
|
||||
.filter(TableDocumentResponse.ColumnDocumentResponse::getIsPrimaryKey)
|
||||
.forEach(primaryCol -> {
|
||||
dslBuilder.append(LINE);
|
||||
dslBuilder.append("*")
|
||||
.append(primaryCol.getName())
|
||||
.append(" : ")
|
||||
.append(primaryCol.getType())
|
||||
.append("(")
|
||||
.append(primaryCol.getSize())
|
||||
.append(")")
|
||||
.append(" <PK> ");
|
||||
dslBuilder.append(LINE);
|
||||
dslBuilder.append("--");
|
||||
});
|
||||
table.getColumns()
|
||||
.stream()
|
||||
.filter(col -> !col.getIsPrimaryKey())
|
||||
.forEach(col -> {
|
||||
dslBuilder.append(LINE);
|
||||
if ("NO".equalsIgnoreCase(col.getNullable())) {
|
||||
dslBuilder.append("*");
|
||||
}
|
||||
dslBuilder.append(col.getName())
|
||||
.append(" : ")
|
||||
.append(col.getType())
|
||||
.append("(")
|
||||
.append(col.getSize())
|
||||
.append(")");
|
||||
if (col.getComment() != null && !"".equals(col.getComment().trim())) {
|
||||
dslBuilder.append(" /* ").append(col.getComment()).append(" */");
|
||||
}
|
||||
dslBuilder.append(LINE);
|
||||
});
|
||||
dslBuilder.append("}");
|
||||
dslBuilder.append(LINE);
|
||||
|
||||
table.getForeignKeys().forEach(fk -> {
|
||||
String fkTableName = fk.getFkTableName();
|
||||
String fkColumnName = fk.getFkColumnName();
|
||||
String pkTableName = fk.getPkTableName();
|
||||
String pkColumnName = fk.getPkColumnName();
|
||||
StringBuilder relationBuilder = new StringBuilder();
|
||||
relationBuilder.append(fkTableName).append("::").append(fkColumnName)
|
||||
.append(" --> ")
|
||||
.append(pkTableName).append("::").append(pkColumnName)
|
||||
.append(" : ")
|
||||
.append(Objects.requireNonNullElse(fk.getFkName(), ""));
|
||||
foreignKeyRelations.add(relationBuilder.toString());
|
||||
});
|
||||
return dslBuilder.toString();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.databasir.core.domain.document.generator.plantuml;
|
||||
|
||||
import com.databasir.core.domain.document.generator.DocumentFileType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class PlantUmlErSvgFileGenerator extends BasePlantUmlFileGenerator {
|
||||
|
||||
@Override
|
||||
public boolean support(DocumentFileType type) {
|
||||
return type == DocumentFileType.PLANT_UML_ER_SVG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileFormatOption fileFormatOption() {
|
||||
return new FileFormatOption(FileFormat.SVG);
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package com.databasir.core.domain.document.generator.plantuml;
|
||||
|
||||
import com.databasir.core.domain.document.generator.DocumentFileType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class PlantUmlPngFileGenerator extends BasePlantUmlFileGenerator {
|
||||
|
||||
@Override
|
||||
public boolean support(DocumentFileType type) {
|
||||
return type == DocumentFileType.PLANT_UML_ER_PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileFormatOption fileFormatOption() {
|
||||
return new FileFormatOption(FileFormat.PNG);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user