利用回調簡化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")就可以了。