自定义代码生成器

自定义代码生成器

前提

  1. 这是在开发自己写的数据采集项目中,根据实际需要生成期望模板的生成器,支持多表,支持任意模型的插拔(如:只生成Controller和Service,其他模型不要)
  2. 基于SpringBoot项目,配置文件为yml类型
  3. 使用MySQL数据源
  4. 使用Mybatis-Plus+Spring JPA,所以会有JPA的注解存在

结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

流程

文件结构
在这里插入图片描述

1. 项目上配置好数据源信息

在这里插入图片描述

spring:
  datasource:
	driver-class-name: com.mysql.cj.jdbc.Driver
	url: jdbc:mysql://localhost:3306/自己的数据库?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&generateSimpleParameterMetadata=true&nullCatalogMeansCurrent=true
	username: 数据库账号
	password: 数据库密码

2. 基本信息properites中做好配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jjsARYCE-1686633840240)(:/7a455cb600b141b0ac69aac0e9d7f8ed)]

# 表名,逗号分隔,大小写不敏感
tableName=SINA_ASHARES_QUOTES
# 工程名
projectDirectory=betrice-data-acquisition
# 工程下生成的代码的父目录,程序会拼接在path之后
secondaryModule=finance
# 工程下生成的位置
path=src\\main\\java\\com\\devilvan\\betrice\\
# 作者
author=Evad.Wu
# 父目录下的单位目录
packageName=com.devilvan.betrice

3. BetriceCodeGenerator中选择好生成的模型

在这里插入图片描述

4. 在BetriceCodeGenerator中运行

在这里插入图片描述

代码

BetriceCodeGenerator

public class BetriceCodeGenerator {
	private static final String SUFFIX_JAVA = ".java";
	private static final String SUFFIX_XML = ".xml";
	private static Map<String, Object> basicMap;

	static {
		basicMap = loadBasic();
	}

	public static void main(String[] args) {
		List<String> tableList = Optional.of(Arrays.asList(String.valueOf(basicMap.get("tableName")).toUpperCase(Locale.ROOT).split(",")))
				.filter(f -> f.size() > 0)
				.orElseThrow(() -> new BetriceException("待生成的数据库表名不能为空!"));
		BetriceDataSourceTbDto betriceDataSourceTbDto = assemDataSourceTbDto(tableList);
		List<BetriceDbDto> dbDtoList = printTableStructure(betriceDataSourceTbDto);
		generate(dbDtoList);
	}

	/**
	 * 生成模型文件开关
	 * @param dbDtoList 待生成代码的数据表信息
	 */
	private static void generate(List<BetriceDbDto> dbDtoList) {
		for (BetriceDbDto dbDto : dbDtoList) {
			generateVo(dbDto);
			generatePo(dbDto);
			generateDto(dbDto);
			generateController(dbDto);
			generateService(dbDto);
			generateServiceImpl(dbDto);
			generateRepository(dbDto);
			generateMapper(dbDto);
			generateMapperXml(dbDto);
		}
	}

