hibernate原生sql自动序列化为实体类

发布时间 2023-05-24 18:04:25作者: rm-rf*

如果使用了原生sql查询,无法用实体类接收结果,如果用map<String,Object>接收又很麻烦

代码中name2方法用了原生sql查询,会报错

@Repository
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {

    @Query(value = "select new site.yalong.bark.hibernate.resp.Resp(u.firstName,u.site.id) from User as u where u.id >=?1")
    Page<Resp> name(Long id, PageRequest pageable);

    @Query(nativeQuery = true, value = "select a.first_name as firstName,b.id as id from `user` as a inner join `site`as b on a.sid =b.id where a.id >=?1 limit 10")
    List<Resp> name2(Long id);
}

构造自动转换器

在容器加载后,给需要的类添加转换器

  1. 定义一个注解,给需要转换的类上添加
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JpaDtoConverter {
}
  1. 自动添加转换器
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import java.io.IOException;
import java.util.Map;

/**
 * @author YaLong
 * @date 2023/5/18
 */
@Slf4j
@Configuration
@SuppressWarnings("all")
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //只获取root容器,否则多个容器加载完成后,会重复调用
        if (event.getApplicationContext().getParent() != null) {
            return;
        }
        final String BASE_PACKAGE_PATH = "site.yalong";
        final String RESOURCE_PATTERN = "/**/*.class";
        String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE_PATH) + RESOURCE_PATTERN;
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        GenericConversionService genericConversionService = ((GenericConversionService) DefaultConversionService.getSharedInstance());
        CopyOptions copyOptions = CopyOptions.create()
                .setIgnoreCase(true)
                .setIgnoreError(true)
                .setIgnoreNullValue(true)
                .setFieldNameEditor(StrUtil::toUnderlineCase);
        try {
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                if (resource.isReadable()) {
                    MetadataReader reader = readerFactory.getMetadataReader(resource);
                    //扫描到的class
                    String className = reader.getClassMetadata().getClassName();
                    Class clazz = Class.forName(className);
                    //判断是否有指定注解
                    JpaDtoConverter annotation = (JpaDtoConverter) clazz.getAnnotation(JpaDtoConverter.class);
                    if (annotation != null) {
                        //这个类使用了自定义注解,给它添加转换器
                        genericConversionService.addConverter(Map.class,
                                clazz,
                                m -> {
                                    try {
                                        Object o = clazz.getDeclaredConstructor().newInstance();
                                        return BeanUtil.mapToBean(m, o.getClass(), true, copyOptions);
                                    } catch (Exception e) {
                                        throw new RuntimeException(e);
                                    }

                                }
                        );

                    }
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            log.error("读取class失败", e);
            throw new RuntimeException("MyApplicationListener加载失败");
        }
    }

}