论坛首页 Java企业应用论坛

Without SSH/JSP/Servlet,不走寻常路,Java可以更酷

浏览 213637 次
该帖已经被评为精华帖
作者 正文
   发表时间:2009-11-15  

2.9.5 自定义数据库映射

正如在2.9.2节所说的,如果你喜欢用setXXX或getXXX这样的风格来访问属性值,
你可以自己编写一个实现com.douyu.sql.DatabaseMapping接口的类,
或者更简单的,直接继承com.douyu.sql.DefaultDatabaseMapping类,
然后像下面这样覆盖getPropertySetterGetterStyle()方法(默认是STYLE_DEFAULT),
	public int getPropertySetterGetterStyle() {
		return STYLE_SET_GET_PREFIX;
	}

如果你想完全自定义,那么把STYLE_SET_GET_PREFIX改成STYLE_CUSTOM,
并且实现或覆盖下面两个方法:
String columnName2setterName(String tableName, String columnName);
String columnName2getterName(String tableName, String columnName);


Douyu通过com.douyu.sql.DatabaseMapping接口给开发人员打开了一扇门,
使得开发人员可以对Douyu的ORM进行少量的控制,

DatabaseMapping接口除了上面给出的三个方法外,还有如下方法:
String tableName2className(String tableName);
String columnName2propertyName(String tableName, String columnName);
String getSequenceName(String tableName, String columnName);
String getSQLEventListener(String tableName);
String getPropertyListener(String tableName, String columnName);

