一个通用的Spring Data JPA查询函数

1,781 阅读1分钟

在使用Spring Data JPA进行数据库查询的场景下,经常需要进行结果的映射,不仅加大了工作量,而且编写出来的代码很丑陋,看到那种代码就不想去维护。

以下是本人编写的一个通用型的函数,或可解决这一问题:

环境:spring jpa2.0.8 hibernate-core 5.2.17.Final

package com.cec.dao;

import com.cec.bind.BeanCreater;
import com.cec.exception.CustomException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.hibernate.Session;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.hibernate.type.*;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.EntityManager;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
 * Created by Trace on 2018-07-24.<br/>
 * Desc: entityManager通用型查找类
 */
@SuppressWarnings("unused")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class BaseEm<T> {

    /**
     * 通过entityManager对象构建通用型查找函数.<br/>
     * @param sql         SQL查询语句
     * @param queryParams 需替换的参数K-V
     * @param clazz 映射的结果类型
     * @param paramTypes  返回的各个字段类型
     * @return 查找的结果列表
     */
    public static<T> List<T> query(@Nonnull String sql, @Nullable Map<String, Object> queryParams,
                         @Nonnull Class<T> clazz, @Nonnull Class<?>... paramTypes) {
        EntityManager em = BeanCreater.getBean(EntityManager.class);
        assert em != null;
        NativeQuery query = em.unwrap(Session.class).createNativeQuery(sql);

        if (Objects.nonNull(queryParams) && queryParams.size() > 0) {
            for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
                query.setParameter(entry.getKey(), entry.getValue());
            }
        }

        try {
            Constructor<T> constructor = clazz.getConstructor(paramTypes);
            LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
            String[] params = discoverer.getParameterNames(constructor);
            assert params != null;
            for (int i = 0; i < params.length; i++) {
                Type hibernateType = java2Hibernate(paramTypes[i]);
                query.addScalar(params[i], hibernateType);
            }
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(clazz));
            return query.getResultList();
        } catch (NoSuchMethodException e) {
            throw new CustomException("没有匹配paramTypes的构造器: " + e.getMessage());
        } finally {
            em.close();
        }
    }


    /**
     * 将java类型转换成hibernate类型.<br/>
     * @param javaClass java类型
     * @return hibernate类型
     */
    private static Type java2Hibernate(Class<?> javaClass) {
        Map<Class, Type> map = new HashMap<>();
        map.put(Boolean.class, StandardBasicTypes.BOOLEAN);
        map.put(Byte.class, StandardBasicTypes.BYTE);
        map.put(Short.class, StandardBasicTypes.SHORT);
        map.put(Integer.class, StandardBasicTypes.INTEGER);
        map.put(Long.class, StandardBasicTypes.LONG);
        map.put(Float.class, StandardBasicTypes.FLOAT);
        map.put(Double.class, StandardBasicTypes.DOUBLE);
        map.put(BigInteger.class, StandardBasicTypes.BIG_INTEGER);
        map.put(BigDecimal.class, StandardBasicTypes.BIG_DECIMAL);
        map.put(Character.class, StandardBasicTypes.CHARACTER);
        map.put(String.class, StandardBasicTypes.STRING);
        map.put(Date.class, StandardBasicTypes.DATE);
        map.put(Time.class, StandardBasicTypes.TIME);
        map.put(Timestamp.class, StandardBasicTypes.TIMESTAMP);
        map.put(Calendar.class, StandardBasicTypes.CALENDAR);
        map.put(TimeZone.class, StandardBasicTypes.TIMEZONE);
        map.put(LocalDate.class, LocalDateType.INSTANCE);
        map.put(LocalTime.class, LocalTimeType.INSTANCE);
        map.put(LocalDateTime.class, LocalDateTimeType.INSTANCE);
        map.put(Locale.class, StandardBasicTypes.LOCALE);
        map.put(Currency.class, StandardBasicTypes.CURRENCY);
        return map.getOrDefault(javaClass, StandardBasicTypes.SERIALIZABLE);
    }

}


调用示例:


仅供参考,全文完!