【问题标题】:Spring Ajax @ResponseBody with null returned valuesSpring Ajax @ResponseBody 返回值为空
【发布时间】:2014-10-28 07:27:03
【问题描述】:

我有大约 50 个使用 @ResponseBody 注释的控制器。

像这样:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET)
public @ResponseBody Object getObject(@RequestParam("id") Long id) {
    Object object = provider.getObject(id);
    return object;
}

有时getObject 方法返回null。问题是在客户端我得到 empty response 而不是 null

在最初的实现中,我们有自定义的JsonView 对象,它可以作为没有@ResponseBody 注释的包装器。

像这样:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET)
public JsonView<Object> getObject(@RequestParam("id") Long id) {
    Object object = provider.getObject(id);
    return new JsonView(object);
}

所以它工作正常。

我在How do you override the null serializer in Jackson 2.0? 找到了一些解决方案,但不幸的是它仅适用于 POJO 中的字段。

你知道如何处理它吗?

提前致谢!

【问题讨论】:

  • 你能告诉我们这个通用的JsonView 类来自哪个库吗?

标签: java ajax spring jackson


【解决方案1】:

这不是一个容易解决的问题。

Spring 有一个常见的模式,如果处理程序方法返回null,则表示处理程序已经处理了生成和写入适当的响应内容,并且前面不需要进一步的操作。

Spring 在其RequestResponseBodyMethodProcesser@ResponseBodyHandlerMethodReturnValueHandler 实现)中应用了这种模式。它检查返回值是否为null。它将请求设置为已处理。如果返回值不是null,它会尝试使用适当的HttpMessageConverter 对其进行序列化。

一种选择是创建自己的@ResponseBodyNull 注释和相应的HandlerMethodReturnValueHandler,除了处理null 之外,它的作用相同。请注意,您不一定能重用来自RequestResponseBodyMethodProcess 的代码,因为某些HttpMessageConverters 尝试使用null 会失败。

另一个类似的选项是覆盖RequestResponseBodyMethodProcessor 以接受null(具有上述限制)并将其显式注册到您的RequestMappingHandlerMapping,覆盖默认的HandlerMethodReturnValueHandlers。您必须小心执行此操作(即注册相同的),除非您想失去功能。

IMO 更好的解决方案是不在响应正文中处理 null。如果getObject 没有返回任何东西,那对我来说似乎是 404。设置适当的响应代码,瞧!

您总是可以将HttpServletResponse 注入您的处理程序方法并执行类似的操作

Object object = getObject(..);
if (object == null) {
    response.getWriter().print("null");
    // also set the content type to application/json
}
return object;

假设您知道这必须序列化为 JSON。

【讨论】:

    【解决方案2】:

    当对象为空时,您可以返回一个 ResponseEntity 并将 HTTP 状态指定为错误:

    @RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET)
    public ResponseEntity<Object> getObject(@RequestParam("id") Long id) {
        Object object = provider.getObject(id);
        if (object == null ) {
            return new ResponseEntity<Object> (HttpStatus.BAD_REQUEST); // Or any other error status
        } else {
            return new ResponseEntity<Object> (object, HttpStatus.OK);
        }
    }
    

    通过这种方式,您的客户端将能够知道对象何时为空,检查响应状态。

    如果您确实需要返回的 null 值,您可以配置 Jackson 对其进行序列化(代码来自 tkuty):

    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                        <property name="serializationInclusion">
                            <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
                        </property>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    希望对你有所帮助。

    【讨论】:

    • 不幸的是,任何方法在我的情况下都不起作用:1)第一个继续返回空响应,因为以下代码存在于:Object body = responseEntity.getBody(); if (body != null) { writeWithMessageConverters(body, returnType, inputMessage, outputMessage); } else { // 将标头刷新到 HttpServletResponse outputMessage.getBody(); }。所以它只是 preint null 作为 priviues 并避免 writeWithMessageConverters 方法。
    • 您的第二个建议不起作用,因为null 永远不会到达MappingJackson2HttpMessageConverter,它将停在RequestResponseBodyMethodProcessor
    【解决方案3】:

    首先,我建议你不要这样写:

    @RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET)
    public @ResponseBody Object getObject(@RequestParam("id") Long id) {
        /*
        */
    }
    

    将其作为标准代码。试试这个:

    @RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET)
    @ResponseBody
    public Object getObject(@RequestParam("id") Long id) {
        Object object = provider.getObject(id);
        return object;
    }
    

    我有高质量扫描仪的经验,这种方式可以帮助您避免扫描仪发现的错误。关于您的问题,您可以尝试使用 Transformer 或 addScala() 来返回 POJO。我遇到了这个麻烦,做了一笔交易!祝你好运。

    【讨论】:

    • 你的意思是在方法签名下指定注解,因为这个会引发“Duplicate annotation @ResponseBody”编译错误?谢谢!
    • 不,我的意思是,您不应该在访问器之后和方法的数据类型之前放置注释。用我的方式。 Quality Scanner(例如 SonarQube)会意识到这是一个重大错误,需要重构!我面对它并获得经验。那不是“重复注释”编译错误。它会正确编译,但你应该标准化你的代码。
    • 这是怎么回事?这可能是代码风格的观点,但绝对不是错误。而你的回答并没有回答问题。
    • 是的!这不是语法错误,但如果您应用质量等级。这是一个重大错误,应该改正!如果您不相信,请检查 SonarQube 规则并找出原因!
    • 我不知道您所说的质量等级是什么意思,也不知道您所说的重大错误是什么意思。我了解 SonarQube 不喜欢将其作为其代码政策的一部分。无论如何,您的回答并不能解决问题。
    猜你喜欢
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2011-06-18
    • 2014-12-12
    相关资源
    最近更新 更多