利用回调简化JDBC编程
简单看了一下spring 的jdbc支持,现在又要直接用到jdbc,想想就是痛苦。于是参考了spring,自己写了一些简单的java封装类来简化编程。
废话少说,我这里就用代码来代言吧,看看怎样简化我们的JDBC编程,可以和以前进行对比。
(1) JdbcTemplate。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;import javax.sql.DataSource;import org.winter.util.DBUtil;/**
* a simple JDBC template 模仿spring的JdbcTemplate
*
* @author bluestone
* @version 1.0 2006-8-8
*
*/
public class JdbcTemplate { private DataSource dataSource = null; public JdbcTemplate(DataSource ds) {
this.dataSource = ds;
}/**
* 执行更新操作
*
* @param sql
* @param setter
* @return
* @throws SQLException
*/
public int update(String sql, PreparedStatementSetter setter)
throws SQLException {
Connection conn = null;
reparedStatement ps = null;
try {
conn = dataSource.getConnection();
ps = conn.prepareStatement(sql);
setter.setValues(ps);
return ps.executeUpdate();
} finally {
DBUtil.colseConnection(conn, ps, null);
}
} /**
*
* @param sql
* @return
* @throws SQLException
*/
public boolean execute(String sql) throws SQLException {
Connection conn = null;
Statement stmt = null;
try {
conn = dataSource.getConnection();
stmt = conn.createStatement();
return stmt.execute(sql);
} finally {
DBUtil.colseConnection(conn, stmt, null);
}
} /**
*
* @param sql
* @param setter
* @param extractor
* @return
* @throws SQLException
*/
public Object query(String sql, PreparedStatementSetter setter,
ResultSetExtractor extractor) throws SQLException {
Connection conn = null;
reparedStatement ps = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
ps = conn.prepareStatement(sql);
setter.setValues(ps);
rs = ps.executeQuery();
return extractor.extractData(rs);
} finally {
DBUtil.colseConnection(conn, ps, rs);
}
} // .........................
}(2) PreparedStatementSetterpublic interface PreparedStatementSetter {
void setValues(PreparedStatement ps) throws SQLException;
}(3)
ResultSetExtractorpublic interface ResultSetExtractor {
Object extractData(ResultSet rs) throws SQLException;
}(4) 可以参考spring自己定义其他接口。。。
用了这些辅助类,我们就可以像用spring那样编程了(当然这只能用在对事务要求不高的应用环境中)。看看怎么使用:
private JdbcTemplate template; public JobManageDao() throws BusinessException {
try {
template = new JdbcTemplate(DBHelper.getDataSource());
} catch (NamingException e) {
throw new BusinessException(e);
}
}public long saveJobInfo(final JobInfo info) throws BusinessException {
final long id = IdGenerator.getIdLong();
try {
int j = template.update(INSERT_JOB_SQL, new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException {
int i = 1;
ps.setLong(i++, id); //...... }
});
return j > 0 ? id : 0L;
} catch (SQLException e) {
throw new BusinessException(e);
}
}
web开发经常遇到这样的情形:写代码的模式基本相同,特别是在写jdbc代码时,会经常要先写sql,然后调用PreparedStatement的setXXX方法,而读取数据时要调用ResultSet的getXXX方法。如果表中的字段很多,那可够你受的了;等你耐心把这些写完,可能在某个地方却出错了。
如果没有用ORM工具,这些又不能省了不写。于是我考虑用代码来生成这些sql 和 setXXX及getXXX方法。
生成代码有许多方法,比如可以用脚本语言(个人喜欢用perl),也可以用模板技术。发现java里面已经有很多模板技术可以直接使用了,比如velocity、freemaker等。我一开始是直接用perl来生成代码的,方法比较原始,就是字符串拼凑在一起。 后来发现有许多的模板技术可以利用。现在打算用velocity来生成代码。说不定可以直接生成DAO、Biz、Bean、XML等一大堆东西,呵呵。等有空要好好研究一下。
在jsp页面,一个表单如果字段很多的话,要写很多request.getParameter(name)之类的代码,如果用web framework的话,则可以免去写这些代码的麻烦。但如果不用framework是否也可以达到参数自动填充的功能呢? 答案是肯定的。
下面是我在就业网重构时用到的一个java类,其中就是对BeanUtils进行了简单的封装。
import java.sql.Date;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.SqlDateConverter;
public class NullSafeBeanUtils {
public final static String EMPTY_STRING = "";
public static boolean isNull(Object obj) {
return obj == null;
}
public static String getProperty(Object bean, String property) {
if (bean == null) {
return EMPTY_STRING;
}
try {
String str = BeanUtils.getProperty(bean, property);
if (str == null) {
return EMPTY_STRING;
}
return str;
} catch (Exception e) {
return EMPTY_STRING;
}
}
public static void populate(Object bean, Map props) {
if (bean == null) {
return;
}
try {
SqlDateConverter con = new SqlDateConverter(new Date(System.currentTimeMillis()));
ConvertUtils.register(con, java.sql.Date.class);
BeanUtils.populate(bean, props);
} catch (Exception e) {
e.printStackTrace();
}
}
// 此处省略了一些其他代码
}
在这里,poplulate方法就是我用来自动填充参数的。要实现自动填充,只需简单调用此方法就行了。看一个例子:
JobExperience jobExp = new JobExperience();
NullSafeBeanUtils.populate(jobExp, request.getParameterMap());
是不是简单了许多?要注意的是表单的各输入字段名要和bean的各属性名对应才能自动填充。另外NullSafeBeanUtils 的getProperty方法也很有用,可以避免写
if (bean != null) {
yyy = bean.getXXX()==null?"":bean.getXXX()
}
这样的代码,直接写NullSafeBeanUtils.getProperty(bean, "XXX")就可以了。