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

io.github.shmilyjxs.core.impl.BaseBeanDao Maven / Gradle / Ivy

There is a newer version: 1.37
Show newest version
package io.github.shmilyjxs.core.impl;

import io.github.shmilyjxs.utils.BeanUtil;
import io.github.shmilyjxs.utils.PageResult;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public abstract class BaseBeanDao extends BaseSqlDao {

    private static final Logger logger = LoggerFactory.getLogger(BaseBeanDao.class);

    private static final Map, Triple, Map>> CLASS_CACHE = new ConcurrentHashMap<>();

    private static  Map buildMap(T obj, Map convertMap) {
        return buildMap(obj, convertMap, true);
    }

    private static  Map buildMap(T obj, Map convertMap, boolean skipBlank) {
        Map beanMap = BeanUtil.beanToMap(obj);
        if (skipBlank) {
            beanMap = BeanUtil.skipBlank(beanMap);
        }
        Map map = new LinkedHashMap<>();
        for (Map.Entry entry : convertMap.entrySet()) {
            if (beanMap.containsKey(entry.getKey())) {
                map.put(entry.getValue(), beanMap.get(entry.getKey()));
            }
        }
        return map;
    }

    @Override
    public  Triple, Map> getTableInfo(T obj) {
        return Optional.of(obj).map(T::getClass).map(this::getTableInfo).get();
    }

    @Override
    public  Triple, Map> getTableInfo(Class clazz) {
        Triple, Map> triple = CLASS_CACHE.get(clazz);
        if (Objects.isNull(triple)) {
            synchronized (this) {
                triple = CLASS_CACHE.get(clazz);
                if (Objects.isNull(triple)) {
                    String tableName = BeanUtil.getTableName(clazz);
                    Field idFiled = BeanUtil.idFiled(clazz);

                    String sql = getDBType().getDialect().columnSql(tableName);
                    List columnList = scalarList(sql, String.class);
                    Map map = new LinkedCaseInsensitiveMap<>();
                    columnList.forEach(e -> map.put(e, e));
                    columnList.forEach(e -> map.putIfAbsent(JdbcUtils.convertUnderscoreNameToPropertyName(e), e));
                    columnList.forEach(e -> map.putIfAbsent(BeanUtil.dbToJava(e), e));

                    Map.Entry entry = new AbstractMap.SimpleImmutableEntry<>(idFiled, Objects.requireNonNull(map.get(idFiled.getName())));
                    Map convertMap = new LinkedHashMap<>();
                    Arrays.stream(BeanUtils.getPropertyDescriptors(clazz))
                            .map(PropertyDescriptor::getName)
                            .filter(map::containsKey)
                            .map(e -> new AbstractMap.SimpleImmutableEntry<>(e, map.get(e)))
                            .sorted(Comparator.comparingInt(e -> columnList.indexOf(e.getValue())))
                            .forEach(e -> convertMap.put(e.getKey(), e.getValue()));
                    triple = Triple.of(tableName, entry, Collections.unmodifiableMap(convertMap));
                    CLASS_CACHE.put(clazz, triple);
                }
            }
        }
        logger.info("class {} ===>>> table {}", clazz.getName(), triple.getLeft());
        logger.info("id {} ===>>> column {}", triple.getMiddle().getKey().getName(), triple.getMiddle().getValue());
        triple.getRight().forEach((key, val) -> logger.info("property {} ===>>> column {}", key, val));
        return triple;
    }

    @Override
    public  T insert(T obj, boolean skipBlank) {
        Triple, Map> tableInfo = getTableInfo(obj);
        Field idField = tableInfo.getMiddle().getKey();
        ReflectionUtils.makeAccessible(idField);
        Object idValue = ReflectionUtils.getField(idField, obj);
        if (ObjectUtils.isEmpty(idValue)) {
            ReflectionUtils.setField(idField, obj, idGenerator());
        }
        insert(tableInfo.getLeft(), buildMap(obj, tableInfo.getRight(), skipBlank));
        return obj;
    }

    @Override
    public void batchInsert(Collection objs) {
        objs.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(Object::getClass)).forEach((key, val) -> {
            Triple, Map> tableInfo = getTableInfo(key);
            StringBuilder stringBuilder = new StringBuilder("INSERT INTO ");
            stringBuilder.append(tableInfo.getLeft());
            stringBuilder.append(tableInfo.getRight().values().stream().collect(Collectors.joining(" , ", " ( ", " ) ")));
            stringBuilder.append("VALUES");
            stringBuilder.append(tableInfo.getRight().values().stream().map(e -> "?").collect(Collectors.joining(" , ", " ( ", " ) ")));
            String sql = stringBuilder.toString();
            List batchArgs = new ArrayList<>();
            Field idField = tableInfo.getMiddle().getKey();
            ReflectionUtils.makeAccessible(idField);
            val.forEach(obj -> {
                Object idValue = ReflectionUtils.getField(idField, obj);
                if (ObjectUtils.isEmpty(idValue)) {
                    ReflectionUtils.setField(idField, obj, idGenerator());
                }
                Map map = buildMap(obj, tableInfo.getRight(), false);
                batchArgs.add(map.values().toArray());
            });
            logger.info("sql = {}", sql);
            batchArgs.forEach(e -> logger.info("args = {}", Arrays.asList(e)));
            getJdbcTemplate().batchUpdate(sql, batchArgs);
        });
    }

    @Override
    public  T updateById(T obj, boolean skipBlank) {
        Triple, Map> tableInfo = getTableInfo(obj);
        update(tableInfo.getLeft(), buildMap(obj, tableInfo.getRight(), skipBlank), tableInfo.getMiddle().getValue());
        return obj;
    }

    @Override
    public void batchUpdate(Collection objs) {
        objs.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(Object::getClass)).forEach((key, val) -> {
            Triple, Map> tableInfo = getTableInfo(key);
            StringBuilder stringBuilder = new StringBuilder("UPDATE ");
            stringBuilder.append(tableInfo.getLeft());
            stringBuilder.append(" SET ");
            stringBuilder.append(tableInfo.getRight().values().stream().filter(e -> ObjectUtils.notEqual(e, tableInfo.getMiddle().getValue())).map(e -> e.concat(" = ?")).collect(Collectors.joining(" , ")));
            stringBuilder.append(" WHERE ");
            stringBuilder.append(tableInfo.getMiddle().getValue().concat(" = ?"));
            String sql = stringBuilder.toString();
            List batchArgs = new ArrayList<>();
            val.forEach(obj -> {
                Map map = buildMap(obj, tableInfo.getRight(), false);
                Object idValue = map.remove(tableInfo.getMiddle().getValue());
                batchArgs.add(ArrayUtils.add(map.values().toArray(), idValue));
            });
            logger.info("sql = {}", sql);
            batchArgs.forEach(e -> logger.info("args = {}", Arrays.asList(e)));
            getJdbcTemplate().batchUpdate(sql, batchArgs);
        });
    }

    @Override
    public  T insertOrUpdate(T obj, boolean skipBlank) {
        Triple, Map> tableInfo = getTableInfo(obj);
        Field idField = tableInfo.getMiddle().getKey();
        ReflectionUtils.makeAccessible(idField);
        Object idValue = ReflectionUtils.getField(idField, obj);
        if (ObjectUtils.isEmpty(idValue)) {
            ReflectionUtils.setField(idField, obj, idGenerator());
            insert(tableInfo.getLeft(), buildMap(obj, tableInfo.getRight(), skipBlank));
        } else {
            Map map = getMap(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValue);
            if (Objects.isNull(map)) {
                insert(tableInfo.getLeft(), buildMap(obj, tableInfo.getRight(), skipBlank));
            } else {
                update(tableInfo.getLeft(), buildMap(obj, tableInfo.getRight(), skipBlank), tableInfo.getMiddle().getValue());
            }
        }
        return obj;
    }

    @Override
    public void batchInsertOrUpdate(Collection objs) {
        List insertList = new ArrayList<>();
        List updateList = new ArrayList<>();
        objs.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(Object::getClass)).forEach((key, val) -> {
            Triple, Map> tableInfo = getTableInfo(key);
            Field idField = tableInfo.getMiddle().getKey();
            ReflectionUtils.makeAccessible(idField);
            List idList = val.stream().map(e -> ReflectionUtils.getField(idField, e)).filter(ObjectUtils::isNotEmpty).collect(Collectors.toList());
            Map>> idGroup = getList(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idList).stream().collect(Collectors.groupingBy(e -> e.get(tableInfo.getMiddle().getValue())));
            val.forEach(obj -> {
                Object idValue = ReflectionUtils.getField(idField, obj);
                if (ObjectUtils.isEmpty(idValue)) {
                    insertList.add(obj);
                } else if (idGroup.containsKey(idValue)) {
                    updateList.add(obj);
                } else {
                    insertList.add(obj);
                }
            });
        });
        batchInsert(insertList);
        batchUpdate(updateList);
    }

    @Override
    public  int deleteById(T obj) {
        Triple, Map> tableInfo = getTableInfo(obj);
        Field idFiled = tableInfo.getMiddle().getKey();
        ReflectionUtils.makeAccessible(idFiled);
        Object idValue = ReflectionUtils.getField(idFiled, obj);
        return delete(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValue);
    }

    @Override
    public void batchDelete(Collection objs) {
        objs.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(Object::getClass)).forEach((key, val) -> {
            Triple, Map> tableInfo = getTableInfo(key);
            Field idFiled = tableInfo.getMiddle().getKey();
            ReflectionUtils.makeAccessible(idFiled);
            List idValues = val.stream().map(e -> ReflectionUtils.getField(idFiled, e)).collect(Collectors.toList());
            batchDelete(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValues);
        });
    }

    @Override
    public  int delete(ID idValue, Class mappedClass) {
        Triple, Map> tableInfo = getTableInfo(mappedClass);
        return delete(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValue);
    }

    @Override
    public  int batchDelete(Collection idValues, Class mappedClass) {
        Triple, Map> tableInfo = getTableInfo(mappedClass);
        return batchDelete(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValues);
    }

    @Override
    public  T getBean(ID idValue, Class mappedClass) {
        Triple, Map> tableInfo = getTableInfo(mappedClass);
        return getBean(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValue, mappedClass);
    }

    @Override
    public  List getBeans(Collection idValues, Class mappedClass, String... orderBy) {
        Triple, Map> tableInfo = getTableInfo(mappedClass);
        return getBeans(tableInfo.getLeft(), tableInfo.getMiddle().getValue(), idValues, mappedClass, orderBy);
    }

    @Override
    public  int delete(T example) {
        Triple, Map> tableInfo = getTableInfo(example);
        return delete(tableInfo.getLeft(), buildMap(example, tableInfo.getRight()));
    }

    @Override
    public  T getBean(T example) {
        Triple, Map> tableInfo = getTableInfo(example);
        return getBean(tableInfo.getLeft(), buildMap(example, tableInfo.getRight()), (Class) example.getClass());
    }

    @Override
    public  List getBeans(T example, String... orderBy) {
        Triple, Map> tableInfo = getTableInfo(example);
        return getBeans(tableInfo.getLeft(), buildMap(example, tableInfo.getRight()), (Class) example.getClass(), orderBy);
    }

    @Override
    public  PageResult getPage(T example, long pageNum, long pageSize, String... orderBy) {
        Triple, Map> tableInfo = getTableInfo(example);
        return selectPage(tableInfo.getLeft(), buildMap(example, tableInfo.getRight()), pageNum, pageSize, (Class) example.getClass(), orderBy);
    }
}