2025-05-23

 

首先說說為什麼要用到回調這個方式,

    我們在日常生活和工作中,有一種情況是這樣的,做一件事,但是這件事中有些步驟是不確定如何做的,但是可以先約定好怎麼做.對於程序來說,就是有一段業務,其中有幾段小邏輯不確定如何做,但是我們可以先定義好一些方法(統一的參數和返回值)對應這些邏輯, 具體這些邏輯的實現交給具體執行的代碼去實現.

    下面舉個例子,JDBC 訪問,假設我們都用PreparedStatement來處理SQL, 我們都要初始化連接,初始化PreparedStatement,封裝PreparedStatement插入SQL參數,執行SQL,獲得ResultSet,封裝ResultSet成我們要的對象,關閉連接,其中封裝PreparedStatement插入SQL參數和封裝ResultSet成我們要的對象是不確定的,我們就可以把這2步定義成回調函數,教給具體執行代碼去做.

    根據上面說的,我們可以定一個JdbcCallback接口來定義這個回調函數,

 

Java代碼 

package com.balance.easycalendar.dao.template; 

 

import java.sql.PreparedStatement; 

import java.sql.ResultSet; 

import java.sql.SQLException; 

import java.util.List; 

 

import com.balance.easycalendar.to.BaseTO; 

 

public interface JdbcCallback { 

     

    public List<BaseTO> packResult(ResultSet rs) throws SQLException; 

    public void packParams(PreparedStatement stmt) throws SQLException; 

 

再定義一個JdbcCallbackTemplate來執行具體的方法,其中引用一個JdbcCallback來完成不確定的步驟,

Java代碼 

package com.balance.easycalendar.dao.template; 

 

import java.sql.Connection; 

import java.sql.DriverManager; 

import java.sql.PreparedStatement; 

import java.sql.ResultSet; 

import java.util.List; 

 

import com.balance.easycalendar.dao.exception.DAOException; 

import com.balance.easycalendar.to.BaseTO; 

import com.balance.easycalendar.util.MessageProperties; 

 

public class JdbcCallbackTemplate { 

 

    private JdbcCallback temp; 

     

    public void setTemp(JdbcCallback temp) { 

        this.temp = temp; 

    } 

 

    protected String url; 

    protected String username; 

    protected String password; 

    protected String driver; 

     

    private PreparedStatement stmt = null; 

    private Connection con = null; 

     

    public JdbcCallbackTemplate(){ 

        MessageProperties pro = MessageProperties.getInstance("jdbc.properties"); 

         

        url = pro.getValue("db.url"); 

        driver = pro.getValue("db.driver"); 

        username = pro.getValue("db.username"); 

        password = pro.getValue("db.password");  

    } 

     

    public List<BaseTO> query(String sql) throws DAOException{ 

        try{ 

            Class.forName(driver); 

            con = DriverManager.getConnection(url, username, password); 

     

            stmt = con.prepareStatement(sql); 

            temp.packParams(stmt); 

             

            ResultSet rs = stmt.executeQuery(); 

              

            return temp.packResult(rs); 

             

        }catch(Exception e){ 

            throw new DAOException(e); 

        }finally{ 

            try{ 

                stmt.close(); 

                con.close(); 

            }catch(Exception e){ 

                e.printStackTrace(); 

            } 

        } 

    } 

     

    public boolean excute(String sql) throws DAOException{ 

        try{ 

            Class.forName(driver); 

            con = DriverManager.getConnection(url, username, password); 

     

            stmt = con.prepareStatement(sql); 

            temp.packParams(stmt); 

             

            return stmt.execute(); 

             

        }catch(Exception e){ 

            throw new DAOException(e); 

        }finally{ 

            try{ 

                stmt.close(); 

                con.close(); 

            }catch(Exception e){ 

                e.printStackTrace(); 

            } 

        } 

    } 

     

    這個Template定義瞭2個方法, excute用來執行增加,修改,刪除等,query用來執行查詢,在這2個方法裡,封裝參數,封裝result都不確定,所以用瞭上面定義的回調函數來實行,具體實現交給具體的實現類去做.(MessageProperties 是我寫的一個資源引用類,可以參考我的另一篇blog:利用多例模式編寫配置文件讀取器)

 

   下面我們看看具體的實現,

    BaseDAO裡實例化一個jdbcCallbackTemplate

Java代碼 

package com.balance.easycalendar.dao; 

 

import com.balance.easycalendar.dao.template.JdbcCallbackTemplate; 

import com.balance.easycalendar.util.MessageProperties; 

 

 

public abstract class BaseDAO { 

     

         

    protected JdbcCallbackTemplate jdbcCallbackTemplate = new JdbcCallbackTemplate(); 

     

    public String getSql(String sqlId){ 

        MessageProperties pro = MessageProperties.getInstance("sqls.properties");    

        return pro.getValue(sqlId); 

    } 

 

定義一個TaskDAO,用來執行具體的數據庫訪問.首先給jdbcCallbackTemplate註入實例化的JdbcCallback(實現具體的回調函數),然後就可以調用Template裡的query和excute方法瞭.

Java代碼 

package com.balance.easycalendar.dao; 

 

import java.sql.PreparedStatement; 

import java.sql.ResultSet; 

import java.sql.SQLException; 

import java.util.ArrayList; 

import java.util.List; 

 

import com.balance.easycalendar.dao.exception.DAOException; 

import com.balance.easycalendar.dao.template.JdbcCallback; 

import com.balance.easycalendar.dao.template.JdbcCallbackAdapter; 

import com.balance.easycalendar.to.BaseTO; 

import com.balance.easycalendar.to.TaskTO; 

 

public class TaskDAO extends BaseDAO{ 

 

    public TaskTO getTask(final String taskId) throws DAOException { 

        jdbcCallbackTemplate.setTemp(new JdbcCallback(){ 

            @Override 

            public void packParams(PreparedStatement stmt) throws SQLException { 

                stmt.setString(1, taskId);       

            } 

 

            @Override 

            public List<BaseTO> packResult(ResultSet rs) throws SQLException { 

                List<BaseTO> tasks = new ArrayList<BaseTO>();        

                while (rs.next()) { 

                    TaskTO taskTO = new TaskTO(); 

                    taskTO.setTaskId(rs.getString("TASK_ID")); 

                    taskTO.setTaskName(rs.getString("TASK_NAME")); 

                    taskTO.setTaskDesc(rs.getString("TASK_DESC")); 

                     

                    tasks.add(taskTO); 

                } 

                 

                return tasks; 

            } 

        }); 

     

        List<BaseTO> tasks = jdbcCallbackTemplate.query(getSql("task.search.bytaskid")); 

        return (TaskTO)tasks.get(0); 

    } 

     

    public boolean insertTask(final String taskId, final String taskName, final String taskDesc) throws DAOException { 

        jdbcCallbackTemplate.setTemp(new JdbcCallbackAdapter(){ 

 

            @Override 

            public void packParams(PreparedStatement stmt) throws SQLException { 

                stmt.setString(1, taskId); 

                stmt.setString(2, taskName); 

                stmt.setString(3, taskDesc); 

            }            

        }); 

         

        return jdbcCallbackTemplate.excute(getSql("task.insert")); 

    } 

     

    public boolean delTask(final String taskId) throws DAOException { 

        jdbcCallbackTemplate.setTemp(new JdbcCallbackAdapter(){ 

 

            @Override 

            public void packParams(PreparedStatement stmt) throws SQLException { 

                stmt.setString(1, taskId); 

            }            

        }); 

         

        return jdbcCallbackTemplate.excute(getSql("task.delete.bytaskid")); 

    } 

 

 

sql我也用MessageProperties來讀取瞭,定義在一個單獨的properties文件裡,

Sql代碼 

task.search.bytaskid = select TASK_ID,TASK_NAME,TASK_DESC from TB_TASKS where TASK_ID = ? 

task.insert = insert into TB_TASKS (TASK_ID,TASK_NAME,TASK_DESC) values (?,?,?) 

task.delete.bytaskid = Delete from TB_TASKS where TASK_ID = ?   

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *