freemarker入门 - 关于java代码生成器 .
分类: JAVA编程 2014-02-11 16:44 1299人阅读 评论(0) 收藏 举报
http://blog.csdn.net/zxycode007/article/details/6211538
讲代码生成器之前先要说说模板,什么叫模板呢,举个例子吧,汇款单都见过吧,你不填写的那些内容都属于模板范畴
说到这应该明白了吧,模板就是把共性提取出来反复使用,节约时间、工作量。。。。。
那跟代码生成器有什么关系呢,思考一下在编程语言中所有的语言是不是都用共性或者说规范,这些都是固定不变的,在具体点,软件行业也是分主营业务 的,比如OA、CRM、ERP、SCM等等,那么各个业务方向的软件是不是也有其行业特点,这是不是也是固定的,那么这就完了,这些独特的地方是不是可以 提取出来作为模板呢,不言而喻
言归正传,说到模板就不得不说现在主流的模板技术了,FreeMarker、Velocity(这个google在用),模板技术推崇一种模式:
输出=模板+数据,所以运用到代码生成器上也是一样的道理,举个简单例子比如要生成一个javabean组件,就普通的pojo类,
那么先分析一下生成这种类有什么共性呢,关键字就不用说了,getter和setter方法都是get+属性名uppercase首字母和set+ 属性名uppercase首字母,还有“{}”、“;”、“()”等等这些都是不变的,那么这些内容就可以作为模板内容,包名、类名、属性名这些是人为要 取的,这些是变化的,故变的这部分就作为数据,这样就可以根据不同的‘数据’来生成不同的javabean
项目准备:先去down个freemarker.jar包, http://freemarker.org/freemarkerdownload.html
上篇讨论了代码生成器的原理,输出=模板+数据,那么现在就生成一个Student.java文件做个简单例子。
首先先写出模板,先解决一个问题,上篇有讲到属性名首字母大写的问题
由于freemarker中不支持将首字母大写(属性名中用到),那么自己先写一个自定义宏如下:
源码 打印 ?
01. package com;
02.
03. import java.io.IOException;
04. import java.io.Writer;
05. import java.util.Map;
06.
07. import freemarker.core.Environment;
08. import freemarker.template.TemplateDirectiveBody;
09. import freemarker.template.TemplateDirectiveModel;
10. import freemarker.template.TemplateException;
11. import freemarker.template.TemplateModel;
12. import freemarker.template.TemplateModelException;
13.
14. public class UpperFirstCharacter implements TemplateDirectiveModel {
15.
16. public void execute(Environment env,
17. Map params, TemplateModel[] loopVars,
18. TemplateDirectiveBody body)
19. throws TemplateException, IOException {
20. // Check if no parameters were given:
21. if (!params.isEmpty()) {
22. throw new TemplateModelException(
23. "This directive doesn't allow parameters." );
24. }
25. if (loopVars.length != 0 ) {
26. throw new TemplateModelException(
27. "This directive doesn't allow loop variables." );
28. }
29.
30. // If there is non-empty nested content:
31. if (body != null ) {
32. // Executes the nested body. Same as <#nested> in FTL, except
33. // that we use our own writer instead of the current output writer.
34. body.render(new UpperCaseFilterWriter(env.getOut()));
35. } else {
36. throw new RuntimeException( "missing body" );
37. }
38. }
39.
40. /**
41. * A {@link Writer} that transforms the character stream to upper case
42. * and forwards it to another {@link Writer}.
43. */
44. private static class UpperCaseFilterWriter extends Writer {
45.
46. private final Writer out;
47.
48. UpperCaseFilterWriter (Writer out) {
49. this .out = out;
50. }
51.
52. public void write( char [] cbuf, int off, int len)
53. throws IOException {
54. // char[] transformedCbuf = new char[len];
55. // for (int i = 0; i < len; i++) {
56. // transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);
57. // }
58. // out.write(transformedCbuf);
59. cbuf[0 ] = Character.toUpperCase(cbuf[ 0 ]);
60. out.write(String.valueOf(cbuf).trim());///把右边空格去掉
61. }
62.
63. public void flush() throws IOException {
64. out.flush();
65. }
66.
67. public void close() throws IOException {
68. out.close();
69. }
70. }
71.
72. }
[Java] view plaincopy
01. package com;
02.
03. import java.io.IOException;
04. import java.io.Writer;
05. import java.util.Map;
06.
07. import freemarker.core.Environment;
08. import freemarker.template.TemplateDirectiveBody;
09. import freemarker.template.TemplateDirectiveModel;
10. import freemarker.template.TemplateException;
11. import freemarker.template.TemplateModel;
12. import freemarker.template.TemplateModelException;
13.
14. public class UpperFirstCharacter implements TemplateDirectiveModel {
15.
16. public void execute(Environment env,
17. Map params, TemplateModel[] loopVars,
18. TemplateDirectiveBody body)
19. throws TemplateException, IOException {
20. // Check if no parameters were given:
21. if (!params.isEmpty()) {
22. throw new TemplateModelException(
23. "This directive doesn't allow parameters.");
24. }
25. if (loopVars.length != 0) {
26. throw new TemplateModelException(
27. "This directive doesn't allow loop variables.");
28. }
29.
30. // If there is non-empty nested content:
31. if (body != null) {
32. // Executes the nested body. Same as <#nested> in FTL, except
33. // that we use our own writer instead of the current output writer.
34. body.render(new UpperCaseFilterWriter(env.getOut()));
35. } else {
36. throw new RuntimeException("missing body");
37. }
38. }
39.
40. /**
41. * A {@link Writer} that transforms the character stream to upper case
42. * and forwards it to another {@link Writer}.
43. */
44. private static class UpperCaseFilterWriter extends Writer {
45.
46. private final Writer out;
47.
48. UpperCaseFilterWriter (Writer out) {
49. this.out = out;
50. }
51.
52. public void write(char[] cbuf, int off, int len)
53. throws IOException {
54. // char[] transformedCbuf = new char[len];
55. // for (int i = 0; i < len; i++) {
56. // transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);
57. // }
58. // out.write(transformedCbuf);
59. cbuf[0] = Character.toUpperCase(cbuf[0]);
60. out.write(String.valueOf(cbuf).trim());///把右边空格去掉
61. }
62.
63. public void flush() throws IOException {
64. out.flush();
65. }
66.
67. public void close() throws IOException {
68. out.close();
69. }
70. }
71.
72. }
下面呢就可以编写模板了,代码如下:
源码 打印 ?
01. package ${ package };
02.
03. //这个地方可以事先定义好需要的类
04. import java.util.Date;
05.
06. import java.io.Serializable;
07.
08. public class ${className} implements Serializable{
09. <#list properties as pro>
10. private ${pro.proType} ${pro.proName};
11. </#list>
12.
13. <#list properties as pro>
14. public void set< @upperFC >${pro.proName}</ @upperFC >(${pro.proType} ${pro.proName}){
15. this .${pro.proName}=${pro.proName};
16. }
17.
18. public ${pro.proType} get< @upperFC >${pro.proName}</ @upperFC >(){
19. return this .${pro.proName};
20. }
21.
22. </#list>
23. }
[Java] view plaincopy
01. package ${package};
02.
03. //这个地方可以事先定义好需要的类
04. import java.util.Date;
05.
06. import java.io.Serializable;
07.
08. public class ${className} implements Serializable{
09. <#list properties as pro>
10. private ${pro.proType} ${pro.proName};
11. </#list>
12.
13. <#list properties as pro>
14. public void set<@upperFC>${pro.proName}</@upperFC>(${pro.proType} ${pro.proName}){
15. this.${pro.proName}=${pro.proName};
16. }
17.
18. public ${pro.proType} get<@upperFC>${pro.proName}</@upperFC>(){
19. return this.${pro.proName};
20. }
21.
22. </#list>
23. }
模板文件取名为javabean.html,在com包下
下面编写测试类:
源码 打印 ?
01. package com;
02.
03. import java.io.File;
04. import java.io.FileOutputStream;
05. import java.io.IOException;
06. import java.io.OutputStreamWriter;
07. import java.util.ArrayList;
08. import java.util.HashMap;
09. import java.util.List;
10. import java.util.Map;
11.
12. import freemarker.template.Configuration;
13. import freemarker.template.Template;
14. import freemarker.template.TemplateException;
15.
16. public class Test {
17.
18. /**
19. * @param args
20. */
21. public static void main(String[] args) {
22. //System.out.println(System.getProperty("user.dir")+"============");
23. Configuration cfg = new Configuration();
24. try {
25. cfg.setClassForTemplateLoading(Test.class , "/com" ); //指定模板所在的classpath目录
26. cfg.setSharedVariable("upperFC" , new UpperFirstCharacter()); //添加一个"宏"共享变量用来将属性名首字母大写
27. Template t = cfg.getTemplate("javabean.html" ); //指定模板
28. FileOutputStream fos = new FileOutputStream( new File( "d:/Student.java")); //java文件的生成目录
29.
30. //模拟数据源
31. Map data = new HashMap();
32. data.put("package" , "edu" ); //包名
33. data.put("className" , "Student" );
34.
35. List pros = new ArrayList();
36. Map pro_1 = new HashMap();
37. pro_1.put("proType" , String. class .getSimpleName());
38. pro_1.put("proName" , "name" );
39. pros.add(pro_1);
40.
41. Map pro_2 = new HashMap();
42. pro_2.put("proType" , String. class .getSimpleName());
43. pro_2.put("proName" , "sex" );
44. pros.add(pro_2);
45.
46. Map pro_3 = new HashMap();
47. pro_3.put("proType" , Integer. class .getSimpleName());
48. pro_3.put("proName" , "age" );
49. pros.add(pro_3);
50.
51. data.put("properties" , pros);
52. t.process(data, new OutputStreamWriter(fos, "utf-8" )); //
53. fos.flush();
54. fos.close();
55. } catch (IOException e) {
56. e.printStackTrace();
57. } catch (TemplateException e) {
58. e.printStackTrace();
59. }
60. }
61.
62. }
[Java] view plaincopy
01. package com;
02.
03. import java.io.File;
04. import java.io.FileOutputStream;
05. import java.io.IOException;
06. import java.io.OutputStreamWriter;
07. import java.util.ArrayList;
08. import java.util.HashMap;
09. import java.util.List;
10. import java.util.Map;
11.
12. import freemarker.template.Configuration;
13. import freemarker.template.Template;
14. import freemarker.template.TemplateException;
15.
16. public class Test {
17.
18. /**
19. * @param args
20. */
21. public static void main(String[] args) {
22. //System.out.println(System.getProperty("user.dir")+"============");
23. Configuration cfg = new Configuration();
24. try {
25. cfg.setClassForTemplateLoading(Test.class, "/com");//指定模板所在的classpath目录
26. cfg.setSharedVariable("upperFC", new UpperFirstCharacter());//添加一个"宏"共享变量用来将属性名首字母大写
27. Template t = cfg.getTemplate("javabean.html");//指定模板
28. FileOutputStream fos = new FileOutputStream(new File("d:/Student.java"));//java文件的生成目录
29.
30. //模拟数据源
31. Map data = new HashMap();
32. data.put("package", "edu");//包名
33. data.put("className", "Student");
34.
35. List pros = new ArrayList();
36. Map pro_1 = new HashMap();
37. pro_1.put("proType", String.class.getSimpleName());
38. pro_1.put("proName", "name");
39. pros.add(pro_1);
40.
41. Map pro_2 = new HashMap();
42. pro_2.put("proType", String.class.getSimpleName());
43. pro_2.put("proName", "sex");
44. pros.add(pro_2);
45.
46. Map pro_3 = new HashMap();
47. pro_3.put("proType", Integer.class.getSimpleName());
48. pro_3.put("proName", "age");
49. pros.add(pro_3);
50.
51. data.put("properties", pros);
52. t.process(data, new OutputStreamWriter(fos,"utf-8"));//
53. fos.flush();
54. fos.close();
55. } catch (IOException e) {
56. e.printStackTrace();
57. } catch (TemplateException e) {
58. e.printStackTrace();
59. }
60. }
61.
62. }