欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于Spring Data JPA转换自定义实体的一些方案

程序员文章站 2022-04-23 15:57:28
...

使用JPA的时候,对于特别复杂的关联查询总是显得很麻烦,对于这个问题,网上有很多解决方案,但是有的尝试之后又发现并不成功,所以决定自己写一个转换类工具类,留作记录

import org.hibernate.transform.ResultTransformer;

import java.util.List;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import org.apache.commons.lang.StringUtils;
import org.hibernate.HibernateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.util.NumberUtils;

import java.sql.Date;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @desc 转化自定义实体类的工具类,一般情况没问题,给大家使用
 * <p>
 * @author Leao.lv
 */
public class IgnoreTypeeResultTransformer implements ResultTransformer {

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

    private static final long serialVersionUID = -3779317531110592988L;

    public static ConcurrentMap<String, BeanMap> beanMapCache = new ConcurrentHashMap<String, BeanMap>();
    private final Class<?> resultClass;

    public IgnoreTypeeResultTransformer(final Class<?> resultClass) {
        this.resultClass = resultClass;
    }

    private BeanMap getBeanMap(Object object) {
        return BeanMap.create(object);
    }

    private Object transforObject(Object src, Class dest) throws ClassCastException, IllegalArgumentException {
        Object clo = null;
        String arrayStr = null;
        if (dest.equals(String.class)) {
            clo = arrayStr;
        } else if (dest.getSuperclass().equals(Number.class) || dest.equals(Number.class)) {
            // 只处理 字符转入 或 数值类型转入
            clo = NumberUtils.parseNumber(src.toString(), dest);
        } else if (dest.getSuperclass().equals(Instant.class) || dest.equals(Instant.class)) {
            Timestamp tp = (Timestamp) src;
            clo = tp.toInstant();
        }else if (dest.getSuperclass().equals(LocalDate.class) || dest.equals(LocalDate.class)) {
            Date tp = (Date) src;
            clo =  tp.toLocalDate();
        }  else {
            //error 设置 null
            logger.error("未转化值src:{}, dest:{}", src, dest);
        }
        return clo;
    }

    /**
     * aliases为每条记录的数据库字段名,
     * tupe为与aliases对应的字段的值
     */
    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        Object result;
        try {
            result = resultClass.newInstance();
            BeanMap beanMap = getBeanMap(result);
            for (int i = 0, len = tuple.length; i < len; i++) {
                String key = BeanNaming.underLineToCamel(aliases[i]);
                Class target = beanMap.getPropertyType(key);
                if (target == null) {
                    continue;
                }
                Object src = tuple[i];
                if (src != null && !src.getClass().equals(target)) {
                    //存在需要转化的的值。。
                    src = transforObject(src, target);
                }
                beanMap.put(key, src);
            }

        } catch (Exception e) {
            throw new HibernateException("Could not instantiate resultclass: " + this.resultClass.getName(), e);
        }
        return result;
    }

    @Override
    public List transformList(List collection) {
        return collection;
    }

    private static class BeanNaming extends PropertyNamingStrategy.SnakeCaseStrategy {
        private static final char UNDERLINE = '_';
        public static Map<String, String> CACHING = new ConcurrentHashMap<>();

        protected static String underLineToCamel(String param) {
            if (StringUtils.isBlank(param)) {
                return "";
            }
            if (param.indexOf(UNDERLINE) == -1) {
                //不需要转化
                return param;
            }
            if (CACHING.containsKey(param)) {
                return CACHING.get(param);
            }
            int len = param.length();
            StringBuilder sb = new StringBuilder(len);
            for (int i = 0; i < len; i++) {
                char c = param.charAt(i);
                if (c == UNDERLINE) {
                    if (++i < len) {
                        sb.append(Character.toUpperCase(param.charAt(i)));
                    }
                } else {
                    sb.append(c);
                }
            }
            CACHING.put(param, sb.toString());
            return sb.toString();
        }
    }
}

用法是
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.hibernate.query.internal.NativeQueryImpl;

 Query query = entityManager.createNativeQuery(sql.toString());
  query.unwrap(NativeQueryImpl.class).setResultTransformer(new IgnoreTypeeResultTransformer(对应实体.class)).list();
相关标签: jpa Spring data Jpa