简单封装JDBC

本文介绍了面向对象的封装概念,探讨了封装JDBC的动机和好处。通过反射和注解实现数据库表与对象的映射,详细讲解了如何使用注解创建表和字段映射,以及如何利用反射组装SQL语句并封装结果到实体对象。同时提到了使用数据库连接池进行连接管理。

一、简要介绍一下自己封装一个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 F
 *
 */
@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 F
 *
 */
@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 F
 *
 */
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 F
 *
 */
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;
		//主要保存主键值(用户替换where后边的id=?)
		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));
				}
			}
		}
		//该判断只会替换where后边的id=?,所以只会针对修改和删除
		//1,如果是新增,将不会对id值进行替换,所以参数将会比总参数少一个,而i是从1开始计算,过滤掉主键i的值每次+1之后,将会超过paramCount的值,所以下边的替换永远不会执行
		//2,如果是修改或者删除,会算上id,所以paramCount参数总个数将会与需要替换的参数i的值是相同的,因此会执行下列的操作
		//3,当paramCount与i相等的时候,表示需要替换的id在最后一位,即表示修改(删除)动作
		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 F
 *
 * @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 F
 *
 * @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;
	}
}

  • 希望各位前辈能够给予意见,小弟万分感谢
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值