	/**
	 * 初始化方法,加载basic.properties 获取如表名、包名、作者等基础信息
	 * @return 解析properties的key-value后封装的Map
	 */
	private static Map<String, Object> loadBasic() {
		HashMap<String, Object> map = new HashMap<>();
		Properties pro = new Properties();
		try {
			pro.load(new FileReader("betrice-common\\betrice-common-codegen\\src\\main\\resources\\basic.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		String tableName = String.valueOf(pro.get("tableName"));
		String projectDirectory = String.valueOf(pro.get("projectDirectory"));
		String secondaryModule = String.valueOf(pro.get("secondaryModule"));
		String path = pro.get("path") + secondaryModule + "\\";
		String author = String.valueOf(pro.get("author"));
		String packageName = pro.get("packageName") + "." + secondaryModule;
		map.put("tableName", tableName);
		map.put("projectDirectory", projectDirectory);
		map.put("secondaryModule", secondaryModule);
		map.put("path", path);
		map.put("author", author);
		map.put("packageName", packageName);
		map.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
		return map;
	}

	/**
	 * springboot项目,获取application.yml中数据源信息
	 * @param tableList 需要生成的表名
	 * @return 数据源信息
	 */
	private static BetriceDataSourceTbDto assemDataSourceTbDto(List<String> tableList) {
		ClassPathResource resource = new ClassPathResource("application-parent.yml");
		YamlPropertiesFactoryBean ymlFactory = new YamlPropertiesFactoryBean();
		ymlFactory.setResources(resource);
		Properties pro = Optional.ofNullable(ymlFactory.getObject()).orElseThrow(() -> new BetriceException("获取配置失败!"));
		String driver = String.valueOf(pro.get("spring.datasource.driver-class-name"));
		String url = String.valueOf(pro.get("spring.datasource.url"));
		String uname = String.valueOf(pro.get("spring.datasource.username"));
		String pwd = String.valueOf(pro.get("spring.datasource.password"));
		BetriceDataSourceTbDto tbDto = new BetriceDataSourceTbDto(driver, url, uname, pwd);
		tbDto.setTableList(tableList);
		return tbDto;
	}

	/**
	 * 根据数据源信息获取到对应数据表的字段
	 * @param tbDto 数据源信息
	 * @return 数据表、字段信息
	 */
	private static List<BetriceDbDto> printTableStructure(BetriceDataSourceTbDto tbDto) {
		List<BetriceDbDto> dbDtoList = new ArrayList<>();
		// 每张表默认的审计字段,在生成的Model中只显示业务字段,而通过继承一个BasePo管理这些审计字段
		List<String> auditList = List.of("ID", "CREATOR", "CREATE_TIME", "MODIFIER", "MODIFY_TIME", "LOGIC_DEL", "REC_VER");
		try {
			// JDBC的过程了,加载MySQL驱动-连接-执行-结果集
			Class.forName(tbDto.getDriver());
			Connection connection = DriverManager.getConnection(tbDto.getUrl(), tbDto.getUname(), tbDto.getPwd());
			DatabaseMetaData metaData = connection.getMetaData();
			// 获取所有表
			List<String> tableList = tbDto.getTableList();
			for (String table : tableList) {
				// 根据表名获取数据表的元数据
				ResultSet tableResultSet = metaData.getTables(null, null, table, new String[]{"TABLE"});
				while (tableResultSet.next()) {
					String tableName = tableResultSet.getString("TABLE_NAME").toUpperCase(Locale.ROOT);
					// 将表名转化成类名
					String className = tableName2className(table);
					System.out.println("tableName: " + tableName);
					// 获取数据表的描述-comment
					String comment = tableResultSet.getString("REMARKS");
					if (StrUtil.isNotEmpty(comment)) {
						throw new BetriceException("表描述不能为空!");
					}
					System.out.println("comment: " + comment);
					BetriceDbDto dbDto = new BetriceDbDto(table, className, comment);
					// 获取表字段结构
					ResultSet columnResultSet = metaData.getColumns(null, "%", tableName, "%");
					List<BetriceCgField> betriceCgFieldList = new ArrayList<>();
					// 遍历表中每个字段
					while (columnResultSet.next()) {
						String columnName = columnResultSet.getString("COLUMN_NAME");
						if (auditList.contains(columnName)) {
							continue;
						}
						String fieldName = columnName2Field(columnName);
						String columnType = columnResultSet.getString("TYPE_NAME");
						String javaType = columnType2JavaType(columnType);
						int datasize = columnResultSet.getInt("COLUMN_SIZE");
						int digits = columnResultSet.getInt("DECIMAL_DIGITS");
						// false-不可为空
						boolean nullable = columnResultSet.getInt("NULLABLE") == 1;
						String remarks = columnResultSet.getString("REMARKS");
						BetriceCgField betriceCgField = new BetriceCgField(columnName, fieldName, columnType, javaType, datasize, digits, nullable, remarks);
						betriceCgFieldList.add(betriceCgField);
					}
					dbDto.setFieldList(betriceCgFieldList);
					dbDtoList.add(dbDto);
					System.out.println("=================================");
				}
			}
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		}
		return dbDtoList;
	}

	/**
	 * 表名转类名
	 * @param table 表名
	 * @return 类名
	 */
	private static String tableName2className(String table) {
		StringBuilder sb = new StringBuilder();
		String[] split = table.toLowerCase(Locale.ROOT).split("_");
		for (String s : split) {
			if (s.length() == 1) {
				sb.append(s.toUpperCase(Locale.ROOT));
			} else {
				sb.append(s.substring(0, 1).toUpperCase(Locale.ROOT)).append(s.substring(1));
			}
		}
		return sb.toString();
	}

	/**
	 * DB字段类型转Java类型
	 * @param columnType 字段类型
	 * @return Java类型
	 */
	private static String columnType2JavaType(String columnType) {
		if ("VARCHAR".equals(columnType) || "CHAR".equals(columnType) || "TINYTEXT".equals(columnType) ||
				"MEDIUNTEXT".equals(columnType) || "TEXT".equals(columnType) || "LONGTEXT".equals(columnType)) {
			return "String";
		} else if ("DATE".equals(columnType) || "TIME".equals(columnType) || "DATETIME".equals(columnType) ||
				"TIMESTAMP".equals(columnType) || "YEAR".equals(columnType)) {
			return "Date";
		} else if ("TINYINT".equals(columnType) || "SMALLINT".equals(columnType) || "MEDIUMINT".equals(columnType) ||
				"INT".equals(columnType)) {
			return "Integer";
		} else if ("BIGINT".equals(columnType)) {
			return "Long";
		} else if ("FLOAT".equals(columnType)) {
			return "Float";
		} else if ("DOUBLE".equals(columnType)) {
			return "Double";
		} else if ("DECIMAL".equals(columnType)) {
			return "BigDecimal";
		}
		return "String";
	}

	/**
	 * DB字段名转Java属性名
	 * @param columnName DB字段名
	 * @return Java属性名
	 */
	private static String columnName2Field(String columnName) {
		StringBuilder sb = new StringBuilder();
		String[] split = columnName.toLowerCase(Locale.ROOT).split("_");
		for (int i = 0; i < split.length; i++) {
			if (i == 0) {
				sb.append(split[0]);
			} else if (split[i].length() == 1) {
				sb.append(split[i].toUpperCase(Locale.ROOT));
			} else {
				sb.append(split[i].substring(0, 1).toUpperCase(Locale.ROOT)).append(split[i].substring(1));
			}
		}
		return sb.toString();
	}

	/**
	 * 根据freemarker模板,生成文件到对应目录下
	 * @param templateName 模板名称
	 * @param file 待生成的文件名
	 * @param basicMap 待生成的文件中的基本信息
	 */
	private static void generateFileByTemplate(String templateName, File file, Map<String, Object> basicMap) {
		try {
			Template template = FreemarkerTemplateUtil.getTemplate(templateName);
			FileOutputStream fos = new FileOutputStream(file);
			Writer out = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8), 10240);
			template.process(basicMap, out);
			FreemarkerTemplateUtil.clearCache();
		} catch (IOException | TemplateException e) {
			e.printStackTrace();
		}
	}

	private static void generateVo(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\vo\\";
		String templateName = "vo.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Vo" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generatePo(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\po\\";
		String templateName = "po.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Po" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateController(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\controller\\";
		String templateName = "controller.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Controller" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateDto(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\dto\\";
		String templateName = "dto.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Dto" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateService(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\service\\";
		String templateName = "service.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Service" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateServiceImpl(BetriceDbDto dbDto) {
		String parentpPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\service\\impl\\";
		String templateName = "serviceImpl.ftl";
		File mapperFile = new File(parentpPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentpPath + dbDto.getClassName() + "ServiceImpl" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateMapper(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\mapper\\";
		String templateName = "mapper.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Mapper" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateMapperXml(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\src\\main\\resources\\mapper\\";
		String templateName = "mapperXml.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Mapper" + SUFFIX_XML);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}

	private static void generateRepository(BetriceDbDto dbDto) {
		String parentPath = basicMap.get("projectDirectory") + "\\" + basicMap.get("path") + "\\repository\\";
		String templateName = "repository.ftl";
		File mapperFile = new File(parentPath);
		if (!mapperFile.exists()) {
			mapperFile.mkdirs();
		}
		File path = new File(parentPath + dbDto.getClassName() + "Repository" + SUFFIX_JAVA);
		Map<String, Object> map = new HashMap<>(basicMap);
		map.put("dbDto", dbDto);
		generateFileByTemplate(templateName, path, map);
	}
}

BetriceDbDto

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "数据库表信息 数据传输对象")
public class BetriceDbDto implements Serializable {
	@Serial
	private static final long serialVersionUID = -179434144799166939L;
	@ApiModelProperty(value = "表名")
	private String tableName;
	@ApiModelProperty(value = "类名")
	private String className;
	@ApiModelProperty(value = "表描述")
	private String comment;
	@ApiModelProperty(value = "字段值对象")
	private List<BetriceCgField> fieldList;

	public BetriceDbDto(String tableName, String className, String comment) {
		this.tableName = tableName;
		this.className = className;
		this.comment = comment;
	}
}

BetriceDataSourceTbDto

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "数据源信息 数据传输对象")
public class BetriceDataSourceTbDto extends BetriceDataSourceDto{
	@ApiModelProperty(value = "需要生成的表名")
	private List<String> tableList;

	public BetriceDataSourceTbDto(String driver, String url, String uname, String pwd) {
		super(driver, url, uname, pwd);
	}
}

BetriceDataSourceDto

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "数据源信息 数据传输对象")
public class BetriceDataSourceDto{
	@ApiModelProperty(value = "数据库驱动")
	private String driver;
	@ApiModelProperty(value = "数据库URL")
	private String url;
	@ApiModelProperty(value = "账号")
	private String uname;
	@ApiModelProperty(value = "密码")
	private String pwd;
}

BetriceCgField

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "表字段及转换相关字段")
public class BetriceCgField {
	@ApiModelProperty(value = "字段名称")
	private String columnName;
	@ApiModelProperty(value = "字段名称转换的属性名称")
	private String fieldName;
	@ApiModelProperty(value = "字段类型")
	private String columnType;
	@ApiModelProperty(value = "Java类型")
	private String javaType;
	@ApiModelProperty(value = "字段长度")
	private Integer dataSize;
	@ApiModelProperty(value = "精度")
	private Integer digits;
	@ApiModelProperty(value = "是否为空")
	private Boolean nullable;
	@ApiModelProperty(value = "字段描述")
	private String remark;
}

FreemarkerTemplateUtil-Freemarker生成模板工具类

public class FreemarkerTemplateUtil {
	private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_31);

	static {
		//这里比较重要,用来指定加载模板所在的路径
		CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreemarkerTemplateUtil.class,
				"/static/ftl"));
		CONFIGURATION.setDefaultEncoding("UTF-8");
		CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
		CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
	}

	public static Template getTemplate(String templateName) throws IOException {
		return CONFIGURATION.getTemplate(templateName);
	}

	public static void clearCache() {
		CONFIGURATION.clearTemplateCache();
	}
}

模型模板ftl文件

controller.ftl

package ${packageName}.controller;

import ${packageName}.po.${dbDto.className}Po;
import ${packageName}.service.${dbDto.className}Service;
import com.devilvan.betrice.common.BetriceResultVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * @author ${author}
 * @Description ${dbDto.comment} 控制器
 * @date ${date}
 */
@RestController
@RequestMapping(value = "${dbDto.className?uncap_first}Controller")
@Api(tags = "${dbDto.comment} 控制器")
public class ${dbDto.className}Controller {
    @Resource(name = "${dbDto.className?uncap_first}ServiceImpl")
    private ${dbDto.className}Service ${dbDto.className?uncap_first}Service;

