hibernate原生sql自动序列化为实体类
如果使用了原生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);
}
构造自动转换器
在容器加载后,给需要的类添加转换器
- 定义一个注解,给需要转换的类上添加
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JpaDtoConverter {
}
- 自动添加转换器
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加载失败");
}
}
}
你要是觉得写的还不错,就点个关注,可以评论区留下足迹,以后方便查看.
你要是觉得写的很辣鸡,评论区欢迎来对线!
欢迎转载!