本站建设:代码生成功能集成

原创 临窗旋墨 2021-06-22 阅读:5192 分类: 专题: 本站建设 标签: springboot

[TOC]

003-代码生成功能集成

2019-11-14

1- 代码生成思路

​ 网上关于代码自动生成的开源项目很多,基本可以拿来之后修改模板文件直接使用.本项目的代码自动生成主要是17年左右借鉴人人开源上面的代码而来.

​ 基本思路都是一样的:

  1. 连接数据库获取数据库表的全部信息(本项目只实现mysql版本)
    • 如需支持多种数据库,则定义dao接口,不同的数据库做不同的实现,根据配置文件指定Primary
  2. 解析表的基本信息,列的基本信息映射成对象
  3. 编写各层模板,根据解析的数据对模板进行填充
  4. 导出填充后的模板

2-本项目中代码生成功能的大概实现

2.1 配置文件与映射

generator-config.properties

properties 复制代码
 #代码生成器,配置信息
#包名
packageName=pers.vic
#模块名
moduleName=system
#作者
author=Vic.xu
#Email
email=xuduochoua@163.com
#表前缀(类名不会包含表前缀)
tablePrefix=
#需要填充的模板
templates[0]=generator/templates/Entity.java.vm
#略
#数据类型转换,配置信息:数据库类型->java类型
tinyint=Integer
#略

2.2 解析表后的实体

  1. TableEntity 对应一张表的基本数据:表名/备注/主键/对应的类名/创建时间/关联的ColumnEntity列表等
  2. ColumnEntity对应列的属性:列名/列属性/备注/属性名/属性类型/是否主键/对应的ColumnExtend
  3. ColumnExtend列的扩展:本项目额外增加的根据备注对列做的额外的处理说明

2.3service层大体代码

java 复制代码
@Service
public class GeneratorService{
	@Resource
	private ConfigurationOfGenerator configurationOfGenerator;
	@Resource
	private GeneratorMapper generatorMapper;

	public List<TableEntity> list(Lookup lookup) {
		List<TableEntity> datas = generatorMapper.queryList(lookup);
		return datas;
	}

	private List<ColumnEntity> queryColumns(String tableName) {
		return generatorMapper.queryColumns(tableName);
	}

	private TableEntity queryTable(String tableName) {
		return generatorMapper.queryTable(tableName);
	}

	/**
	 * 根据表名生成代码
	 * 
	 * @param moduleName
	 * @param packageName
	 */
	public byte[] generatorCode(String[] tableNames, String packageName, String moduleName) {
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ZipOutputStream zip = new ZipOutputStream(outputStream);

		for (String tableName : tableNames) {
			// 查询表信息
			TableEntity table = queryTable(tableName);
			// 查询列信息
			List<ColumnEntity> columns = queryColumns(tableName);
			// 生成代码
			generatorCode(table, packageName, moduleName, columns, zip);
		}
		IOUtils.closeQuietly(zip);
		return outputStream.toByteArray();
	}

	private void generatorCode(TableEntity table, String packageName, String moduleName, List<ColumnEntity> columns,
			ZipOutputStream zip) {
		
		Map<String, Object> map = getTemplateData(table, packageName, moduleName, columns);
		VelocityContext context = new VelocityContext(map);

		// 获取模板列表
		List<String> templates = getTemplates();
		for (String template : templates) {
			// 渲染模板
			StringWriter sw = new StringWriter();
			Template tpl = Velocity.getTemplate(template, "UTF-8");
			tpl.merge(context, sw);
			try {
				// 添加到zip
				String fileName = getFileName(template, table.getClassName(), configurationOfGenerator.getPackageName(),
						configurationOfGenerator.getModuleName());
				zip.putNextEntry(new ZipEntry(fileName));
				IOUtils.write(sw.toString(), zip, "UTF-8");
				IOUtils.closeQuietly(sw);
				zip.closeEntry();
			} catch (Exception e) {
				throw new RuntimeException("渲染模板失败,表名:" + table.getTableName(), e);
			}

		}
	}

	//获得渲染模板的数据
	private Map<String, Object> getTemplateData(TableEntity table, String packageName,  String moduleName, List<ColumnEntity> columns) {
		// 配置信息
		Configuration config = getConfig();
		boolean hasBigDecimal = false;
		String className = tableToJava(table.getTableName(), configurationOfGenerator.getTablePrefix());

		table.setClassName(className);
		// 第一个字母小写
		table.setClassname(StringUtils.uncapitalize(className));

		// 列信息
		for (ColumnEntity column : columns) {
			// 列名转换成Java属性名
			String attrName = columnToJava(column.getColumnName());
			column.setAttrName(attrName);
			column.setAttrname(StringUtils.uncapitalize(attrName));

			// 列的数据类型,转换成Java类型
			String attrType = config.getString(column.getDataType(), "unknowType");
			column.setAttrType(attrType);
			if (!hasBigDecimal && attrType.equals("BigDecimal")) {
				hasBigDecimal = true;
			}
			if ("Date".equals(attrType)) {
				table.setHasDate(true);
			}

			// 是否主键
			if ("PRI".equalsIgnoreCase(column.getColumnKey()) && table.getPk() == null) {
				table.setPk(column);
			}
			// 根据列是否是图片和日期 判断表中是否含有图片和日期
			ColumnExtend extend = ColumnExtend.initExtends(column);
			table.findExtend(extend);

		}
		// 没主键,则第一个字段为主键
		table.setColumns(columns);
		if (table.getPk() == null) {
			table.setPk(columns.get(0));
		}

		// 设置velocity资源加载器
		Properties prop = new Properties();
		prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
		Velocity.init(prop);

		// 封装模板数据
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("table", table);
		map.put("tableName", table.getTableName());
		map.put("comments", table.getComments());
		map.put("pk", table.getPk());
		map.put("className", table.getClassName());
		map.put("classname", table.getClassname());
		map.put("pathName", table.getClassname().toLowerCase());
		map.put("columns", table.getColumns());
		map.put("hasBigDecimal", hasBigDecimal);
		if (StringUtils.isEmpty(packageName)) {
			map.put("package", config.getString("packageName"));
		} else {
			map.put("package", packageName);
		}
		if (StringUtils.isEmpty(packageName)) {
			map.put("moduleName", config.getString("moduleName"));
		} else {
			map.put("moduleName", moduleName);
		}
		map.put("author", config.getString("author"));
		map.put("email", config.getString("email"));
		map.put("datetime", DateFormatUtils.format(new Date(), "yyyy-mm-dd HH:mm"));
		return map;
	}

