这节课我们来进一步封装jdbc
首先来分析下,jdbc的使用:
jdbc使用:
1. 建立好表对应的类(我们称为bean),要求每一列对应一个属性,且数据类型对应上
2. 建立连接,获取Connection对象
3. 使用Connection对象获取Statement或PreparedStatement对象
4. 写好sql
5. 使用Statement或PreparedStatement执行查询语句,如果是select语句,获取ResultSet对象,并执行6和7
6. 建一个或多个bean对象
7. 获取ResultSet里存储的值,并封装到bean对象中
8. 关闭连接
第1步的封装以后讲,这个可以算是另一个小项目了
第2、3步我们已经封装好了,就是dbc
接下来就是封装4、5、6、7
代码:
package com.tool;
import com.bean.Employee;
import com.util.ClassUtil;
import com.util.ObjectUtil;
import com.util.StringUtil;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
*
* @param <E> bean的类型
* 一个bean对应一个表,且bean的类名用驼峰式命名,表的命名用下划线全小写命名
* 这个类是一个抽象类,必须有子类继承并且给定E的类型
*/
public abstract class Mapper<E> {
private Connection connection;
public Mapper(Connection connection)
{
this.connection = connection;
}
public Mapper(String dbcPropertiesPath) throws SQLException, IOException, ClassNotFoundException {
this.connection = Dbc.getConnection(dbcPropertiesPath);
}
/**
* 将value转换成合适的类型插入到合适的位置
*/
private void castToSuitType(PreparedStatement preparedStatement,int index, Object value) throws SQLException {
Class<?> valueClass = value.getClass();
if (valueClass == String.class)
{
preparedStatement.setString(index, String.valueOf(value));
}
else if(valueClass == Integer.class || valueClass == int.class)
{
preparedStatement.setInt(index,(Integer)value);
}
else if (valueClass == Float.class || valueClass == float.class)
{
preparedStatement.setFloat(index,(Float) value);
}
else if (valueClass == Double.class || valueClass == double.class)
{
preparedStatement.setDouble(index,(Double) value);
}
else if (valueClass == Short.class || valueClass == short.class)
{
preparedStatement.setShort(index,(Short)value);
}
else
{
preparedStatement.setString(index, String.valueOf(value));
}
}
private <T> T castToSuitType(ResultSet resultSet,int index, Class<T> fieldClass) throws SQLException
{
Object value;
if (fieldClass == String.class)
{
value = resultSet.getString(index);
}
else if(fieldClass == Integer.class || fieldClass == int.class)
{
value = resultSet.getInt(index);
}
else if (fieldClass == Float.class || fieldClass == float.class)
{
value = resultSet.getFloat(index);
}
else if (fieldClass == Double.class || fieldClass == double.class)
{
value = resultSet.getDouble(index);
}
else if (fieldClass == Short.class || fieldClass == short.class)
{
value = resultSet.getShort(index);
}
else
{
value = resultSet.getString(index);
}
return (T)value;
}
/**
* 首先,我们要获取所有的类列
* 每一列对应bean的类的一个属性
* 列名用全小写下划线式
* 属性名用首字母小写的驼峰式
*
* 接下来我们需要几个一个工具类来处理字符串
* 当然,要用的工具类我都提前写好了
*/
/**
* 获取泛型E的Class对象,即bean的类型的Class对象
* @return
*/
public Class<E> getBeanClass()
{
return ClassUtil.getSuperClassGenricType(this.getClass());
}
/**
* 获取表名
* @param
*/
public String getTableName()
{
Class<E> beanClass = getBeanClass();
String className = beanClass.getName();
className = className.substring(className.lastIndexOf(".") +1);
String tableName = StringUtil.castCamelCaseToUnderline(className);
//保险起见首字母转下小写
tableName = StringUtil.firstLetterToLowerCase(tableName);
return tableName;
}
/**
* 获取列名
* @return
*/
public List<String> getColumnNames()
{
Class<E> beanClass = getBeanClass();
Field[] fields = beanClass.getDeclaredFields();
List<String> columnNames = new ArrayList<String>(fields.length);
for (Field field : fields) {
String columnName = StringUtil.castCamelCaseToUnderline(field.getName());
//保险起见首字母转下小写
columnName = StringUtil.firstLetterToLowerCase(columnName);
columnNames.add(columnName);
}
return columnNames;
}
//接下来封装增删改查操作
public void insert(E e) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//String sql = "insert into tbl_employee (id,last_name,email,gender,d_id) values (?,?,?,?,?)";
String sql = "insert into ";
sql += getTableName() + " (";
List<String> columnNames = getColumnNames();
for (String columnName : columnNames) {
sql += columnName + ",";
}
//删除最后一个逗号
sql = StringUtil.deleteLastChildString(sql,1);
sql += ") values (";
//说了含金量高的,索性写复杂点
List<Object> valueList = ObjectUtil.getAllFieldValue(e);
for (Object value : valueList) {
//用?当占位符
sql += "?,";
}
//删除最后一个逗号
sql = StringUtil.deleteLastChildString(sql,1);
sql += ");";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < valueList.size(); i++) {
//这个也是从1开始
castToSuitType(preparedStatement,i + 1,valueList.get(i));
}
preparedStatement.executeUpdate();
//总算把insert写完了,后面的都差不多,我快点写,就不写注释了
}
public void delete(int id) throws SQLException {
//String sql = "delete from tbl_employee where id = ?";
String sql = "delete from ";
sql += getTableName() + " ";
sql += "where ";
Class<E> beanClass = getBeanClass();
//注意,在写bean类的时候必须将主键写在最前面,否则,这个代码要写的更加复杂,因为涉及到注解
String primaryKeyName = beanClass.getDeclaredFields()[0].getName();
sql += primaryKeyName + "= ?;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,id);
preparedStatement.executeUpdate();
}
public void update(E e) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//String sql = "update tbl_employee set last_name = ?,email = ?,gender = ?, d_id = ? where id = ?";
String sql = "update " + getTableName() + " set ";
List<String> columnNames = getColumnNames();
String primaryKeyName = columnNames.remove(0);
for (String columnName : columnNames) {
sql += columnName + "=?,";
}
sql = StringUtil.deleteLastChildString(sql,1);
sql += " where " + primaryKeyName + "=?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
List<Object> valueList = ObjectUtil.getAllFieldValue(e);
Object primaryKeyValue = valueList.remove(0);
//主键被挪到了最后,在where那里
valueList.add(primaryKeyValue);
for (int i = 0; i < valueList.size(); i++) {
castToSuitType(preparedStatement,i + 1,valueList.get(i));
}
preparedStatement.executeUpdate();
}
public E selectByPrimaryKey(Object primaryKey) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
Class<E> beanClass = getBeanClass();
//以前说过,java bean必须有空构造函数,其实就是为了方便通过反射构造对象
E e = null;
//String sql = "select * from tbl_employee where id = ?";
String sql = "select ";
List<String> columnNames = getColumnNames();
for (String columnName : columnNames) {
sql += columnName + ",";
}
sql = StringUtil.deleteLastChildString(sql,1);
sql += " from " + getTableName() + " where ";
//获取主键名称
String primaryKeyName = beanClass.getDeclaredFields()[0].getName();
sql += primaryKeyName + "= ?;";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
castToSuitType(preparedStatement,1,primaryKey);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next())
{
//查得到数据才new,否则返回null
e = getBeanFromResultSet(resultSet, beanClass);
}
return e;
}
/**
*
* @param conditionMap 键是列名,值是要匹配的值
* @return
*/
public List<E> selectByExample(Map<String,Object> conditionMap) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
List<E> resultList = new ArrayList<E>();
int size = conditionMap.keySet().size();
String[] keyArr = new String[size];
Object[] valueArr = conditionMap.values().toArray();
conditionMap.keySet().toArray(keyArr);
//String sql = "select * from tbl_employee where ";
String sql = "select ";
List<String> columnNames = getColumnNames();
for (String columnName : columnNames) {
sql += columnName + ",";
}
sql = StringUtil.deleteLastChildString(sql,1);
sql += " from " + getTableName() + " where ";
for (int i = 0; i < size; i++) {
sql += keyArr[i] + "=? and "; //and前后要加空格
}
//末尾多了一个and,去掉
sql = sql.substring(0,sql.lastIndexOf("and") - 1);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < valueArr.length; i++) {
castToSuitType(preparedStatement,i + 1,valueArr[i]);
}
ResultSet resultSet = preparedStatement.executeQuery();
Class<E> beanClass = getBeanClass();
while (resultSet.next())
{
E e = getBeanFromResultSet(resultSet, beanClass);
resultList.add(e);
}
return resultList;
}
//提取点公共代码
public E getBeanFromResultSet(ResultSet resultSet,Class<E> beanClass) throws IllegalAccessException, InstantiationException, SQLException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
E e = beanClass.newInstance();
Field[] fields = beanClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
//列数从1开始
Object value = castToSuitType(resultSet, i + 1, fields[i].getType());
ObjectUtil.setFieldValue(e,fields[i],value);
}
return e;
}
}
使用:
public class EmployeeMapper extends Mapper<Employee> {
public EmployeeMapper(Connection connection) {
super(connection);
}
public EmployeeMapper(String dbcPropertiesPath) throws SQLException, IOException, ClassNotFoundException {
super(dbcPropertiesPath);
}
}
测试:
public static void main(String[] args) throws Exception {
//测一下,我也不确定我能不能一次写对
EmployeeMapper mapper = new EmployeeMapper("src/com/resource/dbc.properties");
//通过
Employee employee = mapper.selectByPrimaryKey(3);
System.out.println(employee);
//通过
mapper.delete(100);
//通过
employee = new Employee(13,"mahuateng","mahuateng@qq.com","1",1004);
mapper.update(employee);
//通过
employee = new Employee(100,"xiaowang","xiaowang@163.com","0",1002);
mapper.insert(employee);
//通过
Map<String,Object > map = new HashMap<String, Object>();
map.put("gender","1");
map.put("d_id",1002);
List<Employee> employees = mapper.selectByExample(map);
for (Employee employee1 : employees) {
System.out.println(employee1);
}
}
工具类:
package com.util;
//字符串工具类
//这个工具类里的所有方法要求看懂并且可以自己写出来
//这个里的所有方法全是我自己手写出来的,要求你们也要可以手写出来
public class StringUtil {
/**
* 将字符串首字母转换成大写
*
* @param str 要转换的字符串
* @return 返回str首字母大写后的字符串
*/
public static String firstLetterToUpperCase(String str)
{
//这里只替换第一个
return str.replaceFirst(String.valueOf(str.charAt(0)),String.valueOf(str.charAt(0)).toUpperCase());
}
/**
* 将字符串首字母转换成小写
*
* @param str 要转换的字符串
* @return 返回str首字母瞎写写后的字符串
*/
public static String firstLetterToLowerCase(String str)
{
//这里只替换第一个
return str.replaceFirst(String.valueOf(str.charAt(0)),String.valueOf(str.charAt(0)).toLowerCase());
}
/**
* 驼峰转下划线
* 解释下什么叫驼峰式,就是每个单词的首字母大写,其余字母都小写
* java推荐所有变量、方法、类都使用驼峰式命名
* 类名一般第一个单词的首字母也要大写
* 变量、方法第一个单词的首字母小写
* 下划线式是指全字母小写或全字母大写,单词之间用下划线分割,如cast_camel_case_to_underline
* 常量采用全字母大写加下划线式
*/
/**
* 将驼峰式字符串转换成下划线式
*
* @param str 驼峰式字符串
* @return 下划线式字符串
*/
public static String castCamelCaseToUnderline(String str)
{
char[] chars = str.toCharArray();
String result = "";
for (char i : chars)
{
if (i >= 'A' && i <= 'Z')
{
result += "_" + String.valueOf(i).toLowerCase();
}
else
{
result += i;
}
}
if (result.startsWith("_"))
{
result = result.substring(1);
}
return result;
}
/**
* 将下划线字符串转换成驼峰式
*
* @param str 下划线式字符串
* @return 驼峰式字符串
*/
public static String castUnderlineToCamelCase(String str)
{
String[] split = str.split("_");
String result = "";
for (String s : split)
{
result += firstLetterToUpperCase(s);
}
return firstLetterToLowerCase(result);
}
/**
* 删除下划线最后length位字符
*
* @param str 要处理的字符串
* @param length 要删除字符串最后多少位字符
* @return 删除str字符串最后length位字符后的新字符串
*/
public static String deleteLastChildString(String str,int length)
{
return str.substring(0,str.length() - length);
}
}
package com.util;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class ObjectUtil {
/**
* 获取object的属性值
* @param object 要获取属性值的镀锡
* @param fieldName 属性名
* @return object的filedName对应的属性值
*/
public static Object getFieldValue(Object object,String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String getterMethodName = "get" + StringUtil.firstLetterToUpperCase(fieldName);
//只要public的getter方法
Method getterMethod = object.getClass().getMethod(getterMethodName);
if (getterMethod != null)
{
Object value = getterMethod.invoke(object);
return value;
}
return null;
}
/**
* 获取object的属性值
* @param object 要获取属性值的镀锡
* @param field 属性
* @return object的filed对应的属性值
*/
public static Object getFieldValue(Object object,Field field) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return getFieldValue(object,field.getName());
}
/**
* 获取object的所有属性值
* @param object 要获取属性值的镀锡
* @return object的所有属性值组成的List集合
*/
public static List<Object> getAllFieldValue(Object object) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Field[] declaredFields = object.getClass().getDeclaredFields();
List<Object> valueList = new ArrayList<Object>(declaredFields.length);
for (Field field : declaredFields) {
valueList.add(getFieldValue(object,field));
}
return valueList;
}
/**
* 设置object的属性值
* @param object 要获取属性值的镀锡
* @param fieldName 属性名
* @param value 要设置的属性值
* @return object的filedName对应的属性值
*/
public static void setFieldValue(Object object,String fieldName,Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
String setterMethodName = "set" + StringUtil.firstLetterToUpperCase(fieldName);
Class<?> fieldClass = object.getClass().getDeclaredField(fieldName).getType();
//只要public的getter方法
Method setterMethod = object.getClass().getMethod(setterMethodName,fieldClass);
if (setterMethod != null)
{
setterMethod.invoke(object,value);
}
}
/**
* 设置object的属性值
* @param object 要获取属性值的镀锡
* @param field 属性
* @param value 要设置的属性值
* @return object的filedName对应的属性值
*/
public static void setFieldValue(Object object, Field field, Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
setFieldValue(object,field.getName(),value);
}
}
package com.util;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
//这个工具类的所有方法会用就行,以后需要就直接复制粘贴
//反正这个玩意我也是百度的
public class ClassUtil {
/**
* 获取父类的泛型的类型
* @param clazz 子类
* @return 父类的泛型的Class对象
*/
public static Class getSuperClassGenricType(Class clazz) {
return getSuperClassGenricType(clazz, 0);
}
/**
* 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
*/
public static Class getSuperClassGenricType(Class clazz, int index)
throws IndexOutOfBoundsException {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
return Object.class;
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class) params[index];
}
}