Rapae 弱化DAO的一种方法

vlinux 2008-06-16 08:56:25
可怜的DAO层已经被各位大侠蹂躏得体肤完肤了,从范型DAO一直被蹂躏到现在只剩下一个可怜巴巴的接口,无不体现Java人追求敏捷开发的热情。其实,DAO层本来的作用就应该自从Hibernate一类优秀的ORM框架诞生之日起就应该消失灭迹了的。既然如此,那么我们就毁灭得更彻底一点。



下面是我对Service与DAO层整合的一些构想



约定优先于配置
一、Rapae代理接口标签定义
query属性:查询语句或者命名查询名称

1. 不止由一个单词组成时:简单查询语句
2. 由单个单词组成时:为命名查询,名称规则为[query的值]
3. 为默认值""时:为命名查询,名称规则为[类名.方法名]

count属性:用于统计个数的查询语句或者命名查询名称,固定返回为一个Long型的数据

1. 不止由一个单词组成时:简单查询语句
2. 由单个单词组成时:为民命查询,名称规则为[count的值]
3. 为默认值""时:自动生成count(*)语句
* query为语句查询时:count自动生成为语句查询,规则为:select count(*) + query从第一个from开始到语句结束
* query为命名查询时:count自动生成为命名查询,规则为:[query命名查询名称_count]

PS:当接口的方法没有Rapae注释的时候,按query与count均属于默认值情况处理








二、Pagination翻页注释
注释定义:

1. FirstResult注释:方法级上的Annotation,它标记了分页查询时所要知道的第一条记录所在的位置。期待的类型为int
2. MaxSize注释:方法级上的Annotation,它标记了分页查询时所要知道的每页最大查询记录数。期待的类型为int
3. Total注释:方法级上的Annotation,它标记了分页查询后返回的总数统计。期待的类型为long
4. Result注释:方法级上的Annotation,它标记了分页查询后返回的结果。期待的类型为java.util.Collection<E>

详细说明:

1. 分页查询时:第一个参数必须是能同时提供有FirstResult和MaxSize注释方法的类,并且方法期待的返回类型都必须匹配,否则将会抛出异常。Rapae通过调用被标注的方法来进行分页查询。
2. 分页查询返回时:返回的类必须同时提供有Result和Total注释的方法,参数个数为1,并且期待的类型都必须匹配,否则将会抛出异常。与此同时,若返回的类同时还能提供FirstResult、MaxSize注释的方法,方法的参数个数为1且为期待类型,那么Rapae在分页查询完成后将查询用到的 FirstResult、MaxSize值原封不动的通过标注的方法设回给返回类。






三、CRUD基本查询注释
注释定义:

1. Create注释:格式 T [方法名] (T t);
2. Read注释:格式 T [方法名] (java.io.Serializable pk);
3. Update注释:格式 T [方法名] (T t);
4. Delete注释:格式 T [方法名] (java.io.Serializable pk);

一旦被标注上了CRUD标签,则必须严格遵循标签所规定的格式,否则抛出异常。






四、查询行为方式与方法的返回类型、参数类型、参数个数以及方法名称之间的约定

查询行为方式:

1.
1. 执行查询
* 返回值必须为void
2. 查询多条记录(不翻页)
* 返回值是java.util.Collection<E>的实现
3. 查询多条记录(翻页)
* 返回类必须同时提供标注有Result与Total的方法,并且参数个数为1,参数类型为标签所期待的类型
* 返回类可以选择性的提供标注有FirstResult和MaxSize的方法,并且参数个数为1,参数类型为标签所期待的类型
* 传入的第一个参数必须同时提供标注有FirstResult与MaxSize的方法,参数个数为0,返回类型为标签所期待的类型
4. 查询单条记录
* 返回值必须是一个对象

查询条件传递:

1. 若是翻页查询,则参数个数至少为一个,且第一个参数必须为提供标标注有FirstResult与MaxSize的方法。
2. 若查询条件是通过可变参或者Collection集合类进行传递的,则按顺序对查询条件进行设置
3. 若查询条件是通过参数列表直接传递进来的,则按参数列表定义的顺序对查询条件进行设置
4. 若查询条件是通过Map传递进来的,则可通过Map对参数的参数进行设置
...全文
78 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
vlinux 2008-06-16
  • 打赏
  • 举报
回复
如果很不幸,你要求的业务逻辑比较复杂(这种情况比比皆是,业务逻辑本来就是为了处理比较繁琐的事情而存在,DAO封装了数据访问后,就可以在业务层安心的进行数据无关的业务操作)

那么,我们就可以用一个抽象类去实现接口中某些复杂业务的方法。其他的简单的业务逻辑的方法则仍可由Rapae去代理实现。


import java.util.List;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.transaction.annotation.Transactional;
import test.com.rapae.model.Account;

@Transactional
public abstract class AccountServiceImpl extends JpaDaoSupport implements AccountService {

public Account login(String username, String password) {
List<?> result = getJpaTemplate().find("from Account where username = ? and password = ?", username, password);
return (Account) (result.isEmpty()?null:result.get(0));
}

}


