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. }