SpringBoot+jpa+hibernate返回json数据实现按需加载数据

96
山猫233
2017.07.10 15:15* 字数 512
  1. 使用spring boot默认的jpa和hibernate实现对象的映射非常方便,如果controller返回json对象,会发现,返回的json对象默认会把所有相关联的对象都加载出来,序列化成json数据,特别要命的是如果hibernate配置的是双向关联,还存在循环引用加载的问题。 这对于前后端分离的应用来说,非常要命。
  2. 如何实现按需加载

第一步:引入一个jackson官网开发的插件

<dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-hibernate5</artifactId>
            <version>2.9.0.pr4</version>
</dependency>

注意:这个插件根据你hibernate的版本号不同选择不同的,如果hibernate4,则选择 jackson-datatype-hibernate4

第二步: 重新实现自己的MappingJackson2HttpMessageConverter

MappingJackson2HttpMessageConverter是springMVC中几个常用转换器之一,功能就是把要返回到前端的数据转换成json格式结果。这个转换器默认的实现里会调用结果数据的get方法反射一层一层地进行转换,自然在这个过程中就会把懒加载的数据也一并序列化出来。所以我要用jackson-datatype-hibernateX重新注册一个model。 方法很简单在任意springboot能扫描到的位置注册一个bean,用我们自己json转换器覆盖原来的转换器。

@Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = jsonConverter.getObjectMapper();
        objectMapper.registerModule(new Hibernate5Module());
        
        return jsonConverter;
    }

同理这里根据hibernate版本号设置相应的 Hibernate*Module, 如你用的hibernate4,这里就是objectMapper.registerModule(new Hibernate4Module());

第三步,根据需要取自己需要的对象

按上面两步配置之后,默认转化出来的json数据不会加载任何懒加载的数据,而你需要对象下面的那个子对象数据,就需要自己在方法里显式的调用一下,如调用size()方法,这样就实现了我们自己的按需加载。如需要加载project项目下的模块

@RequestMapping(value = "/getAll")
    @ResponseBody
    public Map getAll(){
        Map<String, List<Project>> map = new HashMap<>();
        List<Project> projects = projectService.getAll();
        projects.forEach(project -> System.out.println(project.getModules().size()));
        map.put("data",projects);
        return map;
    }

这样做,即避免了循环引用的问题,也达到了按需所取的目的

随笔
Gupao