自定義框架之JDBC的簡要封裝

一、簡要介紹一下自己封裝一個jdbc的思路

  • 封裝是什麼,爲什麼要封裝

    封裝:是面向對象的一種表現形式,主要是面對可相信的對象提供方便,讓這類對象具有使用的權利,對其它對象進行攔截,在沒有相應權限的情況下是沒有使用權利的。
    對於一些工具類就是這樣的情況,把具體實現的過程封裝到類中,只提供你使用的最終接口,只要能實現你的業務就可以,其他的具體操作你沒有辦法拿到

    封裝就是爲了將一團分佈的東西集中在一起,所以纔會有了面向對象的思想,因爲將一個具體的事物抽象的放在了一個類中,該類中保存了這個事物的具體屬性和行爲,
    屬性就是一個事物的特點,比如:一個人的姓名、身高、體重、性別、年齡等
    行爲就是一個事物的動作,比如:一個人有吃飯,睡覺,學習的動作

    因此,被封裝的對象就更加具體化,誰需要訪問一個對象的任何成員,就只需要找到該對象就可以了,但是這個對象也有一些成員不想讓你看到,比如說每個人都有隱私或者密碼,或者不想公開的信息,這些信息,一般人是不知道的,這就是封裝。

    還有比如說你的qq好友的訪問權限一樣,你可以把陌生人設置爲沒有空間的訪問權限,一般的好友含有空間訪問的權限,但不能看照片,不能評論,好朋友就可以看照片,可以評論,但是你有一些隱私的照片或者留言,你不想讓任何人看到,或者你給留言者看到,那麼就會被限制大部分的人,另外還有一些信息,你不想被任何人知道,那麼能夠看到的人也就只有你一個人,這些就屬於封裝的不同的表現形式,封裝就是根據不同的對象給定不同的訪問權限,以此達到封裝的效果

  • jdbc的封裝特點:

    通過反射打破原有封裝,使用對象中的成員,並對成員進行操作,再封裝回該對象
    但需要處理一個問題,那就是數據庫中的表名,字段不一定和你的對象是一致的,這個時候就需要將數據庫中的表名,表字段和你的對象進行匹配,但是怎麼匹配呢,其實匹配的方法挺多,我自己呢使用過兩種匹配的方法,一種的使用map進行匹配,另一種是通過註解進行匹配,我個人推薦使用註解匹配吧

  • 需要知道反射和註解的使用方法

    反射:根據名字可以大概猜測就是反過來映射的意思,其實就是在不通過直接new的情況下創建實例或者拿到這個對象的成員就是反射。有人肯定會問,我直接通過new創建對象不是更加簡單嗎,使用反射來創建不是跟家複雜麻煩。有這樣想法是很正常的,通常都是直接new就可以了,但是有時候你需要在運行之前就要拿到裏邊的成員,並且對其中的成員做相應的封裝的時候,那就需要使用反射了,因爲如果你使用new的話,你只能拿到當前的一個封裝,裏邊並沒有做任何處理,這不是你想要的結果,所以反射是很重要的,就連很多設置模式都使用了反射的原理,spring的工廠的自動化接口一節對象的實例化也是通過反射來創建,因爲spring不能直接new對象,它是通過你在配置文件中設置的bean對象的class路徑,通過反射才創建的對象,spring的第二種通過註解對bean的依賴注入也是通過反射,雖然減少了傳統的配置文件的配置,但是在配置文件中卻需要自動掃描某一個路徑或者全包下的所有類文件,然後對標註了這個註解類中的屬性對象進行實例化的操作,
    其實就是使用反射加載字節碼文件也就是class文件,
    Class clz = (Class)Class.forName(“com.ucai.entity.Student”);
    T newInstance = clz.newInstance();//調用無參構造函數

    註解:註解比較深的應用我不是特別清楚,現在我使用的最對的也就是一個標註的功能,再通過反射的情況來判斷或者含有相應註解的類或者類成員,因爲註解可以放在類的所有成員上,類上邊也是可以的
    所以通過反射和註解就可以對數據庫表和實體對象之間做一個聯繫了,俗話說 一 一 對應就是這麼個道理

