在appfuse手册中的开发步骤是先建立数据库表,然后通过自动化的工具产生pojo以及其他的对象。但是对于复杂的pojo,用数据库表现出来就显得力不从心。因此,适当的方法应当是先去写pojo,然后自动产生其他的代码。这里是我总结的开发步骤。
1。首先编写pojo,继承BaseObject,通过自动化工具产生set/get方法,以及hashCode(), toString(), equals()方法。我用了网上的一段开源代码放到我的工程里面,在eclipse里面直接调用:
- package org.appfuse.tools;
- import java.lang.reflect.Field;
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * A utility class that generates source code for good
- *
boolean equals()
,int hashCode()
, and - *
String toString()
implementations. - *
- *
- * The algorithms used here are based largely on those presented in
- * "Effective Java" by
- * Josh Bloch, with some variations based on conversations with colleagues.
- *
- *
- * @author Erick G. Reid
- */
- public class SourcecodeGenerator {
- /**
- * Returns a
String
representing usable - *
boolean equals(Object)
sourcecode for the given - *
Class
. - *
- * @param source the
Class
to inspect. - * @return a
String
representing usable - *
boolean equals(Object)
sourcecode for the given - *
Class
. - */
- public static String getEqualsSourceCode(Class source) {
- Field[] fields = _getEligibleFields(source);
- StringBuffer sb = new StringBuffer();
- String className = _getClassName(source);
- sb.append("/**\n");
- sb.append(" * Compares this object to the specified object. The result is\n");
- sb.append(" *
true
if and only if the argument is notnull
\n"); - sb.append(" * and is an instance of
"
which represents a\n" + className + "); - sb.append(" * value equivalent to this
"
.\n" + className + "); - sb.append(" *\n");
- sb.append(" * @param object the object to compare with.\n");
- sb.append(" * @return
true
if the objects are the same,\n)"); - sb.append(" * returns
false
otherwise.\n"); - sb.append(" */\n");
- sb.append("public boolean equals(Object object) {\n");
- sb.append(" if (object != this) {\n");
- if (fields.length == 0) {
- sb.append(
- " return object != null && getClass().equals(object.getClass());\n");
- }
- else {
- sb.append(" if (object != null && getClass().equals(object.getClass())) {\n");
- sb.append(" final " + className + " other = (" + className + ") object;\n");
- for (int i = 0; i < fields.length; i++) {
- if (i == 0) sb.append(" return ");
- else sb.append(" ");
- if (fields[i].getType().isPrimitive()) {
- sb.append("(" + fields[i].getName() + " == other." + fields[i].getName() + ")");
- }
- else {
- sb.append("(" + fields[i].getName() + " == null ? other." +
- fields[i].getName() + " == null : " + fields[i].getName() +
- ".equals(other." + fields[i].getName() + "))");
- }
- if (i == fields.length - 1) sb.append(";\n");
- else sb.append(" &&\n");
- }
- sb.append(" }\n");
- sb.append(" return false;\n");
- }
- sb.append(" }\n");
- sb.append(" return true;\n");
- sb.append("}\n");
- return sb.toString();
- }
- /**
- * Returns a
String
representing usablehashCode()
- * sourcecode for the given
Class
. - *
- * @param source the
Class
to inspect. - * @return a
String
representing usablehashCode()
- * sourcecode for the given
Class
. - */
- public static String getHashCodeSourceCode(Class source) {
- Field[] fields = _getEligibleFields(source);
- String className = _getClassName(source);
- StringBuffer sb = new StringBuffer();
- sb.append("/**\n");
- sb.append(" * Returns a hash code value for this
"
.\n" + - className + ");
- sb.append(" *\n");
- sb.append(" * @return a hash code value for this
"
.\n" + - className + ");
- sb.append(" */\n");
- sb.append("public int hashCode() {\n");
- sb.append(" int hashCode = " + source.getName().hashCode() +
- "; // result of getClass().getName().hashCode() \n");
- for (int i = 0; i < fields.length; i++) {
- if (fields[i].getType().isArray()) {
- sb.append(" for (int i = 0; i < " +
- fields[i].getName() + ".length; i++) {\n");
- _appendFieldHashCalculation(
- sb, fields[i].getType().getComponentType(),
- fields[i].getName() + "[i]", " ");
- sb.append(" }\n");
- continue;
- }
- _appendFieldHashCalculation(
- sb, fields[i].getType(), fields[i].getName(), " ");
- }
- sb.append(" return hashCode;\n");
- sb.append("}\n");
- return sb.toString();
- }
- /**
- * Returns a
String
representing usable - *
String toString()
sourcecode for the givenClass
. - *
- * @param source the
Class
to inspect. - * @return a
String
representing usable - *
String toString()
sourcecode for the given - *
Class
. - */
- public static String getToStringSourceCode(Class source) {
- Field[] fields = _getEligibleFields(source);
- StringBuffer sb = new StringBuffer();
- String className = _getClassName(source);
- sb.append("/**\n");
- sb.append(" * Returns a
String
representation of this"
.\n" + - className + ");
- sb.append(" *\n");
- sb.append(" * @return a
String
representation of this"
.\n" + - className + ");
- sb.append(" */\n");
- sb.append("public String toString() {\n");
- if (fields.length == 0) {
- sb.append(" return \"" + className + "()\";\n");
- }
- else {
- sb.append(" StringBuffer buffer = new StringBuffer(\"" +
- className + "(\");\n");
- for (int i = 0; i < fields.length; i++) {
- sb.append(" buffer.append(\"" + fields[i].getName() + "=\" + " +
- fields[i].getName());
- if (i == fields.length - 1) sb.append(" + \")\");\n");
- else sb.append(" + \",\");\n");
- }
- sb.append(" return buffer.toString();\n");
- }
- sb.append("}\n");
- return sb.toString();
- }
- //--------------------------------------------------
- // implementation:
- //--------------------------------------------------
- private static void _appendFieldHashCalculation(
- StringBuffer sb, Class type, String fieldName, String indent) {
- if (type.isPrimitive()) {
- if (Boolean.TYPE.equals(type)) {
- sb.append(indent +
- "hashCode = 37 * hashCode + (" + fieldName + " ? 0 : 1);\n");
- }
- else if (Byte.TYPE.equals(type) || Character.TYPE.equals(type) ||
- Short.TYPE.equals(type) || Integer.TYPE.equals(type)) {
- sb.append(indent + "hashCode = 37 * hashCode + " +
- (Integer.TYPE.equals(type) ? "" : "(int) ") + fieldName + ";\n");
- }
- else if (Long.TYPE.equals(type)) {
- sb.append(indent + "hashCode = 37 * hashCode + (int)(" + fieldName +
- " ^ (" + fieldName + " >>> 32));\n");
- }
- else if (Float.TYPE.equals(type)) {
- sb.append(indent + "hashCode = 37 * hashCode + Float.floatToIntBits(" +
- fieldName + ");\n");
- }
- else if (Double.TYPE.equals(type)) {
- sb.append(indent + "long longBits = Double.doubleToLongBits(" +
- fieldName + ");\n");
- sb.append(indent +
- "hashCode = 37 * hashCode + (int)(longBits ^ (longBits >>> 32));\n");
- }
- return;
- }
- sb.append(indent + "hashCode = 37 * hashCode + (" +
- fieldName + " == null ? 0 : " + fieldName + ".hashCode());\n");
- }
- /**
- * Returns all instance fields from the given class that are found to be
- * non-public.
- */
- private static Field[] _getEligibleFields(Class source) {
- Field[] fields = source.getDeclaredFields();
- List<field></field> eligibleFields = new ArrayList<field></field>();
- for (int i = 0; i < fields.length; i++) {
- int modifiers = fields[i].getModifiers();
- if (!Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
- eligibleFields.add(fields[i]);
- }
- }
- return (Field[]) eligibleFields.toArray(new Field[eligibleFields.size()]);
- }
- private static String _getClassName(Class source) {
- String className = source.getName();
- return className.substring(className.lastIndexOf(".") + 1);
- }
- public static void main(String[] args) {
- Class source=null;
- //reslove object
- try {
- source=Class.forName(args[0]);
- } catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return;
- }
- System.out.println(SourcecodeGenerator.getEqualsSourceCode(source));
- System.out.println(SourcecodeGenerator.getHashCodeSourceCode(source));
- System.out.println(SourcecodeGenerator.getToStringSourceCode(source));
- }
- }
产生pojo以后,加上xdoclet的tag,主要包含@hibernate以及◎spring.validator两方面的tag。通过tag的增加,规定了如何产生数据库的表。
2。运行ant hibernatedoclet自动产生hbm文件,在build/dao/gen/目录下。
3。通过如下的脚本工具可以根据指定的hbm文件创建数据库,当然也可以使用hibernate的schemaexport工具。
- import java.io.FileInputStream;
- import java.io.InputStream;
- import java.util.Properties;
- import org.appfuse.util.XmlTools;
- import org.hibernate.cfg.Configuration;
- import org.hibernate.tool.hbm2ddl.SchemaExport;
- import org.w3c.dom.Document;
- /**
- *
- * @author Cheney Yuan
- *
- */
- public class HibernateSchemaExport {
- /**
- * @param args
- */
- public static void main(String[] args) {
- if (args.length < 1) {
- System.err.println("Usage: HibernateSchemaExport [full file path]hibernate.cfg.xml/database.properties "
- + "[resource path]mapping.hbm.xml\n");
- System.exit(-1);
- }
- Configuration config=new Configuration();
- Properties properties=new Properties();
- String fullPathName=args[0];
- try {
- if (fullPathName.indexOf(".xml")>0) {
- System.out.println("use xml file to configure.");
- Document doc = null;
- doc = XmlTools.getDocumentFromXmlFile(fullPathName);
- config.configure(doc);
- }else if (fullPathName.indexOf(".properties")>0) {
- System.out.println("use properties to configure.");
- Properties props = new Properties();
- props.putAll( config.getProperties() );
- props.load( new FileInputStream( fullPathName ) );
- config.setProperties( props );
- }
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
- //add hbm resources
- for (int i=1;i
- config.addResource(args[i]);
- }
- /**
- * @param script print the DDL to the console
- * @param export export the script to the database
- */
- new SchemaExport(config).create(true, false);
- }
- }
4。到extras/appgen下面运行ant install-detailed产生其他的类和测试程序。
5。applicationContext-hibernate.xml里面的hbm文件必须自己添加,该文件的位置在src/dao/org/appfuse/dao/hibernate/目录下。
6。运行ant deploy即可完成整个开发步骤。