博客统计信息

用户名:wolfoxer
文章数:8
评论数:6
访问量:40887
无忧币:25
博客积分:806
博客等级:4
注册日期:2006-10-08

背景音乐

我的音乐

00:00 | 00:00

2012-05-16 12:15:27
几篇拙文,阅着数千,激励之下,坚持拙之。
2006-12-07 18:05:51
摘要
        在J2EE 应用中,业务组件通常使用JDBC API
访问和改变关系数据库中的持久化数据。这样经常导致将持久化代码和业务逻辑混合在一起--- a bad idea. Data Access
Object (DAO) 设计模式通过把持久化逻辑分离到数据访问类中从而解决了这个问题。

       本篇文章有关于DAO 设计模式的入门 ,重点放在DAO模式的优缺点。然后介绍了Spring 2.0 JDBC/DAO 框架并展示了它如何优雅的解决传统DAO 设计中的缺点。 

传统DAO设计
     按照J2EE 核心设计模式( Core J2EE Desgin  Pattern) 这本书中的分类,Data Access
Object(DAO) 属于集成层设计模式。DAO在一个分开的层中封装了持久化存储访问和操作的代码。本篇文章中设计到的持久存储指的是RDBMS。

DAO模式是业务逻辑层和持久存储层之间的抽象层,例如图1. 业务对象通过数据访问对象访问RDBMS(data
source)。这个抽象层可以灵活的介入并简化了应用程序代码。理想情况下,当改变数据源,比如更换数据库厂商或者类型,只需要改变数据访问对象并对业
务对象的影响最小。







图1 使用DAO之前和之后的对比

现在我已经说明了基本的DAO设计模式,到了写一些代码的时候了.下面的例子是一个公司的域模型(domain
model).为了简单化,界定公司有若干工作在不同部门的雇员,比如销售,市场和人力资源.因为简化的原因,我将只关注一个单一的实体叫做雇员
“Employee”。



面向接口编程(Program to an Interface(P2I))
       DAO设计模式提供的灵活性主要归因于一个对象设计的最佳实践(best
pratice):面向接口编程。这个规则是指具体对象必须实现一个接口,在调用程序中使用接口而不是具体对象本身。这样做,你可以很容易的代理到一个不
同的实现而对客户端的代码影响最小。

      按照这个规则,我将定义Employee DAO 接口,IEmployeeDAO ,并定义findBySalaryRange()方法。业务组件和DAO的这个方法交互。

import java.util.Map;
public interface IEmployeeDAO {
//被执行的SQL 语句
public String FIND_BY_SAL_RNG = "SELECT EMP_NO, EMP_NAME, "
+ "SALARY FROM EMP WHERE SALARY >= ? AND SALARY <= ?";

//Returns the list of employees who fall into the given salary
//range. The input parameter is the immutable map object
//obtained from the HttpServletRequest. This is an early
//refactoring based on "Introduce Parameter Object"

public List findBySalaryRange(Map salaryMap);
}
DAO实现类

已经定义了DAO类,现在必须提供一个DAO的实现类EmployeeDAOImpl


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import com.bea.dev2dev.to.EmployeeTO;