    /**
     * 总请求控制器
     *
     * @return 形式返回
     */
    @ApiOperation(value = "总请求控制器")
    @RequestMapping(value = "do${dbDto.className}")
    public BetriceResultVo<${dbDto.className}Po> do${dbDto.className}() {
        BetriceResultVo<${dbDto.className}Po> betriceResultVo = new BetriceResultVo<>();
        return betriceResultVo;
    }

    /**
     * 采集报文控制器
     *
     * @return 形式返回
     */
    @ApiOperation(value = "采集报文控制器")
    @RequestMapping(value = "do${dbDto.className}Crawler")
    public BetriceResultVo<${dbDto.className}Po> do${dbDto.className}Crawler() {
        BetriceResultVo<${dbDto.className}Po> betriceResultVo = new BetriceResultVo<>();
        return betriceResultVo;
    }

    /**
     * 解析报文控制器
     *
     * @param request 报文
     * @return 形式返回
     */
    @ApiOperation(value = "解析报文控制器")
    @RequestMapping(value = "do${dbDto.className}Request")
    public BetriceResultVo<${dbDto.className}Po> do${dbDto.className}Request(@RequestBody String request) {
        BetriceResultVo<${dbDto.className}Po> betriceResultVo = new BetriceResultVo<>();
        return betriceResultVo;
    }
}

dto.ftl

package ${packageName}.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;

import java.util.Date;

/**
* @author ${author}
* @Description ${dbDto.comment} 数据传输对象
* @date ${date}
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "${dbDto.comment} 数据传输对象")
public class ${dbDto.className}Dto {
<#if dbDto.fieldList ??>
    <#list dbDto.fieldList as field>
    @ApiModelProperty(value = "${field.remark ! ''}")
    private <#if field.columnType == 'BIT'>Boolean<#else>${field.javaType}</#if> ${field.fieldName};
    </#list>
</#if>
}

mapper.ftl

package ${packageName}.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ${packageName}.po.${dbDto.className}Po;
import org.apache.ibatis.annotations.Mapper;

/**
* @author ${author}
* @Description ${dbDto.comment} 持久层
* @date ${date}
*/
@Mapper
public interface ${dbDto.className}Mapper extends BaseMapper<${dbDto.className}Po> {

}

mapperXml.ftl

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="${packageName}.mapper.${dbDto.className}Mapper">
</mapper>

po.ftl

package ${packageName}.po;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.devilvan.betrice.common.BasePo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.hibernate.annotations.DynamicInsert;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;

/**
* @author ${author}
* @Description ${dbDto.comment} 映射
* @date ${date}
*/
@Setter
@Getter
@ToString
@NoArgsConstructor
@Accessors(chain = true)
@TableName(value = "${dbDto.tableName}")

@Entity
@Table(name = "${dbDto.tableName}")
@DynamicInsert
@EntityListeners(AuditingEntityListener.class)
@ApiModel(value = "${dbDto.comment} 映射")
public class ${dbDto.className}Po extends BasePo implements Serializable {
<#if dbDto.fieldList ??>
    <#list dbDto.fieldList as field>
    @ApiModelProperty(value = "${field.remark ! ''}")
    @TableField(value = "${field.columnName}")
    @Column(name = "${field.columnName}", columnDefinition = "<#if field.javaType != 'Date'>${field.columnType}(${field.dataSize}) <#else>${field.columnType} </#if><#if field.nullable = false>NOT NULL </#if>COMMENT '${field.remark}'")
    private <#if field.columnType == 'BIT'>Boolean<#else>${field.javaType}</#if> ${field.fieldName};
    </#list>
</#if>
}

repository.ftl

package ${packageName}.repository;


import ${packageName}.po.${dbDto.className}Po;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
* @author ${author}
* @Description ${dbDto.comment} 持久层
* @date ${date}
*/
@Repository
public interface ${dbDto.className}Repository extends JpaRepository<${dbDto.className}Po, Long> {
}

service.ftl

package ${packageName}.service;

import ${packageName}.dto.${dbDto.className}Dto;
import ${packageName}.po.${dbDto.className}Po;

import java.util.List;

/**
* @author ${author}
* @Description ${dbDto.comment} 业务逻辑接口
* @date ${date}
*/
public interface ${dbDto.className}Service {
    /**
    * 保存
    *
    * @param ${dbDto.className?uncap_first}Dto 控制层处理后的数据传输对象
    * @return 保存回调对象
    */
    ${dbDto.className}Po saveUpdate(${dbDto.className}Dto ${dbDto.className?uncap_first}Dto);
    /**
    * 批量保存
    *
    * @param list 控制层处理后的数据传输对象集合
    * @return 保存回调对象
    */
    List<${dbDto.className}Po> saveUpdateBatch(List<${dbDto.className}Dto> list);
}

serviceImpl.ftl

package ${packageName}.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${packageName}.dto.${dbDto.className}Dto;
import ${packageName}.po.${dbDto.className}Po;
import ${packageName}.service.${dbDto.className}Service;
import ${packageName}.mapper.${dbDto.className}Mapper;
import ${packageName}.repository.${dbDto.className}Repository;
import org.springframework.stereotype.Service;
import com.devilvan.betrice.util.CopyUtil;

import javax.annotation.Resource;
import java.util.List;

/**
* @author ${author}
* @Description ${dbDto.comment} 业务逻辑类
* @date ${date}
*/
@Service
public class ${dbDto.className}ServiceImpl extends ServiceImpl<${dbDto.className}Mapper, ${dbDto.className}Po> implements ${dbDto.className}Service {
    @Resource(name = "${dbDto.className?uncap_first}Repository")
    private ${dbDto.className}Repository ${dbDto.className?uncap_first}Repository;