所有的tableName、columnName参数都是小写的,
如果数据库表中有一个表名所包含的字符是Java语言中不允许的(如表名含#号),
那么你可以通过tableName2className来转换,返回的类名是不含包名的,
通常的做法是写个Map<String,String>,在初始化时把表名和类名放进去。

columnName2propertyName方法也类似,
有些表的列名是不能出现在Java语言中的,如一个叫"default"的列就是非法的,
在初始化时,你也可以用一个两级Map来实现,第一级是表名,第二级是列名。
默认情况下columnName2propertyName方法返回的属性名总是跟列名一样的,
所有的Setter、Getter都是由这个返回的属性名来生成的,
如果把模型类作为控制器Action方法的参数,那么也用这个属性名来自动获取http请求参数值。
总之此方法返回的属性名是相当重要的。

其他三个方法并不常用,通常是返回null就可以了,
如果数据库不支持auto_increment(比如Oracle就不支持),
那么可以为此列单独建个序列,用getSequenceName方法返回此序列名,
Douyu就会自动根据这个序列名来模拟auto_increment,这样就可以自动填充主键值了。

但是为每个列单独建个序列这可能太浪费了,所以这个方法并不常用,
Douyu提供了一个配置参数:defaultSequenceName,默认是"douyu_sequence",
如果getSequenceName方法返回null,对应的表中又存在主键,
并且还把另一个配置参数:autoFillPrimaryKey设为true了,
当你在增加记录时,如果没有提供主键值,Douyu就会根据序列名来自动生成一个主键值。


getSQLEventListener方法用来返回一个com.douyu.sql.SQLEventListener接口的实现类名,
这样你可以监听对应的模型类的一些事件,SQLEventListener接口定义了如下方法:
	void beforeInsert(Context context, Object entity);
	void beforeUpdate(Context context, Object entity);
	void beforeDelete(Context context, Object entity);

	void afterInsert(Context context, Object entity);
	void afterUpdate(Context context, Object entity);
	void afterDelete(Context context, Object entity);

getPropertyListener方法用来返回一个com.douyu.sql.PropertyListener接口的实现类名,
这样你可以监听对应的模型类中某个属性的事件,PropertyListener接口定义了如下方法:
	void init(Context context);
	Object getPropertyValue(Object entity, String propertyName, Object oldPropertyValue);
	Object setPropertyValue(Object entity, String propertyName, Object newPropertyValue);

init方法只在模型类作为控制器Action方法的参数时有用,
此时初始化模型类时会同时初始化PropertyListener,并通过init方法把Context传给PropertyListener,
其他两个方法的作用类似这样(假定name是某个模型类的属性):
public String getName() {
	return (String)propertyListener.getPropertyValue(this,"name",this.name);
}

public void setName(String name) {
	this.name = (String)propertyListener.setPropertyValue(this,"name",name);
}


最后,请修改服务器的配置文件,
在相应的@Database数据库配置项中加上一个参数:
databaseMapping = "pck.MyDatabaseMapping",
当然了,你必须把"pck.MyDatabaseMapping"改成你自己的类名,类名前面要加包名。
0 请登录后投票
   发表时间:2009-11-15  

2.9.6 自动校验

Douyu内置了一个简单的自动校验功能,
如果把模型类作为控制器Action方法的参数,那么就会自动启用自动校验功能,
自动校验目的是为了维护表中数据的完整性和正确性,

只有校验全部通过后,才允许对表进行更新操作,
你可以通过com.douyu.main.Context接口的
public List<ContextMessage> getContextMessageList();

来获得所有的校验失败消息.

com.douyu.main.ContextMessage类的完整代码如下:
package com.douyu.main;

public class ContextMessage {
	//通过组合这四个字段,你可以定义出更具体化的消息
	Class enclosingClass; //一般是对应的模型类
	String propertyName;  //属性名
	String propertyValue; //属性值(一般是从http请求中获得的不合法的参数值)
	String message;       //一条本地化的简短消息(比如不能为空,或必须是数字等等)

	public ContextMessage() {
	}

	public ContextMessage(String propertyName, String propertyValue, String message) {
		this.propertyName = propertyName;
		this.propertyValue = propertyValue;
		this.message = message;
	}

	public ContextMessage(Class enclosingClass, String propertyName,
		String propertyValue, String message) {
		this.enclosingClass = enclosingClass;
		this.propertyName = propertyName;
		this.propertyValue = propertyValue;
		this.message = message;
	}

	public void setEnclosingClass(Class enclosingClass) {
		this.enclosingClass = enclosingClass;
	}

	public void setPropertyName(String propertyName) {
		this.propertyName = propertyName;
	}

	public void setPropertyValue(String propertyValue) {
		this.propertyValue = propertyValue;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Class getEnclosingClass() {
		return enclosingClass;
	}

	public String getPropertyName() {
		return propertyName;
	}

	public String getPropertyValue() {
		return propertyValue;
	}

	public String getMessage() {
		return message;
	}


	public String toString() {
		StringBuilder s = new StringBuilder("ContextMessage[propertyName=");
		s.append(propertyName)
		 .append(", propertyValue=").append(propertyValue)
		 .append(", message=").append(message)
		 .append(", enclosingClass=").append(enclosingClass).append("]");
		return s.toString();
	}
}
0 请登录后投票
   发表时间:2009-11-16  
很好、很强大

很感兴趣的是应用服务器这块,非常好   令人钦佩的老鸟
0 请登录后投票
   发表时间:2009-11-16  
楼主是疯子+技术狂人,不加精说不过去了!!
虽然看的我蒙蒙的,哈哈。国内期待有这样的大牛来开天辟地啊。
0 请登录后投票
   发表时间:2009-11-16  
超佩服你的耐力和执着精神,不过的确看的我晕、、、深奥
0 请登录后投票
   发表时间:2009-11-16  
linliangyi2007 写道
楼主是疯子+技术狂人,不加精说不过去了!!
虽然看的我蒙蒙的,哈哈。国内期待有这样的大牛来开天辟地啊。


深有同感,很狂,很牛。。。。
0 请登录后投票
   发表时间:2009-11-16  
无论Douyu最后的结果如何,楼主的对技术执着令人钦佩
0 请登录后投票
   发表时间:2009-11-16  
真有时间啊。
0 请登录后投票
   发表时间:2009-11-16  
引用
那三个月内时常有沮丧感,似乎已走近了死胡同!
后来心一狠,决心甩开JSP/Servlet那一堆条条框框,把设计的起点再往下深一个层次。

无数牛人都是死在这里的吧!但楼主突破了,杀出了一条血路

真是了不起,真是了不起!
0 请登录后投票
   发表时间:2009-11-16  
这是从服务器入手,直接支持
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics