All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pers.zr.opensource.magic.dao.MagicGenericDao Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
package pers.zr.opensource.magic.dao;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.util.CollectionUtils;
import pers.zr.opensource.magic.dao.action.*;
import pers.zr.opensource.magic.dao.annotation.Column;
import pers.zr.opensource.magic.dao.annotation.Key;
import pers.zr.opensource.magic.dao.annotation.TableShard;
import pers.zr.opensource.magic.dao.annotation.Table;
import pers.zr.opensource.magic.dao.constants.ActionMode;
import pers.zr.opensource.magic.dao.mapper.GenericMapper;
import pers.zr.opensource.magic.dao.constants.MethodType;
import pers.zr.opensource.magic.dao.mapper.MapperContextHolder;
import pers.zr.opensource.magic.dao.matcher.EqualsMatcher;
import pers.zr.opensource.magic.dao.matcher.Matcher;
import pers.zr.opensource.magic.dao.order.Order;
import pers.zr.opensource.magic.dao.page.Page;
import pers.zr.opensource.magic.dao.shard.DefaultTableShardHandler;
import pers.zr.opensource.magic.dao.shard.TableShardHandler;
import pers.zr.opensource.magic.dao.shard.TableShardStrategy;
import pers.zr.opensource.magic.dao.utils.ClassUtil;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.PreparedStatement;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 

* Common and abstract implements of MagicDao *