二、jdbc的映射,表映射,將對象中的屬性映射成表字段

注:下邊使用的是數據庫連接池來獲取的連接,數據庫連接池的編碼,在上一章事務管理中已經給出

  • 表註解(Tab.java)
package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 實體類映射數據庫表類
 * @author facebook
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE})
public @interface Tab {
    /**
     * 用於修飾實體類,表示實體類名與數據庫表名之間的映射
     * @return
     */
    String table() default "";

}
  • 字段註解(Column.java)
package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 實體類屬性數據庫映射標識類
 * @author facebook
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Column {
    /**
     * 字段名稱
     * @return
     */
    String name();
    /**
     * 字段類型
     * @return
     */
    Class<?> type();
    /**
     * 字段長度
     * @return
     */
    int len() default 11;
    /**
     * 是否爲主鍵
     * @return
     */
    boolean isPrimary() default false;
    /**
     * 是否可爲空
     * @return
     */
    boolean isNull() default true;
    /**
     * 是否自增長
     * @return
     */
    boolean isAutoIncrement() default false;
    /**
     * 是否可重複
     * @return
     */
    boolean isUnique() default true;
}
  • 實體類employee.java
package entity;

import java.io.Serializable;

import annotation.Column;
import annotation.Tab;

@Tab(table = "employee")
public class Employee implements Serializable{
    private static final long serialVersionUID = 1L;

    @Column(name="emp_id",type=Integer.class,isNull = false,isPrimary = true,isAutoIncrement=true)
    private Integer emp_id;

    @Column(name="emp_code",type=String.class,len = 30,isNull = false,isUnique = false)
    private String emp_code;

    @Column(name="emp_name",type=String.class,len = 30,isNull = true)
    private String emp_name;

    public Employee(){
        super();
    }

    public Employee(String emp_code, String emp_name) {
        this();
        this.emp_code = emp_code;
        this.emp_name = emp_name;
    }

    public Integer getEmp_id() {
        return emp_id;
    }
    public void setEmp_id(Integer emp_id) {
        this.emp_id = emp_id;
    }
    public String getEmp_code() {
        return emp_code;
    }
    public void setEmp_code(String emp_code) {
        this.emp_code = emp_code;
    }
    public String getEmp_name() {
        return emp_name;
    }
    public void setEmp_name(String emp_name) {
        this.emp_name = emp_name;
    }

    /**
     * 重寫父類的toString方法,將對象屬性以field&value的形式組裝起來
     */
    @Override
    public String toString() {
        return "emp_id=" + emp_id + "&emp_code=" + emp_code + "&emp_name=" + emp_name;
    }

}
  • 組裝增刪改查的sql語句,通過反射和註解,將實體類中的屬性映射成與數據庫表對應的字段名,組成一個完整的sql語句SQLMapping.java
package utils.jdbc;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Set;

import utils.page.Page;
import annotation.Column;
import annotation.Tab;
import exception.BaseException;

/**
 * 主要實現將實體類映射成sql語句
 * @author facebook
 *
 */
public final class SQLMapping{
    /**
     * 組裝新增的sql語句
     * @param clz
     * @param sb
     */
    public static <T>void insertSql(Class<T> clz,StringBuffer sb){
        sb.append(" insert into ");
        /*
         * 根據類註解添加拼接表名
         * 1.如果Tab註解中無參數,那麼表名是類名的全小寫
         * 2.如果Tab註解中含有參數,那麼表名是參數值
         */
        if(!clz.isAnnotationPresent(Tab.class)){
            sb.append(clz.getSimpleName().toLowerCase()+"( ");
        }else{
            sb.append(clz.getAnnotation(Tab.class).table()+"( ");
        }
        //用於拼接values中的'?'個數
        StringBuffer sbv = new StringBuffer(" values( ");
        for(Field field : clz.getDeclaredFields()){
            if(field.isAnnotationPresent(Column.class)){
                Column column = field.getAnnotation(Column.class);
                if(!column.isPrimary()){
                    /*
                     * 拼接字段名,以','隔開
                     * 拼接結果 insert into employee( emp_code , emp_name , 
                     */
                    sb.append(column.name()+" , ");

                    /*
                     * 拼接values中的'?'個數,以','隔開
                     * 拼接結果 values(  ? , ? ,  
                     */
                    sbv.append(" ? ,");
                }
            }
        }
        /*
         * 刪除拼接好的字符串中最後一個','
         * 得到  insert into employee( emp_code , emp_name
         */
        sb.delete(sb.toString().lastIndexOf(","),sb.length());
        /*
         * 添加第一步拼接結束的')'
         * 得到結果 into employee( emp_code , emp_name  )
         */
        sb.append(" ) ");

        /*
         * 刪除拼接好的字符串中最後一個','
         * 得到結果 values(  ? , ? 
         */
        sbv.delete(sbv.toString().lastIndexOf(","),sbv.length());
        /*
         * 添加第二步拼接結束的')'
         * 得到結果 values(  ? , ?  ) 
         */
        sbv.append(" ) ");

        /*
         * 將拼接好的values添加進sb中
         * 得到完整的insert語句  
         * insert into employee( emp_code , emp_name  )  values(  ? , ?  ) 
         */
        sb.append(sbv);
    }

    /**
     * 組裝需要刪除對象的sql
     * @param clz
     */
    public static <T>void delSql(Class<T> clz,StringBuffer sql){
        sql.append(" delete from ");
        spliceTab(clz, sql);
        sql.append(" where 1=1 ");
        for(Field field : clz.getDeclaredFields()){
            if(field.isAnnotationPresent(Column.class)){
                Column column = field.getAnnotation(Column.class);
                if(column.isPrimary()){
                    sql.append(" and "+column.name() + " = ? ");
                }
            }
        }
    }
    /**
     * 根據傳入的實體,組裝修改語句
     * @param t
     * @param sb
     */
    @SuppressWarnings("unchecked")
    public static <T>void updateSql(T t,StringBuffer sql){
        if(t==null){
            throw new BaseException("操作對象爲空!");
        }
        Class<T> clz = (Class<T>)t.getClass();
        sql.append(" update ");
        spliceTab(clz, sql);
        sql.append(" set ");
        StringBuffer sqlw = new StringBuffer(" where 1=1 ");
        for(Field field:clz.getDeclaredFields()){
            if(field.isAnnotationPresent(Column.class)){
                Column column = field.getAnnotation(Column.class);
                if(!column.isPrimary()){
                    sql.append(column.name()+" = ? , ");
                }else{
                    sqlw.append(" and "+column.name()+" = ? ");
                }
            }
        }
        sql.delete(sql.toString().lastIndexOf(","), sql.length()).append(sqlw);
    }

