SpringBoot+jpa+hibernate返回json数据

作者: 山猫233 | 来源:发表于2017-07-10 15:15 被阅读1545次
    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;
        }
    

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

    相关文章

      网友评论

      • a6893ae6ba15:总表:
        Eva{
        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumns({
        @JoinColumn(name="patientId",referencedColumnName = "patientId",insertable = false,updatable = false),
        @JoinColumn(name="doctorId",referencedColumnName = "doctorId",insertable = false,updatable = false),
        })
        @NotFound(action= NotFoundAction.IGNORE)
        private ViewDoctorPatient doctorPatient; //APP查所有测评记录list时,关联患者信息
        }
        ================
        控制层,只查总表eva:
        @GetMapping("/findByHospitalId")
        public Response<List<PatientEva>> findByHospitalId(Long hospitalId) {
        return service.findByHospitalId(hospitalId);
        }
        =============
        按照老铁的做法,还是执行了一大波查用户表的sql,甚至记录过多,会导致微服务超时;
        求指导啊:sob:
        a6893ae6ba15:@山猫233 恩,感谢大佬了~
        山猫233:@Ecin OneToOne 默认是立即加载的,跟Json没关系的,如果不想查出相关联的,可以用JDBCTemplate去查询
      • 最爱的诺兰:我试了下,不管用,还是会进行查询
        最爱的诺兰:https://stackoverflow.com/a/43236442/9804011,我通过这个配置倒是成功了,rest接口在返回json的时候确实不会在懒加载集合的数据了,感觉你和这个的配置一样:flushed:
        最爱的诺兰:@山猫233 嗯,是懒加载,用的spring boot jpa。我搜了好多资料,有的说有用有的说没用,
        https://stackoverflow.com/questions/47989857/jackson-triggering-jpa-lazy-fetching-on-serialization,我和这个例子很相似,都是查询这种1对多的,多的是懒加载,然后用spring boot 的rest处理返回结果,可是返回结果还是会对懒加载的数据进行加载(子查询):joy:
        山猫233:能说具体些吗,首先你查询要是懒加载的

      本文标题:SpringBoot+jpa+hibernate返回json数据

      本文链接:https://www.haomeiwen.com/subject/nsoyhxtx.html