getMap();
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/ITableColumn.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo;
2 |
3 | import com.intellij.database.model.DataType;
4 |
5 | /**
6 | * 数据库表字段信息(数据库表列对象信息)
7 | *
8 | * @author HouKunLin
9 | */
10 | public interface ITableColumn {
11 | /**
12 | * 获得字段名称
13 | *
14 | * @return 字段名称
15 | */
16 | String getName();
17 |
18 | /**
19 | * 获得字段注释内容
20 | *
21 | * @return 注释内容
22 | */
23 | String getComment();
24 |
25 | /**
26 | * 获得字段类型名称(短名称)
27 | *
28 | * @return 字段类型名称(短名称)
29 | */
30 | String getTypeName();
31 |
32 | /**
33 | * 获得数据库的字段数据类型(IDEA内置对象)
34 | *
35 | * @return 字段类型信息
36 | */
37 | DataType getDataType();
38 |
39 | /**
40 | * 获得字段类型名称(长名称、完整名称)
41 | *
42 | * @return 字段类型名称(长名称、完整名称)
43 | */
44 | String getFullTypeName();
45 |
46 | /**
47 | * 获取是否是主键字段
48 | *
49 | * @return 是否是主键
50 | */
51 | boolean isPrimaryKey();
52 |
53 | /**
54 | * 获取是否选中该字段
55 | *
56 | * @return 是否选中该字段
57 | */
58 | boolean isSelected();
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/IEntityField.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo;
2 |
3 | import com.intellij.database.model.DataType;
4 |
5 | /**
6 | * 实体类字段信息
7 | *
8 | * @author HouKunLin
9 | */
10 | public interface IEntityField {
11 | /**
12 | * 获得字段名称(变量名称)
13 | *
14 | * @return 字段名称(驼峰形式,首字母小写)
15 | */
16 | IName getName();
17 |
18 | /**
19 | * 获得字段注释内容
20 | *
21 | * @return 注释内容
22 | */
23 | String getComment();
24 |
25 | /**
26 | * 获得字段类型名称(短名称)
27 | *
28 | * @return 字段类型名称(短名称)
29 | */
30 | String getTypeName();
31 |
32 | /**
33 | * 获得数据库的字段数据类型(IDEA内置对象)
34 | *
35 | * @return 字段类型信息
36 | */
37 | DataType getDataType();
38 |
39 | /**
40 | * 获得字段类型名称(长名称、完整名称)
41 | *
42 | * @return 字段类型名称(长名称、完整名称)
43 | */
44 | String getFullTypeName();
45 |
46 | /**
47 | * 获取是否是主键字段
48 | *
49 | * @return 是否是主键
50 | */
51 | boolean isPrimaryKey();
52 |
53 | /**
54 | * 获取是否选中该字段
55 | *
56 | * @return 是否选中该字段
57 | */
58 | boolean isSelected();
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/resources/templates/default/velocity/java/Entity.java.vm:
--------------------------------------------------------------------------------
1 | ${gen.setType("entity")}
2 | package ${entity.packages.entity};
3 |
4 | import com.baomidou.mybatisplus.annotation.*;
5 |
6 | ${entity.packages}
7 |
8 | import java.io.Serializable;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.NoArgsConstructor;
13 |
14 | /**
15 | * 实体类:${entity.comment}#if($table.comment.trim.length gt 0 && $entity.comment != $table.comment) (${table.comment})#end
16 | *
17 | * @author ${developer.author}
18 | */
19 | @Data
20 | @Builder
21 | @NoArgsConstructor
22 | @AllArgsConstructor
23 | @TableName("${table.name}")
24 | public class ${entity.name.entity} implements Serializable{
25 | #foreach($field in $fields)
26 | #if($field.selected)
27 | /**
28 | * ${field.comment}
29 | #if($field.column.comment.trim.length gt 0 && $field.comment != $field.column.comment) * 数据库字段说明:${field.column.comment}
#end
30 | */
31 | #if ($field.primaryKey)
32 | @TableId(type = IdType.ASSIGN_ID)
33 | #end
34 | private ${field.typeName} ${field.name};
35 | #end
36 | #end
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/resources/templates/default/freemarker/java/EntityVo.java.ftl:
--------------------------------------------------------------------------------
1 | ${gen.setFilename("${entity.name}Vo.java")}
2 | ${gen.setFilepath("${settings.javaPath}/${entity.packages.entity}/")}
3 | package ${entity.packages.entity};
4 |
5 | ${entity.packages}
6 |
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.NoArgsConstructor;
13 | import java.io.Serializable;
14 |
15 | /**
16 | * 视图对象:${entity.comment}<#if table.comment?trim?length gt 0 && entity.comment != table.comment> (${table.comment})#if>
17 | *
18 | * @author ${developer.author}
19 | */
20 | @ApiModel("视图对象:${entity.comment}")
21 | @Data
22 | @Builder
23 | @NoArgsConstructor
24 | @AllArgsConstructor
25 | public class ${entity.name}Vo implements Serializable {
26 | <#list fields as field>
27 | <#if field.selected>
28 | /**
29 | * ${field.comment}
30 | <#if field.column.comment?trim?length gt 0 && field.comment != field.column.comment> * 数据库字段说明:${field.column.comment}
#if>
31 | */
32 | @ApiModelProperty("${field.comment}")
33 | private ${field.typeName} ${field.name};
34 | #if>
35 | #list>
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | Database Generator
3 | 侯坤林
4 |
5 |
7 | com.intellij.modules.lang
8 | com.intellij.modules.platform
9 | com.intellij.modules.java
10 | com.intellij.database
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/SelectTemplate.form:
--------------------------------------------------------------------------------
1 |
2 |
32 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/BaseTypeMap.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Settings;
4 | import com.github.houkunlin.model.FileType;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 | import java.util.function.Function;
9 |
10 | /**
11 | * 一个基础的类型映射,子类必须显示调用{@link #init(Settings, Function)} 进行初始化。
12 | *
13 | * @author daiwenzh5
14 | */
15 | public abstract class BaseTypeMap {
16 |
17 | private final Map map = new HashMap<>();
18 |
19 | private boolean initialized = false;
20 |
21 | /**
22 | * 根据类型获取值
23 | *
24 | * @param type 类型
25 | * @return 映射值
26 | */
27 | public final T get(String type) {
28 | if (!initialized) {
29 | throw new IllegalStateException("请先调用 init() 方法初始化");
30 | }
31 | return map.get(type);
32 | }
33 |
34 | /**
35 | * 初始化类型映射
36 | *
37 | * @param settings 设置信息
38 | * @param mapping 映射器
39 | */
40 | protected void init(Settings settings, Function mapping) {
41 | map.clear();
42 | settings.getFileTypes()
43 | .forEach(item -> map.put(item.getType(), mapping.apply(item)));
44 | this.initialized = true;
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/FieldNameInfo.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.vo.IName;
5 | import com.google.common.base.CaseFormat;
6 | import com.intellij.database.model.DasColumn;
7 | import lombok.Getter;
8 |
9 | /**
10 | * Java字段名称对象
11 | *
12 | * @author HouKunLin
13 | */
14 | @Getter
15 | public class FieldNameInfo implements IName {
16 | private final String value;
17 | private final String firstUpper;
18 | private final String firstLower;
19 |
20 | /**
21 | * @param firstLower 首字母小写
22 | */
23 | public FieldNameInfo(String firstLower) {
24 | this.value = firstLower;
25 | this.firstUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, value);
26 | this.firstLower = firstLower;
27 | }
28 |
29 | public FieldNameInfo(DasColumn dbColumn, Options options) {
30 | // 把减号替换成下划线
31 | this.value = options.obtainCaseFormat().to(CaseFormat.LOWER_CAMEL, dbColumn.getName().replaceAll("-", "_"));
32 | this.firstUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, value);
33 | this.firstLower = value;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return value;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/template/beetl/BeetlErrorHandler.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.template.beetl;
2 |
3 | import org.beetl.core.ConsoleErrorHandler;
4 | import org.beetl.core.GroupTemplate;
5 | import org.beetl.core.exception.BeetlException;
6 | import org.beetl.core.io.NoLockStringWriter;
7 |
8 | import java.io.IOException;
9 | import java.io.Writer;
10 |
11 | /**
12 | * Beetl 模板的异常处理器
13 | *
14 | * @author HouKunLin
15 | */
16 | public class BeetlErrorHandler extends ConsoleErrorHandler {
17 | @Override
18 | public void processException(BeetlException ex, GroupTemplate groupTemplate, Writer writer) {
19 | Writer w = new NoLockStringWriter();
20 | super.processException(ex, groupTemplate, w);
21 | throw new RuntimeException(w.toString(), ex);
22 | }
23 |
24 | @Override
25 | protected void println(Writer w, String msg) {
26 | append(w, msg, "\n");
27 | super.println(w, msg);
28 | }
29 |
30 | @Override
31 | protected void print(Writer w, String msg) {
32 | append(w, msg);
33 | super.print(w, msg);
34 | }
35 |
36 | private void append(Writer w, String... strings) {
37 | try {
38 | for (String string : strings) {
39 | w.append(string);
40 | }
41 | } catch (IOException ignored) {
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/EntityPackage.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Settings;
4 | import lombok.Getter;
5 |
6 | import java.util.HashSet;
7 | import java.util.stream.Collectors;
8 |
9 | /**
10 | * 实体类对象的包信息
11 | *
12 | * @author HouKunLin
13 | */
14 | @Getter
15 | public class EntityPackage extends BaseTypeMap {
16 | /**
17 | * 实体类字段所需要导入的包列表
18 | */
19 | private final HashSet list = new HashSet<>();
20 | private String toString = "";
21 |
22 | public void add(String fullPackageName) {
23 | if (fullPackageName.startsWith("java.lang.")) {
24 | return;
25 | }
26 | list.add(fullPackageName);
27 | }
28 |
29 |
30 | public void initMore(Settings settings, EntityName entityName) {
31 | init(settings, item -> new EntityPackageInfo(item.getPackageName(), entityName.get(item.getType())));
32 | }
33 |
34 |
35 | public void clear() {
36 | list.clear();
37 | toString = "";
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | if (toString == null || toString.isBlank()) {
43 | toString = list.stream().map(item -> String.format("import %s;\n", item)).collect(Collectors.joining());
44 | }
45 | return toString;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/resources/templates/default/freemarker/java/EntityQuery.java.ftl:
--------------------------------------------------------------------------------
1 | ${gen.setFilename("${entity.name}Query.java")}
2 | ${gen.setFilepath("${settings.javaPath}/${entity.packages.entity}/")}
3 | package ${entity.packages.entity};
4 |
5 | ${entity.packages}
6 |
7 | import io.swagger.annotations.ApiModel;
8 | import io.swagger.annotations.ApiModelProperty;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.NoArgsConstructor;
13 |
14 | /**
15 | * 查询对象:${entity.comment}<#if table.comment?trim?length gt 0 && entity.comment != table.comment> (${table.comment})#if>
16 | *
17 | * @author ${developer.author}
18 | */
19 | @ApiModel("查询对象:${entity.comment}")
20 | @Data
21 | @Builder
22 | @NoArgsConstructor
23 | @AllArgsConstructor
24 | public class ${entity.name}Query {
25 | <#list fields as field>
26 | <#if field.selected>
27 | <#if field.name?starts_with("created") || field.name?starts_with("updated") || field.name?starts_with("deleted") >
28 | <#else>
29 | /**
30 | * ${field.comment}
31 | <#if field.column.comment?trim?length gt 0 && field.comment != field.column.comment> * 数据库字段说明:${field.column.comment}
#if>
32 | */
33 | @ApiModelProperty("${field.comment}")
34 | private ${field.typeName} ${field.name};
35 | #if>
36 | #if>
37 | #list>
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/resources/templates/default/freemarker/java/Entity.java.ftl:
--------------------------------------------------------------------------------
1 | ${gen.setType("entity")}
2 | package ${entity.packages.entity};
3 |
4 | import com.baomidou.mybatisplus.annotation.*;
5 |
6 | ${entity.packages}
7 |
8 | import java.io.Serializable;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.NoArgsConstructor;
13 |
14 | /**
15 | * 实体类:${entity.comment}<#if table.comment?trim?length gt 0 && entity.comment != table.comment> (${table.comment})#if>
16 | *
17 | * @author ${developer.author}
18 | */
19 | @Data
20 | @Builder
21 | @NoArgsConstructor
22 | @AllArgsConstructor
23 | @TableName("${table.name}")
24 | public class ${entity.name.entity} implements Serializable {
25 | <#list fields as field>
26 | <#if field.selected>
27 | /**
28 | * ${field.comment}
29 | <#if field.column.comment?trim?length gt 0 && field.comment != field.column.comment> * 数据库字段说明:${field.column.comment}
#if>
30 | */
31 | <#if field.primaryKey>
32 | @TableId(type = IdType.ASSIGN_ID)
33 | #if>
34 | <#if field.name?starts_with("created") || field.name?starts_with("updated") || field.name?starts_with("deleted")>
35 | @TableField(insertStrategy = FieldStrategy.NEVER, updateStrategy = FieldStrategy.NEVER)
36 | #if>
37 | private ${field.typeName} ${field.name};
38 | #if>
39 | #list>
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/TextFieldDocumentUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win;
2 |
3 | import com.intellij.openapi.editor.Document;
4 | import com.intellij.ui.EditorTextField;
5 |
6 | import javax.swing.text.JTextComponent;
7 | import java.util.function.Consumer;
8 |
9 | /**
10 | * 输入框修改内容工具
11 | *
12 | * @author HouKunLin
13 | */
14 | public class TextFieldDocumentUtil {
15 |
16 | /**
17 | * 更新配置信息的值
18 | *
19 | * @param document 文档
20 | * @param component 输入框组件
21 | * @param setValue 设置配置信息的set方法
22 | * @return 是否成功
23 | */
24 | public static boolean updateSettingValue(Document document, EditorTextField component, Consumer setValue) {
25 | if (document == component.getDocument()) {
26 | setValue.accept(component.getText());
27 | return true;
28 | }
29 | return false;
30 | }
31 |
32 | /**
33 | * 更新配置信息的值
34 | *
35 | * @param document 文档
36 | * @param component 输入框组件
37 | * @param setValue 设置配置信息的set方法
38 | * @return 是否成功
39 | */
40 | public static boolean updateSettingValue(javax.swing.text.Document document, JTextComponent component, Consumer setValue) {
41 | if (document == component.getDocument()) {
42 | setValue.accept(component.getText());
43 | return true;
44 | }
45 | return false;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/EntityImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.config.Settings;
5 | import com.github.houkunlin.vo.IEntity;
6 | import com.intellij.database.psi.DbTable;
7 | import lombok.Getter;
8 | import lombok.Setter;
9 |
10 | import java.util.Objects;
11 | import java.util.Set;
12 |
13 | /**
14 | * 实体类信息
15 | *
16 | * @author HouKunLin
17 | */
18 | @Getter
19 | public class EntityImpl implements IEntity {
20 | private final EntityPackage packages = new EntityPackage();
21 | private EntityName name;
22 | @Setter
23 | private String comment;
24 | @Setter
25 | private String uri;
26 |
27 | public EntityImpl(DbTable dbTable, Options options) {
28 | this.comment = Objects.toString(dbTable.getComment(), "");
29 | this.name = new EntityName(dbTable, options);
30 | }
31 |
32 | public void setName(String name) {
33 | this.name = new EntityName(name);
34 | }
35 |
36 | /**
37 | * 初始化更多的信息
38 | *
39 | * @param fullTypeNames 字段类型名称列表
40 | * @param settings 设置信息对象(用来初始化包名信息)
41 | */
42 | public void initMore(Set fullTypeNames, Settings settings) {
43 | packages.clear();
44 | fullTypeNames.forEach(packages::add);
45 | name.initMore(settings);
46 | packages.initMore(settings, name);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/Variable.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * 模板传递给程序的变量信息
7 | *
8 | * @author HouKunLin
9 | */
10 | public class Variable {
11 | @Getter
12 | public static String filename;
13 | @Getter
14 | public static String filepath;
15 | @Getter
16 | public static String type;
17 |
18 | private static Variable instance;
19 |
20 | private Variable() {
21 | }
22 |
23 | public synchronized static Variable getInstance() {
24 | if (instance == null) {
25 | instance = new Variable();
26 | }
27 | resetVariables();
28 | return instance;
29 | }
30 |
31 | public static void resetVariables() {
32 | filename = null;
33 | filepath = null;
34 | type = null;
35 | }
36 |
37 | public static void setFilename(String filename) {
38 | Variable.filename = filename;
39 | }
40 |
41 | public static void setFilepath(String filepath) {
42 | Variable.filepath = filepath;
43 | }
44 |
45 | public static void setType(String type) {
46 | Variable.type = type;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return "Variable{" +
52 | "filename='" + filename + '\'' +
53 | ", filepath='" + filepath + '\'' +
54 | ", type='" + type + '\'' +
55 | '}';
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 |
24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
25 | hs_err_pid*
26 |
27 | ### JetBrains template
28 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
29 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
30 |
31 | # User-specific stuff
32 | .idea/
33 | *.iml
34 |
35 | # CMake
36 | cmake-build-*/
37 |
38 | # File-based project format
39 | *.iws
40 |
41 | # IntelliJ
42 | out/
43 |
44 | # mpeltonen/sbt-idea plugin
45 | .idea_modules/
46 |
47 | # JIRA plugin
48 | atlassian-ide-plugin.xml
49 |
50 | # Crashlytics plugin (for Android Studio and IntelliJ)
51 | com_crashlytics_export_strings.xml
52 | crashlytics.properties
53 | crashlytics-build.properties
54 | fabric.properties
55 |
56 | ### Gradle template
57 | .gradle
58 | gradle.properties
59 | /build/
60 |
61 | # Ignore Gradle GUI config
62 | gradle-app.setting
63 |
64 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
65 | !gradle-wrapper.jar
66 |
67 | # Cache of project
68 | .gradletasknamecache
69 |
70 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
71 | # gradle/wrapper/gradle-wrapper.properties
72 |
73 | idea-sandbox/
74 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/EntityName.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.config.Settings;
5 | import com.github.houkunlin.vo.IName;
6 | import com.google.common.base.CaseFormat;
7 | import com.intellij.database.psi.DbTable;
8 | import lombok.Getter;
9 |
10 | /**
11 | * 实体类名称对象。提供方便直接获取 Entity、Service、ServiceImpl、Dao、Controller 的对象完整名称
12 | *
13 | * @author HouKunLin
14 | */
15 | @Getter
16 | public class EntityName extends BaseTypeMap implements IName {
17 | private final String value;
18 | private final String firstUpper;
19 | private final String firstLower;
20 |
21 | public EntityName(DbTable dbTable, Options options) {
22 | // 把减号替换成下划线
23 | this.value = options.obtainCaseFormat().to(CaseFormat.UPPER_CAMEL, dbTable.getName().replaceAll("-", "_"));
24 | this.firstUpper = value;
25 | this.firstLower = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, value);
26 | }
27 |
28 | public EntityName(String name) {
29 | this.value = name;
30 | this.firstUpper = value;
31 | this.firstLower = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, value);
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return value;
37 | }
38 |
39 | public void initMore(Settings settings) {
40 | init(settings, item -> new EntityNameInfo(value, item.getSuffix()));
41 | }
42 |
43 | private IName build(String suffix) {
44 | return new EntityNameInfo(value, suffix);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/table/ColumnSpec.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.table;
2 |
3 | import lombok.AccessLevel;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Getter;
6 |
7 | import javax.swing.table.TableCellEditor;
8 | import java.util.function.BiConsumer;
9 | import java.util.function.Function;
10 |
11 | /**
12 | * 通用的列信息
13 | *
14 | * @author daiwenzh5
15 | * @since 2.8.4
16 | */
17 | @Getter
18 | @AllArgsConstructor(access = AccessLevel.PRIVATE)
19 | public class ColumnSpec {
20 | private final String name;
21 | private final Class type;
22 | private final Function getter;
23 | private final BiConsumer setter;
24 | private boolean editable;
25 | private TableCellEditor cellEditor;
26 | private String placeholder;
27 | private int width;
28 |
29 |
30 | public static ColumnSpec of(String name, Class type, Function getter, BiConsumer setter) {
31 | return new ColumnSpec<>(name, type, getter, setter, true, null, null, 0);
32 | }
33 |
34 | public ColumnSpec withEditable(boolean editable) {
35 | this.editable = editable;
36 | return this;
37 | }
38 |
39 | public ColumnSpec withCellEditor(TableCellEditor cellEditor) {
40 | this.cellEditor = cellEditor;
41 | return this;
42 | }
43 |
44 | public ColumnSpec withPlaceholder(String placeholder) {
45 | this.placeholder = placeholder;
46 | return this;
47 | }
48 |
49 | public ColumnSpec withWidth(int width) {
50 | this.width = width;
51 | return this;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/RootModel.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.config.Settings;
5 | import com.github.houkunlin.vo.IEntityField;
6 | import com.github.houkunlin.vo.ITable;
7 | import com.github.houkunlin.vo.ITableColumn;
8 | import com.intellij.database.psi.DbTable;
9 | import lombok.Getter;
10 |
11 | import java.util.List;
12 | import java.util.Set;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * 完整的类型信息
17 | *
18 | * @author HouKunLin
19 | */
20 | @Getter
21 | public class RootModel {
22 | /**
23 | * 实体对象信息
24 | */
25 | private final EntityImpl entity;
26 | /**
27 | * 实体对象字段列表
28 | */
29 | private final List extends IEntityField> fields;
30 | /**
31 | * 数据库表信息
32 | */
33 | private final ITable table;
34 | /**
35 | * 数据库表字段列表
36 | */
37 | private final List extends ITableColumn> columns;
38 |
39 | private final PrimaryInfo primary;
40 |
41 | public RootModel(DbTable dbTable, List fields, List columns, Options options) {
42 | this.table = new TableImpl(dbTable);
43 | this.entity = new EntityImpl(dbTable, options);
44 | this.fields = fields;
45 | this.columns = columns;
46 | this.primary = new PrimaryInfo(fields);
47 | }
48 |
49 | public EntityImpl getEntity(Settings settings) {
50 | Set fullTypeNames = fields.stream().map(IEntityField::getFullTypeName).collect(Collectors.toSet());
51 | entity.initMore(fullTypeNames, settings);
52 | return entity;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/model/TableColumnType.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.model;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.List;
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | /**
10 | * 字段类型数据
11 | *
12 | * @author HouKunLin
13 | */
14 | @Data
15 | public class TableColumnType {
16 | public static final TableColumnType DEFAULT = new TableColumnType(true);
17 | /**
18 | * 数据库对应的类型
19 | */
20 | private List dbTypes;
21 | /**
22 | * 短名称
23 | */
24 | private String shortName;
25 | /**
26 | * 长名称
27 | */
28 | private String longName;
29 | /**
30 | * 是否是默认的类型
31 | */
32 | private Boolean isDefault = false;
33 |
34 | public TableColumnType() {
35 | }
36 |
37 | private TableColumnType(boolean isDefault) {
38 | this.isDefault = isDefault;
39 | if (isDefault) {
40 | this.shortName = "Object";
41 | this.longName = "java.lang.Object";
42 | }
43 | }
44 |
45 | /**
46 | * 判断一个数据库类型是否在这个对象里面
47 | *
48 | * @param dbType 数据库字段类
49 | * @return 判断结果
50 | */
51 | public boolean at(String dbType) {
52 | if (dbTypes == null) {
53 | return false;
54 | }
55 | if (dbTypes.contains(dbType)) {
56 | return true;
57 | }
58 | for (String type : dbTypes) {
59 | Matcher matcher = Pattern.compile(type).matcher(dbType);
60 | if (matcher.find()) {
61 | return true;
62 | }
63 | }
64 | return false;
65 | }
66 |
67 | public boolean isDefault() {
68 | return isDefault != null && isDefault;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/PrimaryInfo.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.vo.IEntityField;
4 | import com.github.houkunlin.vo.ITableColumn;
5 | import lombok.Getter;
6 |
7 | import java.util.List;
8 | import java.util.stream.Collectors;
9 |
10 | /**
11 | * 主键信息
12 | *
13 | * @author HouKunLin
14 | */
15 | @Getter
16 | public class PrimaryInfo {
17 | /**
18 | * 主键的Java字段对象
19 | */
20 | private final IEntityField field;
21 |
22 | /**
23 | * 主键的数据库字段对象
24 | */
25 | private final ITableColumn column;
26 |
27 | /**
28 | * 实体对象字段列表(主键列表)
29 | */
30 | private final List extends IEntityField> fields;
31 |
32 | /**
33 | * 数据库表字段列表(主键列表)
34 | */
35 | private final List extends ITableColumn> columns;
36 |
37 | public PrimaryInfo(List fields) {
38 | List collect = fields.stream().filter(EntityFieldImpl::isPrimaryKey).collect(Collectors.toList());
39 | EntityFieldImpl primaryField;
40 | if (collect.isEmpty()) {
41 | // 没有主键对象,创建一个默认的主键对象
42 | primaryField = EntityFieldImpl.primaryField("id", "String", "java.lang.String", "主键ID");
43 | TableColumnImpl tableColumn = TableColumnImpl.primaryColumn("id", "varchar", "varchar(255)", "主键ID");
44 | primaryField.setColumn(tableColumn);
45 | tableColumn.setField(primaryField);
46 | } else {
47 | primaryField = collect.get(0);
48 | }
49 | this.field = primaryField;
50 | this.column = primaryField.getColumn();
51 | this.fields = collect;
52 | this.columns = collect.stream().map(EntityFieldImpl::getColumn).collect(Collectors.toList());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/template/freemarker/FreemarkerTemplateGenerator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.template.freemarker;
2 |
3 | import com.github.houkunlin.template.AbstractScriptedTemplateGenerator;
4 | import freemarker.template.Configuration;
5 | import freemarker.template.Template;
6 |
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.io.StringReader;
10 | import java.io.StringWriter;
11 | import java.util.Map;
12 |
13 | /**
14 | * @author daiwenzh5
15 | * @since 1.0
16 | */
17 | public class FreemarkerTemplateGenerator extends AbstractScriptedTemplateGenerator {
18 |
19 | private final Configuration configuration;
20 |
21 | public FreemarkerTemplateGenerator(File workspace) throws IOException {
22 | super(workspace);
23 | // 把freemarker的jar包添加到工程中
24 | // 创建一个Configuration对象
25 | configuration = new Configuration(Configuration.VERSION_2_3_30);
26 | // 设置config的默认字符集。一般是utf-8
27 | configuration.setDefaultEncoding("utf-8");
28 | configuration.setDirectoryForTemplateLoading(getTemplateDir());
29 | }
30 |
31 | @Override
32 | protected String doGenerate(String templateName, Map context) throws Exception {
33 | var template = configuration.getTemplate(templateName);
34 | var out = new StringWriter();
35 | template.process(context, out);
36 | return out.toString();
37 | }
38 |
39 | @Override
40 | protected String doGenerateInline(String templateContent, Map context) throws Exception {
41 | var template = new Template(null, new StringReader(templateContent), configuration);
42 | var out = new StringWriter();
43 | template.process(context, out);
44 | return out.toString();
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/table/TableDecorator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.table;
2 |
3 | import com.github.houkunlin.message.Bundles;
4 | import com.intellij.ui.ToolbarDecorator;
5 | import com.intellij.ui.table.JBTable;
6 | import lombok.Getter;
7 |
8 | import javax.swing.*;
9 | import java.util.List;
10 | import java.util.Objects;
11 | import java.util.function.BiConsumer;
12 |
13 | /**
14 | * 通用的表格装饰器
15 | *
16 | * @author daiwenzh5
17 | * @since 2.8.4
18 | */
19 | @SuppressWarnings("unchecked")
20 | public class TableDecorator> {
21 |
22 | protected final JBTable table = new JBTable();
23 |
24 | @Getter
25 | private GenericTableModel model;
26 |
27 | public final T setModel(GenericTableModel model) {
28 | Objects.requireNonNull(model, Bundles.message("table-decorator.not-null"));
29 | this.model = model.bindTable(table);
30 | return getSelf();
31 | }
32 |
33 | /**
34 | * 添加工具类
35 | *
36 | * @param configuration 配置
37 | * @return 带工具栏的表格面板
38 | */
39 | public final JPanel applyToolbar(BiConsumer configuration) {
40 | var decorator = ToolbarDecorator.createDecorator(table);
41 | configuration.accept(getSelf(), decorator);
42 | return decorator.createPanel();
43 | }
44 |
45 | /**
46 | * 重置表格数据
47 | */
48 | public void reset() {
49 | this.model.clear();
50 | }
51 |
52 | /**
53 | * 重置表格数据,并添加数据
54 | *
55 | * @param data 表格数据
56 | */
57 | public void reset(List data) {
58 | this.model
59 | .clear(false)
60 | .addRows(data);
61 | }
62 |
63 | private T getSelf() {
64 | return (T) this;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/template/velocity/VelocityTemplateGenerator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.template.velocity;
2 |
3 | import com.github.houkunlin.template.AbstractScriptedTemplateGenerator;
4 | import com.github.houkunlin.util.IO;
5 | import org.apache.velocity.VelocityContext;
6 | import org.apache.velocity.app.VelocityEngine;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.io.StringWriter;
11 | import java.util.Map;
12 | import java.util.Properties;
13 |
14 | /**
15 | * 基于velocity的模板生成器
16 | *
17 | * @author daiwenzh5
18 | * @since 1.0
19 | */
20 | public class VelocityTemplateGenerator extends AbstractScriptedTemplateGenerator {
21 |
22 | private final VelocityEngine engine;
23 |
24 | public VelocityTemplateGenerator(File workspace) throws IOException {
25 | super(workspace);
26 | var properties = new Properties();
27 | properties.load(IO.getInputStream("velocity.properties"));
28 | engine = new VelocityEngine(properties);
29 | engine.setProperty("resource.loader.file.path", getTemplateDir().getAbsolutePath());
30 | engine.init();
31 | }
32 |
33 | @Override
34 | protected String doGenerate(String templateName, Map context_) {
35 | var context = new VelocityContext(context_);
36 | var template = engine.getTemplate(templateName);
37 | var out = new StringWriter();
38 | template.merge(context, out);
39 | return out.toString();
40 | }
41 |
42 | @Override
43 | protected String doGenerateInline(String templateContent, Map context_) {
44 | var context = new VelocityContext(context_);
45 | var out = new StringWriter();
46 | engine.evaluate(context, out, "", templateContent);
47 | return out.toString();
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/templates/jdbc-type.ftl:
--------------------------------------------------------------------------------
1 | <#-- MyBatis 官方的JdbcType列表:https://mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html -->
2 | <#assign JdbcTypes = {
3 | "ARRAY":"ARRAY",
4 | "BIGINT":"BIGINT",
5 | "BINARY":"BINARY",
6 | "BIT":"BIT",
7 | "BLOB":"BLOB",
8 | "BOOLEAN":"BOOLEAN",
9 | "CHAR":"CHAR",
10 | "CLOB":"CLOB",
11 | "CURSOR":"CURSOR",
12 | "DATALINK":"DATALINK",
13 | "DATE":"DATE",
14 | "DATETIMEOFFSET":"DATETIMEOFFSET",
15 | "DECIMAL":"DECIMAL",
16 | "DISTINCT":"DISTINCT",
17 | "DOUBLE":"DOUBLE",
18 | "FLOAT":"FLOAT",
19 | "INTEGER":"INTEGER",
20 | "JAVA_OBJECT":"JAVA_OBJECT",
21 | "LONGNVARCHAR":"LONGNVARCHAR",
22 | "LONGVARBINARY":"LONGVARBINARY",
23 | "LONGVARCHAR":"LONGVARCHAR",
24 | "NCHAR":"NCHAR",
25 | "NCLOB":"NCLOB",
26 | "NULL":"NULL",
27 | "NUMERIC":"NUMERIC",
28 | "NVARCHAR":"NVARCHAR",
29 | "REAL":"REAL",
30 | "REF":"REF",
31 | "ROWID":"ROWID",
32 | "SMALLINT":"SMALLINT",
33 | "SQLXML":"SQLXML",
34 | "STRUCT":"STRUCT",
35 | "TIME":"TIME",
36 | "TIMESTAMP":"TIMESTAMP",
37 | "TINYINT":"TINYINT",
38 | "UNDEFINED":"UNDEFINED",
39 | "VARBINARY":"VARBINARY",
40 | "VARCHAR":"VARCHAR"
41 | } />
42 | <#-- 部分未考虑到的类型映射 -->
43 | <#assign OtherTypes = {
44 | "DATETIME":"TIMESTAMP",
45 | "INT":"INTEGER",
46 | "TINYINT":"INTEGER",
47 | "MEDIUMINT":"INTEGER",
48 | "SMALLINT":"INTEGER",
49 | "YEAR":"INTEGER",
50 | "MULTIPOINT":"INTEGER",
51 | "POINT":"INTEGER",
52 | "TEXT":"LONGVARCHAR",
53 | "LONGTEXT":"LONGVARCHAR",
54 | "MEDIUMTEXT":"VARCHAR",
55 | "MULTILINESTRING":"VARCHAR",
56 | "TINYTEXT":"VARCHAR",
57 | "LINESTRING":"VARCHAR",
58 | "LONGBLOB":"BLOB",
59 | "MEDIUMBLOB":"BLOB",
60 | "TINYBLOB":"BLOB"
61 | } />
62 | <#-- 获取JdbcType信息 -->
63 | <#function jdbcType column>
64 | <#assign type = column.typeName?replace(" unsigned", "")?upper_case />
65 | <#if JdbcTypes[type]??>
66 | <#return JdbcTypes[type]>
67 | #if>
68 | <#if OtherTypes[type]??>
69 | <#return OtherTypes[type]>
70 | #if>
71 | <#return 'OTHER'>
72 | #function>
--------------------------------------------------------------------------------
/templates/jdbc-typescript-type.ftl:
--------------------------------------------------------------------------------
1 | <#-- MyBatis 官方的JdbcType列表:https://mybatis.org/mybatis-3/apidocs/reference/org/apache/ibatis/type/JdbcType.html -->
2 | <#assign JdbcTypeToTypeScriptTypes = {
3 | "ARRAY":"any",
4 | "BIGINT":"bigint",
5 | "BINARY":"any",
6 | "BIT":"boolean",
7 | "BLOB":"any",
8 | "BOOLEAN":"boolean",
9 | "CHAR":"string",
10 | "CLOB":"any",
11 | "CURSOR":"any",
12 | "DATALINK":"any",
13 | "DATE":"Date",
14 | "DATETIMEOFFSET":"any",
15 | "DECIMAL":"number",
16 | "DISTINCT":"any",
17 | "DOUBLE":"number",
18 | "FLOAT":"number",
19 | "INTEGER":"number",
20 | "JAVA_OBJECT":"any",
21 | "LONGNVARCHAR":"string",
22 | "LONGVARBINARY":"any",
23 | "LONGVARCHAR":"number",
24 | "NCHAR":"string",
25 | "NCLOB":"any",
26 | "NULL":"any",
27 | "NUMERIC":"number",
28 | "NVARCHAR":"string",
29 | "REAL":"any",
30 | "REF":"any",
31 | "ROWID":"string",
32 | "SMALLINT":"number",
33 | "SQLXML":"any",
34 | "STRUCT":"any",
35 | "TIME":"Date",
36 | "TIMESTAMP":"Date",
37 | "TINYINT":"number",
38 | "UNDEFINED":"any",
39 | "VARBINARY":"any",
40 | "VARCHAR":"string"
41 | } />
42 | <#-- 部分未考虑到的类型映射 -->
43 | <#assign OtherJdbcTypeToTypeScriptTypes = {
44 | "DATETIME":"Date",
45 | "INT":"number",
46 | "TINYINT":"number",
47 | "MEDIUMINT":"number",
48 | "SMALLINT":"number",
49 | "YEAR":"number",
50 | "MULTIPOINT":"number",
51 | "POINT":"number",
52 | "TEXT":"string",
53 | "LONGTEXT":"string",
54 | "MEDIUMTEXT":"string",
55 | "MULTILINESTRING":"string",
56 | "TINYTEXT":"string",
57 | "LINESTRING":"string",
58 | "LONGBLOB":"any",
59 | "MEDIUMBLOB":"any",
60 | "TINYBLOB":"any"
61 | } />
62 | <#-- 获取 JdbcType 对应的 TypeScript 类型信息 -->
63 | <#function getTypeScriptType column>
64 | <#assign type = column.typeName?replace(" unsigned", "")?upper_case />
65 | <#if JdbcTypeToTypeScriptTypes[type]??>
66 | <#return JdbcTypeToTypeScriptTypes[type]>
67 | #if>
68 | <#if OtherJdbcTypeToTypeScriptTypes[type]??>
69 | <#return OtherJdbcTypeToTypeScriptTypes[type]>
70 | #if>
71 | <#return 'any'>
72 | #function>
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/TableSetting.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.util.PluginUtils;
5 | import com.github.houkunlin.vo.impl.RootModel;
6 | import com.intellij.database.psi.DbTable;
7 | import com.intellij.psi.PsiElement;
8 | import lombok.Data;
9 |
10 | import javax.swing.*;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | /**
15 | * 数据库表配置面板(涵盖多个数据库表的内容)
16 | *
17 | * @author HouKunLin
18 | */
19 | @Data
20 | public class TableSetting implements IWindows {
21 | /**
22 | * 面板:顶级内容面板
23 | */
24 | private JPanel content;
25 | /**
26 | * 标签:包含多个数据库表的标签界面
27 | */
28 | private JTabbedPane tableTabbedPane;
29 | private PsiElement[] psiElements;
30 | private Options options;
31 | private List tablePanels = new ArrayList<>();
32 |
33 | public TableSetting(PsiElement[] psiElements, Options options) {
34 | this.psiElements = psiElements;
35 | this.options = options;
36 | this.reset();
37 | }
38 |
39 | /**
40 | * 重置配置面板
41 | */
42 | public void reset() {
43 | tableTabbedPane.removeAll();
44 | tablePanels.clear();
45 | // 确保即时加载types信息
46 | PluginUtils.resetColumnTypes();
47 | for (PsiElement psiElement : psiElements) {
48 | if (psiElement instanceof DbTable dbTable) {
49 | TablePanel tablePanel = new TablePanel(dbTable, options);
50 | tableTabbedPane.addTab(dbTable.getName(), tablePanel.getContent());
51 | tablePanels.add(tablePanel);
52 | }
53 | }
54 | }
55 |
56 | public List getRootModels() {
57 | List rootModels = new ArrayList<>();
58 | for (TablePanel tablePanel : tablePanels) {
59 | rootModels.add(tablePanel.toModel());
60 | }
61 | return rootModels;
62 | }
63 |
64 | @Override
65 | public JPanel getContent() {
66 | return content;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/util/IO.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.util;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 |
5 | import java.io.ByteArrayOutputStream;
6 | import java.io.Closeable;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 |
10 | public class IO {
11 | private static final Logger log = Logger.getInstance(IO.class);
12 | /**
13 | * 获取资源文件的输入流
14 | *
15 | * @param resources 资源文件
16 | * @return 文件输入流
17 | */
18 | public static InputStream getInputStream(String resources) {
19 | return IO.class.getClassLoader().getResourceAsStream(resources);
20 | }
21 |
22 | /**
23 | * 读取插件内部 Classpath 资源文件内容信息
24 | *
25 | * @param resources 资源路径
26 | * @return 文件内容
27 | */
28 | public static String readResources(String resources) {
29 | return read(getInputStream(resources));
30 | }
31 |
32 | /**
33 | * 从输入流中读取字符串内容
34 | *
35 | * @param inputStream 输入流
36 | * @return 字符串内容
37 | */
38 | public static String read(InputStream inputStream) {
39 | if (inputStream == null) {
40 | return "";
41 | }
42 | byte[] bytes = new byte[1024];
43 | int len;
44 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
45 | try {
46 | while ((len = inputStream.read(bytes)) != -1) {
47 | outputStream.write(bytes, 0, len);
48 | }
49 | outputStream.flush();
50 | return outputStream.toString();
51 | } catch (IOException e) {
52 | log.error("读取文件失败", e);
53 | } finally {
54 | close(outputStream, inputStream);
55 | }
56 | return "";
57 | }
58 |
59 | /**
60 | * 关闭输入、输出流
61 | *
62 | * @param closeables 可关闭流对象
63 | */
64 | public static void close(Closeable... closeables) {
65 | for (Closeable closeable : closeables) {
66 | try {
67 | closeable.close();
68 | } catch (IOException ignore) {
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Database Generator
4 |
5 | > 一个依赖 IDEA DatabaseTools 的代码生成器,通过数据库表结构生成相应的Java代码,插件提供一套简单的增删查改代码模板,也可以新增自定义模板来生成前端代码或其他相关的代码。
6 |
7 |
8 |
9 | 插件初次运行时会在当前目录下创建 `generator` 目录用来存放插件所需要的信息,其中 `generator/templates` 目录中存放了所需要生成的代码模板文件。
10 |
11 | 本插件支持 `beetl`/`freemarker`/`velocity` 三种模板引擎的代码模板,通过文件后缀(`btl`/`ftl`/`vm`)来选择使用什么模板引擎渲染,自定义模板请阅读 [模板变量文档](./doc/template-document.md) 了解相关变量内容后再进行自定义开发。
12 |
13 |
14 |
15 | [更新日志](./doc/changeNotes.md) | [模板变量说明](./doc/template-document.md) | [旧版模板升级2.0.0插件版本指南](./doc/upgrade-2.0.0.md) | [插件截图](./doc/images.md) | [所有变量使用 all-variable.ftl](https://github.com/houkunlin/Database-Generator/blob/master/src/main/resources/templates/all-variable.ftl) | [渲染输出结果示例 all-variable.md](doc/all-variable.md)
16 |
17 |
18 |
19 | 默认提供三种模板引擎(`beetl`/`freemarker`/`velocity`)的代码模板(SpringBoot+MyBatis-Plus+自定义工具),可选择保留其中一种模板引擎的代码模板,然后根据自己的需求对代码模板进行修改,阅读 [模板变量说明](./doc/template-document.md) 了解模板变量的具体内容。
20 |
21 | 支持在模板中使用自定义的Groovy脚本,需要在模板父级目录下创建 `scripts` 文件夹,然后放置 `*.groovy` 文件即可。阅读 [Groovy脚本使用文档](./doc/groovy-scripts.md) 了解如何使用 Groovy 脚本。
22 | ```text
23 | ${工作空间}
24 | |-templates
25 | |-scripts
26 | |--*.groovy
27 | ```
28 | ## 代码模板文件在IDEA中存放的位置
29 |
30 | - 代码模板文件默认放到:`Scratches and Consoles/Extensions` (中文:草稿文件和控制台/扩展/Database Generator)
31 | - 同时支持以下模板路径:`${project.dir}/.idea/generator/templates` 和 `${project.dir}/generator/templates`
32 |
33 |
34 |
35 | ## 注意事项
36 |
37 | **版本 `v2.7.0` 对配置文件产生了破坏性变更,由原来的 `config/*.json` JSON格式配置文件改为 `config.yml` YAML配置文件**
38 |
39 | **在旧版本升级后,原来的 `config/*.json` 配置文件将失效,请参照 `src/main/resources/config.yml` 文件重制你自定义的配置文件**
40 |
41 | **也可以删除本地的 `init.properties` 文件然后重新生成配置文件,但请注意备份您的自定义模板文件**
42 |
43 |
44 |
45 | ## 截图
46 |
47 | 
48 |
49 | 
50 |
51 | 
52 |
53 | 
54 |
55 | 
56 |
57 |
58 |
59 |
60 |
61 | ## 参考代码
62 | - better-mybatis-generator https://github.com/kmaster/better-mybatis-generator
63 | - EasyCode https://github.com/makejavas/EasyCode
64 |
65 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/config/Settings.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.config;
2 |
3 | import com.github.houkunlin.model.FileType;
4 | import com.google.common.collect.Lists;
5 | import lombok.Data;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * 设置信息
11 | *
12 | * @author HouKunLin
13 | */
14 | @Data
15 | public class Settings {
16 | /**
17 | * 项目路径
18 | */
19 | private String projectPath;
20 | /**
21 | * Java代码路径
22 | */
23 | private String javaPath = "src/main/java";
24 | /**
25 | * 资源文件路径
26 | */
27 | private String resourcesPath = "src/main/resources";
28 | /**
29 | * 文件类型
30 | */
31 | private List fileTypes;
32 |
33 | public String getResourcesPathAt(String filename) {
34 | return resourcesPath + "/" + filename;
35 | }
36 |
37 | public String getJavaPathAt(String filename) {
38 | return javaPath + "/" + filename;
39 | }
40 |
41 | /**
42 | * 获取文件路径
43 | *
44 | * @param path_ 路径
45 | * @param filename 文件名
46 | * @return 文件路径
47 | * @since 2.8.4
48 | */
49 | public String getPathAt(String path_, String filename) {
50 | var path = (path_ == null || path_.isBlank()) ? javaPath : path_;
51 | return path + "/" + filename;
52 | }
53 |
54 | public List getFileTypes() {
55 | if (fileTypes == null) {
56 | initFileTypes();
57 | }
58 | return fileTypes;
59 | }
60 |
61 | private void initFileTypes() {
62 | fileTypes = Lists.newArrayList(
63 | FileType.of("entity", "Entity", "com.example.entity", ".java", "src/main/java", true),
64 | FileType.of("dao", "Repository", "com.example.repository", ".java", "src/main/java", true),
65 | FileType.of("service", "Service", "com.example.service", ".java", "src/main/java", true),
66 | FileType.of("serviceImpl", "ServiceImpl", "com.example.service.impl", ".java", "src/main/java", true),
67 | FileType.of("controller", "Controller", "com.example.controller", ".java", "src/main/java", true),
68 | FileType.of("xml", "Mapper", "mapper", ".xml", "src/main/resources", true)
69 | );
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/action/MainAction.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.action;
2 |
3 | import com.github.houkunlin.config.ConfigService;
4 | import com.github.houkunlin.ui.win.Main;
5 | import com.github.houkunlin.util.PluginUtils;
6 | import com.intellij.database.psi.DbTable;
7 | import com.intellij.openapi.actionSystem.AnAction;
8 | import com.intellij.openapi.actionSystem.AnActionEvent;
9 | import com.intellij.openapi.actionSystem.LangDataKeys;
10 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
11 | import com.intellij.openapi.project.Project;
12 | import com.intellij.openapi.ui.Messages;
13 | import com.intellij.psi.PsiElement;
14 |
15 | /**
16 | * 操作入口
17 | *
18 | * @author HouKunLin
19 | */
20 | public class MainAction extends AnAction {
21 |
22 | /**
23 | * 在 Database 面板中右键打开插件主页面
24 | *
25 | * @param actionEvent 操作对象
26 | */
27 | @Override
28 | public void actionPerformed(AnActionEvent actionEvent) {
29 | PsiElement[] psiElements = actionEvent.getData(LangDataKeys.PSI_ELEMENT_ARRAY);
30 | if (psiElements == null || psiElements.length == 0) {
31 | Messages.showWarningDialog("请至少选择一张表", "通知");
32 | return;
33 | }
34 | boolean isOk = false;
35 | for (PsiElement psiElement : psiElements) {
36 | if (psiElement instanceof DbTable) {
37 | isOk = true;
38 | break;
39 | }
40 | }
41 | if (!isOk) {
42 | Messages.showWarningDialog("请至少选择一张表", "通知");
43 | return;
44 | }
45 | Project project = actionEvent.getData(PlatformDataKeys.PROJECT);
46 | if (project == null) {
47 | Messages.showErrorDialog("无法获取到当前项目的 Project 对象", "错误");
48 | return;
49 | }
50 | PluginUtils.setProject(project);
51 | PluginUtils.syncResources(project);
52 | ConfigService configService = ConfigService.getInstance(project);
53 | if (configService == null) {
54 | Messages.showWarningDialog("初始化配置信息失败,但并不影响继续使用!", "错误");
55 | configService = new ConfigService();
56 | }
57 | PluginUtils.resetColumnTypes();
58 | new Main(project, psiElements, configService);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/table/PlaceholderTableCellRenderer.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.table;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.DefaultTableCellRenderer;
5 | import java.awt.*;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * 单元格占位符渲染器,允许配置多尔个列的占位符
11 | *
12 | * @author daiwenzh5
13 | * @since 2.8.4
14 | */
15 | public class PlaceholderTableCellRenderer extends DefaultTableCellRenderer {
16 |
17 | private final Map placeholders = new HashMap<>();
18 |
19 | private final String defaultPlaceholder;
20 |
21 | public PlaceholderTableCellRenderer() {
22 | this("");
23 | }
24 |
25 | public PlaceholderTableCellRenderer(String defaultPlaceholder) {
26 | this.defaultPlaceholder = defaultPlaceholder;
27 | }
28 |
29 | @Override
30 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
31 | var component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
32 | if (component instanceof JLabel label) {
33 | resetLabelText(value, label, column);
34 | }
35 | return component;
36 | }
37 |
38 | private void resetLabelText(Object value, JLabel label, int column) {
39 | if (value == null || value.toString()
40 | .trim()
41 | .isEmpty()) {
42 | label.setText(placeholders.getOrDefault(column, defaultPlaceholder));
43 | // label.setForeground(UIManager.getColor("TextField.inactiveForeground"));
44 | label.setForeground(UIManager.getColor("Component.infoForeground"));
45 | } else {
46 | label.setText(value.toString());
47 | label.setForeground(UIManager.getColor("TextField.foreground"));
48 | }
49 | }
50 |
51 | /**
52 | * 设置单个列的占位符
53 | *
54 | * @param column 列序号
55 | * @param placeholder 占位符
56 | * @return 当前对象
57 | */
58 | public PlaceholderTableCellRenderer setColumn(int column, String placeholder) {
59 | placeholders.put(column, placeholder);
60 | return this;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/util/SyncResources.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.util;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.util.ExceptionUtil;
5 | import lombok.Data;
6 | import lombok.RequiredArgsConstructor;
7 |
8 | import java.io.File;
9 | import java.io.InputStream;
10 |
11 | /**
12 | * 同步插件资源到项目路径
13 | *
14 | * @author HouKunLin
15 | */
16 | @Data
17 | @RequiredArgsConstructor
18 | public class SyncResources implements Runnable {
19 | /**
20 | * 插件初始化文件
21 | */
22 | private static final String INIT_FILENAME = "init.properties";
23 | private final Project project;
24 |
25 | /**
26 | * 复制插件内部的模板文件到项目路径中
27 | */
28 | @Override
29 | public void run() {
30 | File initFile = PluginUtils.getExtensionPluginDirFile(INIT_FILENAME);
31 | boolean initFileExists = initFile.exists();
32 | if (initFileExists) {
33 | // 不再强制覆盖 初始化文件
34 | return;
35 | }
36 | try {
37 | // 只处理不存在的初始化文件
38 | String content = IO.readResources(INIT_FILENAME);
39 | FileUtils.copyFile(project, initFile, content, false);
40 | } catch (Throwable e) {
41 | ExceptionUtil.rethrow(new RuntimeException("同步插件init文件到本地出现错误:\r\n" + e.getMessage(), e));
42 | }
43 | try {
44 | syncFiles();
45 | } catch (Throwable e) {
46 | ExceptionUtil.rethrow(new RuntimeException("同步插件配置文件到本地出现错误:\r\n" + e.getMessage(), e));
47 | }
48 |
49 | PluginUtils.refreshWorkspace();
50 | }
51 |
52 | /**
53 | * 复制插件内部的代码模板到项目路径中
54 | *
55 | */
56 | private void syncFiles() {
57 | String syncFiles = IO.readResources("syncFiles.txt");
58 | String[] split = syncFiles.split("\n");
59 | for (String filePath : split) {
60 | if (filePath == null || filePath.isBlank()) {
61 | continue;
62 | }
63 | InputStream inputStream = IO.getInputStream(filePath);
64 | if (inputStream == null) {
65 | continue;
66 | }
67 | String content = IO.read(inputStream);
68 |
69 | FileUtils.copyFile(project, PluginUtils.getExtensionPluginDirFile(filePath), content, true);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/resources/templates/README.md:
--------------------------------------------------------------------------------
1 | # README.md
2 |
3 | ## ZH-CN
4 |
5 | **注意:请不要信任及使用来源不明、未经您工作团队安全审查的脚本及模板文件!!!**
6 | **注意:请不要信任及使用来源不明、未经您工作团队安全审查的脚本及模板文件!!!**
7 | **注意:请不要信任及使用来源不明、未经您工作团队安全审查的脚本及模板文件!!!**
8 |
9 | 本插件默认提供三种模板引擎的参照模板代码,在正式使用时,请选择想要使用的一种模板引擎的模板代码保留,然后删除其他模板引擎的模板代码。
10 |
11 | 代码模板变量参数信息请查看 [模板变量用法](https://github.com/houkunlin/Database-Generator/blob/master/doc/template-document.md)
12 |
13 | Groovy 脚本使用详情请查看 [Groovy 脚本使用说明](https://github.com/houkunlin/Database-Generator/blob/master/doc/groovy-scripts.md)
14 |
15 | 2.5.0 版本默认会在 `Scratches and Consoles - Extensions` 路径下创建代码模板和配置文件,不会在 `${project.dir}/generator` 存放相关文件。
16 |
17 | 支持以下路径的代码模板:
18 |
19 | 1. `${project.dir}/.idea/generator/templates`
20 | 2. `${project.dir}/generator/templates`
21 | 3. `Scratches and Consoles - Extensions/Plugin/generator/templates`
22 |
23 | ## EN
24 |
25 | **Note: Please do not trust or use scripts and template files from unknown sources that have not been reviewed by your work team!!!**
26 | **Note: Please do not trust or use scripts and template files from unknown sources that have not been reviewed by your work team!!!**
27 | **Note: Please do not trust or use scripts and template files from unknown sources that have not been reviewed by your work team!!!**
28 |
29 | This plug-in provides reference template codes for three template engines by default. When officially used, please select the template code of one template engine you want to use to keep, and then delete the template codes of other template engines.
30 |
31 | Please check the variable parameter information of the code template [Template variable usage](https://github.com/houkunlin/Database-Generator/blob/master/doc/template-document.md)
32 |
33 | For more information about using Groovy scripts, see [Groovy Script Instructions](https://github.com/houkunlin/Database-Generator/blob/master/doc/groovy-scripts.md)
34 |
35 | The 2.5.0 version will create code templates and configuration files in the `Scratches and Consoles - Extensions` path by default, and will not store related files in `${project.dir}/generator`.
36 |
37 | Support the code templates of the following paths:
38 |
39 | 1. `${project.dir}/.idea/generator/templates`
40 | 2. `${project.dir}/generator/templates`
41 | 3. `Scratches and Consoles - Extensions/Plugin/generator/templates`
42 |
--------------------------------------------------------------------------------
/src/main/resources/templates/default/freemarker/java/EntityForm.java.ftl:
--------------------------------------------------------------------------------
1 | ${gen.setFilename("${entity.name}Form.java")}
2 | ${gen.setFilepath("${settings.javaPath}/${entity.packages.entity}/")}
3 | package ${entity.packages.entity};
4 |
5 | import com.baomidou.mybatisplus.annotation.*;
6 |
7 | ${entity.packages}
8 |
9 | import io.swagger.annotations.ApiModel;
10 | import io.swagger.annotations.ApiModelProperty;
11 | import javax.persistence.*;
12 | import java.io.Serializable;
13 | import lombok.AllArgsConstructor;
14 | import lombok.Builder;
15 | import lombok.Data;
16 | import lombok.NoArgsConstructor;
17 | import org.hibernate.validator.constraints.Length;
18 | import org.springline.web.mvc.SpringlineCommand;
19 | import javax.validation.constraints.NotBlank;
20 |
21 | /**
22 | * 表单对象:${entity.comment}<#if table.comment?trim?length gt 0 && entity.comment != table.comment> (${table.comment})#if>
23 | *
24 | * @author ${developer.author}
25 | */
26 | @ApiModel("表单对象:${entity.comment}")
27 | @Data
28 | @Builder
29 | @NoArgsConstructor
30 | @AllArgsConstructor
31 | public class ${entity.name}Form implements Serializable {
32 | <#list fields as field>
33 | <#if field.selected>
34 | <#if field.name?starts_with("created") || field.name?starts_with("updated") || field.name?starts_with("deleted") >
35 | <#else>
36 | /**
37 | * ${field.comment}
38 | <#if field.column.comment?trim?length gt 0 && field.comment != field.column.comment> * 数据库字段说明:${field.column.comment}
#if>
39 | */
40 | <#if field.typeName == "String">
41 | <#if field.primaryKey>
42 | @Length(max = ${field.dataType.length}, message = "${field.comment} 在 ${field.dataType.length} 个字符以内")
43 | <#else>
44 | <#if field.name == "remark">
45 | @Length(max = ${field.dataType.length}, message = "${field.comment} 在 ${field.dataType.length} 个字符以内")
46 | <#else>
47 | @Length(max = ${field.dataType.length}, message = "${field.comment} 在 ${field.dataType.length} 个字符以内")
48 | @NotBlank(message = "${field.comment} 不能为空")
49 | #if>
50 | #if>
51 | #if>
52 | @ApiModelProperty("${field.comment}")
53 | private ${field.typeName} ${field.name};
54 | #if>
55 | #if>
56 | #list>
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/TablePanel.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.model.JTableModel;
5 | import com.github.houkunlin.vo.impl.EntityImpl;
6 | import com.github.houkunlin.vo.impl.RootModel;
7 | import com.intellij.database.psi.DbTable;
8 | import lombok.Data;
9 |
10 | import javax.swing.*;
11 | import java.util.Objects;
12 |
13 | /**
14 | * 数据库表面板(对应了单个表的配置信息)
15 | *
16 | * @author HouKunLin
17 | */
18 | @Data
19 | public class TablePanel implements IWindows {
20 | /**
21 | * 数据库表对象
22 | */
23 | private final DbTable dbTable;
24 | /**
25 | * 面板:顶级内容面板
26 | */
27 | private JPanel content;
28 | /**
29 | * 输入框:数据库表名
30 | */
31 | private JTextField tableNameField;
32 | /**
33 | * 输入框:Entity 名称
34 | */
35 | private JTextField entityNameField;
36 | /**
37 | * 输入框:Entity 注释
38 | */
39 | private JTextField commentField;
40 | /**
41 | * 表格:数据库表的字段信息
42 | */
43 | private JTable table1;
44 | private JTextField uriField;
45 | /**
46 | * 界面表格对象的数据模型
47 | */
48 | private JTableModel model;
49 | /**
50 | * 生成代码时需要用到的model对象
51 | */
52 | private RootModel rootModel;
53 | private Options options;
54 |
55 | public TablePanel(DbTable dbTable, Options options) {
56 | this.dbTable = dbTable;
57 | this.options = options;
58 |
59 | model = new JTableModel(table1, dbTable, options);
60 | toModel();
61 | }
62 |
63 | public RootModel toModel() {
64 | if (rootModel == null) {
65 | rootModel = new RootModel(dbTable, model.getFieldImpls(), model.getColumnImpls(), options);
66 | tableNameField.setText(rootModel.getTable().getName());
67 | entityNameField.setText(String.valueOf(rootModel.getEntity().getName()));
68 | commentField.setText(rootModel.getTable().getComment());
69 | uriField.setText(rootModel.getTable().getName().replace("_", "-"));
70 | return rootModel;
71 | }
72 | EntityImpl entity = rootModel.getEntity();
73 | entity.setName(entityNameField.getText());
74 | entity.setComment(Objects.toString(commentField.getText(), ""));
75 | entity.setUri(Objects.toString(uriField.getText(), ""));
76 | return rootModel;
77 | }
78 |
79 | @Override
80 | public JPanel getContent() {
81 | return content;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Java CI with Gradle
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up JDK 17
20 | uses: actions/setup-java@v1
21 | with:
22 | java-version: 17
23 | - name: Grant execute permission for gradlew
24 | run: chmod +x gradlew
25 | - name: Generator Plugin Doc Markdown Text
26 | env: # Or as an environment variable
27 | intellijPublishToken: ${{ secrets.INTELLIJPUBLISHTOKEN }}
28 | # 不打包 Kotlin 标准依赖:https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library
29 | run: ./gradlew markdownToHtml
30 | - name: Build Plugin with Gradle
31 | env: # Or as an environment variable
32 | intellijPublishToken: ${{ secrets.INTELLIJPUBLISHTOKEN }}
33 | # 不打包 Kotlin 标准依赖:https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library
34 | run: ./gradlew buildPlugin -Pkotlin.stdlib.default.dependency=false
35 | - name: Rename
36 | run: mv build/distributions/*.zip build/distributions/plugin.zip
37 | - name: Unpack Plugin Zip
38 | run: unzip -d tmp/ build/distributions/plugin.zip
39 | - uses: actions/upload-artifact@v4
40 | with:
41 | # Name of the artifact to upload.
42 | # Optional. Default is 'artifact'
43 | name: Database_Generator
44 | # A file, directory or wildcard pattern that describes what to upload
45 | # Required.
46 | path: tmp/**/*
47 | # The desired behavior if no files are found using the provided path.
48 | # Available Options:
49 | # warn: Output a warning but do not fail the action
50 | # error: Fail the action with an error message
51 | # ignore: Do not output any warnings or errors, the action does not fail
52 | # Optional. Default is 'warn'
53 | if-no-files-found: warn
54 | # Duration after which artifact will expire in days. 0 means using default retention.
55 | # Minimum 1 day.
56 | # Maximum 90 days unless changed from the repository settings page.
57 | # Optional. Defaults to repository settings.
58 | retention-days: 7
59 |
--------------------------------------------------------------------------------
/src/main/java/velocity_implicit.vm:
--------------------------------------------------------------------------------
1 | #* @implicitly included *#
2 | #* @vtlvariable name="date" type="org.joda.time.DateTime" *#
3 | #* @vtlvariable name="gen" type="com.github.houkunlin.vo.Variable.static" *#
4 | #* @vtlvariable name="settings" type="com.github.houkunlin.config.Settings" *#
5 | #* @vtlvariable name="settings.projectPath" type="java.lang.String" *#
6 | #* @vtlvariable name="settings.javaPath" type="java.lang.String" *#
7 | #* @vtlvariable name="settings.resourcesPath" type="java.lang.String" *#
8 | #* @vtlvariable name="developer" type="com.github.houkunlin.config.Developer" *#
9 | #* @vtlvariable name="developer.author" type="java.lang.String" *#
10 | #* @vtlvariable name="developer.email" type="java.lang.String" *#
11 | #* @vtlvariable name="entity" type="com.github.houkunlin.vo.impl.EntityImpl" *#
12 | #* @vtlvariable name="entity.name" type="java.util.Map" *#
13 | #* @vtlvariable name="entity.name.entity" type="com.github.houkunlin.vo.impl.EntityName" *#
14 | #* @vtlvariable name="entity.name.service" type="com.github.houkunlin.vo.impl.EntityName" *#
15 | #* @vtlvariable name="entity.name.serviceImpl" type="com.github.houkunlin.vo.impl.EntityName" *#
16 | #* @vtlvariable name="entity.name.dao" type="com.github.houkunlin.vo.impl.EntityName" *#
17 | #* @vtlvariable name="entity.name.controller" type="com.github.houkunlin.vo.impl.EntityName" *#
18 | #* @vtlvariable name="entity.name.xml" type="com.github.houkunlin.vo.impl.EntityName" *#
19 | #* @vtlvariable name="entity.packages" type="com.github.houkunlin.vo.impl.EntityPackage" *#
20 | #* @vtlvariable name="entity.packages.entity" type="com.github.houkunlin.vo.impl.EntityPackageInfo" *#
21 | #* @vtlvariable name="entity.packages.service" type="com.github.houkunlin.vo.impl.EntityPackageInfo" *#
22 | #* @vtlvariable name="entity.packages.serviceImpl" type="com.github.houkunlin.vo.impl.EntityPackageInfo" *#
23 | #* @vtlvariable name="entity.packages.dao" type="com.github.houkunlin.vo.impl.EntityPackageInfo" *#
24 | #* @vtlvariable name="entity.packages.controller" type="com.github.houkunlin.vo.impl.EntityPackageInfo" *#
25 | #* @vtlvariable name="entity.packages.xml" type="com.github.houkunlin.vo.impl.EntityPackageInfo" *#
26 | #* @vtlvariable name="table" type="com.github.houkunlin.vo.impl.TableImpl" *#
27 | #* @vtlvariable name="primary" type="com.github.houkunlin.vo.impl.PrimaryInfo" *#
28 | #* @vtlvariable name="fields" type="java.util.List" *#
29 | #* @vtlvariable name="columns" type="java.util.List" *#
30 |
--------------------------------------------------------------------------------
/src/main/java/freemarker_implicit.ftl:
--------------------------------------------------------------------------------
1 | [#ftl]
2 | [#-- @implicitly included --]
3 | [#-- @ftlvariable name="date" type="org.joda.time.DateTime" --]
4 | [#-- @ftlvariable name="gen" type="com.github.houkunlin.vo.Variable.static" --]
5 | [#-- @ftlvariable name="settings" type="com.github.houkunlin.config.Settings" --]
6 | [#-- @ftlvariable name="settings.projectPath" type="java.lang.String" --]
7 | [#-- @ftlvariable name="settings.javaPath" type="java.lang.String" --]
8 | [#-- @ftlvariable name="settings.resourcesPath" type="java.lang.String" --]
9 | [#-- @ftlvariable name="developer" type="com.github.houkunlin.config.Developer" --]
10 | [#-- @ftlvariable name="developer.author" type="java.lang.String" --]
11 | [#-- @ftlvariable name="developer.email" type="java.lang.String" --]
12 | [#-- @ftlvariable name="entity" type="com.github.houkunlin.vo.impl.EntityImpl" --]
13 | [#-- @ftlvariable name="entity.name" type="java.util.Map" --]
14 | [#-- @ftlvariable name="entity.name.entity" type="com.github.houkunlin.vo.impl.EntityName" --]
15 | [#-- @ftlvariable name="entity.name.service" type="com.github.houkunlin.vo.impl.EntityName" --]
16 | [#-- @ftlvariable name="entity.name.serviceImpl" type="com.github.houkunlin.vo.impl.EntityName" --]
17 | [#-- @ftlvariable name="entity.name.dao" type="com.github.houkunlin.vo.impl.EntityName" --]
18 | [#-- @ftlvariable name="entity.name.controller" type="com.github.houkunlin.vo.impl.EntityName" --]
19 | [#-- @ftlvariable name="entity.name.xml" type="com.github.houkunlin.vo.impl.EntityName" --]
20 | [#-- @ftlvariable name="entity.packages" type="com.github.houkunlin.vo.impl.EntityPackage" --]
21 | [#-- @ftlvariable name="entity.packages.entity" type="com.github.houkunlin.vo.impl.EntityPackageInfo" --]
22 | [#-- @ftlvariable name="entity.packages.service" type="com.github.houkunlin.vo.impl.EntityPackageInfo" --]
23 | [#-- @ftlvariable name="entity.packages.serviceImpl" type="com.github.houkunlin.vo.impl.EntityPackageInfo" --]
24 | [#-- @ftlvariable name="entity.packages.dao" type="com.github.houkunlin.vo.impl.EntityPackageInfo" --]
25 | [#-- @ftlvariable name="entity.packages.controller" type="com.github.houkunlin.vo.impl.EntityPackageInfo" --]
26 | [#-- @ftlvariable name="entity.packages.xml" type="com.github.houkunlin.vo.impl.EntityPackageInfo" --]
27 | [#-- @ftlvariable name="table" type="com.github.houkunlin.vo.impl.TableImpl" --]
28 | [#-- @ftlvariable name="primary" type="com.github.houkunlin.vo.impl.PrimaryInfo" --]
29 | [#-- @ftlvariable name="fields" type="java.util.List" --]
30 | [#-- @ftlvariable name="columns" type="java.util.List" --]
31 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/TableColumnImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.vo.IEntityField;
4 | import com.github.houkunlin.vo.ITableColumn;
5 | import com.intellij.database.model.DasColumn;
6 | import com.intellij.database.model.DataType;
7 | import com.intellij.database.util.DasUtil;
8 | import com.intellij.util.ReflectionUtil;
9 | import lombok.EqualsAndHashCode;
10 | import lombok.Getter;
11 | import lombok.Setter;
12 | import lombok.ToString;
13 |
14 | import java.util.Objects;
15 |
16 | /**
17 | * 数据库表字段信息(数据库表列对象信息)
18 | *
19 | * @author HouKunLin
20 | */
21 | @Getter
22 | public class TableColumnImpl implements ITableColumn {
23 | /**
24 | * 数据库表的原始字段对象
25 | */
26 | @ToString.Exclude
27 | @EqualsAndHashCode.Exclude
28 | private final DasColumn dbColumn;
29 | private final String name;
30 | private final String comment;
31 | private final String typeName;
32 | private final DataType dataType;
33 | private final String fullTypeName;
34 | private final boolean primaryKey;
35 | @Setter
36 | @ToString.Exclude
37 | @EqualsAndHashCode.Exclude
38 | private IEntityField field;
39 | @Setter
40 | private boolean selected;
41 |
42 | private TableColumnImpl(String name, String typeName, String fullTypeName, String comment, boolean primaryKey, boolean selected) {
43 | this.dbColumn = null;
44 | this.name = name;
45 | this.typeName = typeName;
46 | this.dataType = null;
47 | this.fullTypeName = fullTypeName;
48 | this.comment = comment;
49 | this.primaryKey = primaryKey;
50 | this.selected = selected;
51 | }
52 |
53 | public TableColumnImpl(DasColumn dbColumn) {
54 | this.dbColumn = dbColumn;
55 | this.name = dbColumn.getName();
56 | this.dataType = dbColumn.getDasType().toDataType();
57 | this.fullTypeName = dataType.getSpecification();
58 | this.typeName = ReflectionUtil.getField(DataType.class, dataType, String.class, "typeName");
59 | this.comment = Objects.toString(dbColumn.getComment(), "");
60 | this.primaryKey = DasUtil.isPrimary(dbColumn);
61 | this.selected = true;
62 | }
63 |
64 | /**
65 | * 创建主键字段对象
66 | *
67 | * @param name 字段名称
68 | * @param typeName 字段类型
69 | * @param fullTypeName 字段完整类型
70 | * @param comment 字段注释
71 | * @return 字段对象
72 | */
73 | public static TableColumnImpl primaryColumn(String name, String typeName, String fullTypeName, String comment) {
74 | return new TableColumnImpl(name, typeName, fullTypeName, comment, true, true);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/template/beetl/BeetlTemplateGenerator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.template.beetl;
2 |
3 | import com.github.houkunlin.template.AbstractScriptedTemplateGenerator;
4 | import com.github.houkunlin.util.ScriptManager;
5 | import org.beetl.core.Configuration;
6 | import org.beetl.core.GroupTemplate;
7 | import org.beetl.core.ResourceLoader;
8 | import org.beetl.core.resource.FileResourceLoader;
9 | import org.beetl.core.resource.StringTemplateResourceLoader;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 | import java.util.Map;
14 |
15 | /**
16 | * @author daiwenzh5
17 | * @since 1.0
18 | */
19 | public class BeetlTemplateGenerator extends AbstractScriptedTemplateGenerator {
20 |
21 | private final GroupTemplate groupTemplateString;
22 | private final GroupTemplate groupTemplateFile;
23 |
24 | public BeetlTemplateGenerator(File workspace) throws IOException {
25 | super(workspace);
26 | //初始化代码
27 | var configuration = Configuration.defaultConfiguration();
28 | configuration.setNativeCall(true);
29 | configuration.setNativeSecurity("org.beetl.core.DefaultNativeSecurityManager");
30 | groupTemplateString = createGroupTemplate(new StringTemplateResourceLoader(), configuration);
31 | groupTemplateFile = createGroupTemplate(new FileResourceLoader(getTemplateDir().getAbsolutePath()), configuration);
32 |
33 | }
34 |
35 | private GroupTemplate createGroupTemplate(ResourceLoader> loader, Configuration configuration) {
36 | var groupTemplate = new GroupTemplate(loader, configuration, GroupTemplate.class.getClassLoader());
37 | groupTemplate.setErrorHandler(new BeetlErrorHandler());
38 | return groupTemplate;
39 | }
40 |
41 | @Override
42 | protected String doGenerate(String templateName, Map context) {
43 | //获取模板
44 | var template = groupTemplateFile.getTemplate(templateName);
45 | template.binding(context);
46 | //渲染结果
47 | return template.render();
48 | }
49 |
50 | @Override
51 | protected String doGenerateInline(String templateContent, Map context) {
52 | //获取模板
53 | var template = groupTemplateString.getTemplate(templateContent);
54 | template.binding(context);
55 | //渲染结果
56 | return template.render();
57 | }
58 |
59 | @Override
60 | protected void registerScriptManager(Map context, ScriptManager scriptManager) {
61 | scriptManager.forEach(this::registerScriptMethods);
62 | }
63 |
64 | private void registerScriptMethods(String name, Object script) {
65 | groupTemplateFile.registerFunctionPackage(ScriptManager.NAMESPACE + name, script);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/model/SaveFilePath.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.model;
2 |
3 | import com.github.houkunlin.config.Settings;
4 | import com.github.houkunlin.vo.Variable;
5 | import com.github.houkunlin.vo.impl.RootModel;
6 | import com.intellij.openapi.util.text.StringUtil;
7 | import lombok.Getter;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | /**
11 | * 保存文件信息
12 | *
13 | * @author HouKunLin
14 | */
15 | public class SaveFilePath {
16 |
17 | /**
18 | * 模板文件的 type 类型
19 | */
20 | private final String type;
21 | /**
22 | * 模板文件保存路径
23 | */
24 | private String toString;
25 |
26 | @Getter
27 | private final boolean override;
28 |
29 | public SaveFilePath(String filename, String filepath, boolean override) {
30 | String name = getValue(Variable.filename, filename);
31 | String path = getValue(Variable.filepath, filepath);
32 | type = Variable.type;
33 | toString = (path.replace(".", "/") + "/" + name);
34 | toString = toString.replace("\\", "/").replaceAll("/+", "/");
35 | this.override = override;
36 | Variable.resetVariables();
37 | }
38 |
39 | public static SaveFilePath create(RootModel rootModel, Settings settings) {
40 | var entityName = String.valueOf(rootModel.getEntity().getName());
41 | if (Variable.type == null) {
42 | return createTemp(entityName, settings);
43 | }
44 | return settings.getFileTypes()
45 | .stream()
46 | .filter(item -> item.getType()
47 | .equals(Variable.type))
48 | .map(item -> createSaveFilePath(settings, entityName, item))
49 | .findFirst()
50 | .orElseGet(() -> createTemp(entityName, settings));
51 | }
52 |
53 | private static @NotNull SaveFilePath createSaveFilePath(Settings settings, String entityName, FileType item) {
54 | var filename = entityName + item.getSuffix() + StringUtil.defaultIfEmpty(item.getExt(), ".java");
55 | var relativePath = settings.getPathAt(item.getPath(), item.getPackageName());
56 | return new SaveFilePath(filename, relativePath, item.isOverride());
57 | }
58 |
59 | private String getValue(String tempValue, String defaultValue) {
60 | if (tempValue != null) {
61 | return tempValue;
62 | } else {
63 | return defaultValue;
64 | }
65 | }
66 |
67 | @Override
68 | public String toString() {
69 | return toString;
70 | }
71 |
72 | public static SaveFilePath createTemp(String filename, Settings settings) {
73 | return new SaveFilePath(filename, settings.getResourcesPathAt("temp"), true);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/template/TemplateGeneratorFactory.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.template;
2 |
3 | import com.github.houkunlin.template.beetl.BeetlTemplateGenerator;
4 | import com.github.houkunlin.template.freemarker.FreemarkerTemplateGenerator;
5 | import com.github.houkunlin.template.velocity.VelocityTemplateGenerator;
6 | import com.github.houkunlin.util.PluginUtils;
7 | import com.google.common.collect.HashBasedTable;
8 | import com.google.common.collect.Table;
9 |
10 | import java.io.File;
11 | import java.io.IOException;
12 |
13 | /**
14 | * 模板生成器工厂
15 | *
16 | * @author daiwenzh5
17 | * @since 1.0
18 | */
19 | public class TemplateGeneratorFactory {
20 |
21 | private static final Table cache = HashBasedTable.create();
22 |
23 | /**
24 | * 创建模板生成器
25 | *
26 | * @param templateFile 模板文件
27 | * @return 模板生成器
28 | */
29 | public static ITemplateGenerator create(File templateFile) {
30 | var workspace = getTemplateWorkspace(templateFile);
31 | var workspacePath = workspace.getAbsolutePath();
32 | var type = TplType.create(templateFile);
33 | var value = cache.get(workspacePath, type);
34 | if (value != null) {
35 | return value;
36 | }
37 | var generator = create(workspace, type);
38 | cache.put(workspacePath, type, generator);
39 | return generator;
40 | }
41 |
42 | private static ITemplateGenerator create(File workspace, TplType type) {
43 | try {
44 | return switch (type) {
45 | case BEETL -> new BeetlTemplateGenerator(workspace);
46 | case FREEMARKER -> new FreemarkerTemplateGenerator(workspace);
47 | case VELOCITY -> new VelocityTemplateGenerator(workspace);
48 | default -> null;
49 | };
50 | } catch (IOException e) {
51 | throw new RuntimeException("创建 Root 模板处理器失败:" + workspace.getAbsolutePath() + "\r\n" + e.getMessage(), e);
52 | }
53 | }
54 |
55 | private static File getTemplateWorkspace(File templateFile) {
56 | var absolutePath = templateFile.getAbsolutePath();
57 | var file = PluginUtils.getProjectWorkspacePluginDir();
58 | if (absolutePath.startsWith(file.getAbsolutePath())) {
59 | return file;
60 | }
61 | file = PluginUtils.getProjectPluginDir();
62 | if (absolutePath.startsWith(file.getAbsolutePath())) {
63 | return file;
64 | }
65 | file = PluginUtils.getExtensionPluginDir();
66 | if (absolutePath.startsWith(file.getAbsolutePath())) {
67 | return file;
68 | }
69 | throw new RuntimeException("无法找到代码模板文件在插件中的根路径:" + templateFile.getAbsolutePath());
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/template/AbstractScriptedTemplateGenerator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.template;
2 |
3 | import com.github.houkunlin.util.PluginUtils;
4 | import com.github.houkunlin.util.ScriptManager;
5 | import lombok.Getter;
6 |
7 | import java.io.File;
8 | import java.util.Map;
9 |
10 | /**
11 | * 可执行脚本的模板生成器
12 | *
13 | * @author daiwenzh5
14 | * @since 1.0
15 | */
16 | @Getter
17 | public abstract class AbstractScriptedTemplateGenerator implements ITemplateGenerator {
18 |
19 | /**
20 | * 工作空间
21 | */
22 | private final File workspace;
23 |
24 | /**
25 | * 模板目录
26 | */
27 | private final File templateDir;
28 |
29 | public AbstractScriptedTemplateGenerator(File workspace) {
30 | this.workspace = workspace;
31 | this.templateDir = workspace.toPath()
32 | .resolve(PluginUtils.TEMPLATE_DIR)
33 | .toFile();
34 | }
35 |
36 | @Override
37 | public final String generate(String templateName, Map context) throws Exception {
38 | var scriptManager = ScriptManager.of(workspace.toPath()
39 | .resolve(ScriptManager.DIR), true);
40 | registerScriptManager(context, scriptManager);
41 | return doGenerate(templateName, context);
42 | }
43 |
44 | @Override
45 | public final String generateInline(String templateContent, Map context) throws Exception {
46 | var scriptManager = ScriptManager.of(workspace.toPath()
47 | .resolve(ScriptManager.DIR), true);
48 | registerScriptManager(context, scriptManager);
49 | return doGenerateInline(templateContent, context);
50 | }
51 |
52 | /**
53 | * 将{@link ScriptManager}注册到模板引擎的上下文中
54 | *
55 | * @param context 上下文
56 | * @param scriptManager 脚本管理器
57 | */
58 | protected void registerScriptManager(Map context, ScriptManager scriptManager) {
59 | context.put(ScriptManager.VARIABLE, scriptManager);
60 | }
61 |
62 | /**
63 | * 根据传入的模板名称,读取模板,并执行生成逻辑
64 | *
65 | * @param templateName 模板名称
66 | * @param context 上下文
67 | * @return 生成的代码
68 | * @throws Exception 可能出现的异常
69 | */
70 | protected abstract String doGenerate(String templateName, Map context) throws Exception;
71 |
72 | /**
73 | * 根据传入的模板内容,直接执行生成逻辑
74 | *
75 | * @param templateContent 模板内容
76 | * @param context 上下文
77 | * @return 生成的代码
78 | * @throws Exception 可能出现的异常
79 | */
80 | protected abstract String doGenerateInline(String templateContent, Map context) throws Exception;
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/doc/upgrade-2.0.0.md:
--------------------------------------------------------------------------------
1 | # 模板升级到 2.x 指南
2 |
3 | 本次发布涉及到目标变量重构,并且不兼容旧版本的模板信息,因此需要针对代码模板进行升级。
4 |
5 | 本文仅涉及部分内容,详细的新版模板变量用法请查看 [模板变量用法](./template-document.md)
6 |
7 |
8 |
9 | 旧版的 `` 指令,改为直接调用 `${gen.setType("TYPE")}` 方法,详细说明请查看模板变量 `gen` 变量说明。
10 |
11 |
12 |
13 | ## 对象名称
14 |
15 | |旧的|新的|
16 | |---|---|
17 | |Entity对象名称
`<#assign entityClass = "${table.entityName}${settings.entitySuffix}" />`|使用`${entity.name.entity}`|
18 | |Service对象名称
`<#assign serviceClass = "${table.entityName}${settings.serviceSuffix}" />`|使用`${entity.name.service}`|
19 | |`<#assign serviceImplClass = "${table.entityName}${settings.serviceSuffix}Impl" />`|使用`${entity.name.serviceImpl}`|
20 | |`<#assign daoClass = "${table.entityName}${settings.daoSuffix}" />`|使用`${entity.name.dao}`|
21 | |`<#assign controllerClass = "${table.entityName}${settings.controllerSuffix}" />`|使用`${entity.name.controller}`|
22 | |`<#assign serviceVar = "${table.entityVar}${settings.serviceSuffix}" />`|使用`${entity.name.service.firstLower}`|
23 |
24 |
25 |
26 | ## 包名
27 |
28 | |旧的|新的|
29 | |---|---|
30 | |`${settings.entityPackage}`|`${entity.packages.entity}`|
31 | |`${settings.dao}`|`${entity.packages.dao}`|
32 | |`${settings.servicePackage}`|`${entity.packages.service}`|
33 | |`${settings.servicePackage}.impl`|`${entity.packages.serviceImpl}`|
34 | |`${settings.controllerPackage}`|`${entity.packages.controller}`|
35 | |---|---|
36 | |`import ${settings.entityPackage}.${entityClass}`|`import ${entity.packages.entity.full}`|
37 | |`import ${settings.servicePackage}.${serviceClass}`|`import ${entity.packages.service.full}`|
38 | |`import ${settings.daoPackage}.${daoClass}`|`import ${entity.packages.dao.full}`|
39 | |---|---|
40 | |实体类导入包|`${entity.packages}`|
41 |
42 |
43 |
44 | ## 实体类
45 |
46 | | 旧的 | 新的 |
47 | | ---- | ---- |
48 | |导入包 `<#list table.getPackages() as package>import ${package};#list>`| `${entity.packages}`|
49 | |实体类名称`${table.entityName}`| `${entity.name}` 不含后缀 |
50 | |实体类名称`${table.entityName}${settings.entitySuffix}`| `${entity.name.entity}`含后缀 |
51 | |数据库表名`${table.tableName}`|`${table.name}`|
52 | |Entity注释`${table.comment}`|`${entity.comment}`|
53 | |Entity字段`<#list table.columns as col>`|`<#list fields as field>`|
54 | |获取Entity字段类型`${col.columnType.shortName}`|`${field.typeName}`|
55 | |获取Entity字段名`${col.fieldName}`|`${field.name}`|
56 | |获取Entity字段注释`${col.comment}`|`${field.comment}`|
57 | |Entity字段首字母大写`${col.fieldMethod}`|`${field.name.firstUpper}`|
58 |
59 |
60 |
61 | ## 其他
62 |
63 | 在 1.x 版本中有一个 `${table.getPrimaryColumn().fieldMethod}` 获取主键字段信息,在 2.0.0 中未引入该功能,在 2.1.0 中重新引入了该功能,具体用法为 `${primary.field.name.firstUpper}` 通过 `primary` 变量来获取到主键的信息,详细用法请查看模板变量说明文档。
64 |
65 |
66 |
67 | 在 1.x 版本中可在 `table.columns` 中获取到数据库字段、Java字段的字段名称,在 2.0.0 版本中未引入改功能,在 2.1.0 中重新引入了该功能,具体用法为 `${field.column.name}` 从Java字段获取该字段对应的数据库字段对象的字段名称,或者 `${column.field.name}` 从数据库字段获取该字段对应的Java字段对象的字段名称。
--------------------------------------------------------------------------------
/doc/plugin/description.md:
--------------------------------------------------------------------------------
1 | [Github](https://github.com/houkunlin/Database-Generator) | [Gitee](https://gitee.com/houkunlin/Database-Generator) | Document
2 |
3 | **English (Google Translate)** / 中文
4 |
5 | A code generator that relies on the IDEA Database tool to generate the corresponding Java code through the database table structure. The plug-in provides a simple set of add, delete, and modify code templates. You can also add custom templates to generate front-end code or other related code.
6 |
7 | Provide `all-variable.ftl` template file to illustrate all variable usage and corresponding results.
8 |
9 | This plugin supports `beetl`/`freemarker`/`velocity` code templates of three template engines. You can choose which template engine to use for the file suffix (`btl`/`ftl`/`vm`). For custom templates, please Read Template Variable Document to understand the contents of related variables before custom development.
10 |
11 | This plug-in supports calling the methods in the Groovy script defined by yourself in the template file, please refer to the Groovy Script Instructions for details 。
12 |
13 | **Please check the Code Template Upgrade Guide, and check the detailed writing Template Variable Document, or check out the code template that covers the use of all variables all-variable.ftl**
14 |
15 |
16 |
17 | **中文** / English
18 |
19 | 一个依赖 IDEA Database 工具的代码生成器,通过数据库表结构生成相应的Java代码,插件提供一套简单的增删查改代码模板,也可以新增自定义模板来生成前端代码或其他相关的代码。
20 |
21 | 提供 `all-variable.ftl` 模板文件来说明所有的变量使用和对应结果。
22 |
23 | 本插件支持 `beetl`/`freemarker`/`velocity` 三种模板引擎的代码模板,通过文件后缀(`btl`/`ftl`/`vm`)来选择使用什么模板引擎渲染,自定义模板请阅读 模板变量文档 了解相关变量内容后再进行自定义开发。
24 |
25 | 本插件支持在模板文件中调用自己定义好的 Groovy 脚本中的方法,详细用法请参考 Groovy 脚本使用说明 。
26 |
27 | **请查看 代码模板升级指南 ,和查看详细的编写 模板变量文档 ,或者查看涵盖所有变量使用的代码模板 all-variable.ftl**
28 |
29 |
30 | Author: HouKunLin
31 | Email: houkunlin@aliyun.com
32 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/tree/CheckBoxTreeCellRenderer.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.tree;
2 |
3 | import javax.swing.*;
4 | import javax.swing.tree.TreeCellRenderer;
5 | import java.awt.*;
6 |
7 | /**
8 | * 复选框的树形渲染
9 | *
10 | * @author HouKunLin
11 | */
12 | public class CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer {
13 | protected final JCheckBox check;
14 | protected final CheckBoxTreeLabel label;
15 |
16 | public CheckBoxTreeCellRenderer() {
17 | setLayout(null);
18 | add(check = new JCheckBox());
19 | add(label = new CheckBoxTreeLabel());
20 | check.setBackground(UIManager.getColor("Tree.textBackground"));
21 | check.setOpaque(false);
22 | label.setForeground(UIManager.getColor("Tree.textForeground"));
23 | }
24 |
25 | /**
26 | * 返回的是一个JPanel对象,该对象中包含一个JCheckBox对象
27 | * 和一个JLabel对象。并且根据每个结点是否被选中来决定JCheckBox
28 | * 是否被选中。
29 | */
30 | @Override
31 | public Component getTreeCellRendererComponent(JTree tree, Object value,
32 | boolean selected, boolean expanded, boolean leaf, int row,
33 | boolean hasFocus) {
34 | String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);
35 | setEnabled(tree.isEnabled());
36 | check.setSelected(((CheckBoxTreeNode) value).isSelected());
37 | label.setFont(tree.getFont());
38 | label.setText(stringValue);
39 | label.setSelected(selected);
40 | label.setHasFocus(hasFocus);
41 | /*if (leaf)
42 | label.setIcon(UIManager.getIcon("Tree.leafIcon"));
43 | else if (expanded)
44 | label.setIcon(UIManager.getIcon("Tree.openIcon"));
45 | else
46 | label.setIcon(UIManager.getIcon("Tree.closedIcon"));*/
47 | label.setOpaque(false);
48 | this.setOpaque(false);
49 | return this;
50 | }
51 |
52 | @Override
53 | public Dimension getPreferredSize() {
54 | Dimension dCheck = check.getPreferredSize();
55 | Dimension dLabel = label.getPreferredSize();
56 | return new Dimension(dCheck.width + dLabel.width, Math.max(dCheck.height, dLabel.height));
57 | }
58 |
59 | @Override
60 | public void doLayout() {
61 | Dimension dCheck = check.getPreferredSize();
62 | Dimension dLabel = label.getPreferredSize();
63 | int yCheck = 0;
64 | int yLabel = 0;
65 | if (dCheck.height < dLabel.height) {
66 | yCheck = (dLabel.height - dCheck.height) / 2;
67 | } else {
68 | yLabel = (dCheck.height - dLabel.height) / 2;
69 | }
70 | check.setLocation(0, yCheck);
71 | check.setBounds(0, yCheck, dCheck.width, dCheck.height);
72 | label.setLocation(dCheck.width, yLabel);
73 | label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/table/EditorTableCellEditor.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.table;
2 |
3 | import com.intellij.ide.highlighter.JavaFileType;
4 | import com.intellij.openapi.editor.Document;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.psi.JavaCodeFragment;
7 | import com.intellij.psi.JavaCodeFragmentFactory;
8 | import com.intellij.psi.PsiDocumentManager;
9 | import com.intellij.ui.EditorTextField;
10 | import com.intellij.util.ui.AbstractTableCellEditor;
11 |
12 | import javax.swing.*;
13 | import java.awt.*;
14 | import java.awt.event.FocusEvent;
15 | import java.awt.event.FocusListener;
16 | import java.awt.event.MouseEvent;
17 | import java.util.EventObject;
18 | import java.util.Objects;
19 |
20 | /**
21 | * 支持自动完成包名的表格编辑器
22 | *
23 | * @author daiwenzh5
24 | * @since 2.8.4
25 | */
26 | public class EditorTableCellEditor extends AbstractTableCellEditor {
27 |
28 | private final EditorTextField editorTextField;
29 |
30 | /**
31 | * 获取焦点时的单元格值
32 | */
33 | private String cellValue;
34 |
35 | public EditorTableCellEditor(Project project) {
36 | this.editorTextField = createEditorTextField(project);
37 | // 当获取到焦点时,尝试将输入框的值设置为单元格值
38 | this.editorTextField.addFocusListener(new FocusListener() {
39 | @Override
40 | public void focusGained(FocusEvent e) {
41 | if (editorTextField.getText()
42 | .equals(cellValue)) {
43 | return;
44 | }
45 | editorTextField.setText(Objects.toString(cellValue, ""));
46 | }
47 |
48 | @Override
49 | public void focusLost(FocusEvent e) {
50 |
51 | }
52 | });
53 | }
54 |
55 | @Override
56 | public boolean isCellEditable(EventObject e) {
57 | if (e instanceof MouseEvent mouseEvent) {
58 | return mouseEvent.getClickCount() >= 2;
59 | }
60 | return false;
61 | }
62 |
63 | @Override
64 | public Object getCellEditorValue() {
65 | return editorTextField.getText();
66 | }
67 |
68 | @Override
69 | public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
70 | // 记录单元格的值
71 | this.cellValue = value.toString();
72 | return editorTextField;
73 | }
74 |
75 | private EditorTextField createEditorTextField(Project project) {
76 | // https://jetbrains.org/intellij/sdk/docs/user_interface_components/editor_components.html
77 | JavaCodeFragment code = JavaCodeFragmentFactory.getInstance(project)
78 | .createReferenceCodeFragment("", null, true, false);
79 | Document document = PsiDocumentManager.getInstance(project)
80 | .getDocument(code);
81 | JavaFileType fileType = JavaFileType.INSTANCE;
82 | return new EditorTextField(document, project, fileType);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/resources/config.yml:
--------------------------------------------------------------------------------
1 | developer:
2 | author: ''
3 | email: ''
4 | options:
5 | overrideJava: true
6 | overrideXml: true
7 | overrideOther: true
8 | settings:
9 | javaPath: src/main/java
10 | resourcesPath: src/main/resources
11 | fileTypes:
12 | - type: entity
13 | suffix: Entity
14 | packageName: com.example.entity
15 | ext: .java
16 | path: src/main/java
17 | override: true
18 | - type: dao
19 | suffix: Repository
20 | packageName: com.example.repository
21 | ext: .java
22 | path: src/main/java
23 | override: true
24 | - type: service
25 | suffix: Service
26 | packageName: com.example.service
27 | ext: .java
28 | path: src/main/java
29 | override: true
30 | - type: serviceImpl
31 | suffix: ServiceImpl
32 | packageName: com.example.service.impl
33 | ext: .java
34 | path: src/main/java
35 | override: true
36 | - type: controller
37 | suffix: Controller
38 | packageName: com.example.controller
39 | ext: .java
40 | path: src/main/java
41 | override: true
42 | - type: xml
43 | suffix: Mapper
44 | packageName: mapper
45 | ext: .xml
46 | path: src/main/resources
47 | override: true
48 | types:
49 | - shortName: Object
50 | longName: java.lang.Object
51 | isDefault: true
52 | dbTypes: []
53 | - shortName: Boolean
54 | longName: java.lang.Boolean
55 | dbTypes:
56 | - ^bit$
57 | - ^bool # Postgresql
58 | - ^boolean # Postgresql
59 | - shortName: Long
60 | longName: java.lang.Long
61 | dbTypes:
62 | - ^bigint
63 | - shortName: Integer
64 | longName: java.lang.Integer
65 | dbTypes:
66 | - ^tinyint
67 | - ^smallint
68 | - ^mediumint
69 | - ^integer # Postgresql
70 | - ^interval # Postgresql
71 | - ^int
72 | - shortName: String
73 | longName: java.lang.String
74 | dbTypes:
75 | - ^char
76 | - ^varchar
77 | - ^text
78 | - ^longtext
79 | - ^tinytext
80 | - ^cidr # Postgresql
81 | - ^inet # Postgresql
82 | - ^macaddr # Postgresql
83 | - ^path # Postgresql
84 | - ^uuid # Postgresql
85 | - ^xml # Postgresql
86 | - shortName: BigDecimal
87 | longName: java.math.BigDecimal
88 | dbTypes:
89 | - ^decimal
90 | - ^numeric
91 | - ^money # Postgresql
92 | - shortName: Float
93 | longName: java.lang.Float
94 | dbTypes:
95 | - ^float
96 | - ^real # Postgresql
97 | - shortName: Double
98 | longName: java.lang.Double
99 | dbTypes:
100 | - ^double
101 | - shortName: LocalDateTime
102 | longName: java.time.LocalDateTime
103 | dbTypes:
104 | - ^datetime
105 | - ^timestamp
106 | - shortName: LocalDate
107 | longName: java.time.LocalDate
108 | dbTypes:
109 | - ^date
110 | - shortName: LocalTime
111 | longName: java.time.LocalTime
112 | dbTypes:
113 | - ^time
114 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/vo/impl/EntityFieldImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.vo.impl;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.model.TableColumnType;
5 | import com.github.houkunlin.util.PluginUtils;
6 | import com.github.houkunlin.vo.IEntityField;
7 | import com.github.houkunlin.vo.ITableColumn;
8 | import com.intellij.database.model.DasColumn;
9 | import com.intellij.database.model.DataType;
10 | import com.intellij.database.util.DasUtil;
11 | import lombok.EqualsAndHashCode;
12 | import lombok.Getter;
13 | import lombok.Setter;
14 | import lombok.ToString;
15 |
16 | import java.util.Objects;
17 |
18 | /**
19 | * 实体类字段信息
20 | *
21 | * @author HouKunLin
22 | */
23 | @Getter
24 | public class EntityFieldImpl implements IEntityField {
25 | private final FieldNameInfo name;
26 | private final String typeName;
27 | private final DataType dataType;
28 | private final String fullTypeName;
29 | private final boolean primaryKey;
30 | @Setter
31 | @ToString.Exclude
32 | @EqualsAndHashCode.Exclude
33 | private ITableColumn column;
34 | @Setter
35 | private String comment;
36 | @Setter
37 | private boolean selected;
38 |
39 | private EntityFieldImpl(FieldNameInfo name, String typeName, String fullTypeName, boolean primaryKey, String comment, boolean selected) {
40 | this.name = name;
41 | this.typeName = typeName;
42 | this.dataType = null;
43 | this.fullTypeName = fullTypeName;
44 | this.primaryKey = primaryKey;
45 | this.comment = comment;
46 | this.selected = selected;
47 | }
48 |
49 | public EntityFieldImpl(DasColumn dbColumn, Options options) {
50 | this.name = new FieldNameInfo(dbColumn, options);
51 | this.dataType = dbColumn.getDasType().toDataType();
52 | // 获取完整的数据库类型,如:varchar(255),char(1)
53 | var columnType = type(dataType.toString());
54 | this.typeName = columnType.getShortName();
55 | this.fullTypeName = columnType.getLongName();
56 | this.comment = Objects.toString(dbColumn.getComment(), "");
57 | this.primaryKey = DasUtil.isPrimary(dbColumn);
58 | this.selected = true;
59 | }
60 |
61 | /**
62 | * 创建主键字段对象
63 | *
64 | * @param name 字段名称
65 | * @param typeName 字段类型
66 | * @param fullTypeName 字段完整类型
67 | * @param comment 字段注释
68 | * @return 字段对象
69 | */
70 | public static EntityFieldImpl primaryField(String name, String typeName, String fullTypeName, String comment) {
71 | FieldNameInfo fieldNameInfo = new FieldNameInfo(name);
72 | return new EntityFieldImpl(fieldNameInfo, typeName, fullTypeName, true, comment, true);
73 | }
74 |
75 | public TableColumnType type(String dbType) {
76 | TableColumnType[] columnTypes = PluginUtils.getColumnTypes();
77 | if (dbType == null) {
78 | return TableColumnType.DEFAULT;
79 | }
80 | if (columnTypes == null) {
81 | return TableColumnType.DEFAULT;
82 | }
83 | for (TableColumnType columnType : columnTypes) {
84 | if (columnType.at(dbType)) {
85 | return columnType;
86 | }
87 | }
88 | for (TableColumnType columnType : columnTypes) {
89 | if (columnType.isDefault()) {
90 | return columnType;
91 | }
92 | }
93 | return columnTypes.length > 0 ? columnTypes[0] : TableColumnType.DEFAULT;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/util/YamlUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.util;
2 |
3 | import lombok.experimental.UtilityClass;
4 | import org.yaml.snakeyaml.LoaderOptions;
5 | import org.yaml.snakeyaml.Yaml;
6 | import org.yaml.snakeyaml.constructor.Constructor;
7 | import org.yaml.snakeyaml.introspector.Property;
8 | import org.yaml.snakeyaml.introspector.PropertyUtils;
9 |
10 | import java.io.InputStream;
11 | import java.io.Reader;
12 | import java.util.Map;
13 | import java.util.Optional;
14 | import java.util.concurrent.ConcurrentHashMap;
15 | import java.util.function.Function;
16 |
17 | /**
18 | * yaml工具
19 | * @author daiwenzh5
20 | * @since 2.8.4
21 | */
22 | @UtilityClass
23 | public class YamlUtils {
24 |
25 | private final static Map cache = new ConcurrentHashMap<>();
26 |
27 | /**
28 | * 从输入流中读取yaml文件,并转换为指定对象
29 | *
30 | * @param input 输入流
31 | * @param clazz 类
32 | * @param 对象类型
33 | * @return 对象
34 | */
35 | public Optional load(InputStream input, Class clazz) {
36 | return load(clazz, yaml -> yaml.loadAs(input, clazz));
37 | }
38 |
39 | /**
40 | * 从阅读字符流中读取yaml文件,并转换为指定对象
41 | *
42 | * @param input 阅读字符流
43 | * @param clazz 类
44 | * @param 对象类型
45 | * @return 对象
46 | */
47 | public Optional load(Reader input, Class clazz) {
48 | return load(clazz, yaml -> yaml.loadAs(input, clazz));
49 | }
50 |
51 | /**
52 | * 从字符串中读取yaml文件,并转换为指定对象
53 | *
54 | * @param input 输入字符串
55 | * @param clazz 类
56 | * @param 对象类型
57 | * @return 对象
58 | */
59 | public Optional load(String input, Class clazz) {
60 | return load(clazz, yaml -> yaml.loadAs(input, clazz));
61 | }
62 |
63 | private Optional load(Class clazz, Function loader) {
64 | try {
65 | var yaml = cache.computeIfAbsent(clazz.getName(), k -> buildYamlInstance(clazz));
66 | return Optional.ofNullable(loader.apply(yaml));
67 | } catch (Exception e) {
68 | return Optional.empty();
69 | }
70 | }
71 |
72 | private Yaml buildYamlInstance(Class> clazz) {
73 | var constructor = new Constructor(clazz, new LoaderOptions());
74 | constructor.setPropertyUtils(new PropertyUtils() {
75 | @Override
76 | public Property getProperty(Class> type, String name) {
77 | if (name.indexOf('-') > -1) {
78 | name = camelize(name);
79 | }
80 | // 关键代码 忽略yaml中无法在类中找到属性的字段
81 | setSkipMissingProperties(true);
82 | return super.getProperty(type, name);
83 | }
84 | });
85 | return new Yaml(constructor);
86 | }
87 |
88 | private static String camelize(String input) {
89 | for (int i = 0; i < input.length(); i++) {
90 | if (input.charAt(i) == '-') {
91 | input = input.substring(0, i) + input.substring(i + 1, i + 2)
92 | .toUpperCase() + input.substring(i + 2);
93 | }
94 | if (input.charAt(i) == ' ') {
95 | input = input.substring(0, i) + input.substring(i + 1, i + 2)
96 | .toUpperCase() + input.substring(i + 2);
97 | }
98 | }
99 | return input;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/BaseSetting.form:
--------------------------------------------------------------------------------
1 |
2 |
87 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/task/GeneratorTask.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.task;
2 |
3 | import com.github.houkunlin.util.FileUtils;
4 | import com.github.houkunlin.util.Generator;
5 | import com.github.houkunlin.util.PluginUtils;
6 | import com.github.houkunlin.vo.impl.RootModel;
7 | import com.intellij.openapi.progress.ProgressIndicator;
8 | import com.intellij.openapi.progress.Task;
9 | import com.intellij.openapi.project.DumbService;
10 | import com.intellij.openapi.project.Project;
11 | import com.intellij.openapi.ui.Messages;
12 | import com.intellij.psi.PsiFile;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import javax.swing.*;
16 | import java.io.File;
17 | import java.util.List;
18 |
19 | /**
20 | * @author HouKunLin
21 | */
22 | public class GeneratorTask extends Task.Modal {
23 | private final Project project;
24 | private final JFrame windows;
25 | private final Generator generator;
26 | private final List templates;
27 | private final List rootModels;
28 |
29 | public GeneratorTask(@NotNull Project project, JFrame windows, Generator generator, List templates, List rootModels) {
30 | super(project, "生成代码", false);
31 | this.project = project;
32 | this.windows = windows;
33 | this.generator = generator;
34 | this.templates = templates;
35 | this.rootModels = rootModels;
36 | }
37 |
38 | @Override
39 | public void run(@NotNull ProgressIndicator indicator) {
40 | indicator.setIndeterminate(false);
41 |
42 | generator(indicator);
43 | }
44 |
45 | public void generator(ProgressIndicator indicator) {
46 | indicator.setText("正在生成代码 ......");
47 |
48 | indicator.setFraction(0.0);
49 |
50 | int modelSize = rootModels.size();
51 | int templateSize = templates.size();
52 |
53 | int countInt = modelSize * templateSize;
54 | double count = (countInt) * 1.0;
55 | for (int i = 0; i < modelSize; i++) {
56 | RootModel rootModel = rootModels.get(i);
57 | int start = i * templateSize;
58 | generator.generator(rootModel, templates, (integer, filename) -> {
59 | int index = start + integer + 1;
60 | indicator.setText2(String.format("[%s/%s] [%s] --> %s",
61 | index, countInt, rootModel.getTable().getName(), filename));
62 | indicator.setFraction(index / count);
63 | });
64 | }
65 | indicator.setText("生成代码完毕!");
66 | indicator.setText2("正在执行收尾工作,请稍候 ......");
67 |
68 | indicator.setFraction(1.0);
69 | indicator.setIndeterminate(true);
70 | PluginUtils.refreshProject();
71 | }
72 |
73 | @Override
74 | public void onSuccess() {
75 | super.onSuccess();
76 | windows.dispose();
77 | DumbService dumbService = DumbService.getInstance(project);
78 | if (dumbService.isDumb()) {
79 | dumbService.showDumbModeNotification("正在等待其他任务完成后才能进行格式化代码操作 ...");
80 | }
81 | dumbService.smartInvokeLater(() -> {
82 | List saveFiles = generator.getSaveFiles();
83 | if (!saveFiles.isEmpty()) {
84 | FileUtils.getInstance().reformatCode(project, saveFiles.toArray(new PsiFile[0]));
85 | }
86 | });
87 | Messages.showInfoMessage(String.format("代码构建完毕,涉及 %s 个数据库表和 %s 个模板文件,总共生成 %s 个文件。", rootModels.size(), templates.size(), generator.getSaveFiles().size()), "完成");
88 | }
89 |
90 | @Override
91 | public void onThrowable(@NotNull Throwable error) {
92 | super.onThrowable(error);
93 | Messages.showErrorDialog("代码生成失败,当前插件 2.x 版本不兼容旧版的代码模板,请升级代码模板,代码模板升级指南请查看插件介绍。\n\n" + error.getMessage(), "生成代码失败");
94 | windows.setVisible(true);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/.github/workflows/upload-plugin.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Upload Plugin
5 |
6 | on:
7 | push:
8 | tags: [ v* ]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up JDK 17
18 | uses: actions/setup-java@v1
19 | with:
20 | java-version: 17
21 | - name: Grant execute permission for gradlew
22 | run: chmod +x gradlew
23 | - name: Generator Plugin Doc Markdown Text
24 | env: # Or as an environment variable
25 | intellijPublishToken: ${{ secrets.INTELLIJPUBLISHTOKEN }}
26 | # 不打包 Kotlin 标准依赖:https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library
27 | run: ./gradlew markdownToHtml
28 | - name: Build Plugin with Gradle
29 | env: # Or as an environment variable
30 | intellijPublishToken: ${{ secrets.INTELLIJPUBLISHTOKEN }}
31 | # 不打包 Kotlin 标准依赖:https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library
32 | run: ./gradlew buildPlugin -Pkotlin.stdlib.default.dependency=false
33 | - name: Publish Plugin with Gradle
34 | env: # Or as an environment variable
35 | intellijPublishToken: ${{ secrets.INTELLIJPUBLISHTOKEN }}
36 | # 不打包 Kotlin 标准依赖:https://kotlinlang.org/docs/reference/using-gradle.html#dependency-on-the-standard-library
37 | run: ./gradlew publishPlugin -Pkotlin.stdlib.default.dependency=false
38 | - name: Rename
39 | run: mv build/distributions/*.zip build/distributions/plugin.zip
40 | - name: Create Release
41 | id: create_release
42 | uses: actions/create-release@v1
43 | env:
44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45 | with:
46 | tag_name: ${{ github.ref }}
47 | release_name: Release ${{ github.ref }}
48 | draft: false
49 | prerelease: false
50 | - name: Upload Release Asset
51 | id: upload-release-asset
52 | uses: actions/upload-release-asset@v1
53 | env:
54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
55 | with:
56 | # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
57 | upload_url: ${{ steps.create_release.outputs.upload_url }}
58 | asset_path: build/distributions/plugin.zip
59 | asset_name: Database_Generator.zip
60 | asset_content_type: application/zip
61 | - name: Unpack Plugin Zip
62 | run: unzip -d tmp/ build/distributions/plugin.zip
63 | - uses: actions/upload-artifact@v4
64 | with:
65 | # Name of the artifact to upload.
66 | # Optional. Default is 'artifact'
67 | name: Database_Generator
68 | # A file, directory or wildcard pattern that describes what to upload
69 | # Required.
70 | path: tmp/**/*
71 | # The desired behavior if no files are found using the provided path.
72 | # Available Options:
73 | # warn: Output a warning but do not fail the action
74 | # error: Fail the action with an error message
75 | # ignore: Do not output any warnings or errors, the action does not fail
76 | # Optional. Default is 'warn'
77 | if-no-files-found: warn
78 | # Duration after which artifact will expire in days. 0 means using default retention.
79 | # Minimum 1 day.
80 | # Maximum 90 days unless changed from the repository settings page.
81 | # Optional. Defaults to repository settings.
82 | retention-days: 7
83 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/TablePanel.form:
--------------------------------------------------------------------------------
1 |
2 |
93 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/util/ScriptManager.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.util;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 | import groovy.lang.GroovyClassLoader;
5 |
6 | import java.io.IOException;
7 | import java.nio.file.Files;
8 | import java.nio.file.Path;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 | import java.util.WeakHashMap;
12 | import java.util.function.BiConsumer;
13 |
14 | /**
15 | * 脚本管理器
16 | *
17 | * @author daiwenzh5
18 | * @since 1.0
19 | */
20 | public class ScriptManager {
21 |
22 | private final static Logger logger = Logger.getInstance(ScriptManager.class);
23 |
24 | /**
25 | * 脚本目录
26 | */
27 | public final static String DIR = "scripts";
28 |
29 | /**
30 | * 变量名
31 | */
32 | public final static String VARIABLE = DIR;
33 |
34 | /**
35 | * 命名空间
36 | */
37 | public final static String NAMESPACE = VARIABLE + ".";
38 |
39 |
40 | /**
41 | * 缓存,确保相同的脚本目录,只加载一次
42 | */
43 | private final static WeakHashMap cache = new WeakHashMap<>();
44 | private final Map scripts = new HashMap<>();
45 | private static final ScriptManager EMPTY = new ScriptManager();
46 | private final Path scriptDir;
47 | private final GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
48 |
49 | private ScriptManager() {
50 | this.scriptDir = null;
51 | }
52 |
53 | private ScriptManager(Path scriptDir) {
54 | if (!Files.exists(scriptDir)) {
55 | logger.warn("脚本: " + scriptDir + "不存在");
56 | this.scriptDir = null;
57 | return;
58 | }
59 | this.scriptDir = scriptDir;
60 | scan();
61 | }
62 |
63 |
64 | /**
65 | * 根据脚本目录获取脚本管理器,如果目录不存在,则返回一个空的脚本管理器。对于相同目录,优先从内存在获取。
66 | *
67 | * @param scriptDir 脚本目录
68 | * @param reload 是否重新加载
69 | * @return 一个脚本管理器
70 | */
71 | public static ScriptManager of(Path scriptDir, boolean reload) {
72 | if (scriptDir == null) {
73 | return EMPTY;
74 | }
75 | var scriptManager = cache.computeIfAbsent(scriptDir.toString(), key -> new ScriptManager(scriptDir));
76 | if (reload) {
77 | scriptManager.scan();
78 | }
79 | return scriptManager;
80 | }
81 |
82 |
83 | private void scan() {
84 | if (scriptDir == null) {
85 | return;
86 | }
87 | // 扫描脚本目录,加载所有.groovy文件
88 | try (var files = Files.walk(scriptDir)) {
89 | files.filter(path -> path.toString()
90 | .endsWith(".groovy"))
91 | .forEach(this::registerScript);
92 | } catch (IOException ignored) {
93 |
94 | }
95 |
96 | }
97 |
98 | private void registerScript(Path path) {
99 | try {
100 | var file = path.toFile();
101 | Class> parsedClass = groovyClassLoader.parseClass(file);
102 | var fileName = file.getName();
103 | var instance = parsedClass.getDeclaredConstructor()
104 | .newInstance();
105 | logger.info("load script: " + scriptDir.relativize(path));
106 | scripts.put(fileName.replace(".groovy", ""), instance);
107 | } catch (Exception e) {
108 | throw new RuntimeException("Failed to load script: " + path, e);
109 | }
110 | }
111 |
112 | public Object get(String fileName) {
113 | return scripts.get(fileName);
114 | }
115 |
116 | /**
117 | * 遍历所有方法
118 | *
119 | * @param action 操作
120 | */
121 | public void forEach(BiConsumer action) {
122 | scripts.forEach(action);
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/config/ConfigService.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.config;
2 |
3 | import com.github.houkunlin.util.PluginUtils;
4 | import com.intellij.openapi.components.PersistentStateComponent;
5 | import com.intellij.openapi.components.State;
6 | import com.intellij.openapi.components.Storage;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.util.xmlb.XmlSerializerUtil;
9 | import lombok.Data;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 | import org.mapstruct.factory.Mappers;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Collections;
16 | import java.util.List;
17 |
18 | /**
19 | * 配置 Service
20 | *
21 | * @author HouKunLin
22 | */
23 | @Data
24 | @State(name = "com.github.houkunlin.database.generator.config.ConfigService",
25 | defaultStateAsResource = true,
26 | storages = {@Storage("database-generator-config.xml")})
27 | public class ConfigService implements PersistentStateComponent {
28 | public static final BeanTransform BEAN_TRANSFORM = Mappers.getMapper(BeanTransform.class);
29 | private Developer developer;
30 | private Options options;
31 | private Settings settings;
32 | private final List lastSelectionTemplates = new ArrayList<>();
33 |
34 | public ConfigService() {
35 | ConfigVo configVo = PluginUtils.loadConfig();
36 | developer = configVo.getDeveloper();
37 | options = configVo.getOptions();
38 | settings = configVo.getSettings();
39 | assert developer != null;
40 | assert options != null;
41 | assert settings != null;
42 | }
43 |
44 | /**
45 | * 重新从配置文件中读取配置信息
46 | */
47 | public synchronized void reset(){
48 | ConfigVo configVo = PluginUtils.loadConfig();
49 | Developer developer = configVo.getDeveloper();
50 | Options options = configVo.getOptions();
51 | Settings settings = configVo.getSettings();
52 | assert developer != null;
53 | assert options != null;
54 | assert settings != null;
55 | if (settings.getProjectPath() == null) {
56 | settings.setProjectPath(PluginUtils.getProjectPath().normalize().toString());
57 | }
58 | this.lastSelectionTemplates.clear();
59 | BEAN_TRANSFORM.copyTo(developer, this.developer);
60 | BEAN_TRANSFORM.copyTo(options, this.options);
61 | BEAN_TRANSFORM.copyTo(settings, this.settings);
62 | }
63 |
64 | @Nullable
65 | public static ConfigService getInstance(Project project) {
66 | return project.getService(ConfigService.class);
67 | }
68 |
69 | @Nullable
70 | @Override
71 | public ConfigService getState() {
72 | return this;
73 | }
74 |
75 | @Override
76 | public void loadState(@NotNull ConfigService state) {
77 | XmlSerializerUtil.copyBean(state, this);
78 | }
79 |
80 | /**
81 | * 设置上次选择的模板列表,仅当启用 "记住上次选择的模板" 选项时,才生效
82 | *
83 | * @param lastSelectionTemplates 上次选择的模板列表
84 | */
85 | public void setLastSelectionTemplates(List lastSelectionTemplates) {
86 | if (this.options == null || !this.options.isRetainLastSelectionTemplates()) {
87 | return;
88 | }
89 | this.lastSelectionTemplates.clear();
90 | this.lastSelectionTemplates.addAll(lastSelectionTemplates);
91 | }
92 |
93 | /**
94 | * 获取上次选择的模板列表, 当未启用 "记住上次选择的模板" 选项时,直接返回空列表
95 | * @return 上次选择的模板列表
96 | */
97 | public List getLastSelectionTemplates() {
98 | if (this.options == null || !this.options.isRetainLastSelectionTemplates()) {
99 | return Collections.emptyList();
100 | }
101 | return this.lastSelectionTemplates;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/templates/MyBatisMapper.xml.ftl:
--------------------------------------------------------------------------------
1 | <#include "jdbc-type.ftl">
2 | ${gen.setType("xml")}<#-- 生成 MyBatis 的 Mapper.xml 内容代码模板 -->
3 |
4 |
5 |
6 |
7 | <#list columns as column>
8 | <#-- ${column.name}:${column.typeName} -->
9 | <#if column.primaryKey>
10 |
11 | <#else>
12 |
13 | #if>
14 | #list>
15 |
16 |
17 | <#list columns as column>${column.name}<#if column?has_next>,#if>#list>
18 |
19 |
25 |
26 | delete from ${table.name}
27 | where ${primary.column.name} = ${r'#'}{${primary.field.name},jdbcType=${jdbcType(primary.column)}}
28 |
29 |
31 | insert into ${table.name} (
32 | <#list columns as column>${column.name}<#if column?has_next>,#if>#list>
33 | )
34 | values (
35 | <#list columns as column>${r'#'}{${column.field.name},jdbcType=${jdbcType(column)}}<#if column?has_next>,#if>#list>
36 | )
37 |
38 |
40 | insert into ${table.name}
41 |
42 | <#list columns as column>
43 |
44 | ${column.name},
45 |
46 | #list>
47 |
48 |
49 | <#list columns as column>
50 |
51 | ${r'#'}{${column.field.name},jdbcType=${jdbcType(column)}},
52 |
53 | #list>
54 |
55 |
56 |
57 | update ${table.name}
58 |
59 | <#list columns as column>
60 |
61 | ${column.name} = ${r'#'}{${column.field.name},jdbcType=${jdbcType(column)}},
62 |
63 | #list>
64 |
65 | where ${primary.column.name} = ${r'#'}{${primary.field.name},jdbcType=${jdbcType(primary.column)}}
66 |
67 |
68 | update ${table.name}
69 | set
70 | <#list columns as column>
71 | ${column.name} = ${r'#'}{${column.field.name},jdbcType=${jdbcType(column)}}<#if column?has_next>,#if>
72 | #list>
73 | where ${primary.column.name} = ${r'#'}{${primary.field.name},jdbcType=${jdbcType(primary.column)}}
74 |
75 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/Main.form:
--------------------------------------------------------------------------------
1 |
2 |
99 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/table/FileTypeTableDecorator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.table;
2 |
3 | import com.github.houkunlin.config.Settings;
4 | import com.github.houkunlin.message.Bundles;
5 | import com.github.houkunlin.model.FileType;
6 | import com.github.houkunlin.util.PluginUtils;
7 | import com.intellij.openapi.actionSystem.ActionToolbarPosition;
8 | import com.intellij.openapi.project.Project;
9 | import com.intellij.ui.ToolbarDecorator;
10 | import com.intellij.util.ObjectUtils;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import javax.swing.*;
14 |
15 | /**
16 | * 文件类型表格
17 | *
18 | * @author daiwenzh5
19 | * @since 2.8.4
20 | */
21 | public class FileTypeTableDecorator extends TableDecorator {
22 |
23 | private FileTypeTableDecorator() {
24 | }
25 |
26 | public static JPanel create(Project project, Settings settings) {
27 | return new FileTypeTableDecorator()
28 | .setModel(createTableModel(project, settings))
29 | .applyToolbar((tableDecorator, toolbarDecorator) -> configurationToolbar(settings, tableDecorator, toolbarDecorator));
30 | }
31 |
32 | private static void configurationToolbar(Settings settings, FileTypeTableDecorator tableDecorator, ToolbarDecorator toolbarDecorator) {
33 | toolbarDecorator
34 | .setToolbarPosition(ActionToolbarPosition.TOP)
35 | .setAddAction(btn -> tableDecorator.getModel()
36 | // 添加新行并设置默认值
37 | .addRows(FileType.of("", "", "", ".java", settings.getJavaPath(), true)))
38 | .setRemoveAction(btn -> {
39 | if (tableDecorator.table.getSelectedRows().length == 0) {
40 | return;
41 | }
42 | var selectedRows = tableDecorator.table.getSelectedRows();
43 | tableDecorator.getModel()
44 | .removeRows(selectedRows);
45 | tableDecorator.table.clearSelection();
46 | });
47 | }
48 |
49 | private static @NotNull GenericTableModel createTableModel(Project project, Settings settings) {
50 | var editorTableCellEditor = new EditorTableCellEditor(project);
51 | var extTableCellEditor = new ComboBoxTableCellEditor<>(".java", ".kt", ".xml");
52 | var javaPath = ObjectUtils.notNull(settings.getJavaPath(), "src/main/java");
53 | var pathTableCellEditor = new ComboBoxTableCellEditor<>(
54 | javaPath,
55 | javaPath.replace("java", "kotlin"),
56 | settings.getResourcesPath()
57 | );
58 | return new GenericTableModel<>(settings.getFileTypes())
59 | .addColumn(ColumnSpec.of(Bundles.message("fileTypes.type"), String.class, FileType::getType, FileType::setType))
60 | .addColumn(ColumnSpec.of(Bundles.message("fileTypes.suffix"), String.class, FileType::getSuffix, FileType::setSuffix))
61 | .addColumn(ColumnSpec.of(Bundles.message("fileTypes.package"), String.class, FileType::getPackageName, FileType::setPackageName)
62 | .withWidth(120)
63 | .withCellEditor(editorTableCellEditor))
64 | .addColumn(ColumnSpec.of(Bundles.message("fileTypes.ext"), String.class, FileType::getExt, FileType::setExt)
65 | .withCellEditor(extTableCellEditor)
66 | .withPlaceholder(Bundles.message("fileTypes.ext.placeholder"))
67 | .withWidth(50))
68 | .addColumn(ColumnSpec.of(Bundles.message("fileTypes.path"), String.class, FileType::getPath, FileType::setPath)
69 | .withCellEditor(pathTableCellEditor)
70 | .withPlaceholder(Bundles.message("fileTypes.path.placeholder"))
71 | .withWidth(200))
72 | .addColumn(ColumnSpec.of(Bundles.message("fileTypes.override"), Boolean.class, FileType::isOverride, FileType::setOverride)
73 | .withWidth(30));
74 | }
75 |
76 | @Override
77 | public void reset() {
78 | var fileTypes = PluginUtils.loadConfig()
79 | .getSettings()
80 | .getFileTypes();
81 | this.reset(fileTypes);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/tree/CheckBoxTreeNode.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.tree;
2 |
3 | import lombok.Getter;
4 |
5 | import javax.swing.tree.DefaultMutableTreeNode;
6 | import javax.swing.tree.TreeNode;
7 | import java.io.File;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * 拥有复选框的树形节点
13 | *
14 | * @author HouKunLin
15 | */
16 | @Getter
17 | public class CheckBoxTreeNode extends DefaultMutableTreeNode {
18 | protected boolean selected;
19 |
20 | public CheckBoxTreeNode() {
21 | this(null);
22 | }
23 |
24 | public CheckBoxTreeNode(Object userObject) {
25 | this(userObject, true, false);
26 | }
27 |
28 | public CheckBoxTreeNode(Object userObject, boolean allowsChildren, boolean selected) {
29 | super(userObject, allowsChildren);
30 | this.selected = selected;
31 | }
32 |
33 | public void setSelected(boolean selected) {
34 | this.selected = selected;
35 | if (selected) {
36 | // 如果选中,则将其所有的子结点都选中
37 | if (children != null) {
38 | for (Object obj : children) {
39 | CheckBoxTreeNode node = (CheckBoxTreeNode) obj;
40 | if (!node.isSelected()) {
41 | node.setSelected(true);
42 | }
43 | }
44 | }
45 | // 向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中
46 | CheckBoxTreeNode pNode = (CheckBoxTreeNode) parent;
47 | // 开始检查pNode的所有子节点是否都被选中
48 | if (pNode != null) {
49 | int index = 0;
50 | for (; index < pNode.children.size(); ++index) {
51 | CheckBoxTreeNode pChildNode = (CheckBoxTreeNode) pNode.children.get(index);
52 | if (!pChildNode.isSelected()) {
53 | break;
54 | }
55 | }
56 |
57 | /*表明pNode所有子结点都已经选中,则选中父结点,
58 | 该方法是一个递归方法,因此在此不需要进行迭代,因为
59 | 当选中父结点后,父结点本身会向上检查的。*/
60 |
61 | if (index == pNode.children.size()) {
62 | if (!pNode.isSelected()) {
63 | pNode.setSelected(true);
64 | }
65 | }
66 | }
67 | } else {
68 |
69 | /* 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的;
70 | 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但
71 | 是这时候是不需要取消子结点的。*/
72 |
73 | if (children != null) {
74 | int index = 0;
75 | for (; index < children.size(); ++index) {
76 | CheckBoxTreeNode childNode = (CheckBoxTreeNode) children.get(index);
77 | if (!childNode.isSelected()) {
78 | break;
79 | }
80 | }
81 | // 从上向下取消的时候
82 | if (index == children.size()) {
83 | for (javax.swing.tree.TreeNode child : children) {
84 | CheckBoxTreeNode node = (CheckBoxTreeNode) child;
85 | if (node.isSelected()) {
86 | node.setSelected(false);
87 | }
88 | }
89 | }
90 | }
91 |
92 | // 向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。
93 | //这一块注释之后,子节点的取消不会影响父节点的勾选,为实现取消子节点,单独只选择父节点自己查看
94 | CheckBoxTreeNode pNode = (CheckBoxTreeNode) parent;
95 | if (pNode != null && pNode.isSelected()) {
96 | pNode.setSelected(false);
97 | }
98 | }
99 | }
100 |
101 | public List getAllSelectNodes() {
102 | List list = new ArrayList<>();
103 | if (selected) {
104 | list.add(this);
105 | }
106 | if (children != null) {
107 | for (TreeNode child : children) {
108 | if (child instanceof CheckBoxTreeNode node) {
109 | list.addAll(node.getAllSelectNodes());
110 | }
111 | }
112 | }
113 | return list;
114 | }
115 |
116 | @Override
117 | public String toString() {
118 | if (userObject == null) {
119 | return "";
120 | }
121 | if (userObject instanceof File) {
122 | return ((File) userObject).getName();
123 | } else {
124 | return userObject.toString();
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/RootModel.uml:
--------------------------------------------------------------------------------
1 |
2 |
3 | JAVA
4 | com.github.houkunlin.vo.impl.RootModel
5 |
6 | com.github.houkunlin.vo.impl.EntityFieldImpl
7 | com.github.houkunlin.vo.impl.EntityNameInfo
8 | com.github.houkunlin.vo.impl.TableColumnImpl
9 | com.github.houkunlin.vo.impl.EntityImpl
10 | com.github.houkunlin.vo.impl.RootModel
11 | com.github.houkunlin.vo.impl.PrimaryInfo
12 | com.github.houkunlin.vo.impl.FieldNameInfo
13 | com.github.houkunlin.vo.impl.EntityName
14 | com.github.houkunlin.vo.impl.TableImpl
15 | com.github.houkunlin.vo.impl.EntityPackageInfo
16 | com.github.houkunlin.vo.impl.EntityPackage
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 | com.github.houkunlin.vo.impl.PrimaryInfo
76 |
77 |
78 | Fields
79 |
80 | All
81 | private
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/util/Generator.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.util;
2 |
3 | import com.github.houkunlin.config.Developer;
4 | import com.github.houkunlin.config.Options;
5 | import com.github.houkunlin.config.Settings;
6 | import com.github.houkunlin.model.SaveFilePath;
7 | import com.github.houkunlin.template.ITemplateGenerator;
8 | import com.github.houkunlin.template.TemplateGeneratorFactory;
9 | import com.github.houkunlin.vo.Variable;
10 | import com.github.houkunlin.vo.impl.RootModel;
11 | import com.intellij.openapi.project.Project;
12 | import com.intellij.psi.PsiFile;
13 | import com.intellij.util.ExceptionUtil;
14 | import lombok.Data;
15 | import org.joda.time.DateTime;
16 |
17 | import java.io.File;
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 | import java.util.function.BiConsumer;
23 |
24 | /**
25 | * 代码生成工具
26 | *
27 | * @author HouKunLin
28 | */
29 | @Data
30 | public class Generator {
31 | private final Settings settings;
32 | private final Options options;
33 | private final Map context;
34 | private final List saveFiles;
35 | private final Project project;
36 |
37 | public Generator(Project project, Settings settings, Options options, Developer developer) {
38 | this.project = project;
39 | this.settings = settings;
40 | this.options = options;
41 | this.saveFiles = new ArrayList<>();
42 | this.context = new HashMap<>(8);
43 | context.put("settings", settings);
44 | context.put("developer", developer);
45 | context.put("gen", Variable.getInstance());
46 | context.put("date", DateTime.now());
47 | }
48 |
49 | /**
50 | * 执行生成代码任务
51 | */
52 | public void generator(RootModel rootModel, List templateFiles, BiConsumer progress) {
53 | if (rootModel == null || templateFiles == null || templateFiles.isEmpty()) {
54 | return;
55 | }
56 | loadContext(rootModel);
57 | for (int i = 0; i < templateFiles.size(); i++) {
58 | var templateFile = templateFiles.get(i);
59 | var generator = TemplateGeneratorFactory.create(templateFile);
60 | var workspace = generator.getWorkspace();
61 | var templateFilename = FileUtils.relativePath(workspace, templateFile)
62 | .replaceFirst(PluginUtils.TEMPLATE_DIR, "");
63 | if (progress != null) {
64 | progress.accept(i, templateFilename);
65 | }
66 | // 重置内容,方便使用默认配置
67 | Variable.resetVariables();
68 | generatorTemplateFile(rootModel, generator, templateFile, templateFilename);
69 | }
70 | }
71 |
72 | private void loadContext(RootModel rootModel) {
73 | context.put("table", rootModel.getTable());
74 | context.put("columns", rootModel.getColumns());
75 | context.put("entity", rootModel.getEntity(settings));
76 | context.put("fields", rootModel.getFields());
77 | context.put("primary", rootModel.getPrimary());
78 | }
79 |
80 | private void generatorTemplateFile(RootModel rootModel, ITemplateGenerator generator, File templateFile, String templateFilename) {
81 | try {
82 | var result = generator.generate(templateFilename, context);
83 | if (result == null || result.isBlank()) {
84 | // 不保存空内容的文件
85 | return;
86 | }
87 | var savePsiFile = getSavePsiFile(rootModel, templateFile, result);
88 | if (savePsiFile != null && !saveFiles.contains(savePsiFile)) {
89 | saveFiles.add(savePsiFile);
90 | }
91 | } catch (Throwable e) {
92 | ExceptionUtil.rethrow(new RuntimeException("解析错误:" + templateFile.getAbsolutePath() + "\r\n" + e.getMessage(), e));
93 | }
94 | }
95 |
96 | private PsiFile getSavePsiFile(RootModel rootModel, File templateFile, String result) {
97 | var saveFilePath = getSaveFilePath(rootModel, templateFile);
98 | var saveFile = new File(settings.getProjectPath(), String.valueOf(saveFilePath));
99 | return FileUtils.getInstance()
100 | .saveFileContent(project, saveFile, result, saveFilePath.isOverride());
101 | }
102 |
103 | private SaveFilePath getSaveFilePath(RootModel rootModel, File templateFile) {
104 | if (Variable.type == null) {
105 | return SaveFilePath.createTemp(templateFile.getName(), settings);
106 | }
107 | return SaveFilePath.create(rootModel, settings);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/model/JTableModel.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.model;
2 |
3 | import com.github.houkunlin.config.Options;
4 | import com.github.houkunlin.vo.impl.EntityFieldImpl;
5 | import com.github.houkunlin.vo.impl.TableColumnImpl;
6 | import com.google.common.collect.HashBasedTable;
7 | import com.google.common.collect.Table;
8 | import com.intellij.database.model.DasColumn;
9 | import com.intellij.database.psi.DbTable;
10 | import com.intellij.database.util.DasUtil;
11 | import com.intellij.util.containers.JBIterable;
12 | import lombok.Data;
13 | import lombok.EqualsAndHashCode;
14 |
15 | import javax.swing.*;
16 | import javax.swing.table.AbstractTableModel;
17 | import javax.swing.table.TableColumn;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * 表格列名信息
23 | *
24 | * @author HouKunLin
25 | */
26 | @Data
27 | @EqualsAndHashCode(callSuper = true)
28 | public class JTableModel extends AbstractTableModel {
29 | private final List fieldImpls = new ArrayList<>();
30 | private final List columnImpls = new ArrayList<>();
31 |
32 | Table table = HashBasedTable.create();
33 | String[] names = {"选中", "DB列名", "Java字段", "DB类型", "Java类型", "注释"};
34 | Boolean[] editable = {true, false, false, false, false, true};
35 |
36 | public JTableModel(JTable columnTable, DbTable dbTable, Options options) {
37 | initTableContent(dbTable, options);
38 | columnTable.setModel(this);
39 | setColumnSelected(columnTable);
40 | }
41 |
42 | private void setColumnSelected(JTable columnTable) {
43 | TableColumn column = columnTable.getColumnModel().getColumn(0);
44 | column.setCellEditor(new DefaultCellEditor(new JCheckBox()));
45 | int width = 30;
46 | column.setMaxWidth(width);
47 | column.setMinWidth(width);
48 | }
49 |
50 | private void initTableContent(DbTable dbTable, Options options) {
51 | // ((DbTableImpl) psiElements[0]).getDelegate().getDasChildren(ObjectKind.COLUMN).get(3)
52 | // ((DbTableImpl)((DbColumnImpl) psiElement).getTable()).getDelegate().getDasChildren(ObjectKind.COLUMN).get(5).getName()
53 | // ((MysqlImplModel.Table) delegate).getKeys().myElements.get(0).getColNames()
54 | // ((MysqlImplModel.Table) delegate).getPrimaryKey().getColNames()
55 | int rowIndex = -1;
56 | JBIterable extends DasColumn> columns = DasUtil.getColumns(dbTable);
57 | for (DasColumn column : columns) {
58 | EntityFieldImpl entityField = new EntityFieldImpl(column, options);
59 | TableColumnImpl tableColumn = new TableColumnImpl(column);
60 | entityField.setColumn(tableColumn);
61 | tableColumn.setField(entityField);
62 | fieldImpls.add(entityField);
63 | columnImpls.add(tableColumn);
64 |
65 | int colIndex = -1;
66 | ++rowIndex;
67 | // 第0列选中复选框
68 | table.put(rowIndex, ++colIndex, true);
69 | // 第1列:DB列名
70 | table.put(rowIndex, ++colIndex, tableColumn.getName());
71 | // 第2列:Java字段
72 | table.put(rowIndex, ++colIndex, entityField.getName());
73 | // 第3列:DB类型
74 | table.put(rowIndex, ++colIndex, tableColumn.getFullTypeName());
75 | // 第4列:Java类型
76 | table.put(rowIndex, ++colIndex, entityField.getTypeName());
77 | // 第5列:注释
78 | table.put(rowIndex, ++colIndex, entityField.getComment());
79 | }
80 | }
81 |
82 | @Override
83 | public int getRowCount() {
84 | return table.rowKeySet().size();
85 | }
86 |
87 | @Override
88 | public int getColumnCount() {
89 | return table.columnKeySet().size();
90 | }
91 |
92 | @Override
93 | public Object getValueAt(int rowIndex, int columnIndex) {
94 | return table.get(rowIndex, columnIndex);
95 | }
96 |
97 | @Override
98 | public String getColumnName(int column) {
99 | return names[column];
100 | }
101 |
102 | @Override
103 | public Class> getColumnClass(int columnIndex) {
104 | return getValueAt(0, columnIndex).getClass();
105 | }
106 |
107 | @Override
108 | public boolean isCellEditable(int row, int column) {
109 | return editable[column];
110 | }
111 |
112 | @Override
113 | public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
114 | if (columnIndex == 0) {
115 | fieldImpls.get(rowIndex).setSelected((Boolean) aValue);
116 | columnImpls.get(rowIndex).setSelected((Boolean) aValue);
117 | update(aValue, rowIndex, columnIndex);
118 | } else if (columnIndex == names.length - 1) {
119 | fieldImpls.get(rowIndex).setComment(String.valueOf(aValue));
120 | update(aValue, rowIndex, columnIndex);
121 | }
122 | }
123 |
124 | private void update(Object aValue, int rowIndex, int columnIndex) {
125 | table.put(rowIndex, columnIndex, aValue);
126 | fireTableCellUpdated(rowIndex, columnIndex);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/BaseSetting.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win;
2 |
3 | import com.github.houkunlin.config.Developer;
4 | import com.github.houkunlin.config.Options;
5 | import com.github.houkunlin.config.Settings;
6 | import com.github.houkunlin.ui.win.table.FileTypeTableDecorator;
7 | import com.google.common.collect.Maps;
8 | import com.intellij.openapi.project.Project;
9 |
10 | import javax.swing.*;
11 | import javax.swing.event.DocumentEvent;
12 | import javax.swing.event.DocumentListener;
13 | import javax.swing.text.JTextComponent;
14 | import java.awt.*;
15 | import java.awt.event.ItemEvent;
16 | import java.util.Map;
17 | import java.util.Set;
18 | import java.util.function.Consumer;
19 |
20 | /**
21 | * 基础设置窗口
22 | *
23 | * @author HouKunLin
24 | */
25 | public class BaseSetting implements IWindows {
26 | private final Project project;
27 | /**
28 | * 配置对象:设置信息
29 | */
30 | private final Settings settings;
31 | /**
32 | * 配置对象:是否覆盖文件
33 | */
34 | private final Options options;
35 | /**
36 | * 配置对象:开发者信息
37 | */
38 | private final Developer developer;
39 | /**
40 | * 输入框:开发者姓名
41 | */
42 | private JTextField authorField;
43 | /**
44 | * 输入框:电子邮件
45 | */
46 | private JTextField emailField;
47 | /**
48 | * 面板:顶级页面面板
49 | */
50 | private JPanel content;
51 | /**
52 | * 下拉框:数据库字段风格类型
53 | */
54 | private JComboBox databaseFieldStyleType;
55 |
56 | /**
57 | * 复选:是否记住上次的模板
58 | */
59 | private JCheckBox retainLastSelectionTemplates;
60 | private JPanel fileTypeTablePanel;
61 | private final Runnable noteReset;
62 |
63 | public BaseSetting(Project project, Settings settings, Developer developer, Options options, Runnable noteReset) {
64 | this.project = project;
65 | this.settings = settings;
66 | this.developer = developer;
67 | this.options = options;
68 | this.noteReset = noteReset;
69 | initFileTypeTable();
70 | initDatabaseFieldStyle();
71 | initConfig();
72 |
73 | /* 普通输入框的输入事件监听 */
74 | class TextFieldDocumentListener implements DocumentListener {
75 | /**
76 | * 存放 setValue 与 输入框 的关系
77 | */
78 | private final Map, JTextComponent> map = Maps.newHashMap();
79 |
80 | public TextFieldDocumentListener() {
81 | map.put(developer::setAuthor, authorField);
82 | map.put(developer::setEmail, emailField);
83 | }
84 |
85 | @Override
86 | public void insertUpdate(DocumentEvent e) {
87 | documentChanged(e);
88 | }
89 |
90 | @Override
91 | public void removeUpdate(DocumentEvent e) {
92 | documentChanged(e);
93 | }
94 |
95 | @Override
96 | public void changedUpdate(DocumentEvent e) {
97 | }
98 |
99 | /**
100 | * swing 输入框组件内容更改事件
101 | *
102 | * @param e 事件
103 | */
104 | public void documentChanged(DocumentEvent e) {
105 | javax.swing.text.Document document = e.getDocument();
106 | Set, JTextComponent>> entries = map.entrySet();
107 | for (Map.Entry, JTextComponent> entry : entries) {
108 | if (TextFieldDocumentUtil.updateSettingValue(document, entry.getValue(), entry.getKey())) {
109 | break;
110 | }
111 | }
112 | }
113 | }
114 |
115 | TextFieldDocumentListener textFieldDocumentListener = new TextFieldDocumentListener();
116 | authorField.getDocument().addDocumentListener(textFieldDocumentListener);
117 | emailField.getDocument().addDocumentListener(textFieldDocumentListener);
118 |
119 |
120 | }
121 |
122 | private void initFileTypeTable() {
123 | fileTypeTablePanel.add(FileTypeTableDecorator.create(project, settings), BorderLayout.CENTER);
124 | }
125 |
126 | private void initDatabaseFieldStyle() {
127 | databaseFieldStyleType.addItem("下划线(LOWER_UNDERSCORE)和连接符(LOWER_HYPHEN)");
128 | databaseFieldStyleType.addItem("下划线(UPPER_UNDERSCORE)和连接符(LOWER_HYPHEN)");
129 | databaseFieldStyleType.addItem("小驼峰(LOWER_CAMEL)");
130 | databaseFieldStyleType.addItem("大坨峰(UPPER_CAMEL)");
131 | // databaseFieldStyleType.addItem("连接符(LOWER_HYPHEN)");
132 | databaseFieldStyleType.addItemListener(e -> {
133 | if (e.getStateChange() != ItemEvent.SELECTED) {
134 | return;
135 | }
136 | options.setDbFieldStyleType(databaseFieldStyleType.getSelectedIndex());
137 | this.noteReset.run();
138 | });
139 | }
140 |
141 | /**
142 | * 初始化开发者信息的输入框内容
143 | */
144 | public void initConfig() {
145 | authorField.setText(developer.getAuthor());
146 | emailField.setText(developer.getEmail());
147 | databaseFieldStyleType.setSelectedIndex(options.getDbFieldStyleType());
148 | retainLastSelectionTemplates.setSelected(options.isRetainLastSelectionTemplates());
149 | }
150 |
151 | @Override
152 | public JPanel getContent() {
153 | return content;
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houkunlin/ui/win/table/GenericTableModel.java:
--------------------------------------------------------------------------------
1 | package com.github.houkunlin.ui.win.table;
2 |
3 | import lombok.Getter;
4 |
5 | import javax.swing.*;
6 | import javax.swing.table.AbstractTableModel;
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.function.BiConsumer;
11 |
12 | /**
13 | * 通用的表格模型
14 | *
15 | * @author daiwenzh5
16 | * @since 2.8.4
17 | */
18 | @SuppressWarnings({"UnusedReturnValue"})
19 | public class GenericTableModel extends AbstractTableModel {
20 |
21 | private final List> columns = new ArrayList<>();
22 |
23 | @Getter
24 | private final List data;
25 |
26 | public GenericTableModel(List data) {
27 | this.data = data;
28 | }
29 |
30 | /**
31 | * 添加行数据
32 | *
33 | * @param items 行数据
34 | * @return 当前表格模型
35 | */
36 | @SafeVarargs
37 | public final GenericTableModel addRows(T... items) {
38 | return addRows(List.of(items));
39 | }
40 |
41 | /**
42 | * 添加行数据
43 | * @param items 行数据
44 | * @return 当前表格模型
45 | */
46 | public final GenericTableModel addRows(List items) {
47 | if (items == null || items.isEmpty()) {
48 | return this;
49 | }
50 | var startRow = data.size();
51 | data.addAll(items);
52 | var endRow = data.size() - 1;
53 | fireTableRowsInserted(startRow, endRow);
54 | return this;
55 | }
56 |
57 | /**
58 | * 根据行号删除数据
59 | *
60 | * @param rows 行号
61 | * @return 当前表格模型
62 | */
63 | public final GenericTableModel removeRows(int... rows) {
64 | // 将rows按降序排序
65 | Arrays.sort(rows);
66 | for (var i = rows.length - 1; i >= 0; i--) {
67 | this.data.remove(rows[i]);
68 | }
69 | fireTableDataChanged();
70 | return this;
71 | }
72 |
73 | /**
74 | * 添加列
75 | *
76 | * @param column 列信息
77 | * @return 当前表格模型
78 | */
79 | public final GenericTableModel addColumn(ColumnSpec column) {
80 | columns.add(column);
81 | return this;
82 | }
83 |
84 | /**
85 | * 绑定表格
86 | *
87 | * @param table 表格
88 | * @return 当前表格模型
89 | */
90 | public final GenericTableModel bindTable(JTable table) {
91 | table.setModel(this);
92 | PlaceholderTableCellRenderer placeholderTableCellRenderer = null;
93 | for (int i = 0; i < columns.size(); i++) {
94 | var columnSpec = columns.get(i);
95 | var tableColumn = table.getColumnModel()
96 | .getColumn(i);
97 | if (columnSpec.getCellEditor() != null) {
98 | tableColumn.setCellEditor(columnSpec.getCellEditor());
99 | }
100 | if (columnSpec.getPlaceholder() != null && !columnSpec.getPlaceholder()
101 | .isBlank()) {
102 | if (placeholderTableCellRenderer == null) {
103 | placeholderTableCellRenderer = new PlaceholderTableCellRenderer();
104 | }
105 | tableColumn.setCellRenderer(placeholderTableCellRenderer.setColumn(i, columnSpec.getPlaceholder()));
106 | }
107 | if (columnSpec.getWidth() > 0) {
108 | tableColumn.setPreferredWidth(columnSpec.getWidth());
109 | }
110 | }
111 | return this;
112 | }
113 |
114 | @Override
115 | public final int getRowCount() {
116 | return data.size();
117 | }
118 |
119 | @Override
120 | public final int getColumnCount() {
121 | return columns.size();
122 | }
123 |
124 | @Override
125 | public final Object getValueAt(int row, int col) {
126 | T item = data.get(row);
127 | return columns.get(col)
128 | .getGetter()
129 | .apply(item);
130 | }
131 |
132 | @Override
133 | @SuppressWarnings("unchecked")
134 | public final void setValueAt(Object value, int row, int col) {
135 | var item = data.get(row);
136 | //noinspection rawtypes
137 | final BiConsumer setter = columns.get(col)
138 | .getSetter();
139 | setter.accept(item, value);
140 | }
141 |
142 | @Override
143 | public final String getColumnName(int column) {
144 | return columns.get(column)
145 | .getName();
146 | }
147 |
148 | @Override
149 | public final Class> getColumnClass(int columnIndex) {
150 | return columns.get(columnIndex)
151 | .getType();
152 | }
153 |
154 | @Override
155 | public boolean isCellEditable(int row, int column) {
156 | return columns.get(column)
157 | .isEditable();
158 | }
159 |
160 | /**
161 | * 清空数据
162 | *
163 | * @return 当前表格模型
164 | */
165 | public GenericTableModel clear() {
166 | return clear(true);
167 | }
168 |
169 | /**
170 | * 清空数据
171 | *
172 | * @param fireTableDataChanged 是否触发表格数据改变事件
173 | * @return 当前表格模型
174 | */
175 | public GenericTableModel clear(boolean fireTableDataChanged) {
176 | if (!this.data.isEmpty()) {
177 | data.clear();
178 | if (fireTableDataChanged) {
179 | fireTableDataChanged();
180 | }
181 | }
182 | return this;
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------