    /**
     * 通過反射組裝查詢sql
     * @param clz
     * @param sb
     * @throws SecurityException 
     * @throws NoSuchFieldException 
     */
    @SuppressWarnings("unchecked")
    public static <T>void querySql(Class<T> clz,StringBuffer sb,Object ... objs) throws Exception{
        if(clz==null){
            throw new BaseException("類對象爲null!");
        }
        StringBuffer sqlb = new StringBuffer(" select ");
        for(Field field : clz.getDeclaredFields()){
            if(field.isAnnotationPresent(Column.class)){
                Column column = field.getAnnotation(Column.class);
                sqlb.append(column.name()+" , ");
            }
        }
        sqlb.delete(sqlb.toString().lastIndexOf(","), sqlb.length());
        sqlb.append("from ");
        spliceTab(clz, sqlb);
        sqlb.append(" where 1=1 ");
        int index=0;
        if(sb!=null){
            index = sqlb.length();
        }
        sb.insert(0, sqlb);
        Set<Object> set=null;
        if(objs.length>0){
            for(Object obj : objs){
                if(obj instanceof Set){
                    set = ( Set<Object>)obj;
                    break;
                }
            }
        }
        if(set==null){
            return;
        }
        for(Iterator<Object> it = set.iterator();it.hasNext();){
            String fieldName = (String) it.next();
            Field field = clz.getDeclaredField(fieldName);
            if(!field.isAnnotationPresent(Column.class)){
                throw new BaseException("屬性 '"+field.getName()+"' 沒有添加映射!");
            }
            Column column = field.getAnnotation(Column.class);
            sb.insert(index," and " +column.name() + " = ? ");
        }
    }
    /**
     * 組裝oracle分頁sql
     * @param sb
     * @param page
     */
    public static <T>void oraclepagesql(StringBuffer sql,Page<T> page){
        StringBuffer sb = new StringBuffer();
        sb.append(" select * from ");
        sb.append(" ( ");
                sb.append(" select t.*, rownum rn from ");
                        sb.append(" ( ");
                                sql.insert(0, sb);
                        sql.append(" ) t ");
                        sql.append(" where rownum <= ").append(page.getRowNum());
        sql.append(" ) "); 
        sql.append(" where rn >=").append(page.getEndNum());
    }
    /**
     * 根據類註解給sql語句添加表名的拼接
     * @param clz
     * @param sb
     */
    public static <T>void spliceTab(Class<T> clz,StringBuffer sql){
        if(!clz.isAnnotationPresent(Tab.class)){
            sql.append(clz.getSimpleName().toLowerCase());
        }else{
            sql.append(clz.getAnnotation(Tab.class).table());
        }
    }
    /**
     * 返回封裝好的查詢sql
     * @param clz
     * @param objs
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T>StringBuffer querySql(Class<T> clz,Object...objs){
        StringBuffer sql = new StringBuffer();
        try{
                if(objs.length>0){
                    for(Object obj : objs){
                        if(obj instanceof StringBuffer){
                            sql = (StringBuffer)obj;
                            querySql(clz,sql);
                        }
                        if(obj instanceof Page){
                            if(sql==null){
                                sql=new StringBuffer();
                            }
                            oraclepagesql(sql,(Page<T>)obj);
                        }
                    }
                }else{
                    sql = new StringBuffer();
                    querySql(clz,sql);
                }
        }catch(Exception e){
            e.printStackTrace();
        }
        return sql;
    }
}
  • 將返回的結果封裝到相應的實體對象中BeanUtils.java
package utils.jdbc;

import java.lang.reflect.Field;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

import annotation.Column;
import exception.BaseException;

/**
 * 該類實現數據庫查詢結果集,封裝成對象結果
 * @author facebook
 *
 */
public final class BeanUtils{
    /**
     * 封裝對象
     * @param clz
     * @param rs
     * @return
     * @throws Exception
     */
    public static <T>T setObject(Class<T> clz,ResultSet rs) throws Exception{
        T t = clz.newInstance();
        for(Field field : clz.getDeclaredFields()){
            field.setAccessible(true);
            if(field.isAnnotationPresent(Column.class)){
                Column column = field.getAnnotation(Column.class);
                field.set(t, rs.getObject(column.name()));
            }
        }
        return t;
    }
    /**
     * 替換PreparedStatement對象的參數
     * @param pst
     * @param map
     * @throws SQLException
     */
    public static void setPstObject(PreparedStatement pst,Map<Object,Object> map) throws SQLException{
        if(map == null || map.size() == 0){
            throw new BaseException("未設置查詢條件!");
        }
        int i =1 ;
        for(Map.Entry<Object, Object> entrySet : map.entrySet()){
            pst.setObject(i++, entrySet.getValue());
        }
    }