    @Override
    public ${dbDto.className}Po saveUpdate(${dbDto.className}Dto ${dbDto.className?uncap_first}Dto) {
        ${dbDto.className}Po ${dbDto.className?uncap_first}Po = new ${dbDto.className}Po();
        CopyUtil.fullCopy(${dbDto.className?uncap_first}Dto, ${dbDto.className?uncap_first}Po);
        return ${dbDto.className?uncap_first}Repository.saveAndFlush(${dbDto.className?uncap_first}Po);
    }

    @Override
    public List<${dbDto.className}Po> saveUpdateBatch(List<${dbDto.className}Dto> list) {
        List<${dbDto.className}Po> ${dbDto.className?uncap_first}PoList = CopyUtil.fullCopyCollections(list, ${dbDto.className}Po.class);
        return ${dbDto.className?uncap_first}Repository.saveAllAndFlush(${dbDto.className?uncap_first}PoList);
    }
}

vo.ftl

package ${packageName}.vo;

import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
* @author ${author}
* @Description ${dbDto.comment} 值对象
* @date ${date}
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "${dbDto.comment} 值对象")
public class ${dbDto.className}Vo {
<#if dbDto.fieldList ??>
    <#list dbDto.fieldList as field>
    @ApiModelProperty(value = "${field.remark ! ''}")
    @JSONField(alternateNames = {"${field.fieldName}"})
    private <#if field.columnType == 'BIT'>Boolean<#else>${field.javaType}</#if> ${field.fieldName};
    </#list>
</#if>
}

