mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-09-11 06:57:12 +08:00
refactor: 抽取代码生成器插件模块(后续会改造为独立插件)
This commit is contained in:
22
continew-admin-generator/pom.xml
Normal file
22
continew-admin-generator/pom.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.charles7c.continew</groupId>
|
||||
<artifactId>continew-admin</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-admin-generator</artifactId>
|
||||
<description>代码生成器插件</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 公共模块(存放公共工具类,公共配置等) -->
|
||||
<dependency>
|
||||
<groupId>top.charles7c.continew</groupId>
|
||||
<artifactId>continew-admin-common</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.config.properties;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
|
||||
/**
|
||||
* 代码生成器配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/5 11:08
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "generator")
|
||||
public class GeneratorProperties {
|
||||
|
||||
/**
|
||||
* 排除数据表(哪些数据表不展示在代码生成中)
|
||||
*/
|
||||
private String[] excludeTables;
|
||||
|
||||
/**
|
||||
* 模板配置
|
||||
*/
|
||||
private Map<String, TemplateConfig> templateConfigs = MapUtil.newHashMap(true);
|
||||
|
||||
/**
|
||||
* 模板配置
|
||||
*/
|
||||
@Data
|
||||
public static class TemplateConfig {
|
||||
|
||||
/**
|
||||
* 模板路径
|
||||
*/
|
||||
private String templatePath;
|
||||
|
||||
/**
|
||||
* 包名称
|
||||
*/
|
||||
private String packageName;
|
||||
|
||||
/**
|
||||
* 排除字段
|
||||
*/
|
||||
private String[] excludeFields;
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import top.charles7c.continew.starter.data.mybatis.plus.base.IBaseEnum;
|
||||
|
||||
/**
|
||||
* 表单类型枚举
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/6 10:49
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum FormTypeEnum implements IBaseEnum<Integer> {
|
||||
|
||||
/**
|
||||
* 文本框
|
||||
*/
|
||||
TEXT(1, "文本框"),
|
||||
/**
|
||||
* 文本域
|
||||
*/
|
||||
TEXT_AREA(2, "文本域"),
|
||||
/**
|
||||
* 下拉框
|
||||
*/
|
||||
SELECT(3, "下拉框"),
|
||||
/**
|
||||
* 单选框
|
||||
*/
|
||||
RADIO(4, "单选框"),
|
||||
/**
|
||||
* 日期框
|
||||
*/
|
||||
DATE(5, "日期框"),
|
||||
/**
|
||||
* 日期时间框
|
||||
*/
|
||||
DATE_TIME(6, "日期时间框"),;
|
||||
|
||||
private final Integer value;
|
||||
private final String description;
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import top.charles7c.continew.starter.data.mybatis.plus.base.IBaseEnum;
|
||||
|
||||
/**
|
||||
* 查询类型枚举
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/6 10:49
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum QueryTypeEnum implements IBaseEnum<Integer> {
|
||||
|
||||
/**
|
||||
* 等于 =,例如:WHERE age = 18
|
||||
*/
|
||||
EQ(1, "="),
|
||||
|
||||
/**
|
||||
* 不等于 !=,例如:WHERE age != 18
|
||||
*/
|
||||
NE(2, "!="),
|
||||
|
||||
/**
|
||||
* 大于 >,例如:WHERE age > 18
|
||||
*/
|
||||
GT(3, ">"),
|
||||
|
||||
/**
|
||||
* 大于等于 >= ,例如:WHERE age >= 18
|
||||
*/
|
||||
GE(4, ">="),
|
||||
|
||||
/**
|
||||
* 小于 <,例如:WHERE age < 18
|
||||
*/
|
||||
LT(5, "<"),
|
||||
|
||||
/**
|
||||
* 小于等于 <=,例如:WHERE age <= 18
|
||||
*/
|
||||
LE(6, "<="),
|
||||
|
||||
/**
|
||||
* 范围查询,例如:WHERE age BETWEEN 10 AND 18
|
||||
*/
|
||||
BETWEEN(7, "BETWEEN"),
|
||||
|
||||
/**
|
||||
* LIKE '%值%',例如:WHERE nickname LIKE '%s%'
|
||||
*/
|
||||
LIKE(8, "LIKE '%s%'"),
|
||||
|
||||
/**
|
||||
* LIKE '%值',例如:WHERE nickname LIKE '%s'
|
||||
*/
|
||||
LIKE_LEFT(9, "LIKE '%s'"),
|
||||
|
||||
/**
|
||||
* LIKE '值%',例如:WHERE nickname LIKE 's%'
|
||||
*/
|
||||
LIKE_RIGHT(10, "LIKE 's%'"),
|
||||
|
||||
/**
|
||||
* 包含查询,例如:WHERE age IN (10, 20, 30)
|
||||
*/
|
||||
IN(11, "IN"),
|
||||
|
||||
/**
|
||||
* 不包含查询,例如:WHERE age NOT IN (20, 30)
|
||||
*/
|
||||
NOT_IN(12, "NOT IN"),
|
||||
|
||||
/**
|
||||
* 空查询,例如:WHERE email IS NULL
|
||||
*/
|
||||
IS_NULL(13, "IS NULL"),
|
||||
|
||||
/**
|
||||
* 非空查询,例如:WHERE email IS NOT NULL
|
||||
*/
|
||||
IS_NOT_NULL(14, "IS NOT NULL"),;
|
||||
|
||||
private final Integer value;
|
||||
private final String description;
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import top.charles7c.continew.admin.generator.model.entity.FieldConfigDO;
|
||||
import top.charles7c.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字段配置 Mapper
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 23:56
|
||||
*/
|
||||
public interface FieldConfigMapper extends BaseMapper<FieldConfigDO> {
|
||||
|
||||
/**
|
||||
* 根据表名称查询
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @return 字段配置信息
|
||||
*/
|
||||
@Select("SELECT * FROM gen_field_config WHERE table_name = #{tableName}")
|
||||
List<FieldConfigDO> selectListByTableName(@Param("tableName") String tableName);
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.mapper;
|
||||
|
||||
import top.charles7c.continew.admin.generator.model.entity.GenConfigDO;
|
||||
import top.charles7c.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||
|
||||
/**
|
||||
* 生成配置 Mapper
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 23:56
|
||||
*/
|
||||
public interface GenConfigMapper extends BaseMapper<GenConfigDO> {}
|
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.model.entity;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.meta.Column;
|
||||
import cn.hutool.setting.dialect.Props;
|
||||
import cn.hutool.setting.dialect.PropsUtil;
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import top.charles7c.continew.admin.generator.enums.FormTypeEnum;
|
||||
import top.charles7c.continew.admin.generator.enums.QueryTypeEnum;
|
||||
import top.charles7c.continew.starter.core.constant.StringConstants;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 字段配置实体
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 20:21
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@TableName("gen_field_config")
|
||||
@Schema(description = "字段配置信息")
|
||||
public class FieldConfigDO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表名称
|
||||
*/
|
||||
@Schema(description = "表名称", example = "sys_user")
|
||||
@NotBlank(message = "表名称不能为空")
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 列名称
|
||||
*/
|
||||
@Schema(description = "列名称", example = "nickname")
|
||||
@NotBlank(message = "列名称不能为空")
|
||||
private String columnName;
|
||||
|
||||
/**
|
||||
* 列类型
|
||||
*/
|
||||
@Schema(description = "列类型", example = "varchar")
|
||||
@NotBlank(message = "列类型不能为空")
|
||||
private String columnType;
|
||||
|
||||
/**
|
||||
* 列大小
|
||||
*/
|
||||
@Schema(description = "列大小", example = "255")
|
||||
private String columnSize;
|
||||
|
||||
/**
|
||||
* 字段名称
|
||||
*/
|
||||
@Schema(description = "字段名称", example = "nickname")
|
||||
@NotBlank(message = "字段名称不能为空")
|
||||
private String fieldName;
|
||||
|
||||
/**
|
||||
* 字段类型
|
||||
*/
|
||||
@Schema(description = "字段类型", example = "String")
|
||||
@NotBlank(message = "字段类型不能为空")
|
||||
private String fieldType;
|
||||
|
||||
/**
|
||||
* 注释
|
||||
*/
|
||||
@Schema(description = "注释", example = "昵称")
|
||||
private String comment;
|
||||
|
||||
/**
|
||||
* 是否必填
|
||||
*/
|
||||
@Schema(description = "是否必填", example = "true")
|
||||
private Boolean isRequired;
|
||||
|
||||
/**
|
||||
* 是否在列表中显示
|
||||
*/
|
||||
@Schema(description = "是否在列表中显示", example = "true")
|
||||
private Boolean showInList;
|
||||
|
||||
/**
|
||||
* 是否在表单中显示
|
||||
*/
|
||||
@Schema(description = "是否在表单中显示", example = "true")
|
||||
private Boolean showInForm;
|
||||
|
||||
/**
|
||||
* 是否在查询中显示
|
||||
*/
|
||||
@Schema(description = "是否在查询中显示", example = "true")
|
||||
private Boolean showInQuery;
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
@Schema(description = "表单类型", type = "Integer", allowableValues = {"1", "2", "3", "4", "5", "6"}, example = "1")
|
||||
private FormTypeEnum formType;
|
||||
|
||||
/**
|
||||
* 查询方式
|
||||
*/
|
||||
@Schema(description = "查询方式", type = "Integer", allowableValues = {"1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"10", "11", "12", "13", "14"}, example = "1")
|
||||
private QueryTypeEnum queryType;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public FieldConfigDO(@NonNull Column column) {
|
||||
this.setTableName(column.getTableName());
|
||||
this.setColumnName(column.getName());
|
||||
this.setColumnType(StrUtil.splitToArray(column.getTypeName(), StringConstants.SPACE)[0].toLowerCase());
|
||||
this.setColumnSize(Convert.toStr(column.getSize()));
|
||||
this.setComment(column.getComment());
|
||||
this.setIsRequired(!column.isPk() && !column.isNullable());
|
||||
this.setShowInList(true);
|
||||
this.setShowInForm(this.getIsRequired());
|
||||
this.setShowInQuery(this.getIsRequired());
|
||||
this.setFormType(FormTypeEnum.TEXT);
|
||||
this.setQueryType("String".equals(this.getFieldType()) ? QueryTypeEnum.LIKE : QueryTypeEnum.EQ);
|
||||
}
|
||||
|
||||
public void setColumnName(String columnName) {
|
||||
this.columnName = columnName;
|
||||
this.fieldName = StrUtil.toCamelCase(this.columnName);
|
||||
}
|
||||
|
||||
public void setColumnType(String columnType) {
|
||||
this.columnType = columnType;
|
||||
Props generatorProp = PropsUtil.get("generator");
|
||||
this.fieldType = generatorProp.getStr(columnType);
|
||||
}
|
||||
}
|
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.model.entity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import top.charles7c.continew.admin.common.constant.RegexConstants;
|
||||
|
||||
/**
|
||||
* 生成配置实体
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 20:21
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@TableName("gen_config")
|
||||
@Schema(description = "生成配置信息")
|
||||
public class GenConfigDO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表名称
|
||||
*/
|
||||
@Schema(description = "表名称", example = "sys_user")
|
||||
@TableId(type = IdType.INPUT)
|
||||
@NotBlank(message = "表名称不能为空")
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 模块名称
|
||||
*/
|
||||
@Schema(description = "模块名称", example = "continew-admin-system")
|
||||
@NotBlank(message = "模块名称不能为空")
|
||||
@Length(max = 60, message = "模块名称不能超过 {max} 个字符")
|
||||
private String moduleName;
|
||||
|
||||
/**
|
||||
* 包名称
|
||||
*/
|
||||
@Schema(description = "包名称", example = "top.charles7c.continew.admin.system")
|
||||
@NotBlank(message = "包名称不能为空")
|
||||
@Pattern(regexp = RegexConstants.PACKAGE_NAME, message = "包名称格式错误")
|
||||
@Length(max = 60, message = "包名称不能超过 {max} 个字符")
|
||||
private String packageName;
|
||||
|
||||
/**
|
||||
* 前端路径
|
||||
*/
|
||||
@Schema(description = "前端路径", example = "D:/continew-admin-ui/src/views/system/user")
|
||||
@Length(max = 255, message = "前端路径不能超过 {max} 个字符")
|
||||
private String frontendPath;
|
||||
|
||||
/**
|
||||
* 业务名称
|
||||
*/
|
||||
@Schema(description = "业务名称", example = "用户")
|
||||
@NotBlank(message = "业务名称不能为空")
|
||||
@Length(max = 50, message = "业务名称不能超过 {max} 个字符")
|
||||
private String businessName;
|
||||
|
||||
/**
|
||||
* 作者
|
||||
*/
|
||||
@Schema(description = "作者", example = "Charles7c")
|
||||
@NotBlank(message = "作者名称不能为空")
|
||||
@Length(max = 100, message = "作者名称不能超过 {max} 个字符")
|
||||
private String author;
|
||||
|
||||
/**
|
||||
* 表前缀
|
||||
*/
|
||||
@Schema(description = "表前缀", example = "sys_")
|
||||
private String tablePrefix;
|
||||
|
||||
/**
|
||||
* 是否覆盖
|
||||
*/
|
||||
@Schema(description = "是否覆盖", example = "false")
|
||||
@NotNull(message = "是否覆盖不能为空")
|
||||
private Boolean isOverride;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@Schema(description = "修改时间", example = "2023-08-08 08:08:08", type = "string")
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 类名前缀
|
||||
*/
|
||||
@Setter(AccessLevel.NONE)
|
||||
@JsonIgnore
|
||||
@TableField(exist = false)
|
||||
private String classNamePrefix;
|
||||
|
||||
public GenConfigDO(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getClassNamePrefix() {
|
||||
String rawClassName = StrUtil.isNotBlank(this.tablePrefix)
|
||||
? StrUtil.removePrefix(this.tableName, this.tablePrefix)
|
||||
: this.tableName;
|
||||
return StrUtil.upperFirst(StrUtil.toCamelCase(rawClassName));
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.model.query;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 表信息查询条件
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 20:21
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "表信息查询条件")
|
||||
public class TableQuery implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表名称
|
||||
*/
|
||||
@Schema(description = "表名称", example = "sys_user")
|
||||
private String tableName;
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.model.req;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import top.charles7c.continew.admin.generator.model.entity.FieldConfigDO;
|
||||
import top.charles7c.continew.admin.generator.model.entity.GenConfigDO;
|
||||
|
||||
/**
|
||||
* 代码生成配置信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/8 20:40
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "代码生成配置信息")
|
||||
public class GenConfigReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 字段配置信息
|
||||
*/
|
||||
@Valid
|
||||
@Schema(description = "字段配置信息")
|
||||
@NotEmpty(message = "字段配置不能为空")
|
||||
private List<FieldConfigDO> fieldConfigs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 生成配置信息
|
||||
*/
|
||||
@Valid
|
||||
@Schema(description = "生成配置信息")
|
||||
@NotNull(message = "生成配置不能为空")
|
||||
private GenConfigDO genConfig;
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.model.resp;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* 生成预览信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/12/19 21:34
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "生成预览信息")
|
||||
public class GeneratePreviewResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
@Schema(description = "文件名", example = "UserController.java")
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@Schema(description = "内容", example = "public class UserController {...}")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 是否为后端代码
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
@JsonIgnore
|
||||
private boolean backend;
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.model.resp;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
/**
|
||||
* 表信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 20:21
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "表信息")
|
||||
public class TableResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 表名称
|
||||
*/
|
||||
@Schema(description = "表名称", example = "sys_user")
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
@Schema(description = "描述", example = "用户表")
|
||||
private String comment;
|
||||
|
||||
/**
|
||||
* 存储引擎
|
||||
*/
|
||||
@Schema(description = "存储引擎", example = "InnoDB")
|
||||
private String engine;
|
||||
|
||||
/**
|
||||
* 字符集
|
||||
*/
|
||||
@Schema(description = "字符集", example = "utf8mb4_general_ci")
|
||||
private String charset;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 是否已配置
|
||||
*/
|
||||
@Schema(description = "是否已配置", example = "true")
|
||||
private Boolean isConfiged;
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.service;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import top.charles7c.continew.admin.generator.model.entity.FieldConfigDO;
|
||||
import top.charles7c.continew.admin.generator.model.entity.GenConfigDO;
|
||||
import top.charles7c.continew.admin.generator.model.query.TableQuery;
|
||||
import top.charles7c.continew.admin.generator.model.req.GenConfigReq;
|
||||
import top.charles7c.continew.admin.generator.model.resp.GeneratePreviewResp;
|
||||
import top.charles7c.continew.admin.generator.model.resp.TableResp;
|
||||
import top.charles7c.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.charles7c.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
/**
|
||||
* 代码生成业务接口
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 23:57
|
||||
*/
|
||||
public interface GeneratorService {
|
||||
|
||||
/**
|
||||
* 分页查询表信息列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param pageQuery 分页查询条件
|
||||
* @return 表信息分页列表
|
||||
* @throws SQLException /
|
||||
*/
|
||||
PageResp<TableResp> pageTable(TableQuery query, PageQuery pageQuery) throws SQLException;
|
||||
|
||||
/**
|
||||
* 查询生成配置信息
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @return 生成配置信息
|
||||
* @throws SQLException /
|
||||
*/
|
||||
GenConfigDO getGenConfig(String tableName) throws SQLException;
|
||||
|
||||
/**
|
||||
* 查询字段配置列表
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @param requireSync 是否需要同步
|
||||
* @return 字段配置列表
|
||||
*/
|
||||
List<FieldConfigDO> listFieldConfig(String tableName, Boolean requireSync);
|
||||
|
||||
/**
|
||||
* 保存代码生成配置信息
|
||||
*
|
||||
* @param req 代码生成配置信息
|
||||
* @param tableName 表名称
|
||||
*/
|
||||
void saveConfig(GenConfigReq req, String tableName);
|
||||
|
||||
/**
|
||||
* 生成预览
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @return 预览信息
|
||||
*/
|
||||
List<GeneratePreviewResp> preview(String tableName);
|
||||
|
||||
/**
|
||||
* 生成代码
|
||||
*
|
||||
* @param tableName 表名称
|
||||
*/
|
||||
void generate(String tableName);
|
||||
}
|
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.charles7c.continew.admin.generator.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.meta.Column;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import top.charles7c.continew.admin.generator.config.properties.GeneratorProperties;
|
||||
import top.charles7c.continew.admin.generator.config.properties.GeneratorProperties.TemplateConfig;
|
||||
import top.charles7c.continew.admin.generator.enums.QueryTypeEnum;
|
||||
import top.charles7c.continew.admin.generator.mapper.FieldConfigMapper;
|
||||
import top.charles7c.continew.admin.generator.mapper.GenConfigMapper;
|
||||
import top.charles7c.continew.admin.generator.model.entity.FieldConfigDO;
|
||||
import top.charles7c.continew.admin.generator.model.entity.GenConfigDO;
|
||||
import top.charles7c.continew.admin.generator.model.query.TableQuery;
|
||||
import top.charles7c.continew.admin.generator.model.req.GenConfigReq;
|
||||
import top.charles7c.continew.admin.generator.model.resp.GeneratePreviewResp;
|
||||
import top.charles7c.continew.admin.generator.model.resp.TableResp;
|
||||
import top.charles7c.continew.admin.generator.service.GeneratorService;
|
||||
import top.charles7c.continew.starter.core.constant.StringConstants;
|
||||
import top.charles7c.continew.starter.core.exception.BusinessException;
|
||||
import top.charles7c.continew.starter.core.util.TemplateUtils;
|
||||
import top.charles7c.continew.starter.data.core.util.MetaUtils;
|
||||
import top.charles7c.continew.starter.data.core.util.Table;
|
||||
import top.charles7c.continew.starter.core.util.validate.CheckUtils;
|
||||
import top.charles7c.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.charles7c.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 代码生成业务实现
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/4/12 23:58
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GeneratorServiceImpl implements GeneratorService {
|
||||
|
||||
private final DataSource dataSource;
|
||||
private final GeneratorProperties generatorProperties;
|
||||
private final FieldConfigMapper fieldConfigMapper;
|
||||
private final GenConfigMapper genConfigMapper;
|
||||
|
||||
@Override
|
||||
public PageResp<TableResp> pageTable(TableQuery query, PageQuery pageQuery) throws SQLException {
|
||||
List<Table> tableList = MetaUtils.getTables(dataSource);
|
||||
String tableName = query.getTableName();
|
||||
if (StrUtil.isNotBlank(tableName)) {
|
||||
tableList.removeIf(table -> !StrUtil.containsAny(table.getTableName(), tableName));
|
||||
}
|
||||
tableList.removeIf(table -> StrUtil.equalsAnyIgnoreCase(table.getTableName(), generatorProperties
|
||||
.getExcludeTables()));
|
||||
CollUtil.sort(tableList, Comparator.comparing(Table::getCreateTime)
|
||||
.thenComparing(table -> Optional.ofNullable(table.getUpdateTime()).orElse(table.getCreateTime()))
|
||||
.reversed());
|
||||
List<TableResp> tableRespList = BeanUtil.copyToList(tableList, TableResp.class);
|
||||
PageResp<TableResp> pageResp = PageResp.build(pageQuery.getPage(), pageQuery.getSize(), tableRespList);
|
||||
for (TableResp tableResp : pageResp.getList()) {
|
||||
long count = genConfigMapper.selectCount(Wrappers.lambdaQuery(GenConfigDO.class)
|
||||
.eq(GenConfigDO::getTableName, tableResp.getTableName()));
|
||||
tableResp.setIsConfiged(count > 0);
|
||||
}
|
||||
return pageResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenConfigDO getGenConfig(String tableName) throws SQLException {
|
||||
GenConfigDO genConfig = genConfigMapper.selectById(tableName);
|
||||
if (null == genConfig) {
|
||||
genConfig = new GenConfigDO(tableName);
|
||||
// 默认包名(当前包名)
|
||||
String packageName = ClassUtil.getPackage(GeneratorService.class);
|
||||
genConfig.setPackageName(StrUtil.subBefore(packageName, StringConstants.DOT, true));
|
||||
// 默认业务名(表注释)
|
||||
List<Table> tableList = MetaUtils.getTables(dataSource, tableName);
|
||||
if (CollUtil.isNotEmpty(tableList)) {
|
||||
Table table = tableList.get(0);
|
||||
genConfig.setBusinessName(StrUtil.replace(table.getComment(), "表", StringConstants.EMPTY));
|
||||
}
|
||||
// 默认作者名称(上次保存使用的作者名称)
|
||||
GenConfigDO lastGenConfig = genConfigMapper.selectOne(Wrappers.lambdaQuery(GenConfigDO.class)
|
||||
.orderByDesc(GenConfigDO::getCreateTime)
|
||||
.last("LIMIT 1"));
|
||||
if (null != lastGenConfig) {
|
||||
genConfig.setAuthor(lastGenConfig.getAuthor());
|
||||
}
|
||||
// 默认表前缀(sys_user -> sys_)
|
||||
int underLineIndex = StrUtil.indexOf(tableName, StringConstants.C_UNDERLINE);
|
||||
if (-1 != underLineIndex) {
|
||||
genConfig.setTablePrefix(StrUtil.subPre(tableName, underLineIndex + 1));
|
||||
}
|
||||
}
|
||||
return genConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FieldConfigDO> listFieldConfig(String tableName, Boolean requireSync) {
|
||||
List<FieldConfigDO> fieldConfigList = fieldConfigMapper.selectListByTableName(tableName);
|
||||
if (CollUtil.isEmpty(fieldConfigList)) {
|
||||
Collection<Column> columnList = MetaUtils.getColumns(dataSource, tableName);
|
||||
return columnList.stream().map(FieldConfigDO::new).toList();
|
||||
}
|
||||
// 同步最新数据表列信息
|
||||
if (Boolean.TRUE.equals(requireSync)) {
|
||||
Collection<Column> columnList = MetaUtils.getColumns(dataSource, tableName);
|
||||
// 移除已不存在的字段配置
|
||||
List<String> columnNameList = columnList.stream().map(Column::getName).toList();
|
||||
fieldConfigList.removeIf(column -> !columnNameList.contains(column.getColumnName()));
|
||||
// 新增或更新字段配置
|
||||
Map<String, FieldConfigDO> fieldConfigMap = fieldConfigList.stream()
|
||||
.collect(Collectors.toMap(FieldConfigDO::getColumnName, Function.identity(), (key1, key2) -> key2));
|
||||
for (Column column : columnList) {
|
||||
FieldConfigDO fieldConfig = fieldConfigMap.get(column.getName());
|
||||
if (null != fieldConfig) {
|
||||
// 更新已有字段配置
|
||||
String columnType = StrUtil.splitToArray(column.getTypeName(), StringConstants.SPACE)[0]
|
||||
.toLowerCase();
|
||||
fieldConfig.setColumnType(columnType);
|
||||
fieldConfig.setColumnSize(Convert.toStr(column.getSize()));
|
||||
fieldConfig.setComment(column.getComment());
|
||||
} else {
|
||||
// 新增字段配置
|
||||
fieldConfig = new FieldConfigDO(column);
|
||||
fieldConfigList.add(fieldConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldConfigList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveConfig(GenConfigReq req, String tableName) {
|
||||
// 保存字段配置
|
||||
fieldConfigMapper.delete(Wrappers.lambdaQuery(FieldConfigDO.class).eq(FieldConfigDO::getTableName, tableName));
|
||||
List<FieldConfigDO> fieldConfigList = req.getFieldConfigs();
|
||||
for (FieldConfigDO fieldConfig : fieldConfigList) {
|
||||
if (Boolean.TRUE.equals(fieldConfig.getShowInForm())) {
|
||||
CheckUtils.throwIfNull(fieldConfig.getFormType(), "字段 [{}] 的表单类型不能为空", fieldConfig.getFieldName());
|
||||
} else {
|
||||
// 在表单中不显示,不需要设置必填
|
||||
fieldConfig.setIsRequired(false);
|
||||
}
|
||||
if (Boolean.TRUE.equals(fieldConfig.getShowInQuery())) {
|
||||
CheckUtils.throwIfNull(fieldConfig.getFormType(), "字段 [{}] 的表单类型不能为空", fieldConfig.getFieldName());
|
||||
CheckUtils.throwIfNull(fieldConfig.getQueryType(), "字段 [{}] 的查询方式不能为空", fieldConfig.getFieldName());
|
||||
} else {
|
||||
// 在查询中不显示,不需要设置查询方式
|
||||
fieldConfig.setQueryType(null);
|
||||
}
|
||||
// 既不在表单也不在查询中显示,不需要设置表单类型
|
||||
if (Boolean.FALSE.equals(fieldConfig.getShowInForm()) && Boolean.FALSE.equals(fieldConfig
|
||||
.getShowInQuery())) {
|
||||
fieldConfig.setFormType(null);
|
||||
}
|
||||
fieldConfig.setTableName(tableName);
|
||||
}
|
||||
fieldConfigMapper.insertBatch(fieldConfigList);
|
||||
// 保存或更新生成配置信息
|
||||
GenConfigDO newGenConfig = req.getGenConfig();
|
||||
String frontendPath = newGenConfig.getFrontendPath();
|
||||
if (StrUtil.isNotBlank(frontendPath)) {
|
||||
CheckUtils.throwIf(!FileUtil.exist(frontendPath), "前端路径不存在");
|
||||
CheckUtils.throwIf(!StrUtil.containsAll(frontendPath, "src", "views"), "前端路径配置错误");
|
||||
}
|
||||
GenConfigDO oldGenConfig = genConfigMapper.selectById(tableName);
|
||||
if (null != oldGenConfig) {
|
||||
BeanUtil.copyProperties(newGenConfig, oldGenConfig);
|
||||
genConfigMapper.updateById(oldGenConfig);
|
||||
} else {
|
||||
genConfigMapper.insert(newGenConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GeneratePreviewResp> preview(String tableName) {
|
||||
List<GeneratePreviewResp> generatePreviewList = new ArrayList<>();
|
||||
// 初始化配置
|
||||
GenConfigDO genConfig = genConfigMapper.selectById(tableName);
|
||||
CheckUtils.throwIfNull(genConfig, "请先进行数据表 [{}] 生成配置", tableName);
|
||||
List<FieldConfigDO> fieldConfigList = fieldConfigMapper.selectListByTableName(tableName);
|
||||
CheckUtils.throwIfEmpty(fieldConfigList, "请先进行数据表 [{}] 字段配置", tableName);
|
||||
Map<String, Object> genConfigMap = BeanUtil.beanToMap(genConfig);
|
||||
genConfigMap.put("date", DateUtil.date().toString("yyyy/MM/dd HH:mm"));
|
||||
String packageName = genConfig.getPackageName();
|
||||
String apiModuleName = StrUtil.subSuf(packageName, StrUtil
|
||||
.lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1);
|
||||
genConfigMap.put("apiModuleName", apiModuleName);
|
||||
genConfigMap.put("apiName", StrUtil.lowerFirst(genConfig.getClassNamePrefix()));
|
||||
// 渲染后端代码
|
||||
String classNamePrefix = genConfig.getClassNamePrefix();
|
||||
Map<String, TemplateConfig> templateConfigMap = generatorProperties.getTemplateConfigs();
|
||||
for (Map.Entry<String, TemplateConfig> templateConfigEntry : templateConfigMap.entrySet()) {
|
||||
this.pretreatment(genConfigMap, fieldConfigList, templateConfigEntry);
|
||||
String className = classNamePrefix + StrUtil.nullToEmpty(templateConfigEntry.getKey());
|
||||
genConfigMap.put("className", className);
|
||||
TemplateConfig templateConfig = templateConfigEntry.getValue();
|
||||
String content = TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap);
|
||||
GeneratePreviewResp codePreview = new GeneratePreviewResp();
|
||||
codePreview.setFileName(className + FileNameUtil.EXT_JAVA);
|
||||
codePreview.setContent(content);
|
||||
codePreview.setBackend(true);
|
||||
generatePreviewList.add(codePreview);
|
||||
}
|
||||
// 渲染前端代码
|
||||
// api 代码
|
||||
genConfigMap.put("fieldConfigs", fieldConfigList);
|
||||
String apiContent = TemplateUtils.render("generator/api.ftl", genConfigMap);
|
||||
GeneratePreviewResp apiCodePreview = new GeneratePreviewResp();
|
||||
apiCodePreview.setFileName(classNamePrefix.toLowerCase() + ".ts");
|
||||
apiCodePreview.setContent(apiContent);
|
||||
generatePreviewList.add(apiCodePreview);
|
||||
// view 代码
|
||||
String viewContent = TemplateUtils.render("generator/index.ftl", genConfigMap);
|
||||
GeneratePreviewResp viewCodePreview = new GeneratePreviewResp();
|
||||
viewCodePreview.setFileName("index.vue");
|
||||
viewCodePreview.setContent(viewContent);
|
||||
generatePreviewList.add(viewCodePreview);
|
||||
return generatePreviewList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(String tableName) {
|
||||
// 初始化配置及数据
|
||||
List<GeneratePreviewResp> generatePreviewList = this.preview(tableName);
|
||||
GenConfigDO genConfig = genConfigMapper.selectById(tableName);
|
||||
Boolean isOverride = genConfig.getIsOverride();
|
||||
// 生成代码
|
||||
String packageName = genConfig.getPackageName();
|
||||
try {
|
||||
// 生成后端代码
|
||||
String classNamePrefix = genConfig.getClassNamePrefix();
|
||||
// 1.确定后端代码基础路径
|
||||
// 例如:D:/continew-admin
|
||||
String projectPath = SystemUtil.getUserInfo().getCurrentDir();
|
||||
// 例如:D:/continew-admin/continew-admin-tool
|
||||
File backendModuleFile = new File(projectPath, genConfig.getModuleName());
|
||||
// 例如:D:/continew-admin/continew-admin-tool/src/main/java/top/charles7c/continew/admin/tool
|
||||
List<String> backendModuleChildPathList = CollUtil.newArrayList("src", "main", "java");
|
||||
backendModuleChildPathList.addAll(StrUtil.split(packageName, StringConstants.DOT));
|
||||
File backendParentFile = FileUtil.file(backendModuleFile, backendModuleChildPathList
|
||||
.toArray(new String[0]));
|
||||
// 2.生成代码
|
||||
List<GeneratePreviewResp> backendCodePreviewList = generatePreviewList.stream()
|
||||
.filter(GeneratePreviewResp::isBackend)
|
||||
.toList();
|
||||
Map<String, TemplateConfig> templateConfigMap = generatorProperties.getTemplateConfigs();
|
||||
for (GeneratePreviewResp codePreview : backendCodePreviewList) {
|
||||
// 例如:D:/continew-admin/continew-admin-tool/src/main/java/top/charles7c/continew/admin/tool/service/impl/XxxServiceImpl.java
|
||||
TemplateConfig templateConfig = templateConfigMap.get(codePreview.getFileName()
|
||||
.replace(classNamePrefix, StringConstants.EMPTY)
|
||||
.replace(FileNameUtil.EXT_JAVA, StringConstants.EMPTY));
|
||||
File classParentFile = FileUtil.file(backendParentFile, StrUtil.splitToArray(templateConfig
|
||||
.getPackageName(), StringConstants.DOT));
|
||||
File classFile = new File(classParentFile, codePreview.getFileName());
|
||||
// 如果已经存在,且不允许覆盖,则跳过
|
||||
if (classFile.exists() && Boolean.FALSE.equals(isOverride)) {
|
||||
continue;
|
||||
}
|
||||
FileUtil.writeUtf8String(codePreview.getContent(), classFile);
|
||||
}
|
||||
// 生成前端代码
|
||||
String frontendPath = genConfig.getFrontendPath();
|
||||
if (StrUtil.isBlank(frontendPath)) {
|
||||
return;
|
||||
}
|
||||
List<GeneratePreviewResp> frontendCodePreviewList = generatePreviewList.stream()
|
||||
.filter(p -> !p.isBackend())
|
||||
.toList();
|
||||
// 1.生成 api 代码
|
||||
String apiModuleName = StrUtil.subSuf(packageName, StrUtil
|
||||
.lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1);
|
||||
GeneratePreviewResp apiCodePreview = frontendCodePreviewList.get(0);
|
||||
// 例如:D:/continew-admin-ui
|
||||
List<String> frontendSubPathList = StrUtil.split(frontendPath, "src");
|
||||
String frontendModulePath = frontendSubPathList.get(0);
|
||||
// 例如:D:/continew-admin-ui/src/api/tool/xxx.ts
|
||||
File apiParentFile = FileUtil.file(frontendModulePath, "src", "api", apiModuleName);
|
||||
File apiFile = new File(apiParentFile, apiCodePreview.getFileName());
|
||||
if (apiFile.exists() && Boolean.FALSE.equals(isOverride)) {
|
||||
return;
|
||||
}
|
||||
FileUtil.writeUtf8String(apiCodePreview.getContent(), apiFile);
|
||||
// 2.生成 view 代码
|
||||
GeneratePreviewResp viewCodePreview = frontendCodePreviewList.get(1);
|
||||
// 例如:D:/continew-admin-ui/src/views/tool/xxx/index.vue
|
||||
File indexFile = FileUtil.file(frontendPath, apiModuleName, StrUtil
|
||||
.lowerFirst(classNamePrefix), "index.vue");
|
||||
if (indexFile.exists() && Boolean.FALSE.equals(isOverride)) {
|
||||
return;
|
||||
}
|
||||
FileUtil.writeUtf8String(viewCodePreview.getContent(), indexFile);
|
||||
} catch (Exception e) {
|
||||
log.error("Generate code occurred an error: {}. tableName: {}.", e.getMessage(), tableName, e);
|
||||
throw new BusinessException("代码生成失败,请手动清理生成文件");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预处理生成配置
|
||||
*
|
||||
* @param genConfigMap 生成配置
|
||||
* @param originFieldConfigList 原始字段配置列表
|
||||
* @param templateConfigEntry 模板配置
|
||||
*/
|
||||
private void pretreatment(Map<String, Object> genConfigMap,
|
||||
List<FieldConfigDO> originFieldConfigList,
|
||||
Map.Entry<String, TemplateConfig> templateConfigEntry) {
|
||||
TemplateConfig templateConfig = templateConfigEntry.getValue();
|
||||
// 移除需要忽略的字段
|
||||
List<FieldConfigDO> fieldConfigList = originFieldConfigList.stream()
|
||||
.filter(fieldConfig -> !StrUtil.equalsAny(fieldConfig.getFieldName(), templateConfig.getExcludeFields()))
|
||||
.toList();
|
||||
genConfigMap.put("fieldConfigs", fieldConfigList);
|
||||
// 统计部分特殊字段特征
|
||||
genConfigMap.put("hasLocalDateTime", false);
|
||||
genConfigMap.put("hasBigDecimal", false);
|
||||
genConfigMap.put("hasRequiredField", false);
|
||||
genConfigMap.put("hasListQueryField", false);
|
||||
for (FieldConfigDO fieldConfig : fieldConfigList) {
|
||||
String fieldType = fieldConfig.getFieldType();
|
||||
if ("LocalDateTime".equals(fieldType)) {
|
||||
genConfigMap.put("hasLocalDateTime", true);
|
||||
}
|
||||
if ("BigDecimal".equals(fieldType)) {
|
||||
genConfigMap.put("hasBigDecimal", true);
|
||||
}
|
||||
if (Boolean.TRUE.equals(fieldConfig.getIsRequired())) {
|
||||
genConfigMap.put("hasRequiredField", true);
|
||||
}
|
||||
QueryTypeEnum queryType = fieldConfig.getQueryType();
|
||||
if (null != queryType && StrUtil.equalsAny(queryType.name(), QueryTypeEnum.IN.name(), QueryTypeEnum.NOT_IN
|
||||
.name(), QueryTypeEnum.BETWEEN.name())) {
|
||||
genConfigMap.put("hasListQueryField", true);
|
||||
}
|
||||
}
|
||||
String subPackageName = templateConfig.getPackageName();
|
||||
genConfigMap.put("subPackageName", subPackageName);
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
tinyint=Integer
|
||||
smallint=Integer
|
||||
mediumint=Integer
|
||||
int=Integer
|
||||
integer=Integer
|
||||
|
||||
bigint=Long
|
||||
|
||||
float=Float
|
||||
|
||||
double=Double
|
||||
|
||||
decimal=BigDecimal
|
||||
|
||||
bit=Boolean
|
||||
|
||||
char=String
|
||||
varchar=String
|
||||
tinytext=String
|
||||
text=String
|
||||
mediumtext=String
|
||||
longtext=String
|
||||
|
||||
date=LocalDate
|
||||
datetime=LocalDateTime
|
||||
timestamp=LocalDateTime
|
@@ -0,0 +1,26 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.charles7c.continew.starter.extension.crud.controller.BaseController;
|
||||
import ${packageName}.model.query.${classNamePrefix}Query;
|
||||
import ${packageName}.model.req.${classNamePrefix}Req;
|
||||
import ${packageName}.model.resp.${classNamePrefix}DetailResp;
|
||||
import ${packageName}.model.resp.${classNamePrefix}Resp;
|
||||
import ${packageName}.service.${classNamePrefix}Service;
|
||||
|
||||
/**
|
||||
* ${businessName}管理 API
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Tag(name = "${businessName}管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/${apiModuleName}/${apiName}", api = {Api.PAGE, Api.GET, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
|
||||
public class ${className} extends BaseController<${classNamePrefix}Service, ${classNamePrefix}Resp, ${classNamePrefix}DetailResp, ${classNamePrefix}Query, ${classNamePrefix}Req> {}
|
@@ -0,0 +1,44 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import java.io.Serial;
|
||||
<#if hasLocalDateTime>
|
||||
import java.time.LocalDateTime;
|
||||
</#if>
|
||||
<#if hasBigDecimal>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.model.resp.BaseDetailResp;
|
||||
|
||||
/**
|
||||
* ${businessName}详情信息
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@Schema(description = "${businessName}详情信息")
|
||||
public class ${className} extends BaseDetailResp {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
|
||||
/**
|
||||
* ${fieldConfig.comment}
|
||||
*/
|
||||
@Schema(description = "${fieldConfig.comment}")
|
||||
@ExcelProperty(value = "${fieldConfig.comment}")
|
||||
private ${fieldConfig.fieldType} ${fieldConfig.fieldName};
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import java.io.Serial;
|
||||
<#if hasLocalDateTime>
|
||||
import java.time.LocalDateTime;
|
||||
</#if>
|
||||
<#if hasBigDecimal>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.model.entity.BaseDO;
|
||||
|
||||
/**
|
||||
* ${businessName}实体
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Data
|
||||
@TableName("${tableName}")
|
||||
public class ${className} extends BaseDO {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
|
||||
/**
|
||||
* ${fieldConfig.comment}
|
||||
*/
|
||||
private ${fieldConfig.fieldType} ${fieldConfig.fieldName};
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import top.charles7c.continew.starter.data.mybatis.plus.base.BaseMapper;
|
||||
import ${packageName}.model.entity.${classNamePrefix}DO;
|
||||
|
||||
/**
|
||||
* ${businessName} Mapper
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
public interface ${className} extends BaseMapper<${classNamePrefix}DO> {}
|
@@ -0,0 +1,51 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
<#if hasLocalDateTime>
|
||||
import java.time.LocalDateTime;
|
||||
</#if>
|
||||
<#if hasBigDecimal>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
<#if hasListQueryField>
|
||||
import java.util.List;
|
||||
</#if>
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import top.charles7c.continew.starter.data.core.annotation.Query;
|
||||
import top.charles7c.continew.starter.data.core.enums.QueryType;
|
||||
|
||||
/**
|
||||
* ${businessName}查询条件
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "${businessName}查询条件")
|
||||
public class ${className} implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInQuery>
|
||||
|
||||
/**
|
||||
* ${fieldConfig.comment}
|
||||
*/
|
||||
@Schema(description = "${fieldConfig.comment}")
|
||||
@Query(type = QueryType.${fieldConfig.queryType})
|
||||
<#if fieldConfig.queryType = 'IN' || fieldConfig.queryType = 'NOT_IN' || fieldConfig.queryType = 'BETWEEN'>
|
||||
private List<${fieldConfig.fieldType}> ${fieldConfig.fieldName};
|
||||
<#else>
|
||||
private ${fieldConfig.fieldType} ${fieldConfig.fieldName};
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import java.io.Serial;
|
||||
<#if hasLocalDateTime>
|
||||
import java.time.LocalDateTime;
|
||||
</#if>
|
||||
<#if hasBigDecimal>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
<#if hasRequiredField>
|
||||
import jakarta.validation.constraints.*;
|
||||
</#if>
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.model.req.BaseReq;
|
||||
|
||||
/**
|
||||
* 创建或修改${businessName}信息
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "创建或修改${businessName}信息")
|
||||
public class ${className} extends BaseReq {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInForm>
|
||||
|
||||
/**
|
||||
* ${fieldConfig.comment}
|
||||
*/
|
||||
@Schema(description = "${fieldConfig.comment}")
|
||||
<#if fieldConfig.isRequired>
|
||||
<#if fieldConfig.fieldType = 'String'>
|
||||
@NotBlank(message = "${fieldConfig.comment}不能为空")
|
||||
<#else>
|
||||
@NotNull(message = "${fieldConfig.comment}不能为空")
|
||||
</#if>
|
||||
</#if>
|
||||
<#if fieldConfig.fieldType = 'String' && fieldConfig.columnSize??>
|
||||
@Length(max = ${fieldConfig.columnSize}, message = "${fieldConfig.comment}长度不能超过 {max} 个字符")
|
||||
</#if>
|
||||
private ${fieldConfig.fieldType} ${fieldConfig.fieldName};
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import java.io.Serial;
|
||||
<#if hasLocalDateTime>
|
||||
import java.time.LocalDateTime;
|
||||
</#if>
|
||||
<#if hasBigDecimal>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.model.resp.BaseResp;
|
||||
|
||||
/**
|
||||
* ${businessName}信息
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "${businessName}信息")
|
||||
public class ${className} extends BaseResp {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInList>
|
||||
|
||||
/**
|
||||
* ${fieldConfig.comment}
|
||||
*/
|
||||
@Schema(description = "${fieldConfig.comment}")
|
||||
private ${fieldConfig.fieldType} ${fieldConfig.fieldName};
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.service.BaseService;
|
||||
import ${packageName}.model.query.${classNamePrefix}Query;
|
||||
import ${packageName}.model.req.${classNamePrefix}Req;
|
||||
import ${packageName}.model.resp.${classNamePrefix}DetailResp;
|
||||
import ${packageName}.model.resp.${classNamePrefix}Resp;
|
||||
|
||||
/**
|
||||
* ${businessName}业务接口
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
public interface ${className} extends BaseService<${classNamePrefix}Resp, ${classNamePrefix}DetailResp, ${classNamePrefix}Query, ${classNamePrefix}Req> {}
|
@@ -0,0 +1,24 @@
|
||||
package ${packageName}.${subPackageName};
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import top.charles7c.continew.starter.extension.crud.service.impl.BaseServiceImpl;
|
||||
import ${packageName}.mapper.${classNamePrefix}Mapper;
|
||||
import ${packageName}.model.entity.${classNamePrefix}DO;
|
||||
import ${packageName}.model.query.${classNamePrefix}Query;
|
||||
import ${packageName}.model.req.${classNamePrefix}Req;
|
||||
import ${packageName}.model.resp.${classNamePrefix}DetailResp;
|
||||
import ${packageName}.model.resp.${classNamePrefix}Resp;
|
||||
import ${packageName}.service.${classNamePrefix}Service;
|
||||
|
||||
/**
|
||||
* ${businessName}业务实现
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date}
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ${className} extends BaseServiceImpl<${classNamePrefix}Mapper, ${classNamePrefix}DO, ${classNamePrefix}Resp, ${classNamePrefix}DetailResp, ${classNamePrefix}Query, ${classNamePrefix}Req> implements ${classNamePrefix}Service {}
|
@@ -0,0 +1,57 @@
|
||||
import axios from 'axios';
|
||||
import qs from 'query-string';
|
||||
|
||||
const BASE_URL = '/${apiModuleName}/${apiName}';
|
||||
|
||||
export interface DataRecord {
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
${fieldConfig.fieldName}?: string;
|
||||
</#list>
|
||||
createUserString?: string;
|
||||
updateUserString?: string;
|
||||
</#if>
|
||||
}
|
||||
|
||||
export interface ListParam {
|
||||
<#if fieldConfigs??>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInQuery>
|
||||
${fieldConfig.fieldName}?: string;
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
page?: number;
|
||||
size?: number;
|
||||
sort?: Array<string>;
|
||||
}
|
||||
|
||||
export interface ListRes {
|
||||
list: DataRecord[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export function list(params: ListParam) {
|
||||
return axios.get<ListRes>(`${'$'}{BASE_URL}`, {
|
||||
params,
|
||||
paramsSerializer: (obj) => {
|
||||
return qs.stringify(obj);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function get(id: string) {
|
||||
return axios.get<DataRecord>(`${'$'}{BASE_URL}/${'$'}{id}`);
|
||||
}
|
||||
|
||||
export function add(req: DataRecord) {
|
||||
return axios.post(BASE_URL, req);
|
||||
}
|
||||
|
||||
export function update(req: DataRecord, id: string) {
|
||||
return axios.put(`${'$'}{BASE_URL}/${'$'}{id}`, req);
|
||||
}
|
||||
|
||||
export function del(ids: string | Array<string>) {
|
||||
return axios.delete(`${'$'}{BASE_URL}/${'$'}{ids}`);
|
||||
}
|
@@ -0,0 +1,510 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
DataRecord,
|
||||
ListParam,
|
||||
list,
|
||||
get,
|
||||
add,
|
||||
update,
|
||||
del,
|
||||
} from '@/api/${apiModuleName}/${apiName}';
|
||||
import checkPermission from '@/utils/permission';
|
||||
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
// const { dis_enable_status_enum } = proxy.useDict('dis_enable_status_enum');
|
||||
|
||||
const dataList = ref<DataRecord[]>([]);
|
||||
const dataDetail = ref<DataRecord>({
|
||||
// TODO 待补充详情字段默认值
|
||||
});
|
||||
const total = ref(0);
|
||||
const ids = ref<Array<string>>([]);
|
||||
const title = ref('');
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const showQuery = ref(true);
|
||||
const loading = ref(false);
|
||||
const detailLoading = ref(false);
|
||||
const exportLoading = ref(false);
|
||||
const visible = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
|
||||
const data = reactive({
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInQuery>
|
||||
${fieldConfig.fieldName}: undefined,
|
||||
</#if>
|
||||
</#list>
|
||||
page: 1,
|
||||
size: 10,
|
||||
sort: ['createTime,desc'],
|
||||
},
|
||||
// 表单数据
|
||||
form: {} as DataRecord,
|
||||
// 表单验证规则
|
||||
rules: {
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInForm && fieldConfig.isRequired>
|
||||
${fieldConfig.fieldName}: [{ required: true, message: '${fieldConfig.comment}不能为空' }],
|
||||
</#if>
|
||||
</#list>
|
||||
},
|
||||
});
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*
|
||||
* @param params 查询参数
|
||||
*/
|
||||
const getList = (params: ListParam = { ...queryParams.value }) => {
|
||||
loading.value = true;
|
||||
list(params)
|
||||
.then((res) => {
|
||||
dataList.value = res.data.list;
|
||||
total.value = res.data.total;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
getList();
|
||||
|
||||
/**
|
||||
* 打开新增对话框
|
||||
*/
|
||||
const toAdd = () => {
|
||||
reset();
|
||||
title.value = '新增${businessName}';
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* 打开修改对话框
|
||||
*
|
||||
* @param id ID
|
||||
*/
|
||||
const toUpdate = (id: string) => {
|
||||
reset();
|
||||
get(id).then((res) => {
|
||||
form.value = res.data;
|
||||
title.value = '修改${businessName}';
|
||||
visible.value = true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const reset = () => {
|
||||
form.value = {
|
||||
// TODO 待补充需要重置的字段默认值,详情请参考其他模块 index.vue
|
||||
};
|
||||
proxy.$refs.formRef?.resetFields();
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
proxy.$refs.formRef.resetFields();
|
||||
};
|
||||
|
||||
/**
|
||||
* 确定
|
||||
*/
|
||||
const handleOk = () => {
|
||||
proxy.$refs.formRef.validate((valid: any) => {
|
||||
if (!valid) {
|
||||
if (form.value.id !== undefined) {
|
||||
update(form.value, form.value.id).then((res) => {
|
||||
handleCancel();
|
||||
getList();
|
||||
proxy.$message.success(res.msg);
|
||||
});
|
||||
} else {
|
||||
add(form.value).then((res) => {
|
||||
handleCancel();
|
||||
getList();
|
||||
proxy.$message.success(res.msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*
|
||||
* @param id ID
|
||||
*/
|
||||
const toDetail = async (id: string) => {
|
||||
if (detailLoading.value) return;
|
||||
detailLoading.value = true;
|
||||
detailVisible.value = true;
|
||||
get(id)
|
||||
.then((res) => {
|
||||
dataDetail.value = res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
detailLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭详情
|
||||
*/
|
||||
const handleDetailCancel = () => {
|
||||
detailVisible.value = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*/
|
||||
const handleBatchDelete = () => {
|
||||
if (ids.value.length === 0) {
|
||||
proxy.$message.info('请选择要删除的数据');
|
||||
} else {
|
||||
proxy.$modal.warning({
|
||||
title: '警告',
|
||||
titleAlign: 'start',
|
||||
content: `是否确定删除所选的${r'${ids.value.length}'}条数据?`,
|
||||
hideCancel: false,
|
||||
onOk: () => {
|
||||
handleDelete(ids.value);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param ids ID 列表
|
||||
*/
|
||||
const handleDelete = (ids: Array<string>) => {
|
||||
del(ids).then((res) => {
|
||||
proxy.$message.success(res.msg);
|
||||
getList();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 已选择的数据行发生改变时触发
|
||||
*
|
||||
* @param rowKeys ID 列表
|
||||
*/
|
||||
const handleSelectionChange = (rowKeys: Array<any>) => {
|
||||
ids.value = rowKeys;
|
||||
single.value = rowKeys.length !== 1;
|
||||
multiple.value = !rowKeys.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*/
|
||||
const handleExport = () => {
|
||||
if (exportLoading.value) return;
|
||||
exportLoading.value = true;
|
||||
proxy
|
||||
.download('/${apiModuleName}/${apiName}/export', { ...queryParams.value }, '${businessName}数据')
|
||||
.finally(() => {
|
||||
exportLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
const handleQuery = () => {
|
||||
getList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
const resetQuery = () => {
|
||||
proxy.$refs.queryRef.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* 切换页码
|
||||
*
|
||||
* @param current 页码
|
||||
*/
|
||||
const handlePageChange = (current: number) => {
|
||||
queryParams.value.page = current;
|
||||
getList();
|
||||
};
|
||||
|
||||
/**
|
||||
* 切换每页条数
|
||||
*
|
||||
* @param pageSize 每页条数
|
||||
*/
|
||||
const handlePageSizeChange = (pageSize: number) => {
|
||||
queryParams.value.size = pageSize;
|
||||
getList();
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: '${classNamePrefix}',
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<Breadcrumb :items="['menu.${apiModuleName}', 'menu.${apiModuleName}.${apiName}.list']" />
|
||||
<a-card class="general-card" :title="$t('menu.${apiModuleName}.${apiName}.list')">
|
||||
<!-- 头部区域 -->
|
||||
<div class="header">
|
||||
<!-- 搜索栏 -->
|
||||
<div v-if="showQuery" class="header-query">
|
||||
<a-form ref="queryRef" :model="queryParams" layout="inline">
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInQuery>
|
||||
<a-form-item field="${fieldConfig.fieldName}" hide-label>
|
||||
<a-input
|
||||
v-model="queryParams.${fieldConfig.fieldName}"
|
||||
placeholder="输入${fieldConfig.comment}搜索"
|
||||
allow-clear
|
||||
style="width: 150px"
|
||||
@press-enter="handleQuery"
|
||||
/>
|
||||
</a-form-item>
|
||||
</#if>
|
||||
</#list>
|
||||
<a-form-item hide-label>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleQuery">
|
||||
<template #icon><icon-search /></template>查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery">
|
||||
<template #icon><icon-refresh /></template>重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
<!-- 操作栏 -->
|
||||
<div class="header-operation">
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-space>
|
||||
<a-button
|
||||
v-permission="['${apiModuleName}:${apiName}:add']"
|
||||
type="primary"
|
||||
@click="toAdd"
|
||||
>
|
||||
<template #icon><icon-plus /></template>新增
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="['${apiModuleName}:${apiName}:update']"
|
||||
type="primary"
|
||||
status="success"
|
||||
:disabled="single"
|
||||
:title="single ? '请选择一条要修改的数据' : ''"
|
||||
@click="toUpdate(ids[0])"
|
||||
>
|
||||
<template #icon><icon-edit /></template>修改
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="['${apiModuleName}:${apiName}:delete']"
|
||||
type="primary"
|
||||
status="danger"
|
||||
:disabled="multiple"
|
||||
:title="multiple ? '请选择要删除的数据' : ''"
|
||||
@click="handleBatchDelete"
|
||||
>
|
||||
<template #icon><icon-delete /></template>删除
|
||||
</a-button>
|
||||
<a-button
|
||||
v-permission="['${apiModuleName}:${apiName}:export']"
|
||||
:loading="exportLoading"
|
||||
type="primary"
|
||||
status="warning"
|
||||
@click="handleExport"
|
||||
>
|
||||
<template #icon><icon-download /></template>导出
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<right-toolbar
|
||||
v-model:show-query="showQuery"
|
||||
@refresh="getList"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 列表区域 -->
|
||||
<a-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:data="dataList"
|
||||
:loading="loading"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
showCheckedAll: true,
|
||||
onlyCurrent: false,
|
||||
}"
|
||||
:pagination="{
|
||||
showTotal: true,
|
||||
showPageSize: true,
|
||||
total: total,
|
||||
current: queryParams.page,
|
||||
}"
|
||||
:bordered="false"
|
||||
column-resizable
|
||||
stripe
|
||||
size="large"
|
||||
@page-change="handlePageChange"
|
||||
@page-size-change="handlePageSizeChange"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<template #columns>
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig_index = 0>
|
||||
<a-table-column title="${fieldConfig.comment}" data-index="${fieldConfig.fieldName}">
|
||||
<template #cell="{ record }">
|
||||
<a-link @click="toDetail(record.id)">{{ record.${fieldConfig.fieldName} }}</a-link>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<#else>
|
||||
<#if fieldConfig.showInList>
|
||||
<a-table-column title="${fieldConfig.comment}" data-index="${fieldConfig.fieldName}" />
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
<a-table-column
|
||||
v-if="checkPermission(['${apiModuleName}:${apiName}:update', '${apiModuleName}:${apiName}:delete'])"
|
||||
title="操作"
|
||||
align="center"
|
||||
>
|
||||
<template #cell="{ record }">
|
||||
<a-button
|
||||
v-permission="['${apiModuleName}:${apiName}:update']"
|
||||
type="text"
|
||||
size="small"
|
||||
title="修改"
|
||||
@click="toUpdate(record.id)"
|
||||
>
|
||||
<template #icon><icon-edit /></template>修改
|
||||
</a-button>
|
||||
<a-popconfirm
|
||||
content="是否确定删除该数据?"
|
||||
type="warning"
|
||||
@ok="handleDelete([record.id])"
|
||||
>
|
||||
<a-button
|
||||
v-permission="['${apiModuleName}:${apiName}:delete']"
|
||||
type="text"
|
||||
size="small"
|
||||
title="删除"
|
||||
:disabled="record.disabled"
|
||||
>
|
||||
<template #icon><icon-delete /></template>删除
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<a-modal
|
||||
:title="title"
|
||||
:visible="visible"
|
||||
:mask-closable="false"
|
||||
:esc-to-close="false"
|
||||
unmount-on-close
|
||||
render-to-body
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<a-form ref="formRef" :model="form" :rules="rules" size="large">
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<#if fieldConfig.showInForm>
|
||||
<a-form-item label="${fieldConfig.comment}" field="${fieldConfig.fieldName}">
|
||||
<#if fieldConfig.formType = 'TEXT'>
|
||||
<a-input v-model="form.${fieldConfig.fieldName}" placeholder="请输入${fieldConfig.comment}" />
|
||||
<#elseif fieldConfig.formType = 'TEXT_AREA'>
|
||||
<a-textarea
|
||||
v-model="form.${fieldConfig.fieldName}"
|
||||
:max-length="200"
|
||||
placeholder="请输入${fieldConfig.comment}"
|
||||
:auto-size="{
|
||||
minRows: 3,
|
||||
}"
|
||||
show-word-limit
|
||||
/>
|
||||
<#elseif fieldConfig.formType = 'SELECT'>
|
||||
<#--<a-select
|
||||
v-model="form.${fieldConfig.fieldName}"
|
||||
:options="${apiName}Options"
|
||||
placeholder="请选择${fieldConfig.comment}"
|
||||
:loading="${apiName}Loading"
|
||||
multiple
|
||||
allow-clear
|
||||
:allow-search="{ retainInputValue: true }"
|
||||
style="width: 416px"
|
||||
/>-->
|
||||
<#elseif fieldConfig.formType = 'RADIO'>
|
||||
<#--<a-radio-group v-model="form.${fieldConfig.fieldName}" type="button">
|
||||
</a-radio-group>-->
|
||||
<#elseif fieldConfig.formType = 'DATE'>
|
||||
<a-date-picker v-model="form.${fieldConfig.fieldName}" placeholder="请选择${fieldConfig.comment}"/>
|
||||
<#elseif fieldConfig.formType = 'DATE_TIME'>
|
||||
<a-date-picker
|
||||
v-model="form.${fieldConfig.fieldName}"
|
||||
placeholder="请选择${fieldConfig.comment}"
|
||||
show-time
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
</#if>
|
||||
</a-form-item>
|
||||
</#if>
|
||||
</#list>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
|
||||
<!-- 详情区域 -->
|
||||
<a-drawer
|
||||
title="${businessName}详情"
|
||||
:visible="detailVisible"
|
||||
:width="580"
|
||||
:footer="false"
|
||||
unmount-on-close
|
||||
render-to-body
|
||||
@cancel="handleDetailCancel"
|
||||
>
|
||||
<a-descriptions :column="2" bordered size="large">
|
||||
<#list fieldConfigs as fieldConfig>
|
||||
<a-descriptions-item label="${fieldConfig.comment}">
|
||||
<a-skeleton v-if="detailLoading" :animation="true">
|
||||
<a-skeleton-line :rows="1" />
|
||||
</a-skeleton>
|
||||
<#if fieldConfig.fieldName = 'createUser'>
|
||||
<span v-else>{{ dataDetail.createUserString }}</span>
|
||||
<#elseif fieldConfig.fieldName = 'updateUser'>
|
||||
<span v-else>{{ dataDetail.updateUserString }}</span>
|
||||
<#else>
|
||||
<span v-else>{{ dataDetail.${fieldConfig.fieldName} }}</span>
|
||||
</#if>
|
||||
</a-descriptions-item>
|
||||
</#list>
|
||||
</a-descriptions>
|
||||
</a-drawer>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less"></style>
|
Reference in New Issue
Block a user