    /**
     * 替換 增、刪、改 傳入的 PreparedStatement 對象的 參數
     * @param t
     * @param sb
     * @throws Exception 
     */
    @SuppressWarnings("unchecked")
    public static <T>void setPstObject(T t,PreparedStatement pst) throws Exception{
        //得到preparedstatement對象的參數列表
        ParameterMetaData paramMetaData= pst.getParameterMetaData();
        int paramCount = paramMetaData.getParameterCount();
        if(t==null){
            throw new BaseException("操作對象爲空!");
        }
        Class<T> clz = (Class<T>) t.getClass();
        int i = 1;
        Object obj = null;
        for (Field field : clz.getDeclaredFields()) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                if(column.isPrimary()){
                    obj = field.get(t);
                    if(paramCount==1){
                        break;
                    }
                }else {
                    pst.setObject(i++, field.get(t));
                }
            }
        }
        //判斷i是否等於pst的最大參數,如果是,那麼替換pst中對應i位置的參數
        //這是爲了區分新增與修改的參數替換
        //如果不滿足下邊的條件,說明不是新增,滿足則是數據新增
        if(paramCount==i){
            pst.setObject(i, obj);
        }
    }
}
  • 對象開放的增刪改查的主要操作類BaseDao.java
package utils.jdbc;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import exception.BaseException;
import utils.page.Page;
import utils.pools.DB;
import utils.pools.DBUtils;
/**
 * 實現增刪改查的基類
 * @author facebook
 *
 * @param <T>
 */
