这是原生的jdbc,只能一个一个取属性.
现在我有这样一个实体类我想要把我的jdbc返回值,直接包装进类里面
package cn.dbutils.analyze;
import java.util.Date;
public class Student {
private Integer id;
private String name;
private Date time;
public Student() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", time=" + time + "]";
}
}
这是查询的工具类(大部分源码都是参考的DBUtils)自己写的可能会有BUG有待大量测试
package cn.dbutils.analyze.piratemodel;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class QueryRunner {
private Connection con;
//这个属性存在的意义
//因为数据库查出来的值很有可能那一列是空的那么返回的值就是null
//我们的实体类有可能是int型 ,float型等等基本类型,是接收不了null,应该给他默认值才对
private static final Map<Class<?>, Object> primitiveDefaults = new HashMap<Class<?>, Object>();
static {
primitiveDefaults.put(Integer.TYPE, Integer.valueOf(0));
primitiveDefaults.put(Short.TYPE, Short.valueOf((short) 0));
primitiveDefaults.put(Byte.TYPE, Byte.valueOf((byte) 0));
primitiveDefaults.put(Float.TYPE, Float.valueOf(0f));
primitiveDefaults.put(Double.TYPE, Double.valueOf(0d));
primitiveDefaults.put(Long.TYPE, Long.valueOf(0L));
primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
primitiveDefaults.put(Character.TYPE, Character.valueOf((char) 0));
}
//把数据源放进来
public QueryRunner(Connection con) {
super();
this.con = con;
}
public <T> T query(String sql,Class<T> type) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException{
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
if (rs.next()) {
return toBean(rs,type);
}
return null;
}
public <T> List<T> queryList(String sql,Class<T> type) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException{
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
//将要返回的list
List<T> list = new ArrayList<T>();
while(rs.next()) {
list.add(toBean(rs,type));
}
return list;
}
//核心方法,根据rs当行数据返回想要的对象
private <T> T toBean(ResultSet rs,Class<T> type) throws IntrospectionException, SQLException, InstantiationException, IllegalAccessException {
//在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件。
BeanInfo beanInfo = Introspector.getBeanInfo(type);
//得 beans PropertyDescriptor
//PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
//获取此 ResultSet 对象的列的编号、类型和属性。
ResultSetMetaData rsmd = rs.getMetaData();
//现在我已经获取了javaBean的所有属性和resultSet返回值的所有属性
//计算出一个对应关系数组,使各个属性对应
int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
return this.createBean(rs, type, props, columnToProperty);
}
private <T> T createBean(ResultSet rs, Class<T> type,
PropertyDescriptor[] props, int[] columnToProperty)
throws SQLException, InstantiationException, IllegalAccessException {
//通过反射new一个对象
T bean = type.newInstance();
for (int i = 1; i < columnToProperty.length; i++) {
//没有符合的属性字段
if (columnToProperty[i] == -1) {
continue;
}
//获得这一列匹配的属性
PropertyDescriptor prop = props[columnToProperty[i]];
//获得属性的 Class 对象
Class<?> propType = prop.getPropertyType();
//判断这个属性是什么数据类型,匹配并返回
Object value = this.processColumn(rs, i, propType);
//如果属性是基本类型,但是值却未成功返回,那么应该给vale初始值 int:0 boolean:false
if (propType != null && value == null && propType.isPrimitive()) {
value = primitiveDefaults.get(propType);
}
//把vale赋值给对象
this.callSetter(bean, prop, value);
}
return bean;
}
//计算出一个对应关系数组,使各个属性对应
protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
PropertyDescriptor[] props) throws SQLException {
//返回此 ResultSet 对象中的列数
int cols = rsmd.getColumnCount();
//将要返回的数组
//因为ResultSet是从坐标1开始的所以坐标数组也要+1
int[] columnToProperty = new int[cols + 1];
//默认都是-1 如果没有找到对应的属性字段那么就是-1
Arrays.fill(columnToProperty, -1);
for(int col = 1; col <= cols; col++) {
//获取这一列的名字
String columnName = rsmd.getColumnName(col);
//循环javaBean中的属性
for(int i=0;i<props.length;i++) {
//不区分大小写比较
if (columnName.equalsIgnoreCase(props[i].getName())) {
//ResultSet 第col列放置的是props[i]这个属性
columnToProperty[col] = i;
break;
}
}
}
return columnToProperty;
}
private Object processColumn(ResultSet rs, int index, Class<?> propType) throws SQLException {
//如果该属性不是一个基本类型并且该列的值为null
//返回一个null
if ( !propType.isPrimitive() && rs.getObject(index) == null ) {
return null;
}
if (propType.equals(String.class)) {
return rs.getString(index);
} else if (
propType.equals(Integer.TYPE) || propType.equals(Integer.class)) {
return Integer.valueOf(rs.getInt(index));
} else if (
propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) {
return Boolean.valueOf(rs.getBoolean(index));
} else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) {
return Long.valueOf(rs.getLong(index));
} else if (
propType.equals(Double.TYPE) || propType.equals(Double.class)) {
return Double.valueOf(rs.getDouble(index));
} else if (
propType.equals(Float.TYPE) || propType.equals(Float.class)) {
return Float.valueOf(rs.getFloat(index));
} else if (
propType.equals(Short.TYPE) || propType.equals(Short.class)) {
return Short.valueOf(rs.getShort(index));
} else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) {
return Byte.valueOf(rs.getByte(index));
} else if (propType.equals(Timestamp.class)) {
return rs.getTimestamp(index);
} else {
return rs.getObject(index);
}
}
private void callSetter(Object target, PropertyDescriptor prop, Object value)
throws SQLException {
//获得应该用于写入属性值的方法。
//知道为什么框架为什么要求实体类需要get,set方法了吧?
Method setter = prop.getWriteMethod();
if (setter == null) {
return;
}
// 返回 Class 对象的数组,这些对象描述了声明将此 Method 对象表示的底层方法抛出的异常类型。
Class<?>[] params = setter.getParameterTypes();
try {
// convert types for some popular ones
if (value != null) {
if (value instanceof java.util.Date) {
if (params[0].getName().equals("java.sql.Date")) {
value = new java.sql.Date(((java.util.Date) value).getTime());
} else
if (params[0].getName().equals("java.sql.Time")) {
value = new java.sql.Time(((java.util.Date) value).getTime());
} else
if (params[0].getName().equals("java.sql.Timestamp")) {
value = new java.sql.Timestamp(((java.util.Date) value).getTime());
}
}
}
// Don't call setter if the value object isn't the right type
if (isCompatibleType(value, params[0])) {
setter.invoke(target, new Object[]{value});
} else {
throw new SQLException(
"Cannot set " + prop.getName() + ": incompatible types.");
}
} catch (IllegalArgumentException e) {
throw new SQLException(
"Cannot set " + prop.getName() + ": " + e.getMessage());
} catch (IllegalAccessException e) {
throw new SQLException(
"Cannot set " + prop.getName() + ": " + e.getMessage());
} catch (InvocationTargetException e) {
throw new SQLException(
"Cannot set " + prop.getName() + ": " + e.getMessage());
}
}
//判断该值和该属性是非兼容
private boolean isCompatibleType(Object value, Class<?> type) {
// Do object check first, then primitives
if (value == null || type.isInstance(value)) {
return true;
} else if (type.equals(Integer.TYPE) && Integer.class.isInstance(value)) {
return true;
} else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) {
return true;
} else if (type.equals(Double.TYPE) && Double.class.isInstance(value)) {
return true;
} else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) {
return true;
} else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) {
return true;
} else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) {
return true;
} else if (type.equals(Character.TYPE) && Character.class.isInstance(value)) {
return true;
} else if (type.equals(Boolean.TYPE) && Boolean.class.isInstance(value)) {
return true;
}
return false;
}
}
使用效果
使用到的DBUtil工具类
package com.zzzy.book.manage.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public final class DBUtil {
private DBUtil() {
}
/**
* 获取数据库连接对象
*
* @return
*/
public static Connection getConn() {
String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf-8";
String user = "root";
String password = "1913599913";
Connection connection = null;
try {
// 加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 获取连接对象
connection = DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
// 关闭数据库连接,静态方法
public static void closeConn(Connection conn) {
try {
// 如果数据库连接不为空且没有被关闭,则执行关闭操作
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closeResource(Connection conn, PreparedStatement ps) {
try {
if (ps != null && !ps.isClosed()) {
ps.close();
}
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void closeResource(Connection conn, PreparedStatement ps,
ResultSet rs) {
try {
if (ps != null && !ps.isClosed()) {
ps.close();
}
if (rs != null && !rs.isClosed()) {
rs.close();
}
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}