可怜的DAO层已经被各位大侠蹂躏得体肤完肤了,从范型DAO一直被蹂躏到现在只剩下一个可怜巴巴的接口,无不体现Java人追求敏捷开发的热情。其实,DAO层本来的作用就应该自从Hibernate一类优秀的ORM框架诞生之日起就应该消失灭迹了的。既然如此,那么我们就毁灭得更彻底一点。
下面是我对Service与DAO层整合的一些构想
约定优先于配置
一、Rapae代理接口标签定义
query属性:查询语句或者命名查询名称
- 不止由一个单词组成时:简单查询语句
- 由单个单词组成时:为命名查询,名称规则为[query的值]
- 为默认值""时:为命名查询,名称规则为[类名.方法名]
count属性:用于统计个数的查询语句或者命名查询名称,固定返回为一个Long型的数据
- 不止由一个单词组成时:简单查询语句
- 由单个单词组成时:为民命查询,名称规则为[count的值]
- 为默认值""时:自动生成count(*)语句
- query为语句查询时:count自动生成为语句查询,规则为:select count(*) + query从第一个from开始到语句结束
- query为命名查询时:count自动生成为命名查询,规则为:[query命名查询名称_count]
PS:当接口的方法没有Rapae注释的时候,按query与count均属于默认值情况处理
二、Pagination翻页注释
注释定义:
- FirstResult注释:方法级上的Annotation,它标记了分页查询时所要知道的第一条记录所在的位置。期待的类型为int
- MaxSize注释:方法级上的Annotation,它标记了分页查询时所要知道的每页最大查询记录数。期待的类型为int
- Total注释:方法级上的Annotation,它标记了分页查询后返回的总数统计。期待的类型为long
- Result注释:方法级上的Annotation,它标记了分页查询后返回的结果。期待的类型为java.util.Collection<E>
详细说明:
- 分页查询时:第一个参数必须是能同时提供有FirstResult和MaxSize注释方法的类,并且方法期待的返回类型都必须匹配,否则将会抛出异常。Rapae通过调用被标注的方法来进行分页查询。
- 分页查询返回时:返回的类必须同时提供有Result和Total注释的方法,参数个数为1,并且期待的类型都必须匹配,否则将会抛出异常。与此同时,若返回的类同时还能提供FirstResult、MaxSize注释的方法,方法的参数个数为1且为期待类型,那么Rapae在分页查询完成后将查询用到的 FirstResult、MaxSize值原封不动的通过标注的方法设回给返回类。
三、CRUD基本查询注释
注释定义:
- Create注释:格式 T [方法名] (T t);
- Read注释:格式 T [方法名] (java.io.Serializable pk);
- Update注释:格式 T [方法名] (T t);
- Delete注释:格式 T [方法名] (java.io.Serializable pk);
一旦被标注上了CRUD标签,则必须严格遵循标签所规定的格式,否则抛出异常。
四、查询行为方式与方法的返回类型、参数类型、参数个数以及方法名称之间的约定
查询行为方式:
-
- 执行查询
- 查询多条记录(不翻页)
- 返回值是java.util.Collection<E>的实现
- 查询多条记录(翻页)
- 返回类必须同时提供标注有Result与Total的方法,并且参数个数为1,参数类型为标签所期待的类型
- 返回类可以选择性的提供标注有FirstResult和MaxSize的方法,并且参数个数为1,参数类型为标签所期待的类型
- 传入的第一个参数必须同时提供标注有FirstResult与MaxSize的方法,参数个数为0,返回类型为标签所期待的类型
- 查询单条记录
查询条件传递:
- 若是翻页查询,则参数个数至少为一个,且第一个参数必须为提供标标注有FirstResult与MaxSize的方法。
- 若查询条件是通过可变参或者Collection集合类进行传递的,则按顺序对查询条件进行设置
- 若查询条件是通过参数列表直接传递进来的,则按参数列表定义的顺序对查询条件进行设置
- 若查询条件是通过Map传递进来的,则可通过Map对参数的参数进行设置
首先我们先来看效果:
假设我们有这样一个Entity类
Java代码
- 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.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;
}
}
那么,我们在实际的开发过程中,只用写一个接口就能实现大部分的业务逻辑功能。
Java代码
- 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);
-
-
- }
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中这样配置
Xml代码
- <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>
<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了。
如果很不幸,你要求的业务逻辑比较复杂(这种情况比比皆是,业务逻辑本来就是为了处理比较繁琐的事情而存在,DAO封装了数据访问后,就可以在业务层安心的进行数据无关的业务操作)
那么,我们就可以用一个抽象类去实现接口中某些复杂业务的方法。其他的简单的业务逻辑的方法则仍可由Rapae去代理实现。
Java代码
- 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));
- }
-
- }
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配置也得做出相应的修改
Xml代码
- <bean id="accountService"
- class="com.javaforge.rapae.factory.GenericRapaeFactoryBean">
- <property name="target"
- value="test.com.rapae.service.AccountServiceImpl" />
- <property name="rapaeProxyHandler" ref="rapaeProxyHandler" />
- </bean>
<bean id="accountService"
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使用。
下面给出我对我的构想的一个基于JPA的参考实现,当然只要你实现了相应的接口就可以写出基于Hibernate或者基于其他ORM框架的实现。比较抱歉的是,我个人不打算将其做成XX框架(本来想做成Java On Rails的,看来....-_-!!),也没这个能力和时间。所以觉得,这个能作为一个弱化DAO层的方案提出,让大家在平时中能进行参考是最好的选择。
该参考实现只涉及到具体实现代码,不自带编译时需要的包。若想编译,请按列表中的包自行准备。
- antlr-2.7.6.jar
- asm-3.1.jar
- cglib-2.2.jar
- commons-collections.jar
- commons-logging.jar
- dom4j-1.6.1.jar
- ejb3-persistence.jar
- hibernate3.jar (版本3.2)
- hibernate-annotations.jar
- hibernate-commons-annotations.jar
- hibernate-entitymanager.jar (版本3.3.2.GA)
- javassist.jar
- jta.jar
- junit-4.4.jar
- log4j-1.2.15.jar
- ojdbc14.jar (这个是ORACLE的JDBC驱动,如果你用其他的数据库例如MySQL,请自行替换成对应的JDBC驱动)
- spring.jar (版本2.5.4)
若想跑起测试用例,请自行配置 persistence.xml
|
分享到:
相关推荐
【方法】采用触杀、胃毒和点滴等方法测定了羽裂蟹甲草中9种化学成分对家蝇Muzca domestica、致倦库蚊Culex pipiens quinquefasciatus、菜粉蝶 Pieris rapae、亚洲玉米螟Ostriniafurnacalis、红火蚁Solenopsis ...
采用“F olin -酚”法,就β-谷甾醇(β-sitosterol)、瑞香亭(daphnoritin)以及狼毒色原酮(chamechromone)3种化合物对菜粉蝶( Pieris rapae L.)5龄幼虫血淋巴中蛋白质含量进行了测定。结果表明 :24 h后,这 3种化合物...
应用地统计学方法分析了西洋菜地黄曲条跳甲Phyllotreta striolata成虫、菜粉蝶Pieris rapae及小菜蛾Plutella xylostella幼虫的空间格局,建立了多个描述东西方向上间隔距离与半方差值之间关系的曲线模型....
田间收集蚜虫宽缘金小蜂Pachyneuron aphidis (Bouche),采用室内饲养的方法,研究了不同龄期菜蚜茧蜂Diaeretiella rapae MIntosh对蚜虫宽缘金小蜂发育的影响。蚜虫宽缘金小蜂寄生菜蚜茧蜂的蛹,是体外寄生蜂,其对...
本研究由张忠、方琦等人完成,对蝶蛹金小蜂(Pteromalus puparum)对不同发育状态的菜粉蝶(Pieris rapae)的选择行为进行了深入的探讨。研究利用Y型嗅觉仪,观察了不同经验状态的蝶蛹金小蜂雌蜂对菜粉蝶各个发育...
为确定苍耳Xanthium sibiricum对昆虫活性最高的部位,测试了苍耳不同器官(果实、叶、茎和根)甲醇提取物对几种重要十字花科蔬菜害虫(包括小菜蛾Plutella xylostella,菜青虫Pieris rapae,桃蚜Myzus persicae和...
记录了浙江西天目山分布的粉蝶属 Pieris Schrank 3种蝴蝶,分别是东方菜粉蝶 Pieris canidia,菜粉蝶 Pieris rapae和黑纹粉蝶 Pieris erutae 。通过对幼虫、蛹、成虫外部形态和成虫雄性外生殖器特征的研究,得出了 3种...
研究了不同猎物虫态、不同猎物密度、不同捕食者密度、不同温度下青翅蚁形隐翅虫(Paederus fuscipesCurtis)对菜粉蝶(Pieris rapae Linnaeus)卵捕食作用的影响。结果表明:1)青翅蚁形隐翅虫对菜粉蝶卵的捕食能力...
实验研究了联苯菊酯对靶标生物菜青虫Pieris rapae L. 和以HepG2细胞为模型的非靶标生物毒性的对映体选择性差异,结果表明对靶标生物菜青虫1R-cis-BF比1S-cis-BF的毒性强300倍以上;而对以HepG2细胞为模型的非靶标...
生物活性测定结果表明:人工合成的11个多炔类化合物对菜粉蝶Pieris,rapae成虫产卵具有忌避活性,化合物2(6,6-二甲基-2,4-庚二炔-1-醇)、化合物5[1-苯基-4-(3,4-亚甲基二氧)-苯基-1,3-丁二炔]、化合物6(1-...
生测结果表明,拟青霉 ( Paecilomyces sp.9 610)孢子悬液对菜青虫( Pieris rapae)致死中浓度为5 .902 4×1 06个/mL。田间药效试验结果表明,用1 .6×107个/mL和1 .6×1 05个/mL拟青霉9610孢子悬液对菜青虫药后7 d的防...
蔬菜作为人们日常饮食不可或缺的一部分,在农业生产中占据着举足轻重的地位。随着现代农业技术的发展,蔬菜种植业不仅成为了许多地区的支柱产业,同时也面临着来自各类害虫的威胁。据统计,蔬菜生产中害虫造成的损失...