faster Efficiency-The simplest code generator implementation
Why you need a code generator.
When the work needs to copy and paste frequently to write the program, the better choice may be to write a code generator to generate the basic content, and then on this basis to modify and improve.
While copying and pasting is simple, there are many inconvenient and potential bugs. Copy and paste many times or we need to modify a number of variable names, do a lot of changes, sometimes if careless without modification of the whole, but will introduce a lot of bugs.
Like the front page, if we need to write our own admin page, we will find that most crud operations are very similar, and usually can be solved by copying and pasting, but if more than one person is developing at the same time, there may be many different styles, and different people need to know different styles when they are maintaining. So if this kind of foreground page, we also through the code generator to build, the effect will be more unified, the implementation will be simpler. Why is the simplest code generator.
Typically, the starting point of the code generator may be the table of the database, which needs to get information about the table from the database and then generate some related classes. This code generator, which starts from the table, is not complicated, but it is not easy to use.
The code generator here is to start with a single entity class that does not have an inheritance, and the entire code generator is completely independent of project execution. After the entity objects are generated from the database, many of our operations are done against the entity classes. The code generator is completely independent, so it does not get all kinds of information about the class through reflection, the general entity class, we can extract most of the information we need by directly parsing the source. This code generator is simple and easy to use by parsing the entity class source from the file stream. Template Tool Class Freemarkerutil
Any kind of template framework, I use freemarker because I can only get freemarker jar packages.
This class is simply to read the template at the specified location, and then output the rendered results to the specified location, the following code:
public class Freemarkerutil {private static final version version = Configuration.version_2_3_0;
Private static final Configuration config = new Configuration (VERSION);
private static final String ENCODING = "Utf-8";
static {Config.setlocale (Locale.china);
Config.setdefaultencoding (ENCODING);
Config.setencoding (Locale.china, ENCODING);
Config.setclassfortemplateloading (Freemarkerutil.class, "");
Config.setobjectwrapper (New Defaultobjectwrapper (VERSION)); public static Writer Newwriter (String filePath) throws Exception {return new BufferedWriter (new Outputstre
Amwriter (New FileOutputStream (FilePath), ENCODING)); public static BufferedReader Newreader (String filePath) throws Exception {return new BufferedReader (New in
Putstreamreader (New FileInputStream (FilePath), ENCODING)); public static Boolean ProcessTemplate (String templatename, map< String, object> params, string outputpath) {try (Writer out = Newwriter (OutputPath
) {StringBuilder Namebuilder = new StringBuilder ();
Namebuilder.append ("//template/"). Append (templatename). Append (". FTL");
Template Template = Config.gettemplate (namebuilder.tostring (), ENCODING);
Template.process (params, out);
Out.flush ();
return true;
catch (Exception e) {e.printstacktrace ();
return false; }
}
}
field Information class FD
This class is defined according to the needs of the individual, generally only the field name and the meaning of the field, because my front-end JSP to special processing date type, so the property as required to adjust the code as follows:
public class Fd {
private String name;
private String text;
private Boolean date;
Public Fd (string name, string text, Boolean date) {
this.name = name;
This.date = date;
if (text!= null && text.length () > 0) {
this.text = text;
} else {
this.text = name;
}
}
//Omit Getter-setter
}
Builder Configuration
Before you say generator classes, look at the configurations that the generator has:
#生成代码的基础路径
gen.basepath=d:/isea533/template
#基础配置
gen.classname=com.github.abel533.model.sysuser
Gen. Entityname= User Information
gen.author=isea533
#字段对应的中文含义
entity.id= primary key
entity.orgid= mechanism ID
Entity.username= user name
# ...
#除了通过上面方法指定外, the program will automatically read the following form of comments as the Chinese meaning
#/**
# * User Password
#/* *
/#private String password;
#
#说明: The program in the reading design of the comparison die, because the code is simple, you can adjust the project at any time
#java文件的路径
#本程序完全通过读取java文件来提取信息
gen.java=d:/ Isea533/workspace/xxxx/xxxx/sysuser.java
#下面是具体的模板配置, after the equals sign is the specific template name, which is #针对同一类型的模板可以有多个不同的模板 in the template directory,
If you configure the line directly here
#如果模板名留空, the template is not generated
#Controller
template.controller=controller
#Dao
Template.dao=dao
template.dao_xml=dao_xml
#Service
template.service=service
Template.serviceimpl=serviceimpl
#JSP
template.pagelist=pagelist
template.pagemodify=pagemodify
Template.pageview=pageview
#想支持更多的模板, can be modified in the source code
These configurations can be added or modified as appropriate. Generator Class Generator
This kind of code is relatively long, first from the insignificant way to say.
public static void print (String str) {
System.out.println (str);
}
public static Boolean isnotempty (String str) {return
!isempty (str);
}
public static Boolean IsEmpty (String str) {return
str = NULL | | str.length () = 0;
}
private static string Mkdirs (String filePath) {
file folder = new File (filePath);
if (!folder.exists () | |!folder.isdirectory ()) {
folder.mkdirs ();
}
return filePath;
}
The above methods are very simple, do not elaborate, the following methods will use the above methods.
private static String GetText (Properties Properties, String field) {
string text = Properties.getproperty ("entity.") + field);
if (Isnotempty (text)) {return
text;
}
return null;
}
This method is to read the configuration from the above configuration of the field meaning, if it exists, use. Here is the simple GetProperty ("entity." + field).
public static list<fd> Readfromentityfile (String FilePath, properties properties) throws Exception
{list<string> lines = new arraylist<string> ();
BufferedReader reader = Freemarkerutil.newreader (FilePath);
String line = Reader.readline ();
while (line!= null) {Lines.add (Line.trim ());
Line.reader.readLine ();
} reader.close ();
list<td> fieldlist = new arraylist<fd> ();
Print ("\n============================================");
Print ("\ n Extract property fields from Java file:");
for (int i = 0; i < lines.size (); i++) {line = Lines.get (i); if (Line.startwith ("private") && Line.endwith (";"))
{string[] ls = l.split ("");
if (ls.length!= 3) {continue;
String name = ls[2].substring (0, Ls[2].length ()-1);
String type = ls[1];
String Text = GetText (properties, name); if (text = = NULL && I-3 > 0) {int num = 2;
if (Lines.get (i-1). Trim (). Startwith ("@")) {num = 3;
String C = lines.get (I-num);
if (C.startswith ("*")) {text = c.substring (C.indexof ("") + 1). Trim ();
}///If there is a special date type, you can increase the judgment Fieldlist.add (name, text, Type.startswith ("date"));
} print ("\ n extract complete");
Print ("============================================");
return fieldlist; }
The above method is a more critical way to simply read the entity. java file and extract the fields and annotation information from the simple logic, which takes precedence over the field meaning obtained by the previous method.
public static void Main (string[] args) {print (\ n Current path: + New File (""). GetAbsolutePath ());
String propertiespath = null;
if (args.length!= 1) {Propertiespath = "template.properties";
Print (\ n uses the default template profile: + Propertiespath);
Print ("\n============================================"); Print ("\ n You can specify the location of the configuration file when you run the command \ n \ nyou Use methods such as:" + "\n\njava-java gen.jar sys_role" + "\ n" Note: SYS_ROLE.PR Operties can not write the \ ". properties\" suffix, "+" but the file must have this suffix.
");
Print ("\n============================================");
else {propertiespath = args[0];
if (!propertiespath.tolowercase (). EndsWith (". Properties")) {Propertiespath + = ". Properties";
Print (\ n Template config file is: + Propertiespath);
File File = new file (Propertiespath);
if (!file.exists () | | |!file.isfile ()) {print (Propertiespath + "file does not exist");
Return } else {print (\ n Profile address: + File.getabsolutepath ());
Properties Properties = new properties ();
try {properties.load (Freemarkerutil.newreader (File.getabsolutepath ()));
Print ("\ n read config file succeeded");
Generator (properties);
catch (Exception e) {e.printstacktrace ();
Print ("Error:" + e.getmessage ()); }
}
The
Above is the main method, which is intended primarily to get the template configuration file, which can be specified by parameters, and after obtaining the configuration file, call the Generator (properties) method to generate the template, and we'll look at this method.
public static void Generator (properties properties) throws Exception {String basepath = Properties.getproperty ("gen.b
Asepath ");
String className = Properties.getproperty ("Gen.classname"); String entityname = Properties.getproperty ("gen".
EntityName ");
String author = properties.getproperty ("Gen.author");
String java = properties.getproperty ("Gen.java");
List<fd> FieldList = Readfromentityfile (Java, properties);
Date Createtime = new Date ();
String Entity = classname.substring (Classname.lastindexof (".") + 1);
String entity = introspector.decapitalize (entity);
String folder = classname.substring (0, Classname.lastindexof ("."));
folder = folder.substring (0, Folder.lastindexof ("."));
String BASEPCK = Folder.replaceall ("\.", "/");
if (!basepck.startwith ("/")) {BASEPCK = "/" + BASEPCK;
} if (!basepck.endswith ("/")) {BASEPCK = = "/";
} folder = Folder.substring (Folder.lastindexof (".") + 1); String MApping = folder + Entity;
Parameter map<string, object> params = new hashmap<string, object> ();
Params.put ("folder", folder);
Params.put ("Entity", Entity);
Params.put ("entity", entity);
Params.put ("EntityName", entityname);
Params.put ("Mapping", mapping);
Params.put ("author", author);
Params.put ("Createtime", createtime);
Params.put ("Fields" fieldlist);
The path if (!basepath.endswith ("/")) {BasePath = = "/";
} basepath = BasePath + Entity + "/";
BasePath = Basepath.replaceall ("\\\\", "/");
String Javapath = mkdirs (BasePath + "Src/main/java" + BASEPCK);
String Daopath = mkdirs (Javapath + "dao/");
String Controllerpath = mkdirs (Javapath + "controller/");
String ServicePath = mkdirs (Javapath + "service/");
String Serviceimplpath = mkdirs (ServicePath + "impl/");
String Daoxmlpath = mkdirs (BasePath + "src/main/resources" + BASEPCK + "dao/"); String Webpath = mkdirs (BasePath + "src/main/webapp/web-inf/views/"+ folder +"/");
Print ("\ n start generating templates \ n \ nthe base path for generating files: \ n \ basepath);"
Generate template based on configuration String controller = properties.getproperty ("Template.controller"); if (Isnotempty (Controller)) {freemarkerutil.processtemplate (Controller, params, Controllerpath + Entity + "Controll")
Er.java ");
Print ("\ n Generate controller.java:\n" + Controllerpath + Entity + "Container.java"); }//Other templates ...//...}
This is mainly based on the configuration file to extract some of the information used in the template. A different directory is created later, based on the project structure of MAVEN.
Generator The whole logic of this code is still very simple, there are Java based should be able to read, there are questions can leave a message. Templates Sample an interface template for generic mapper
DAO.FTL:
Package Com.github.abel533.blog.${folder}.dao;
Import com.github.abel533.blog.${folder}.model.${entity};
Import Com.github.abel533.common.Isea533Mapper;
/**
* ${entity} Mapper
* *
@author ${author}
* @since ${createtime?string (' Yyyy-mm-dd HH:mm:ss ')}
* * Public
Interface ${entity}mapper extends isea533mapper<${entity}> {
//todo Please confirm that the package has been configured to the MyBatis scan path
//custom method can be written below
}
If you use a template to generate, you won't have to tangle with how to generate Xxxdao or xxxmapper interfaces.
DAO_XML.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= "Com.github.abel533.blog.${folder}.dao.${entity}dao" >
</mapper>
JSP page
As the JSP to meet the characteristics and requirements of its own projects, here is an example of the field loop:
<div class= "Table-index" > <table width= "96.4%" border= "0" cellspacing= "0" cellpadding= "0" > <thead> & Lt;tr style= "background: #e2e2e2; line-height:25px;" > < #list fields as field> <th>${field.text}</th> </#list > <t h> operations </th> </tr> </thead> <tbody> <c:foreach items= "${r ' ${page.list} '}" var= "entity" > <tr> < #list fields as Field> < #if field.date> <td><fmt:formatdate Valu
E= "${" $ "}{entity.${field.name}}" pattern= "Yyyy-mm-dd HH:mm:ss"/></td> < #else > <td>${"$"}{entity.${field.name}}</td> <#/if> </#list > <td> <a HRE F= "${" $ "}{ctx}/${mapping}/view?id=${" $ "}{entity.id}" > Details </a> <a href= "${" $ "}{ctx}/${mapping}/edit?i d=${"$"}{entity.id} "> Modify ${entityname}</a> <a href=" ${"$"}{ctx}/${mapping}/delete?id=${"$"}{entity.id} "> Delete ${entityname}</a> </td> </tr> </c:foreach> </tbody> & Lt;/table> </div>
Run
For convenience, I create a base template, and every time I want to generate an object, I copy the file and then modify the template.
Assuming that the above code is finally packaged as a Gen.jar file, and the configuration file is sysrole.properties, then only need to execute in cmd:
Java-jar Gen.jar Sysrole
Note: the. Properties suffix can be omitted, but the configuration file must be this suffix last
If you've used code generators a few times, believe you're going to love this way, if you have a lot of work to generate automatically with the generator, then be sure to write a generator, do not think that write the generator will waste time, which will give you a lot of time to save, perhaps to get rid of the fate of overtime.
For a new project, if you provide a code generator, the entire project will have a more consistent style and can be critical to project efficiency.
If you are not accustomed to this way, find time to try it, write a program that can write code.
This blog is just a minimalist example of code generators, the function may not be comprehensive, but has been able to achieve a lot of code generation, if you want to write from the database table information to start generating entity code and various template code examples, you can refer to the following project:
Http://git.oschina.net/free/DBMetadata
This project supports access to a variety of database annotations and other basic information, and can be better applied to mybatis related code generation.