说明
类似 Mybatis,支持将查询结果封装到 Bean中
缺点
使用 反射 实现,繁琐麻烦,使用 内省 方式,更加简单,详见 链接
继承
需要继承 某个 DbUtils 类 或 子类即可
代码
/**
* 指定封装类,将查询的结果封装到该类中
* 注意:列名要与类成员变量名相同,才能封装
*
* @param sql
* @param clazz 指定封装类
* @return
* @throws SQLException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
public <T> List<T> queryBean(String sql,Class<T> clazz,Object ... objects) throws SQLException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {
List retList = new ArrayList<>();
Map<String, Method> propertyAndSetterMap = getSetterMethod(clazz);
PreparedStatement pstm = null;
ResultSet rs = null;
try {
pstm = conn.prepareStatement(sql);
if (objects != null && objects.length > 0) {
for (int i = 0; i < objects.length; i++) {
pstm.setObject(i + 1, objects[i]);
}
}
rs = pstm.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
// 返回查询结果列的总数
int columnNum = rsmd.getColumnCount();
while (rs.next()) {
// 通过反射方式实例化
Object beanObj = clazz.newInstance();
// 将查询列的值,放入到 javabean(模型类)的 属性中
// ****难点:需要知道列名,还需要指定属性名
// 即:原来写的下面这行代码
// user.setUserId(resultSet.getInt("user_id"));
for (int i = 1; i <= columnNum; i++) {
// 取出查询的列名,都改成小写,成员变量名那里也改成小写了
String columnLabel = rsmd.getColumnLabel(i).toLowerCase();
// 取出与该列名相应的值
Object valueDB = rs.getObject(i);
// 根据列名,从map中取出与列名相同的属性的set方法
Method setMethod = propertyAndSetterMap.get(columnLabel);
// 如果方法为null,表示没有对应的方法,就不再往下执行
if (setMethod == null) {
continue;
}
// set方法一定有一个参数
Class paraType = setMethod.getParameterTypes()[0];
Object dataTemp = null;
if (valueDB instanceof BigDecimal) { // mysql数据库的 decimal 类型,jdbc查询出来的类型是 BigDecimal,需要做额外处理
BigDecimal temp = (BigDecimal) valueDB;
if (paraType == double.class) {
dataTemp = temp.doubleValue();
} else if (paraType == float.class) {
dataTemp = temp.floatValue();
}
} else {
dataTemp = valueDB;
}
// 调用 set 方法,传值
setMethod.invoke(beanObj,dataTemp);
// 动态调用 setXXX 方法,并且传值
try {
setMethod.invoke(beanObj,dataTemp);
}catch (java.lang.IllegalArgumentException e){
throw new IllegalArgumentException(setMethod.getName()+" 形参类型是:"+setMethod.getParameterTypes()[0]+
",从数据库查询出来的数据类型是:"+dataTemp.getClass().getName());
}
}
retList.add(beanObj);
}
return retList;
}finally{
//查询后要释放资源
if(rs!=null) {
rs.close();
}
if(pstm!=null) {
pstm.close();
}
}
}
/**
* 获取setter方法
* @param bean
* @return 返回Map,属性名作为key,setter方法作为value
*/
private Map<String,Method> getSetterMethod(Class bean) throws IntrospectionException {
// 将属性 和 相关的set方法,放入到map中
Map<String,Method> propertyAndSetterMap = new HashMap();
Method[] methods = bean.getMethods();
for (Method method : methods) {
String methodName = method.getName();
// 如果方法以set开头,就认为是set方法
if (methodName.startsWith("set")) {
// 如果方法的参数数量不是1,就说明不是set方法
if(method.getParameterCount()!=1){
continue;
}
// 截取set后面的部分,作为成员变量名,也是列名
String field = methodName.substring(3).toLowerCase();
propertyAndSetterMap.put(field,method);
}
}
return propertyAndSetterMap;
}