public class BaseDao<T>{
    /**
     * 創建一個PreparedStament的空對象
     */
    private PreparedStatement pst = null;
    /**
     * 創建一個ResultSet的空對象
     */
    private ResultSet rs = null;
    /**
     * 得到數據庫具體對象封裝的類實例
     */
    private DBUtils dbUtils = new DBUtils();
    /**
     * 根據數據庫類實例對象獲取數據庫連接
     */
    private Connection conn = dbUtils.conn;
    /**
     * 新增對象到對應的數據庫表
     * @param t
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public int insert(T t) {
        if(t==null){
            throw new BaseException("不能對空對象操作!");
        }
        Class<T> clz = (Class<T>)t.getClass();
        StringBuffer sql = new StringBuffer();
        SQLMapping.insertSql(clz,sql);
        try{
            pst = dbUtils.preparedStatement(sql.toString());
            BeanUtils.setPstObject(t, pst);
            return pst.executeUpdate();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try{
                dbUtils.close(pst);
                dbUtils.close(conn);
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
        return 0;
    }

    /**
     * 根據指定對象刪除對應表數據
     * @param t
     * @return
     */
    @SuppressWarnings("unchecked")
    public int delObject(T t){
        if(t==null){
            throw new BaseException("不能對空對象操作!");
        }
        Class<T> clz = (Class<T>)t.getClass();
        StringBuffer sql = new StringBuffer();
        SQLMapping.delSql(clz,sql);
        try {
            pst = dbUtils.preparedStatement(sql.toString());
            BeanUtils.setPstObject(t, pst);
            return pst.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try{
                dbUtils.close(pst);
                dbUtils.close(conn);
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
        return 0;
    }
    /**
     * 根據指定對象修改對應表數據
     * @param t
     * @return
     */
    public int update(T t){
        StringBuffer sb = new StringBuffer();
        SQLMapping.updateSql(t, sb);
        try {
            pst = dbUtils.preparedStatement(sb.toString());
            BeanUtils.setPstObject(t, pst);
            return pst.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                dbUtils.close(pst);
                dbUtils.close(conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }
    /**
     * 根據指定條件查詢
     * @param clz
     * @param map :key表示clz類中的filed,value表示該屬性對應的值
     * @return
     * @throws Exception 
     */
    public T queryObject(Class<T> clz,Map<Object,Object> map){
        if(map==null||map.size()==0){
            throw new BaseException("未設置查詢條件!");
        }
        StringBuffer sql = new StringBuffer();
        T t = null;
        try{
            SQLMapping.querySql(clz, sql,map.keySet());
            pst = dbUtils.preparedStatement(sql.toString());
            BeanUtils.setPstObject(pst,map);
            rs = pst.executeQuery();
            while(rs.next()){
                t = BeanUtils.setObject(clz,rs);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try{
                dbUtils.close(rs);
                dbUtils.close(pst);
                dbUtils.close(conn);
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
        return t;
    }
    /**
     * 根據實體類查詢相應數據表的所有內容
     * 可變參數可傳入條件類型的StringBuffer,
     * 以及分頁需要的page對象
     * 傳入的StringBuffer表示可支持的sql條件,
     * 傳入示例:new StringBuffer(" and name='張三' ")
     * @param clz
     * @return
     */
    public List<T> queryList(Class<T>clz,Object...objs){
        try{
            StringBuffer sql = SQLMapping.querySql(clz, objs);
            rs = dbUtils.resultSet(sql.toString());
            List<T> queryList = new ArrayList<T>();
            while(rs.next()){
                queryList.add(BeanUtils.setObject(clz,rs));
            }
            return queryList;
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            try {
                dbUtils.close(rs);
                dbUtils.close(pst);
                dbUtils.close(conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * 分頁查詢的返回頁對象
     * 可實現條件分頁
     * 第三個參數爲可變參數,傳入類型需要爲StringBuffer的容器,裏邊保存的是查詢參數的條件
     * 如:new StringBuffer(" and emp_code = '0002' ")
     * @param currentPage
     * @param clz
     * @return
     */
    public  Page<T> pageList(int currentPage,Class<T>clz,Object...objs){
        Page<T> page = new Page<T>(currentPage);
        StringBuffer sql=null;
        if(objs.length==0){
            sql = new StringBuffer();
        }else{
            for(Object obj:objs){
                if(obj instanceof StringBuffer){
                    sql=(StringBuffer)obj;
                }
            }
        }
        if(DB.DB_TYPE.equals("MYSQL")){
            sql.append(" limit "+page.getRowNum()+" , "+page.getOffset());
            page.setPageList(queryList(clz, sql));
        }
        else if(DB.DB_TYPE.equals("ORACLE")){
            page.setPageList(queryList(clz, sql,page));
        }
        return page;
    }
    /**
     * 調用存儲過程(傳入的map鍵只有下邊三個鍵)
     *                  key:proc_name(表示過程名稱)   value:對應的值是字符串形式的過程名稱
     *                  key:proc_in(表示輸入參數)         value:對應一個參數集合
     *                  key:proc_out(表示輸出參數)        value:對應的參數列表是數據庫中對應的輸出參數類型集合
     * 示例:
     *          Map map = new HashMap();
     *          
     *          輸入參數集合封裝:
     *          List proc_in= new ArrayList();
     *          proc_in.add(7936);
     *          proc_in.add("麗彩潔");
     * 
     *          輸出參數集合封裝:
     *          List proc_out = new ArrayList();
     *          proc_out.add(OracleTypes.VARCHAR);
     * 
     *          存入過程名稱:
     *          map.put("proc_name","insert_emp");
     *          
     *          存儲輸入參數列表:
     *          map.put("proc_in",proc_in);
     *          
     *          存入輸出參數列表類型:
     *          map.put("proc_out", proc_out);
     * 
     *          調用存儲過程
     *          new BaseDao().callProcedure(map);
     */
    @SuppressWarnings("unchecked")
    public void callProcedure(Map<String,Object> procMap){
         CallableStatement call = null;
         StringBuffer procedure = new StringBuffer();
         if(procMap==null||procMap.get("proc_name")==null){
              throw new BaseException("未能正確調用過程!");
         }
         if(procMap.get("proc_name").toString().trim().equals("")){
             throw new BaseException("過程名爲空!");
         }
         //拼接過程名稱
         procedure.append(procMap.get("proc_name"));
         //獲得所有的輸入參數
         List<Object> proc_in = (List<Object>) procMap.get("proc_in");
         //獲得所有的輸出參數
         List<Integer> proc_out = (List<Integer>) procMap.get("proc_out");
         /*
          * 得到參數個數
          * 如果輸入參數和輸出參數都不爲空,那麼參數個數爲,輸入參數和輸出參數總和
          * 如果輸入參數不爲空,輸出參數爲空,那麼參數個數爲輸入參數的個數
          * 如果輸入參數爲空,輸出參數不爲空,那麼參數個數爲輸出參數的個數
          */
         int len = proc_in!=null&&proc_out!=null?proc_in.size()+proc_out.size():proc_in!=null&&proc_out==null?proc_in.size():proc_in==null&&proc_out!=null?proc_out.size():0;

         if(len>0){
             procedure.append("(");
             for(int i=0;i<len;i++){
                 procedure.append(" ? , ");
             }
             procedure.delete(procedure.lastIndexOf(","), procedure.length());
             procedure.append(" ) ");
         }
        try {
            call = dbUtils.callableStatement(procedure);

            /*
             * 該變量用於對輸入參數與輸出參數?的定位
             * 首先是定位輸入參數,輸入參數定位結束,再定位輸出參數
             * 處理過程嚴格按照先替換輸入參數,再定位輸出參數,因此數據庫中的存儲過程的創建也需要按照這個規則創建
             * 侷限性比較明顯,後期再進行修改
             */
            int i = 0 ;

            /*
             * 將過程對象中的參數‘?’替換爲具體的值
             */
            if(proc_in!=null){
                for(Iterator<Object> it = proc_in.iterator();it.hasNext();){
                    Object obj = it.next();
                    call.setObject(++i,obj);
                }
            }
            if(proc_out!=null){
                for(Iterator<Integer> it = proc_out.iterator();it.hasNext();){
                    call.registerOutParameter(++i,it.next());
                }
            }
            call.execute();

            //如果存儲過程有輸出,做封裝
            if(proc_out!=null){
                //具體操作根據需求設計
                System.out.println(call.getObject(i));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            try {
                dbUtils.close(call);
                dbUtils.close(conn);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 分頁操作的類Page.java
package utils.page;

import java.util.List;

/**
 * 分頁查詢操作實體類
 * @author facebook
 *
 * @param <T>
 */
public class Page<T> {
    /**
     *  每頁顯示條數
     */
    private final int SHOW_NUM = 2;
    /**
     *  總頁數
     */
    private int totalPage;
    /**
     *  總條數
     */
    private int totalNum;
    /**
     *  首頁 = 1
     */
    private int startPage = 1;
    /**
     *  尾頁
     */
    private int endPage;
    /**
     *  上一頁
     */
    private int prevPage;
    /**
     *  當前頁
     */
    private int currentPage = 1;
    /**
     *  下一頁
     */
    private int nextPage;
    /**
     *  頁面展示的數據信息
     */
    private List<T> pageList;
    /**
     *  顯示的起始行號
     */
    private int rowNum;

    /**
     * 顯示的結束行號,適用於非mysql數據庫
     */
    private int endNum;

    @SuppressWarnings("unused")
    /**
     * 將分頁對象的默認無參構造方法私有化
     * 只提供有參構造方法
     */
    private Page() {}

    /**
     * 通過構造函數設置當前頁 (currentPage)
     * 當前頁顯示的開始行 (rowNum)
     * @param currentPage
     */
    public Page(int currentPage) {
        //避免傳入參數爲<1的當前頁碼,如果真的出現這種數字,默認當前頁爲首頁
        currentPage=currentPage>0?currentPage:1;
        //設置當前頁
        this.setCurrentPage(currentPage);
        //設置開始行號
        this.setRowNum();
    }
    /**
     * 設置查詢結果 
     * 設置查詢結果總記錄數 (totalNum)
     * 設置查詢結果總頁數(totalPage)、尾頁 (endPage)
     * 設置當前頁的前一頁( prevPage)、後一頁(nextPage)
     * @param list
     */
    public void setPageList(List<T> list){
        //將總記錄保存到集合中,用於後續的計算
        this.pageList = list;
        //設置總條數
        this.setTotalNum();
        //設置總頁數
        this.setTotalPage();
        //設置上一頁
        this.setPrevPage();
        //設置下一頁
        this.setNextPage();
    }
    /**
     * 返回分頁後的結果
     * @return
     */
    public List<T> getPageList(){
        return this.pageList;
    }
    /**
     * 返回封裝好的Page對象
     * 
     * @param currentPage
     */
    public Page<T> getPage() {
        return this;
    }
    /**
     * 設置總條數 總條數 = 查詢的list集合長度
     */
    private void setTotalNum() {
        int size = this.pageList != null ? this.pageList.size() : 0;
        this.totalNum = size;
    }
    /**
     * 設置總頁數、尾頁 根據查詢的總條數來設置 如果查詢的總條數能夠除盡每頁顯示的行數,那麼總頁數=總條數/每頁顯示的總記錄數
     * 如果含有餘數,那麼總頁數=(總條數/每頁顯示總記錄數)+1
     * 
     * 尾頁 = 總頁數
     */
    private void setTotalPage() {
        int totalPage = this.totalNum / this.SHOW_NUM;
        if (this.totalNum % this.SHOW_NUM == 0) {
            this.totalPage = totalPage;
        } else {
            this.totalPage = totalPage;
        }
        // 尾頁就等於總頁數
        this.endPage = this.totalPage;
    }
    /**
     * 設置當前頁
     * 
     * @param currentPage
     */
    private void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }
    /**
     * 設置上一頁
     * 
     * @param currentPage
     */
    private void setPrevPage() {
        this.prevPage = this.totalPage > 1 ? 1 : this.currentPage - 1;
    }
    /**
     * 獲取上一頁
     * @return
     */
    public int getPrevPage(){
        return this.prevPage;
    }
    /**
     * 設置下一頁
     */
    private void setNextPage() {
        this.nextPage = this.totalPage > 1 ? 1 : this.currentPage + 1;
    }
    /**
     * 獲取下一頁
     * @return
     */
    public int getNextPage(){
        return this.nextPage;
    }
    /**
     * 獲取首頁
     * @return
     */
    public int getStartPage(){
        return this.startPage;
    }
    /**
     * 獲取尾頁
     * @return
     */
    public int getEndPage(){
        return this.endPage;
    }

    /**
     * 設置開始行號
     * 
     *  0~14 :( 1 - 1 ) * 15~ 1 * 15-1
     *  15~29:( 2 - 1 ) * 15~ 2 * 15-1
     */
    private void setRowNum() {
            this.rowNum = (currentPage-1)* this.SHOW_NUM;
    }
    /**
     * 獲取開始行號
     * 
     * @return
     */
    public int getRowNum() {
        return rowNum;
    }
    /**
     * 設置結束行號,通過偏移量計算出結束行號,適用於非mysql數據庫
     *  0~14 :( 1 - 1 ) * 15~ 1 * 15-1
     *  15~29:( 2 - 1 ) * 15~ 2 * 15-1
     * @param endNum
     */
    public void setEndNum() {
        this.endNum =  currentPage *  this.SHOW_NUM -1;
    }
    /**
     * 獲取結束行號
     * @return
     */
    public int getEndNum() {
        return endNum;
    }
    /**
     * 每頁顯示多少條,適用於mysql
     * @return
     */
    public int getOffset(){
        return this.SHOW_NUM;
    }
}
  • 希望各位前輩能夠給予意見,小弟萬分感謝
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章