代码自动生成工具(三)-Xml读表代码自动生成工具

之前提到了一个工具类XmlReader


这里我们实现一个可以对Xml文件,自动生成其对应的读表代码。

本工具需要boost库支持,本人用的是1.55.0。


首先人为约定两个xml结点属性名称的保留关键字:pk=“”,rk=“”。

pk的值是本结点的某一个字段的名字,用来表示本结点在其父结点中,采用map来管理,键值就是该字段的值。

rk的值是本结点中某两个同类型的字段的名字,这两个字段用来表示一个闭区间,使得本结点在其父结点中,采用rangmap来管理,区间的起始值和终止值,就是这两个字段所填的值。

没有配置键的情况下,子节点在父结点中采用vector管理。

pk或rk 在相同结构路径下,只需要配置一次就可以,不需要每个节点都配置。


对于字段的数据类型,采用正则表达式判断识别,如果同一个字段,即出现整数,又出现浮点数,则按浮点数处理;即出现数字,又出现字符串,按字符串处理;如果同一个字段,出现不能兼容的两种类型,比如同时有数字和时间,按字符串处理。


这里首先定义Xml中支持的几种列类型:XmlMemberType:包括整数,小数,浮点数,字符串,时间戳,子结构等等

enum XmlMemberType
{
	XMT_init = 0,	// 未初始化的
	XMT_uint32,		// 无符号整数
	XMT_int32,		// 整数
	XMT_float,		// 浮点数
	XMT_datetime,	// 年-月-日 时:分:秒表示的时间
	XMT_time,		// 时:分:秒表示的时间
	XMT_rang,		// int-int这样的两个数字表示的区间值
	XMT_string,		// 字符串
	XMT_child,		// 子结构
	XMT_unknow,		// 非法的类型(同一个字段出现了两种不能互相兼容的类型)
	XMT_count,
};

列主键的类型

enum XmlMemberKey
{
	XMK_pk = 0,		// 主键
	XMK_rang,		// 范围主键
	XMK_normal,		// 普通成员
};

xml结构成员的定义,包括名字,类型,是否是主键

class XmlMember
{
public:
	XmlMember();
	XmlMember(const XmlMember &other);
	XmlMember& operator = (const XmlMember &other);
	void Init();
	std::string m_Name;		// xml结构字段名称
	XmlMemberType m_Type;	// xml结构字段类型
	XmlMemberKey m_Key;		// xml结构字段是否作为主键使用
};

xml结构的定义,包含结构名称,结构成员列表

class XmlStruct
{
public:
	XmlStruct();
	XmlStruct(const XmlStruct &other);
	XmlStruct& operator = (const XmlStruct &other);
	void Init();
	const XmlMember* GetPrimaryKey() const;
	std::vector<const XmlMember*> GetRangKey() const;
	std::string m_Name;							// 结构名称
	std::map<std::string, XmlMember> m_Members;	// 结构字段列表
};

整个xml文件:包括文件名,包名,结构列表

class XmlFile
{
public:
	XmlFile();
	XmlFile(const XmlFile &other);
	XmlFile& operator = (const XmlFile &other);
	void Init();
	std::string m_FileName;						// xml文件名(不带扩展名)
	std::string m_Package;						// xml包名xxx.xxx.xxx
	std::map<std::string, XmlStruct> m_Structs;	// xml结构列表
};

xml文件解析类,读取文件文本内容,使用EBNF范式,分析文件内容,按相应配置(命名空间,文件路径等),解析生成相应的XmlFile对象,

class XmlParse
{
public:
	XmlParse();
	~XmlParse();
	bool ParseFile(const char* fullPathName);
private:
	bool ParseXml(const char* expr);
	void ParseXmlStruct(const char* start, const char* end);
	void ParseXmlStructEnd(const char* start, const char* end);
	void ParseXmlStructEnd1(const char* start, const char* end);
	void ParseXmlStructEnd2(const char* start, const char* end);
	void ParseXmlMemberName(const char* start, const char* end);
	void ParseXmlMemberValue(const char* start, const char* end);
public:
	// 解析完毕的xml文件信息列表
	std::map<std::string, XmlFile> m_Files;
private:
	// 解析时,临时xml文件内容对象
	common::tool::FileData m_FileData;
	// 解析时,临时xml文件对象
	XmlFile m_TempFile;
	// 解析时,临时xml结构对象
	XmlStruct m_TempStruct;
	// 解析时,临时xml结构成员对象
	XmlMember m_TempMember;
	// 用于判断结构父子关系的栈 
	std::stack<std::string> m_ChildName;
	// xml文件解析工具输入参数
public:
	std::string m_NameSpace; // 自定义命名空间
	bool m_ThreadSpecific;	// 是否需要线程本地表格数据
	std::vector<std::string> m_XmlFileName; // 待处理的xml文件列表
	std::string m_LoaderPath; // loader输出cpp代码路径
	std::string m_HelperPath; // helper输出cpp代码路径
};


具体的代码生成包含两部分功能:

void ParseXml2LoaderH(const XmlParse& xmlParse)

void ParseXml2LoaderCpp(const XmlParse& xmlParse)

void ParseXml2HelperH(const XmlParse& xmlParse)

void ParseXml2HelperCpp(const XmlParse& xmlParse)

传入一个解析好的XmlParse对象,生成具体代码

Loader生成对应的读取代码,使用boost::ptree读取xml文件,转成相应的数据结构。

Helper生成一个空的辅助类,用于需要对数据重新组织的情况,比如配置中是按某个id列作为主键,存成一个map,提供查找,但是实际逻辑中还需要按某个名称列作为索引,再提供一个map,用于提供按名称查找(或者模糊查找),这时候就需要手动再提供一个新的查找函数,就可以写在helper中


main函数涉及两个小功能:

一个是遍历输入参数,解析名命名空间,待处理的xml文件,代码生成路径

一个是迭代每一个待处理的xml文件名,传入XmlParse解析,然后对解析完的结果,逐个生成相应代码


完整的代码,比较长,这里就不贴了


给一个生成后的代码的示例吧:

xml文件:

<Tests>
	<Node id="10000" pk="id">
		<Time begin="2018-1-18 00:00:00" end="2018-1-18 23:59:59" rk="begin;end" num="1"/>
		<Time begin="2018-1-19 00:00:00" end="2018-1-19 23:59:59" num="1"/>
		<Time begin="2018-1-20 00:00:00" end="2018-1-20 23:59:59" num="1"/>
	</Node>
	<Node id="10001">
		<Time begin="2018-1-18 00:00:00" end="2018-1-18 23:59:59" num="1"/>
		<Time begin="2018-1-19 00:00:00" end="2018-1-19 23:59:59" num="1"/>
		<Time begin="2018-1-20 00:00:00" end="2018-1-20 23:59:59" num="1"/>
	</Node>
</Tasks>
生成的代码:

#ifndef __TestsXmlLoader_h__
#define __TestsXmlLoader_h__

#include <string>
#include <vector>
#include <map>

#include "rangmap.h"

namespace common {
	namespace xml {

		class Tests
		{
		public:
			class Node
			{
			public:
				class Time
				{
				public:
					Time();
					Time(const Time& other);
					Time& operator=(const Time& other);
					~Time();

					time_t m_begin;
					time_t m_end;
					unsigned int m_num;
				};

			public:
				Node();
				Node(const Node& other);
				Node& operator=(const Node& other);
				~Node();

				void AddTime(time_t begin, time_t end, const Time& val);
				const Time* GetTime(time_t key) const;

				common::tool::rangmap<time_t, Time> m_Time;
				unsigned int m_id;
			};

		public:
			Tests();
			Tests(const Tests& other);
			Tests& operator=(const Tests& other);
			~Tests();

			void AddNode(unsigned int key, const Node& val);
			const Node* GetNode(unsigned int key) const;

			std::map<unsigned int, Node> m_Node;
		};

		class TestsXmlLoader
		{
		public:
			TestsXmlLoader()
			{
			}
			~TestsXmlLoader()
			{
			}

			bool LoadFile(const char* szPath);
			bool ReloadFile(const char* szPath);

			const Tests& GetTests() const;

		private:
			Tests m_Tests;
		};


	}
}
#endif

放上完整工程的 下载链接

工程中的boost库的路径为作者本机的路径,VS编译时请选择Release,重新配置boost库的include路径和lib路径

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Mybatis是一个优秀的ORM框架,可以帮助我们快速地进行数据库操作。而Mybatis代码自动生成工具可以帮助我们快速生成Java类和Mybatis对应的SQL语句,从而提高开发效率。以下是两种常用的Mybatis代码自动生成工具: 1. Mybatis Generator Mybatis Generator是Mybatis官方提供的代码自动生成工具,可以根据数据库表生成Java类和Mybatis对应的SQL语句。使用Mybatis Generator需要编写一个XML配置文件,指定数据库连接信息、生成的Java类和SQL语句的包名、生成的表等信息。以下是一个简单的Mybatis Generator配置文件示例: ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="DB2Tables" targetRuntime="MyBatis3"> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/test" userId="root" password="root"> </jdbcConnection> <javaModelGenerator targetPackage="com.example.model" targetProject="src/main/java"> </javaModelGenerator> <sqlMapGenerator targetPackage="com.example.mapper" targetProject="src/main/resources"> </sqlMapGenerator> <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.mapper" targetProject="src/main/java"> </javaClientGenerator> <table tableName="user"></table> </context> </generatorConfiguration> ``` 2. Mybatis-Plus Generator Mybatis-Plus是Mybatis的增强工具,在Mybatis的基础上提供了更多的功能。Mybatis-Plus Generator是Mybatis-Plus提供的代码自动生成工具,可以快速生成Entity、Mapper、Mapper XML、Service、Controller等各个模块的代码。使用Mybatis-Plus Generator需要编写一个Java类,指定数据库连接信息、生成的Java类和SQL语句的包名、生成的表等信息。以下是一个简单的Mybatis-Plus Generator配置类示例: ```java public class CodeGenerator { public static void main(String[] args) { AutoGenerator mpg = new AutoGenerator(); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setParent("com.example"); pc.setEntity("model"); pc.setMapper("mapper"); pc.setXml("mapper.xml"); pc.setService("service"); pc.setServiceImpl("service.impl"); pc.setController("controller"); mpg.setPackageInfo(pc); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); strategy.setInclude("user"); mpg.setStrategy(strategy); // 执行生成 mpg.execute(); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值