	/**
	 * 获取文件名
	 */
	public static String getFileName(String template, String className, String packageName, String moduleName) {
		String packagePath = "generator" + File.separator + className;
		/*
		 * packagePath = "main" + File.separator + "java" + File.separator; if
		 * (StringUtils.isNotBlank(packageName)) { packagePath +=
		 * packageName.replace(".", File.separator) + File.separator + moduleName +
		 * File.separator; }
		 */

		// 实体
		if (template.contains("Entity.java.vm")) {
			return packagePath + File.separator + className + ".java";
		}
		// 查询条件
		if (template.contains("Lookup.java.vm")) {
			return packagePath + File.separator + className + "Lookup.java";
		}

		// mapper.java
		if (template.contains("Mapper.java.vm")) {
			return packagePath + File.separator + className + "Mapper.java";
		}

		// service
		if (template.contains("Service.java.vm")) {
			return packagePath + File.separator + className + "Service.java";
		}

		// controller
		if (template.contains("Controller.java.vm")) {
			return packagePath + File.separator + className + "Controller.java";
		}
		// mapper.xnl
		if (template.contains("Mapper.xml.vm")) {
			return packagePath + File.separator + className + "Mapper.xml";
		}

		// list.jsp
		if (template.contains("list.jsp.vm")) {
			return packagePath + File.separator + "list.jsp";
		}
		// form.jsp
		if (template.contains("form.jsp.vm")) {
			return packagePath + File.separator + "form.jsp";
		}

        return null;
	}


	/**
	 * 获取要填充的模板
	 * @return
	 */
	public List<String> getTemplates() {
		return configurationOfGenerator.getTemplates();
	}


	/**
	 * 表名转换成Java类名
	 */
	private String tableToJava(String tableName, String tablePrefix) {
		if (StringUtils.isNotBlank(tablePrefix)) {
			tableName = tableName.replaceFirst(tablePrefix, "");
		}
		return columnToJava(tableName);
	}

	/**
	 * 列名转换成Java属性名
	 */
	public static String columnToJava(String columnName) {
//		return WordUtils.capitalizeFully(columnName, new char[] { '_' }).replace("_", "");//aaBBcc-->aabbcc  不是我想要的
		return underlineToCamel(columnName);
	}

	/**
	 * 下划线转驼峰 但是不小写
	 * 
	 * @param str
	 * @return
	 */
	static String UNDERLINE = "_";

	public static String underlineToCamel(String str) {
		if (StringUtils.isEmpty(str)) {
			return str;
		}
		StringBuffer sb = new StringBuffer();
		for (String s : str.split(UNDERLINE)) {
			sb.append(StringUtils.capitalize(s));
		}
		return sb.toString();
	}

	/**
	 * 获取配置信息
	 */
	public static Configuration getConfig() {
		try {
			return new PropertiesConfiguration("config/generator-config.properties");
		} catch (ConfigurationException e) {
			throw new RuntimeException("获取配置文件失败,", e);
		}
	}

	public Map<String, String> findTableDetail(String tableName, String packageName, String moduleName) {
		// 查询表信息
		TableEntity table = queryTable(tableName);
		// 查询列信息
		List<ColumnEntity> columns = queryColumns(tableName);
		
		Map<String, Object> map = getTemplateData(table, packageName, moduleName, columns);
		VelocityContext context = new VelocityContext(map);

		// 获取模板列表
		List<String> templates = getTemplates();
		Map<String, String> data = new LinkedHashMap<String, String>();
		for (String template : templates) {
			// 渲染模板
			StringWriter sw = new StringWriter();
			Template tpl = Velocity.getTemplate(template, "UTF-8");
			tpl.merge(context, sw);
			try {
				// 添加到zip
				String fileName = getFileName(template, table.getClassName(), configurationOfGenerator.getPackageName(),
						configurationOfGenerator.getModuleName());
				data.put(fileName.replace("generator" + File.separator, "").replace(File.separator, "_"), sw.toString());
			} catch (Exception e) {
				throw new RuntimeException("渲染模板失败,表名:" + table.getTableName(), e);
			}

		}
		return data;
	}

}

评论区

avatar
未登录

暂无评论,来发表第一条评论吧~