* Created by zhurong on 2016-4-29. */ public abstract class MagicGenericDao implements MagicDao { protected final Log log = LogFactory.getLog(getClass()); /** magic data source*/ protected MagicDataSource magicDataSource; /** table shard handler*/ protected TableShardHandler tableShardHandler = new DefaultTableShardHandler(); /** entity class */ private Class entityClass; /** table */ private ActionTable table; /** key class */ private Class keyClass; /** key fields of entity*/ private List keyFields; /** Generic RowMapper for set data */ protected RowMapper rowMapper; @SuppressWarnings("unchecked") public MagicGenericDao() { if(log.isInfoEnabled()) { log.info("initialize instance of " + getClass()); } //Get entity class & key class Type[] types = ClassUtil.getGenericTypes(getClass()); keyClass = (Class)types[0]; entityClass = (Class)types[1]; String tableName = null; //get table matched by entity (analysis @Table) Table tableAnnotation = entityClass.getAnnotation(Table.class); TableShard tableShardAnnotation = entityClass.getAnnotation(TableShard.class); if(tableShardAnnotation != null) { tableName = tableShardAnnotation.shardTable(); } if(null == tableName && null != tableAnnotation) { tableName = tableAnnotation.name(); } if(null == tableName) { throw new RuntimeException("Class [" + entityClass.getName() +"] must be annotated with TableName!"); } //get all fields of entity Set fields = ClassUtil.getAllFields(entityClass); if(CollectionUtils.isEmpty(fields)) { throw new RuntimeException("Class [" + entityClass.getName() +"] has no fields!"); } //get all methods of entity Set methods = ClassUtil.getAllMethods(entityClass); if(CollectionUtils.isEmpty(methods)) { throw new RuntimeException("Class [" + entityClass.getName() +"] has no methods!"); } //analysis @Key and @Column List keyColumns = new ArrayList(); keyFields = new ArrayList(); List tableColumns = new ArrayList(); List defaultInsertColumns = new ArrayList(); List defaultUpdateColumns = new ArrayList(); for(Field field : fields) { Key keyAnnotation = field.getAnnotation(Key.class); Column columnAnnotation = field.getAnnotation(Column.class); if(null != keyAnnotation) { keyColumns.add(keyAnnotation.column()); keyFields.add(field); tableColumns.add(keyAnnotation.column()); if(!keyAnnotation.autoIncrement()) { defaultInsertColumns.add(keyAnnotation.column()); } MapperContextHolder.setFieldWithColumn(entityClass, keyAnnotation.column(), field); }else if(columnAnnotation != null) { tableColumns.add(columnAnnotation.value()); if(!columnAnnotation.readOnly()) { defaultInsertColumns.add(columnAnnotation.value()); } MapperContextHolder.setFieldWithColumn(entityClass, columnAnnotation.value(), field); } //get setter and getter method String fieldName = field.getName(); for(Method method : methods) { String methodName = method.getName(); if(methodName.equalsIgnoreCase("set" + fieldName) || (fieldName.startsWith("is") && methodName.equalsIgnoreCase("set" + fieldName.substring(2)))) { MapperContextHolder.setMethod(entityClass, field, method, MethodType.SET); }else if(methodName.equalsIgnoreCase("get" + fieldName) || methodName.equalsIgnoreCase("is" + fieldName) || (fieldName.startsWith("is") && methodName.equalsIgnoreCase(fieldName))) { MapperContextHolder.setMethod(entityClass, field, method, MethodType.GET); } } } //update columns which inside inserted columns but not key defaultUpdateColumns.addAll(defaultInsertColumns.stream().filter(column -> !keyColumns.contains(column)).collect(Collectors.toList())); table = new ActionTable(); table.setTableName(tableAnnotation.name()); table.setKeys(keyColumns); table.setColumns(tableColumns); table.setDefaultInsertColumns(defaultInsertColumns); table.setDefaultUpdateColumns(defaultUpdateColumns); rowMapper = new GenericMapper(entityClass); MapperContextHolder.setRowMapper(entityClass, rowMapper); //get shard strategy if(null != tableShardAnnotation) { int shardCount = tableShardAnnotation.shardCount(); String[] shardColumns = tableShardAnnotation.shardColumns(); String separator = tableShardAnnotation.separator(); table.setTableShardStrategy(new TableShardStrategy(tableName, shardCount, shardColumns, separator)); table.setTableShardHandler(tableShardHandler); } } @Override public ENTITY get(KEY key) { Query query = ActionBuilderFactory.getBuilder(ActionMode.QUERY, table).build(); query.setQueryFields(table.getColumns()); query.addConditions(getKeyConditions(key)); List list = magicDataSource.getJdbcTemplate(ActionMode.QUERY).query(query.getSql(), query.getParams(), rowMapper); return CollectionUtils.isEmpty(list) ? null : list.get(0); } @Override public void insert(ENTITY entity){ Insert insert = ActionBuilderFactory.getBuilder(ActionMode.INSERT, table).build(); insert.setInsertFields(getDataMapByColumns(table.getDefaultInsertColumns(), entity)); magicDataSource.getJdbcTemplate(ActionMode.INSERT).update(insert.getSql(), insert.getParams()); } @Override public Long insertForId(ENTITY entity){ Insert insert = ActionBuilderFactory.getBuilder(ActionMode.INSERT, table).build(); Map dataMap = getDataMapByColumns(table.getDefaultInsertColumns(), entity); insert.setInsertFields(dataMap); String sql = insert.getSql(); String[] columnsArray = new String[dataMap.size()]; Object[] paramsArray = new Object[dataMap.size()]; int i=0; for(Map.Entry entry : dataMap.entrySet()) { columnsArray[i] = entry.getKey(); paramsArray[i] = entry.getValue(); i++; } KeyHolder keyHolder = new GeneratedKeyHolder(); JdbcTemplate jdbcTemplate = magicDataSource.getJdbcTemplate(ActionMode.INSERT); jdbcTemplate.update( connection -> { PreparedStatement ps = connection.prepareStatement(sql, columnsArray); for(int k=1; k<=paramsArray.length; k++) { ps.setObject(k, paramsArray[k-1]); } return ps; }, keyHolder); return keyHolder.getKey().longValue(); } @Override public void update(ENTITY entity) { Update update = ActionBuilderFactory.getBuilder(ActionMode.UPDATE, table).build(); update.addConditions(getKeyConditionsFromEntity(entity)); update.setUpdateFields(getDataMapByColumns(table.getDefaultUpdateColumns(), entity)); magicDataSource.getJdbcTemplate(ActionMode.UPDATE).update(update.getSql(), update.getParams()); } @Override public void delete(KEY key){ Delete delete = ActionBuilderFactory.getBuilder(ActionMode.DELETE, table).build(); delete.addConditions(getKeyConditions(key)); magicDataSource.getJdbcTemplate(ActionMode.DELETE).update(delete.getSql(), delete.getParams()); } @Override public void delete(Matcher...conditions) { Delete delete = ActionBuilderFactory.getBuilder(ActionMode.DELETE, table).build(); if(null != conditions && conditions.length >0) { delete.addConditions(Arrays.asList(conditions)); } magicDataSource.getJdbcTemplate(ActionMode.DELETE).update(delete.getSql(), delete.getParams()); } @Override public void update(Map valueMap, Matcher...conditions) { Update update = ActionBuilderFactory.getBuilder(ActionMode.UPDATE, table).build(); if(null != conditions && conditions.length >0) { update.addConditions(Arrays.asList(conditions)); } update.setUpdateFields(valueMap); magicDataSource.getJdbcTemplate(ActionMode.UPDATE).update(update.getSql(), update.getParams()); } @Override public List query(Matcher...conditions) { Query query = ActionBuilderFactory.getBuilder(ActionMode.QUERY, table).build(); query.setQueryFields(table.getColumns()); query.addConditions(Arrays.asList(conditions)); List list = magicDataSource.getJdbcTemplate(ActionMode.QUERY).query(query.getSql(), query.getParams(), rowMapper); return CollectionUtils.isEmpty(list) ? new ArrayList() : list; } @Override public List query(Page page, Matcher...conditions) { return query(page, null, conditions); } @Override public List query(List orders, Matcher...conditions) { return query(null, orders, conditions); } @Override public List query(Page page, List orders, Matcher...conditions){ Query query = ActionBuilderFactory.getBuilder(ActionMode.QUERY, table).build(); query.setQueryFields(table.getColumns()); query.addConditions(Arrays.asList(conditions)); query.setOrders(orders); query.setPage(page); List list = magicDataSource.getJdbcTemplate(ActionMode.QUERY).query(query.getSql(), query.getParams(), rowMapper); return CollectionUtils.isEmpty(list) ? new ArrayList() : list; } @Override public Long getCount(Matcher...conditions) { Query query = ActionBuilderFactory.getBuilder(ActionMode.QUERY, table).build(); query.setQueryFields(Collections.singletonList("COUNT(1)")); query.addConditions(Arrays.asList(conditions)); return magicDataSource.getJdbcTemplate(ActionMode.QUERY).queryForObject(query.getSql(), query.getParams(), Long.class); } private List getKeyConditions(KEY key) { List matcherList = new ArrayList(); List keyColumns = table.getKeys(); if(CollectionUtils.isEmpty(table.getKeys())) { throw new RuntimeException("no key columns found!"); } if(table.getKeys().size() == 1 && ClassUtil.isBasicType(keyClass)) { matcherList.add(new EqualsMatcher(keyColumns.get(0), key)); }else { for(int i=0; i getKeyConditionsFromEntity(ENTITY entity) { List matcherList = new ArrayList(); List keyColumns = table.getKeys(); if(CollectionUtils.isEmpty(keyColumns)) { throw new RuntimeException("no key columns found!"); } for(int i=0; i getDataMapByColumns(List columns, ENTITY entity) { Map dataMap = new HashMap(); for(String column : columns) { Object value = null; Field field = MapperContextHolder.getFieldWithColumn(entityClass, column); if(field == null) { throw new RuntimeException("column [" + column + "] has no appropriate field!"); } Method getMethod = MapperContextHolder.getMethod(entityClass, field, MethodType.GET); if(getMethod == null) { throw new RuntimeException("field [" + field.getName() + "] has no getMethod!"); } try { value = getMethod.invoke(entity); } catch (IllegalAccessException e) { log.error(e.getMessage(), e); } catch (InvocationTargetException e) { log.error(e.getMessage(), e.getTargetException()); } if(value != null) { dataMap.put(column, value); } } return dataMap; } public void setMagicDataSource(MagicDataSource magicDataSource) { this.magicDataSource = magicDataSource; } public void setTableShardHandler(TableShardHandler tableShardHandler) { this.tableShardHandler = tableShardHandler; table.setTableShardHandler(this.tableShardHandler); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy