V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
FreeBSD
V2EX  ›  Java

Spring Boot 如果 RestController 中返回 null,则不会走进自定义 MappingJackson2HttpMessageConverter?

  •  
  •   FreeBSD · 2018-05-04 18:28:12 +08:00 · 7495 次点击
    这是一个创建于 2388 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1. RestController 的代码

        @GetMapping("/{id}")
        @ResponseBody
        XXDto findById(@PathVariable String id) {
            return service.findById(id); // 此处如果返回 null,相应的转换没有做
        }
    

    2. 代码 MappingJackson2HttpMessageConverter

    @Configuration
    public class HttpMessageConverter {
        @Bean
        public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    
            return new MappingJackson2HttpMessageConverter() {
                @Override
                protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
                    if (object instanceof ArrayList) {
                        List list = (List) object;
                        if (!list.isEmpty()) {
                            if (list.get(0) instanceof SwaggerResource) {
                                super.writePrefix(generator, object);
                                return;
                            }
                        }
                    }
    
                    if (object instanceof Json || object instanceof SecurityConfiguration || object instanceof UiConfiguration) {
                        super.writePrefix(generator, object);
                        return;
                    }
    
                    generator.writeRaw("{\"code\": 0, \"result\": ");
                    super.writePrefix(generator, object);
                }
    
                @Override
                protected void writeSuffix(JsonGenerator generator, Object object) throws IOException {
                    if (object instanceof ArrayList) {
                        List list = (List) object;
                        if (!list.isEmpty()) {
                            if (list.get(0) instanceof SwaggerResource) {
                                super.writeSuffix(generator, object);
                                return;
                            }
                        }
                    }
    
                    if (object instanceof Json || object instanceof SecurityConfiguration || object instanceof UiConfiguration) {
                        super.writeSuffix(generator, object);
                        return;
                    }
    
                    generator.writeRaw("}");
                    super.writeSuffix(generator, object);
                }
            };
        }
    }
    

    3. 问题

    当上述 1 中方法返回 null 时,2 中的 writePrefix 和 writeSuffix 不会被调到?有什么办法解决这个问题吗?

    11 条回复    2018-05-16 17:59:34 +08:00
    letitbesqzr
        1
    letitbesqzr  
       2018-05-04 21:27:28 +08:00
    Spring mvc 在 RequestResponseBodyMethodProcesser 会检测返回结果是不是 null , 如果不为 null 才会走 HttpMessageConverter 去处理。
    letitbesqzr
        2
    letitbesqzr  
       2018-05-04 21:35:42 +08:00
    纠错,是 org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor

    如果确实要返回的 null 走你自己的 HttpMessageConverter, 建议自己去覆盖 RequestResponseBodyMethodProcessor 以接受 null。 或者自己定义一个 annotation @ResponseBodyNull 创建一个对应的 HandlerMethodReturnValueHandler
    aa6563679
        3
    aa6563679  
       2018-05-05 00:05:23 +08:00 via iPhone
    我记得在 spring mvc 里如果要手动处理 HttpServletResponse 就需要返回 null 或 void
    FreeBSD
        4
    FreeBSD  
    OP
       2018-05-05 11:10:55 +08:00
    @letitbesqzr 感谢。看来只能手撸了。我之前还想过 AOP 的招
    FreeBSD
        5
    FreeBSD  
    OP
       2018-05-05 16:53:36 +08:00
    按照[Custom HttpMessageConverter in Spring MVC]( https://stackoverflow.com/questions/22890952/custom-httpmessageconverter-in-spring-mvc) 没有成功
    BBCCBB
        6
    BBCCBB  
       2018-05-05 18:22:43 +08:00
    建议你外面套一层
    ```java
    class Response<T> {
    int code;
    String msg;
    T value;
    }
    ```
    然后返回一个 Response<XXDto>
    FreeBSD
        7
    FreeBSD  
    OP
       2018-05-05 19:55:08 +08:00 via Android
    @BBCCBB 嗯,是个方法,但是比较土啊
    BBCCBB
        8
    BBCCBB  
       2018-05-05 20:11:50 +08:00
    @FreeBSD 额,这个方法绝壁不土,我待过的公司都是这种套路,因为你失败的时候可以返回具体的 code 和失败原因 msg,也便于前台展示
    FreeBSD
        9
    FreeBSD  
    OP
       2018-05-05 21:49:42 +08:00
    @letitbesqzr 按照#5 楼链接的实现,发现还是有问题。转换时并没调用自定义的 RequestResponseBodyMethodProcessor 中的 handleReturnValue 方法。能再给点建议吗?
    cqy2016
        10
    cqy2016  
       2018-05-06 14:59:50 +08:00   ❤️ 1
    想在方法上省掉 wrapper 的话,扩展不应该用 message convert
    提供一个 ResponseBodyAdvice 就行了
    james2013
        11
    james2013  
       2018-05-16 17:59:34 +08:00   ❤️ 1
    以前也是用 BBCCBB 的方法,cqy2016 说的很好,试了下,完美解决楼主的问题,并且做了其它几个方面的适配:
    @ControllerAdvice
    public class MyResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    if("org.springframework.http.converter.json.MappingJackson2HttpMessageConverter".equals(converterType.getName())){
    return true;
    }
    return false;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    if(body instanceof BaseResponseBean) return body;
    return ResponseUtil.turnData(body);
    }
    }
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1806 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 16:39 · PVG 00:39 · LAX 08:39 · JFK 11:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.