系统地讲解了如何构建一个日常生产环境实用的基于Spring Boot并且集成springmvc + shiro + mybatis-plus + beetl的后台管理系统,可管理代码生成模版,管理连接生成代码的数据库. Guns框架自带的功能:1.用户管理 2.角色管理 3.部门管理 4.菜单管理 5.字典管理 6.业务日志 7.登录日志 8.监控管理 9.通知管理 10.代码生成 Guns特点: 1. 基于SpringBoot,简化了大量项目配置和maven依赖,让您更专注于业务开发,独特的分包方式,代码多而不乱。 2. 完善的日志记录体系,可记录登录日志,业务操作日志(可记录操作前和操作后的数据),异常日志到数据库,通过@BussinessLog注解和LogObjectHolder.me().set()方法,业务操作日志可具体记录哪个用户,执行了哪些业务,修改了哪些数据,并且日志记录为异步执行,详情请见@BussinessLog注解和LogObjectHolder,LogManager,LogAop类。 3. 利用beetl模板引擎对前台页面进行封装和拆分,使臃肿的html代码变得简洁,更加易维护。 4. 对常用js插件进行二次封装,使js代码变得简洁,更加易维护,具体请见webapp/static/js/common文件夹内js代码。 5. 利用ehcache框架对经常调用的查询进行缓存,提升运行速度,具体请见ConstantFactory类中@Cacheable标记的方法。 6. controller层采用map + warpper方式的返回结果,返回给前端更为灵活的数据,具体参见com.stylefeng.guns.modular.system.warpper包中具体类。 7. 防止XSS攻击,通过XssFilter类对所有的输入的非法字符串进行过滤以及替换。 8. 简单可用的代码生成体系,通过SimpleTemplateEngine可生成带有主页跳转和增删改查的通用控制器、html页面以及相关的js,还可以生成Service和Dao,并且这些生成项都为可选的,通过ContextConfig下的一些列xxxSwitch开关,可灵活控制生成模板代码,让您把时间放在真正的业务上。 9. 控制器层统一的异常拦截机制,利用@ControllerAdvice统一对异常拦截,具体见com.stylefeng.guns.core.aop.GlobalExceptionHandler类。 10. 页面统一的js key-value单例模式写法,每个页面生成一个唯一的全局变量,提高js的利用效率,并且有效防止多个人员开发引起的函数名/类名冲突,并且可以更好地去维护代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加把劲骑士RideOn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值