当然,对应的Spring配置也得做出相应的修改
	
<bean id="accountServiceImpl"
class="com.javaforge.rapae.factory.GenericRapaeFactoryBean">
<property name="target"
value="test.com.rapae.service.AccountServiceImpl" />
<property name="rapaeProxyHandler" ref="rapaeProxyHandler" />
</bean>


我们可以看到,target属性由原来的test.com.rapae.service.AccountService改变为test.com.rapae.service.AccountServiceImpl,其他都不用做任何改变。


剩下的事情大家都可以猜到了:按正常由Spring托管的accountService使用。
vlinux 2008-06-16
  • 打赏
  • 举报
回复
首先我们先来看效果:
假设我们有这样一个Entity类

import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;

@Entity
@Table(name = "ACCOUNT")
@SequenceGenerator(name = "ACCOUNT_SEQUENCE", sequenceName = "SEQ_ACCOUNT", initialValue = 1, allocationSize = 1)
public class Account implements Serializable {

private static final long serialVersionUID = 1L;


@Id
@Column(name = "ACCOUNT_ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ACCOUNT_SEQUENCE")
private Long id;

@Column(name = "USERNAME",length=20, unique = true, nullable = false)
private String username;

@Column(name = "PASSWORD",length=20, nullable = false)
private String password;

@Column(name = "REG_TIME", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date registerTime;

Getter/Setter

public int hashCode() {
return (this.id == null) ? 0 : this.id.hashCode();
}

public boolean equals(Object object) {
if (object instanceof Account) {
final Account obj = (Account) object;
return (this.id != null) ? this.id.equals(obj.id)
: (obj.id == null);
}
return false;
}

}


那么,我们在实际的开发过程中,只用写一个接口就能实现大部分的业务逻辑功能。

import java.util.Collection;

import org.springframework.transaction.annotation.Transactional;

import test.com.rapae.model.Account;

import com.javaforge.rapae.annotation.Rapae;
import com.javaforge.rapae.annotation.crud.*;
import com.javaforge.rapae.util.pagination.Page;
import com.javaforge.rapae.util.pagination.Pagination;

@Transactional
public interface AccountService {

/**
* 注册新帐号
*
* @param account
* @return
*/
@Create
Account register(Account account);

/**
* 通过ID获取帐号
*
* @param id
* @return
*/
@Read
Account getById(Long id);

/**
* 帐号修改
*
* @param account
* @return
*/
@Update
Account update(Account account);

/**
* 删除帐号
*
* @param id
* @return
*/
@Delete
Account delete(Long id);

/**
* 通过用户名获取帐号
*
* @param username
* @return
*/
@Rapae(query = "from Account where username = ?")
Account getByUsername(String username);

/**
* 帐号登录
*
* @param username
* @param password
* @return
*/
@Rapae(query = "from Account where username = ? and password = ?")
Account login(String username, String password);

/**
* 不翻页获取所有的帐号
* @return
*/
@Rapae(query="from Account")
Collection<Account> findAll();

/**
* 翻页查询获取所有的帐号
* @param username
* @return
*/
@Rapae(query="from Account")
Pagination<Account> countPageFindAll(Page page);


}


然后...没有然后了,接口上都已经写得非常清楚了,剩下的就交给Rapae去代理实现吧。
在Spring中这样配置

<bean id="rapaeProxyHandler"
class="com.javaforge.rapae.handler.JPARapaeProxyHandler"
scope="prototype">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
</bean>

<bean id="accountService"
class="com.javaforge.rapae.factory.GenericRapaeFactoryBean">
<property name="target"
value="test.com.rapae.service.AccountService" />
<property name="rapaeProxyHandler" ref="rapaeProxyHandler" />
</bean>


JPARapaeProxyHandler类是负责为Rapae实现代理生成JPA调用的执行者
GenericRapaeFactoryBean则是一个实现了Spring的FactoryBean接口的一个工厂类
然后我们就可以像正常的Spring中被托管的Bean一样使用这个accountService了。
vlinux 2008-06-16
  • 打赏
  • 举报
回复
首先我们先来看效果:

假设我们有这样一个Entity类

import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;

@Entity
@Table(name = "ACCOUNT")
@SequenceGenerator(name = "ACCOUNT_SEQUENCE", sequenceName = "SEQ_ACCOUNT", initialValue = 1, allocationSize = 1)
public class Account implements Serializable {

private static final long serialVersionUID = 1L;


@Id
@Column(name = "ACCOUNT_ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ACCOUNT_SEQUENCE")
private Long id;

@Column(name = "USERNAME",length=20, unique = true, nullable = false)
private String username;

@Column(name = "PASSWORD",length=20, nullable = false)
private String password;

@Column(name = "REG_TIME", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date registerTime;

Getter/Setter

public int hashCode() {
return (this.id == null) ? 0 : this.id.hashCode();
}

public boolean equals(Object object) {
if (object instanceof Account) {
final Account obj = (Account) object;
return (this.id != null) ? this.id.equals(obj.id)
: (obj.id == null);
}
return false;
}

}

67,512

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