public class EmployeeDAOImpl implements IEmployeeDAO{

public List findBySalaryRange(Map salaryMap)
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
List empList = new ArrayList();
//Transfer Object for inter-tier data transfer
EmployeeTO tempEmpTO = null;
try{
//DBUtil - helper classes that retrieve connection from pool
conn = DBUtil.getConnection();
pstmt = conn.prepareStatement(FIND_BY_SAL_RNG);
pstmt.setDouble(1, Double.valueOf( (String)
salaryMap.get("MIN_SALARY") );
pstmt.setDouble(2, Double.valueOf( (String)
salaryMap.get("MIN_SALARY") );
rs = pstmt.executeQuery();
int tmpEmpNo = 0;
String tmpEmpName = "";
double tmpSalary = 0.0D;
while (rs.next()){
tmpEmpNo = rs.getInt("EMP_NO");
tmpEmpName = rs.getString("EMP_NAME");
tmpSalary = rs.getDouble("SALARY");
tempEmpTO = new EmployeeTO(tmpEmpNo,
tmpEmpName,
tmpSalary);
empList.add(tempEmpTO);
}//end while
}//end try
catch (SQLException sqle){
throw new DBException(sqle);
}//end catch
finally{
try{
if (rs != null){
rs.close();
}
}
catch (SQLException sqle){
throw new DBException(sqle);
}
try{
if (pstmt != null){
pstmt.close();
}
}
catch (SQLException sqle){
throw new DBException(sqle);
}
try{
if (conn != null){
conn.close();
}
}
catch (SQLException sqle){
throw new DBException(sqle);
}
}//end of finally block
return empList;
}//end method findBySalaryRange
}
上面的代码展示了DAO方法的几个关键点:



封装了所有的同JDBC API的交互.如果有一个O/R mapping解决方案像Kodo或Hibernate被使用,DAO类可以包装这些具体产品的API。
包装了JDBC API 中立的查询对象,返回给业务层做进一步的处理。本质上他们是无状态的。他们单一的目标是供业务对象去访问和改变持久数据。在处理底层的JDBC API 或数据库时,他们捕获发生的任何错误(比如,数据库不可用,错误SQL 语法),并报告为SQLException.DAO对象把这种错误通知给业务对象使用JDBC中立的,定制构建的运行时异常类DBException。他们释放池中的数据库资源像Connection和PreparedStatement对象 ,在ResultSet使用完后,撤销ResultSet游标占有的内存。
因此,DAO层通过抽象底层的数据访问API,从而提供了一直的数据访问方式。
构建DAO Factory


DAO Factory 是典型的Factory
设计模式的实现,为的是让业务对象能创建和使用具体DAO的实现类。业务对象使用DAO接口而不关心其具体实现类。这种可以依赖倒置的原因是DAO
Factory提供了巨大的灵活性。只有DAO接口建立的约定保持不变,可以很容易的去改变DAO的实现(比如,从直接的JDBC
到基于Kodo的O/R Mapping),而不影响客户端的业务对象。
public class DAOFactory {
private static DAOFactory daoFac;

static{
daoFac = new DAOFactory();
}

private DAOFactory(){}

public DAOFactory getInstance(){
return daoFac;
}

public IEmployeeDAO getEmployeeDAO(){
return new EmployeeDAOImpl();
}
}

和业务组件交互

现在应该看看DAO怎么在整个应用中使用的时候了,正如前面部分提到的,业务层组件通过和DAO的交互去提取和改变持久业务数据,下面列举了业务服务组件和DAO的交互:

public class EmployeeBusinessServiceImpl implements
IEmployeeBusinessService {

public List getEmployeesWithinSalaryRange(Map salaryMap){

IEmployeeDAO empDAO = DAOFactory.getInstance()
.getEmployeeDAO();
List empList = empDAO.findBySalaryRange(salaryMap);
return empList;
}
}
这是很清晰的,根本没有任何对持久化接口的依赖。

问题

DAO设计模式也不是没有缺点:

代码重复:耦合:资源泄露:错误处理:脆弱代码:
让我们看看怎么保持DAO设计的优点而克服这些缺点呢?[/img]..
类别:随笔|阅读(2190)|回复(0)|(0)阅读全文>>
2006-11-22 22:36:21
Eclipse birt 是知名的BI 报表工具,官方网站提供了在Tomcat上进行集成的方法,没有提供
JRun的集成方式,因为公司为客户做的项目使用的是JRun,所以就想办法将Birt集成到了JRun里,下面详细说明一下:
1.在JRun里创建Server;
2.将下载的Eclipse birt Runtime下的ViewReportExample例子压缩成birt.war;
3.在创建的Server下添加Web Applications,浏览到birt.war文件,进行部署。
4.这时候你去访问([url]http://www.url.com/birt[/url])时发现首页可以出现,当点击
example链接时,出现404错误;
5.问题的原因在于: JRun默认会先加载Server的class,后加载应用的class,而JRun自带的包没有birt的新,所以需要修改JRun默认的类加载顺序,具体修改办法如下:
在你部署成功birt.war时,你会发现在同一目录会生成一个jrun.web.xml文件;打开jrun.web.xml文件里的<compiler>tag后添加如下tag;<load-system-classes-first>false</load-system-class-first>
可惜啊,birt不支持cross-table,期待中。。。。
类别:随笔|阅读(744)|回复(1)|(0)阅读全文>>
原来已经做好的一个portlet,使用的是jsp实现的,后来需要增加文件下载的功能,以下是我的解决办法:

开发一个portlet继承com.liferay.portlet.JSPPortlet;
覆盖processAction方法,如下:
       public class DownloadFile extends JSPPortlet {
             public void processAction(ActionRequest req,ActionResponse res){
                    File file = new File("your file ");
                    InputStream is = new FileInputStream(file);
                    com.liferay.util.servlet.ServletResponseUtil.sendFile(((ActionResponseImpl)res).getHttpServletResponse(), file.getName(), is); 
    &n..
类别:随笔|阅读(1974)|回复(0)|(0)阅读全文>>
今天看了一下RSS和ATOM技术,于是萌生了开发个人信息门户的想法,因为在web2.0的大环境下,越来越多的site提供各个频道的RSS,包括时
下流行的blog,所以可以使用RSS+AJAX技术提供类似blog那样高度可customer的个人信息门户,让每个人都可以自定义自己的门户,这些
门户中的信息,可以是自己创造的(提供RSS),也可以是其他blog或者forum等的rss结果。

一个初步的想法而已,不知道前景如何。
类别:未分类|阅读(2030)|回复(2)|(0)阅读全文>>
列举本人常用到的一些javascript操作DOM的函数。

 函数 说明 document.getElementById("element-id")用的最多的函数了,使用它可以在DOM中按照ID返回当前的Element  document.createElement("img") 创建元素,javascript会创建一个结构良好的Element。如:<img>element..setAttribute("src","javaedu.gif")此函数有两个用途:如果元素element没有src属性,那么就会增加一个src属性,并设置其值为javaedu.gif;如果元素element有了src属性,那么就用新的值javaedu.gif覆盖原来的值。

 element.parentNode 获得element的父节点。

 element.insertBefore(newNode,oldNode)在oldNode前插入新节点newNode

 element.removeNode(oldNode);移除oldNode节点

 elment.replace(newNode,oldNode)用newNode替换oldNode节点


类别:技术|阅读(3872)|回复(0)|(0)阅读全文>>
    如果是在html中为一个button 关联一个单击事件,需要按照如下格式来写:

<input type='butt value='save'  onClick="someFun()">

如果是在javascript中指定按钮的关联事件,应该使用onclick,都是小写,javascript中引用函数可以直接使用名称来引用,无需括号。案例如下:



<script>

     function test(){

            var button = document.getElementById("button-id");

            button.onclick=test1;

    }

   function test1(){

          alert("test");

   }

</script>



虽然是小小的差别,如果能遵循DOM和Javascript的规范,可以使你的应用跨browser更好一些。


类别:技术|阅读(8462)|回复(0)|(0)阅读全文>>
2006-10-08 23:55:30
找了很久终于让我的blog在51cto安了家,总担心自己博客的内容以后会丢失,曾经尝试自己搭建自己的blog, 安装配置过blojsom,
pebble和roller,但都感觉样式方面不太适合国人的习惯,另外自己一个人的blog,很少有人能知道,还是和和群吧,来51cto凑个热闹。
类别:生活|阅读(1802)|回复(3)|(0)阅读全文>>

我最近发表的评论

开发个人信息门户.. 回复
不做综合类的,按照行业分类来做