??xml version="1.0" encoding="utf-8" standalone="yes"?>
1. 基本l成Q?/span>
a) q行入口CodeEngineRunner?/span>mainQ)Q里面注册所有的GeneratorQ主要有Q?/span>IbatisGeneratorQ?/span>ControllerGeneratorQ?/span>JSPGenerator三个QQ意一个可以单独运行多ơ;
b) 代码l构Q?/span>*Generator,用于生成domainQ?/span>manager?/span>sqlmapQ?/span>controller{文Ӟ在生成之后ؓ了保持系l的完整性,通常会调用一?/span>ModifierM攚w|文Ӟ׃每个Generator会单独再ơ访问配|文Ӟ所以可以单独和重复生成Q?/span>
c) 主要的配|文件有2个,位于code_engine目录下,分别为:code-engine-config.xmlQ?/span>code-engine-gears.xmlQ但在实际用中Q我们经常要配置的是code-engine-gears.xmlQ前者一般在目开始的时候设定,后者用来生成和修改domainQ?/span>manager?/span>sqlmap, controllerQ?/span>jsp和相关的一些配|文Ӟ
d) 模板文g位于template文g夹下面;可以Ld和调用;语法?/span>freemarkerQ但是,通常只需参照其他模板文gQ一般都可以写出新模板;
e) 每次q行codeengine都会?/span>backup目录下面生成备䆾文gQ以备再ơ生成和修改Q?/span>
f) 生成日志?/span>logs目录下;
g) Framework目录是框架目录,可重用部分,在生成新目时候拷贝用Q?/span>
h) Reference目录是一些开发组Ӟ主要是写jslgQ?/span>
2. code-engine-config.xml 配置?/span>Q?/span>
<?xml version="1.0" encoding="UTF-8"?>
<codeEngineConfiguration>
<context>
<distDir path="D:"wiczone"trunk"wiczone" java="src" web="war"/>
<!--<distDir path="D:"test"trunk"project" java="src" web="war"/>-->
<!--<distDir path="build" java="src" web="war"/>-->
<templateDir path="template"/>
<i18nSupport>true</i18nSupport>
<database classPath="lib"mysql-connector-java-3.1.7-bin.jar">
<driverClass>org.gjt.mm.mysql.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/wiczone</url>
<username>root</username>
<password>root</password>
</database>
<package base="biz.wic" app="application">
<!--<package base="biz.web" app="framework">-->
<domain>domain</domain>
<controller>web</controller>
<manager>manager</manager>
<service>service</service>
</package>
<web layoutComponent="tiles">
<manager>WEB-INF"applicationContext-manager.xml</manager>
<lucene>WEB-INF"applicationContext-lucene.xml</lucene>
<servlet>WEB-INF"action-servlet.xml</servlet>
<security>WEB-INF"applicationContext-acegi.xml</security>
<sqlMapConfig>WEB-INF"sql-map-config.xml</sqlMapConfig>
<messages>WEB-INF"classes"messages.properties</messages>
<tiles>WEB-INF"defs</tiles>
<jdbc>WEB-INF"jdbc.properties</jdbc>
</web>
</context>
<!--
IMPORTANT NOTES:
1.in most cases, we no necessary to modify the <context/> part, since we have already set done;
2.each of controller/jsp can be re-created alternatively.
3.please becareful that metadata's character case.
4.the basis rule is:
if not existed we will created;
if already existed we may overwrited;
-->
</codeEngineConfiguration>
1Q?nbsp;如上所C,< database > 用于配置数据库的q接Q注意要保证driver能访问到Q?/span>
2Q?nbsp;<Package>负责生成各种代码使用Q?/span>
3Q?nbsp;<web>用于指定一些配|文Ӟ
4Q?nbsp;以上文g通常在项目开始的时候设定;
<context>详解
aQ?/span><distDir path="build" java="src" web="war"/>
<!--<distDir path="D:"dist_project" java="src" web="war"/>-->
<templateDir path="template"/>
<i18nSupport>true</i18nSupport>
distDir@path指目标项目的路径Q?#8216;build’是相对\径; @java?/span>java source code的根目录Q?/span>
@web?/span>web application的根目录Q?/span>
templateDir@path?/span>freemarker template所在的目录Q这里设定的?/span>$Code_Engin$"template; 此目录下攄用于生成controller?/span>jsp的模板文Ӟ?/span>ftl为文件后~Q;
template /lib/下面攄的一?/span>common.ftl为通用?/span>functionsQ已l用auto imports引入Q要调用common.ftl?/span>functionQ通常cMQ?/span><@ce.dosth param=paramObj />, ce?/span>namespaceQ用于限定引用;具体代码见(BaseGenerator.javaQ?/span>
5Q?nbsp;i18nSupport是指?/span>jsp是否支持多语aQ一般设定ؓ支持的;
<package base="biz.wic" app="application">
<domain>domain</domain>
<controller>web</controller>
<manager>manager</manager>
<service>service</service>
</package>
用于讑֮java code?/span>packageQ?/span>
<web layoutComponent="tiles">
<manager>WEB-INF"applicationContext-manager.xml</manager>
<servlet>WEB-INF"jbcc-servlet.xml</servlet>
<security>WEB-INF"applicationContext-acegi.xml</security>
<sqlMapConfig>WEB-INF"sql-map-config.xml</sqlMapConfig>
<messages>WEB-INF"classes"messages.properties</messages>
<tiles>WEB-INF"defs</tiles>
6Q?nbsp; </web>
3.code-engine-gears.xml配置详解Q?/span>
<?xml version="1.0" encoding="UTF-8"?>
<gears>
<!--
Generate model, related sqlmap manager file via abator, in most case we don't need modify the abator-config.xml;
just add the following model node will work;
and this model node can create more than one; model name should be unique;
default extends is : biz.web.framework.domain.BaseEntity
-->
<model name="city_model" table="city" domain="City" usingLucene="false"
extends="biz.web.framework.domain.BaseEntity" keyProperty="id"/>
<!--
Create *Controller and *MgrController, modify layout component like Tiles of Sitemesh;
modify action-servlet.xml, applicationContext-*.xml
defaultMethods@keyProperty default to "id"
-->
<controller name="City" springBeanDef="true" template="controller.ftl">
<managers>CityMgr</managers>
<!--<services support="MailService"></services>-->
<defaultMethods refModel="city_model">
<method name="index" style="form" view="list_city"/>
<method name="listAll" style="ajax" />
<method name="list" style="ajax" />
<method name="get" style="ajax"/>
</defaultMethods>
</controller>
<!-- using the option [extends] to generated Mgr controller,
overwrite default to true;
method view default to
-->
<controller name="CityMgr" springBeanDef="true" template="controller_mgr.ftl"
extends="City" overwrite="true">
<!--<services support="CompassService"></services>-->
<defaultMethods refModel="city_model">
<method name="manager" style="form" view="list_mgr_city"/>
<method name="update" style="form" view="edit_city"/>
<method name="create" style="form" view="edit_city"/>
<method name="save" style="form" view="edit_city"/>
<method name="edit" style="form" view="edit_city"/>
<method name="delete" style="ajax"/>
</defaultMethods>
</controller>
<!-- overwrite default to true;
jsp name attribute used for jsp file name, and also used for tiles definition
-->
<jsp name="list_mgr_city" refController="CityMgr" template="list_mgr_jsp.ftl" overwrite="false">
<tiles>main_layout_4</tiles>
</jsp>
<jsp name="edit_city" refController="CityMgr" template="edit_jsp.ftl" overwrite="false">
<!--<tinyMCE>content</tinyMCE>-->
<!--<tiles>main_layout_4</tiles>-->
</jsp>
<!--<jsp name="detail_recommend" refController="City" template="detail_jsp.ftl" overwrite="false">-->
<!--<tinyMCE>content</tinyMCE>-->
<!--<tiles>main_layout_1</tiles>-->
<!--</jsp>-->
<!--overwrite default to true;-->
<!--<jsp name="list_city" refController="City" template="list_jsp.ftl" overwrite="false">-->
<!--<tiles>main_layout_2</tiles>-->
<!--</jsp>-->
</gears>
1Q?/span><model> <controller><jsp> {节点用于生?/span>domainQ?/span>managerQ?/span>controller?/span>jspQ可配置0-n个;ơ序随意; 且每个节炚w有可选属?/span> overwrite Q?/span>true?/span>falseQ;
overwrite指定当目?/span>controller文g存在Ӟ是否要覆写该文gQ否则就生成.generated为后~的文Ӟoverwrite属性是可选的Q默认ؓtrueQ?/span>
2Q?/span><controller name="CityMgr" springBeanDef="true" template="controller_mgr.ftl"
extends="City" overwrite="true">
<managers>CityMgr</managers>
<!--<services support="CompassService"></services>-->
<defaultMethods refModel="city_model">
<method name="manager" style="form" view="list_mgr_city"/>
<method name="update" style="form" view="edit_city"/>
<method name="create" style="form" view="edit_city"/>
<method name="save" style="form" view="edit_city"/>
<method name="edit" style="form" view="edit_city"/>
<method name="delete" style="ajax"/>
</defaultMethods>
</controller>
q个配置看上L些复杂,是ؓ了提供更好的灉|性;name用于?/span>code engine中标?/span>controllerQ同时用于生成的controller.java的命名;在配|文件中应该是唯一的;
springBeanDef用于指出是否在相关的配置文g中添?/span>spring bean的定义,比如xxx-servlet.xml{;否则只是生成controller?/span>javaQ?/span>
template指定freemarker模板Q?/span>
managers指定要注?/span>manager定义Q如果有多个用逗号分割Q可选;
services指定要注?/span>service定义Q如果有多个用逗号分割Q?/span>@support用于指定framework下的common serviceQ比?/span>mailQ?/span>compass{;可选;
defaultMethods里面用于指定生成?/span>controller里面的方法;refModel 指参照的model定义Q?/span> method@name用于指定Ҏ名,比如listQ而且listҎ是预定义写在模板里面?/span>; method@style指定代码风格Q可选有formQ?/span>ajax两种Q这个风g同时影响cotroller部分?/span>jsp部分Q?/span>
method@view指方法返回的tiles定义视图Q当然这个属性在style?/span>form的时候有效;可选;
eQ?/span> <jsp name="edit_user" refController="UserMgr" template="edit_jsp.ftl" >
<tinyMCE>Description</tinyMCE>
<tiles>main_layout_1</tiles>
</jsp>
Jsp?/span>name用于生成?/span>jsp面的文件名Q同时还?/span>tiles的定义,在生?/span>controller时候也是有用的Q?/span>
refController是指明jsp所参照?/span>controller定义Q通过q个refControllerQ?/span>jsp可以扑ֈdefault_methods?/span>styleQ?/span>refModel{信息;
Template指明所使用?/span>freemarker模板Q?/span>
q里省略?/span>overwrite属性,overwrite属性是可选的Q默认ؓtrueQ?/span>
tinyMCE指定要加?/span>tinyMCE支持Q同Ӟ所理的属性ؓ‘Description’Q?/span> 可选属性;
tiles属性定义了Q此jsp所extend?/span>layoutQ可选属性;
f)
<model name="city_model" table="city" domain="City" usingLucene="false"
extends="biz.web.framework.domain.BaseEntity" keyProperty="id"/>
用于生成domainQ?/span>managerQ和sqlmapQ可以配|多个;
luceneSupport可选,如ؓtrue代表在domain?/span>manager以及配置文g中加?/span>lucene的支持;
4.创徏新项?/span>
A.?/span>codeEngineRunner开始执?/span>createNewProjectQ?#8220;distProject”Q;Q将copy必需的框架文件到目标目录Q同时修?/span>jdbc.properties{文Ӟ同时初始化abator-config.xmlQ)
BQ分别用CJDBCPropertiesModifier?/span>CodeEngineInitModifierQ?/span>
CQ执行目标工E?/span>project目录下的initdb.bat;初始化数据库Q加载初始系l表和数据;当然执行此步骤之前要先创建数据库Q?/span>
DQ利?/span>codeEngineRunner的从数据库表Q生成相应的文g后,使用project目录?/span>build.bat~译文gQ?/span>
1. 首先应该ddomain对象Q从而获?/span>field列表Q?/span>
/**
* getDomainFields via jsp name, and should remove the super fields, like lastUpdatedBy, lastUpdatedDate
* @param name of jsp
* @return list of field
*/
public static List<Field> getDomainFields(String name) {
List<Field> ret = new ArrayList<Field>();
try {
Class clz = Class.forName(CodeEngineConfig.getDomainPackage() + "." +
CodeEngineConfig.getControllerDomain(CodeEngineConfig.getJspRef(name)));
for (Field field : clz.getDeclaredFields()) {
if(!"lastUpdateDate".equalsIgnoreCase(field.getName())
&& !"lastUpdateBy".equalsIgnoreCase(field.getName())){
ret.add(field);
// System.out.println("field.getName() + field.getType() = " + (field.getName() + field.getType()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
2. ?/span>Field List传递给freemarker模板Q之所以要传?/span>field而不仅仅?/span>name的原因是Q因为希望在模板里根?/span>field?/span>typeQ从而生成不同的htmlQ比?/span>date可以生成使用js calendar的,boolean生成radioQ或checkboxQ其他的生成textQ?/span>
a) 定义macroQ?/span>
<#macro getHtml field>
<#if field.type?ends_with('Boolean')>
<input type="radio" id="${field.name}" name="${field.name}" class="inp_txt_30" size="80" value="${'$'}{${domain?uncap_first + '.' + field.name}}">
<#elseif field.type?ends_with('Date')>
<input type="text" id="${field.name}" name="${field.name}" readonly="readonly" class="inp_txt_30" size="17" value="<fmt:formatDate value="${'$'}{${domain?uncap_first + '.' + field.name}}" pattern="yyyy-MM-dd hh:mm"/>">
<button id="${field.name}Btn" class="button" >...</button>
<script type="text/javascript">
Calendar.setup(
{
inputField : "${field.name}", // id of the input field
ifFormat : "%Y-%m-%d %H:%M", // the date format
showsTime: true,
button : "${field.name}Btn" // id of the button
}
);
</script>
<#elseif field.type?ends_with('Text')>
<textarea id="${field.name}" name="${field.name}" rows="15" cols="80" style="width: 100%">${'$'}{${domain?uncap_first + '.' + field.name}}</textarea>
<#else>
<input type="text" id="${field.name}" name="${field.name}" class="inp_txt_30" size="80" value="${'$'}{${domain?uncap_first + '.' + field.name}}">
</#if>
</#macro>
bQ调?/span>macro生成htmlQ?/span>
<#list fields! as field>
<tr>
<td class="txt_tit_s" ><spring:message code="${lbl + '.' + domain?uncap_first + '.' + field.name}"/></td>
<td><@getHtml field=field/></td>
</tr>
</#list>
利用xpathQ?/span>freemarker{技术,使得用户通过xml配置文gQ模板等单的方式Q快速开发代码和Ҏ需求调整模板;
Dom4j对实Cxpath 1.0Q?/span> 非常的好用;
所需jar Q?/span>dom4j-1.6.1.jarQ?/span> jaxen-1.1-beta-7.jar
CodeQ?/span>
import junit.framework.TestCase;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import java.util.List;
import java.util.Iterator;
import java.io.File;
/**
* Created by IntelliJ IDEA.
* User: duanbin
* Date: 2007-8-15
* Time: 9:47:17
* To change this template use File | Settings | File Templates.
*/
public class XPathTest extends TestCase {
public void testXPathViaDom4jXpathV1() {
printSelectedNodeValue("D:""xpath""src""test.xml");
}
/**
* 利用XPath操作XML文gQ打印指定节Ҏ者属性的?/span>, using xpath 1.0
*
* @param filename String 待操作的XML文gQ相对\径或者绝对\径)
*/
public void printSelectedNodeValue(String filename) {
try {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File(filename));
List list;
list = document.selectNodes("http://qn1:college/@leader[.!='leader1']");
for (Object aList : list) {
Attribute attribute = (Attribute) aList;
System.out.println("http://qn1:college/@leader: " + attribute.getValue());
}
//打印所?/span>student节点的属?/span>age|如果有的?/span>
// list = document.selectNodes("/students/student/@age");
// for (Object aList : list) {
// Attribute attribute = (Attribute) aList;
// System.out.println("/students/student/@ageQ?/span>" + attribute.getValue());
// }
//打印所?/span>college节点|如果有的?/span>
// list = document.selectNodes("/students/student");
// for (Object aList1 : list) {
// Element bookElement = (Element) aList1;
// Iterator iterator = bookElement.elementIterator("college");
// while (iterator.hasNext()) {
// Element titleElement = (Element) iterator.next();
// System.out.println("/students/student/collegeQ?/span>" + titleElement.getText());
// }
// }
//试节点的一些方?/span>
// list = document.selectNodes("http://city");
// for (Object aList2 : list) {
// Element titleElement = (Element) aList2;
// System.out.print("http://telephoneQ?/span>getName:" + titleElement.getName());
// System.out.print(" ##getNodeType:" + titleElement.getNodeType());
// System.out.print(" ##getTextTrim:" + titleElement.getTextTrim());
// System.out.print(" ##getNamespaceURI:" + titleElement.getNamespaceURI());
// System.out.print(" ##getNodeTypeName:" + titleElement.getNodeTypeName());
// System.out.print(" ##getQualifiedName:" + titleElement.getQualifiedName());
// System.out.print(" ##getUniquePath:" + titleElement.getUniquePath());
// System.out.println(" ##getPath:" + titleElement.getPath());
// }
//打印所?/span>name节点|如果有的话,与上?/span>college的取法不一?/span>
// list = document.selectNodes("/students/student/name");
// Iterator iter = list.iterator();
// for (Object aList3 : list) {
// Element titleElement = (Element) aList3;
// System.out.println("/students/student/nameQ?/span>" + titleElement.getText());
// }
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<students xmlns:qn1="http://qn1.com">
<student age="259911911911"><!--如果没有age属性,默认的ؓ20-->
<qn1:name>崔卫?/span></qn1:name>
<college>PC学院</college>
<telephone>62354666</telephone>
<notes>?/span>,1982q生,士Q现p于北京邮电大?/span></notes>
<addr><city>Beijing</city></addr>
</student>
<student>
<name>cwb</name>
<qn1:college leader="学院领导">PC学院</qn1:college><!--如果没有leader属性,默认的ؓleader-->
<telephone>62358888</telephone>
<notes>?/span>,1987q生,士Q现p于中国农业大?/span></notes>
</student>
<student>
<name>xxxxx</name>
<college leader="">xxx学院</college>
<telephone>66666666</telephone>
<notes>注视中,注释?/span></notes>
</student>
<student age="9911911911">
<name>yyyyyy</name>
<qn1:college leader="leader1">yyyy学院</qn1:college>
<telephone>88888888</telephone>
<notes>注视?/span>111Q注释中222</notes>
</student>
</students>
Freemarker基本CZQ?/span>
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import java.io.File;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.util.Map;
import java.util.HashMap;
import org.apache.log4j.Logger;
/**
* Created by IntelliJ IDEA.
* User: duanbin
* Date: 2007-8-21
* Time: 22:30:13
* To change this template use File | Settings | File Templates.
*/
public abstract class BaseGenerator {
protected Configuration cfg;
protected final Logger logger = Logger.getLogger(this.getClass());
public BaseGenerator() {
try {
cfg = getConfiguration(CodeEngineConfig.getTemplateDir());
} catch (Exception e) {
e.printStackTrace();
}
}
public abstract void generate();
protected void generateFile(String template, Map root, String fileName){
try {
File dist = new File(fileName);
FileOutputStream fos = new FileOutputStream(dist);
Writer out = new OutputStreamWriter(fos);
// Writer out2 = new OutputStreamWriter(System.out);
cfg.getTemplate(template).process(root, out);
out.flush();
out.close();
logger.info("Generated File: " + fileName);
} catch (Exception e) {
e.printStackTrace();
}
}
protected Configuration getConfiguration(String tempDir) throws Exception {
Configuration cfg = new Configuration();
// Specify the data source where the template files come from.
// Here I set a file directory for it:
cfg.setDirectoryForTemplateLoading(
new File(tempDir));
// Specify how templates will see the data model. This is an advanced topic...
// but just use this:
cfg.setObjectWrapper(new DefaultObjectWrapper());
return cfg;
}
}
模板文gCZQ?/span>
package ${package}.application.web;
import biz.web.framework.web.BaseController;
<#list managers! as mgr>
import ${package}.application.manager.${mgr};
</#list>
<#list services! as svc>
import ${package}.application.service.${svc};
</#list>
/**
* Created by IntelliJ IDEA.
* User: ${author!'admin'} "${r"${build.dir}"} "${'$'}{cfg.startDate}
* Date: Sep 1, 2006
* Time: 9:19:17 AM
* To change this template use File | Settings | File Templates.
*/
public class ${name}Controller extends BaseController {
<#list managers! as mgr>
protected ${mgr} ${mgr?uncap_first};
</#list>
<#list services! as svc>
protected ${svc} ${svc?uncap_first};
</#list>
<#list managers! as mgr>
public void set${mgr}(${mgr} ${mgr?uncap_first}) {
this.${mgr?uncap_first} = ${mgr?uncap_first};
}
</#list>
<#list services! as svc>
public void set${svc}(${svc} ${svc?uncap_first}) {
this.${svc?uncap_first} = ${svc?uncap_first};
}
</#list>
public ModelAndView list${name}(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("update_${name?uncap_first}");
Long user = getUserId();
mav.addObject("userId", user);
return mav;
}
}
Selenium
是一个由ThoughtWorks做的专门为web应用所做的非常有效的功能测试工兗Selenium
?tests
直接在浏览器里跑Q就像用L的在操作一栗Selenium
可运?Windows, Linux, ?Macintosh
的各U浏览器Q??
Internet Explorer, Mozilla ?Firefox?
.......
讉K链接Q?
http://forum.springside.org.cn/viewthread.php?tid=195&extra=page%3D1