【Java高级篇】基于反射+注解实现抽象JDBC工具类BaseDao
Pom
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
注解
@TableName
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableName {
String value();
}
@Id
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
String value();
}
@Column
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value();
Class<?> type() default String.class;
int length() default 0;
}
抽象Dao层
BaseDao
public interface BaseDao<T> {
void save(T t) throws Exception;
void deleteById(Object id, Class<T> clazz) throws Exception;
void updateById(T t) throws Exception;
T getById(Object id, Class<T> clazz) throws Exception;
List<T> findAllByConditions(Map<String, Object> sqlWhereMap, Class<T> clazz) throws Exception;
}
BaseDaoImpl
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.*;
import java.util.Date;
public abstract class BaseDaoImpl<T> implements BaseDao<T> {
private static final String TABLE_ALIAS = "t";
@Override
public void save(T t) throws Exception {
Class<?> clazz = t.getClass();
String tableName = getTableName(clazz);
StringBuilder fieldNames = new StringBuilder();
List<Object> fieldValues = new ArrayList<Object>();
StringBuilder placeholders = new StringBuilder();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
if (field.isAnnotationPresent(Id.class)) {
fieldNames.append(field.getAnnotation(Id.class).value()).append(",");
fieldValues.add(pd.getReadMethod().invoke(t));
} else if (field.isAnnotationPresent(Column.class)) {
fieldNames.append(field.getAnnotation(Column.class).value()).append(",");
fieldValues.add(pd.getReadMethod().invoke(t));
}
placeholders.append("?").append(",");
}
fieldNames.deleteCharAt(fieldNames.length() - 1);
placeholders.deleteCharAt(placeholders.length() - 1);
StringBuilder sql = new StringBuilder("");
sql.append("insert into ").append(tableName)
.append(" (").append(fieldNames.toString())
.append(") values (").append(placeholders).append(")");
PreparedStatement ps = JdbcDaoHelper.getConnection().prepareStatement(sql.toString());
setParameter(fieldValues, ps, false);
ps.execute();
JdbcDaoHelper.release(ps, null);
System.out.println(sql + "\n" + clazz.getSimpleName() + "添加成功!");
}
@Override
public void deleteById(Object id, Class<T> clazz) throws Exception {
String tableName = getTableName(clazz);
String idFieldName = "";
boolean flag = false;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Id.class)) {
idFieldName = field.getAnnotation(Id.class).value();
flag = true;
break;
}
}
if (!flag) {
throw new NotFoundAnnotationException(clazz.getName() + " object not found id property.");
}
String sql = "delete from " + tableName + " where " + idFieldName + "=?";
PreparedStatement ps = JdbcDaoHelper.getConnection().prepareStatement(sql);
ps.setObject(1, id);
ps.execute();
JdbcDaoHelper.release(ps, null);
System.out.println(sql + "\n" + clazz.getSimpleName() + "删除成功!");
}
@Override
public void updateById(T t) throws Exception {
Class<?> clazz = t.getClass();
String tableName = getTableName(clazz);
List<Object> fieldNames = new ArrayList<Object>();
List<Object> fieldValues = new ArrayList<Object>();
List<String> placeholders = new ArrayList<String>();
String idFieldName = "";
Object idFieldValue = "";
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), t.getClass());
if (field.isAnnotationPresent(Id.class)) {
if (Objects.isNull(pd.getReadMethod().invoke(t))) {
throw new RuntimeException(field.getName() + " Value cannot be empty.");
}
idFieldName = field.getAnnotation(Id.class).value();
idFieldValue = pd.getReadMethod().invoke(t);
} else if (field.isAnnotationPresent(Column.class)) {
if (Objects.nonNull(pd.getReadMethod().invoke(t))) {
fieldNames.add(field.getAnnotation(Column.class).value());
fieldValues.add(pd.getReadMethod().invoke(t));
placeholders.add("?");
}
}
}
fieldNames.add(idFieldName);
fieldValues.add(idFieldValue);
placeholders.add("?");
StringBuilder sql = new StringBuilder("");
sql.append("update ").append(tableName).append(" set ");
int index = fieldNames.size() - 1;
for (int i = 0; i < index; i++) {
sql.append(fieldNames.get(i)).append("=").append(placeholders.get(i)).append(",");
}
sql.deleteCharAt(sql.length() - 1).append(" where ").append(fieldNames.get(index)).append("=").append("?");
PreparedStatement ps = JdbcDaoHelper.getConnection().prepareStatement(sql.toString());
setParameter(fieldValues, ps, false);
ps.execute();
JdbcDaoHelper.release(ps, null);
System.out.println(sql + "\n" + clazz.getSimpleName() + "修改成功.");
}
@Override
public T getById(Object id, Class<T> clazz) throws Exception {
String idFieldName = "";
Field[] fields = clazz.getDeclaredFields();
boolean flag = false;
for (Field field : fields) {
if (field.isAnnotationPresent(Id.class)) {
idFieldName = field.getAnnotation(Id.class).value();
flag = true;
break;
}
}
if (!flag) {
throw new NotFoundAnnotationException(clazz.getName() + " object not found id property.");
}
Map<String, Object> sqlWhereMap = new HashMap<String, Object>();
sqlWhereMap.put(TABLE_ALIAS + "." + idFieldName, id);
List<T> list = findAllByConditions(sqlWhereMap, clazz);
return list.size() > 0 ? list.get(0) : null;
}
@Override
public List<T> findAllByConditions(Map<String, Object> sqlWhereMap, Class<T> clazz) throws Exception {
List<T> list = new ArrayList<T>();
String tableName = getTableName(clazz);
String idFieldName = "";
StringBuffer fieldNames = new StringBuffer();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String propertyName = field.getName();
if (field.isAnnotationPresent(Id.class)) {
idFieldName = field.getAnnotation(Id.class).value();
fieldNames.append(TABLE_ALIAS + "." + idFieldName)
.append(" as ").append(propertyName).append(",");
} else if (field.isAnnotationPresent(Column.class)) {
fieldNames.append(TABLE_ALIAS + "." + field.getAnnotation(Column.class).value())
.append(" as ").append(propertyName).append(",");
}
}
fieldNames.deleteCharAt(fieldNames.length() - 1);
String sql = "select " + fieldNames + " from " + tableName + " " + TABLE_ALIAS;
PreparedStatement ps = null;
List<Object> values = null;
if (sqlWhereMap != null) {
List<Object> sqlWhereWithValues = getSqlWhereWithValues(sqlWhereMap);
if (sqlWhereWithValues != null) {
String sqlWhere = (String) sqlWhereWithValues.get(0);
sql += sqlWhere;
values = (List<Object>) sqlWhereWithValues.get(1);
}
}
if (values != null) {
ps = JdbcDaoHelper.getConnection().prepareStatement(sql);
setParameter(values, ps, true);
} else {
ps = JdbcDaoHelper.getConnection().prepareStatement(sql);
}
ResultSet rs = ps.executeQuery();
while (rs.next()) {
T t = clazz.newInstance();
initObject(t, fields, rs);
list.add(t);
}
JdbcDaoHelper.release(ps, rs);
System.out.println(sql);
return list;
}
private void initObject(T t, Field[] fields, ResultSet rs)
throws SQLException, IntrospectionException,
IllegalAccessException, InvocationTargetException, IntrospectionException {
for (Field field : fields) {
String propertyName = field.getName();
Object paramVal = null;
Class<?> clazzField = field.getType();
if (clazzField == String.class) {
paramVal = rs.getString(propertyName);
} else if (clazzField == short.class || clazzField == Short.class) {
paramVal = rs.getShort(propertyName);
} else if (clazzField == int.class || clazzField == Integer.class) {
paramVal = rs.getInt(propertyName);
} else if (clazzField == long.class || clazzField == Long.class) {
paramVal = rs.getLong(propertyName);
} else if (clazzField == float.class || clazzField == Float.class) {
paramVal = rs.getFloat(propertyName);
} else if (clazzField == double.class || clazzField == Double.class) {
paramVal = rs.getDouble(propertyName);
} else if (clazzField == boolean.class || clazzField == Boolean.class) {
paramVal = rs.getBoolean(propertyName);
} else if (clazzField == byte.class || clazzField == Byte.class) {
paramVal = rs.getByte(propertyName);
} else if (clazzField == char.class || clazzField == Character.class) {
paramVal = rs.getCharacterStream(propertyName);
} else if (clazzField == Date.class) {
paramVal = rs.getTimestamp(propertyName);
} else if (clazzField.isArray()) {
paramVal = rs.getString(propertyName).split(",");
}
PropertyDescriptor pd = new PropertyDescriptor(propertyName, t.getClass());
pd.getWriteMethod().invoke(t, paramVal);
}
}
private List<Object> getSqlWhereWithValues(Map<String, Object> sqlWhereMap) {
if (sqlWhereMap.size() < 1) return null;
List<Object> list = new ArrayList<Object>();
List<Object> fieldValues = new ArrayList<Object>();
StringBuffer sqlWhere = new StringBuffer(" where ");
Set<Map.Entry<String, Object>> entrySets = sqlWhereMap.entrySet();
for (Iterator<Map.Entry<String, Object>> iteraotr = entrySets.iterator(); iteraotr.hasNext(); ) {
Map.Entry<String, Object> entrySet = iteraotr.next();
fieldValues.add(entrySet.getValue());
Object value = entrySet.getValue();
if (value.getClass() == String.class) {
sqlWhere.append(entrySet.getKey()).append(" like ").append("?").append(" and ");
} else {
sqlWhere.append(entrySet.getKey()).append("=").append("?").append(" and ");
}
}
sqlWhere.delete(sqlWhere.lastIndexOf("and"), sqlWhere.length());
list.add(sqlWhere.toString());
list.add(fieldValues);
return list;
}
private String getTableName(Class<?> clazz) throws NotFoundAnnotationException {
if (clazz.isAnnotationPresent(TableName.class)) {
TableName entity = clazz.getAnnotation(TableName.class);
return entity.value();
} else {
throw new NotFoundAnnotationException(clazz.getName() + " is not Entity Annotation.");
}
}
private void setParameter(List<Object> values, PreparedStatement ps, boolean isSearch) throws SQLException {
for (int i = 1; i <= values.size(); i++) {
Object fieldValue = values.get(i - 1);
Class<?> clazzValue = fieldValue.getClass();
if (clazzValue == String.class) {
if (isSearch)
ps.setString(i, "%" + (String) fieldValue + "%");
else
ps.setString(i, (String) fieldValue);
} else if (clazzValue == boolean.class || clazzValue == Boolean.class) {
ps.setBoolean(i, (Boolean) fieldValue);
} else if (clazzValue == byte.class || clazzValue == Byte.class) {
ps.setByte(i, (Byte) fieldValue);
} else if (clazzValue == char.class || clazzValue == Character.class) {
ps.setObject(i, fieldValue, Types.CHAR);
} else if (clazzValue == Date.class) {
ps.setTimestamp(i, new Timestamp(((Date) fieldValue).getTime()));
} else if (clazzValue.isArray()) {
Object[] arrayValue = (Object[]) fieldValue;
StringBuffer sb = new StringBuffer();
for (int j = 0; j < arrayValue.length; j++) {
sb.append(arrayValue[j]).append("、");
}
ps.setString(i, sb.deleteCharAt(sb.length() - 1).toString());
} else {
ps.setObject(i, fieldValue, Types.NUMERIC);
}
}
}
}
JdbcDaoHelper
public class JdbcDaoHelper {
private static final String USER = "root";
private static final String PASSWORD = "root";
private static final String URL = "jdbc:mysql://localhost:3306/study_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC";
private static Connection conn;
public static Connection getConnection() {
try {
if (conn == null) {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USER, PASSWORD);
} else {
return conn;
}
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public static void release(PreparedStatement ps, ResultSet rs) {
try {
if (conn != null) {
conn.close();
conn = null;
}
if (ps != null) {
ps.close();
ps = null;
}
if (rs != null) {
rs.close();
rs = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
测试
Person
@TableName("t_person")
public class Person {
@Id("id")
private Long id;
@Column("t_isbn")
private String isbn;
@Column("t_name")
private String name;
@Column(value = "t_pubdate")
private Date pubdate;
@Column(value = "t_price")
private double price;
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getPubdate() {
return pubdate;
}
public void setPubdate(Date pubdate) {
this.pubdate = pubdate;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", isbn='" + isbn + '\'' +
", name='" + name + '\'' +
", pubdate=" + pubdate +
", price=" + price +
'}';
}
}
PersonService
public interface PersonService {
}
PersonServiceImpl
public class PersonServiceImpl extends BaseDaoImpl<Person> implements PersonService {
}
PersonTest
public static void main(String[] args) throws Exception {
PersonServiceImpl personService = new PersonServiceImpl();
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("t_name", "唱、跳、rap");
System.out.println(personService.findAllByConditions(hashMap, Person.class));
}
}