Spring MVC-如何在Rest Controller中将简单字符串作为JSON返回


137

我的问题实质上是对该问题的后续行动。

@RestController
public class TestController
{
    @RequestMapping("/getString")
    public String getString()
    {
        return "Hello World";
    }
}

在上面,Spring会将“ Hello World”添加到响应正文中。如何返回String作为JSON响应?我知道我可以添加引号,但这感觉更像是黑客。

请提供任何示例以帮助解释此概念。

注意:我不希望直接将其写到HTTP响应正文中,我想以JSON格式返回字符串(我将控制器与RestyGWT一起使用,这要求响应必须为有效JSON格式)。


您可以返回Map或包含字符串的任何对象/实体
Denys Denysiuk 2015年

因此,您是说要将String值序列化为JSON字符串吗?
Sotirios Delimanolis 2015年

Answers:


150

返回text/plain(例如,从Spring MVC 3 Controller返回仅字符串消息中),或者将String包装为某个对象

public class StringResponse {

    private String response;

    public StringResponse(String s) { 
       this.response = s;
    }

    // get/set omitted...
}


将您的响应类型设置为MediaType.APPLICATION_JSON_VALUE(= "application/json"

@RequestMapping(value = "/getString", method = RequestMethod.GET,
                produces = MediaType.APPLICATION_JSON_VALUE)

并且您将拥有一个类似于

{  "response" : "your string value" }

124
您也可以返回Collections.singletonMap("response", "your string value")以实现相同的结果,而不必创建包装器类。
Bohuslav Burghardt

@Bohuslav这是一个很好的提示。
2015年

6
它要求键和值是不正确的。单个字符串或字符串数​​组都是有效的JSON。如果您不同意,则可以解释为什么jsonlint网站将这两个都接受为有效JSON。
KyleM '02

2
包装器类如何转换为JSON?
Rocky Inde

3
我认为返回就足够了Collections.singleton("your string value")
gauee

54

JSON本质上是PHP或JAVA上下文中的字符串。这意味着可以返回有效的JSON字符串作为响应。以下应该工作。

  @RequestMapping(value="/user/addUser", method=RequestMethod.POST)
  @ResponseBody
  public String addUser(@ModelAttribute("user") User user) {

    if (user != null) {
      logger.info("Inside addIssuer, adding: " + user.toString());
    } else {
      logger.info("Inside addIssuer...");
    }
    users.put(user.getUsername(), user);
    return "{\"success\":1}";
  }

简单的字符串响应就可以了。但是对于复杂的JSON响应,您应该使用Shaun描述的wrapper类。


7
这是可以接受的答案,因为这是对OP问题的确切答案。
2016年

谢谢,@ ResponseBody是我所需要的
Riskop

好奇@ResponseBody在公共关键字之前或之后的“更好”位置是哪个?我一直把它放在后面,因为它更多地由返回值标识。
David Bradley

26

在一个项目中,我们使用JSONObject(maven 依赖项信息)解决了这一问题。我们之所以选择它,是因为我们更喜欢返回一个简单的String而不是包装对象。如果您不想添加新的依赖项,则可以轻松使用内部帮助程序类。

用法示例:

@RestController
public class TestController
{
    @RequestMapping("/getString")
    public String getString()
    {
        return JSONObject.quote("Hello World");
    }
}

1
也许您应该在答案中提到,这"\"Hello World\""与没有额外的依赖关系一样有效-那是什么JSONObject.quote(),对吗?
jerico '18

我不喜欢该解决方案,但是它对我有用。:-)
Michael Hegner

22

您可以JSON通过Stringin属性轻松返回,response如下所示

@RestController
public class TestController {
    @RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE)
    public Map getString() {
        return Collections.singletonMap("response", "Hello World");
    }
}

2
每当你使用“@RestController”,你不需要使用“@ResponseBody”
jitendra varshney

12

只需注销默认StringHttpMessageConverter实例:

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
  /**
   * Unregister the default {@link StringHttpMessageConverter} as we want Strings
   * to be handled by the JSON converter.
   *
   * @param converters List of already configured converters
   * @see WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)
   */
  @Override
  protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.stream()
      .filter(c -> c instanceof StringHttpMessageConverter)
      .findFirst().ifPresent(converters::remove);
  }
}

使用控制器动作处理程序方法和控制器异常处理程序进行了测试:

@RequestMapping("/foo")
public String produceFoo() {
  return "foo";
}

@ExceptionHandler(FooApiException.class)
public String fooException(HttpServletRequest request, Throwable e) {
  return e.getMessage();
}

最后说明:

  • extendMessageConverters从Spring 4.1.3开始可用,如果运行在以前的版本上,则可以使用来实现相同的技术configureMessageConverters,这将花费更多的工作。
  • 这是许多其他可能方法中的一种,如果您的应用程序仅返回JSON而没有其他内容类型,则最好跳过默认转换器并添加单个jackson转换器。另一种方法是添加默认转换器,但顺序不同,以使杰克逊转换器位于字符串一之前。这应该允许控制器操作方法决定它们如何根据响应的媒体类型转换字符串。

1
最好有一个示例代码来说明您的第二个最终音符。
Tony Baguette

1
converters.removeIf(c -> c instanceof StringHttpMessageConverter)
克莱里斯-cautiouslyoptimistic-

10

我知道这个问题很旧,但我也想贡献一点:

其他响应之间的主要区别是哈希图返回。

@GetMapping("...")
@ResponseBody
public Map<String, Object> endPointExample(...) {

    Map<String, Object> rtn = new LinkedHashMap<>();

    rtn.put("pic", image);
    rtn.put("potato", "King Potato");

    return rtn;

}

这将返回:

{"pic":"a17fefab83517fb...beb8ac5a2ae8f0449","potato":"King Potato"}

2
为什么要声明该方法返回HashMap?LHM实现Map。
JL_SO

6

简单点:

    @GetMapping("/health")
    public ResponseEntity<String> healthCheck() {
        LOG.info("REST request health check");
        return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK);
    }

对我来说,使用ResponseEntity似乎是最先进的。+1
亚历山大

5

添加produces = "application/json"@RequestMapping像注释:

@RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")

提示:作为返回值,我建议使用ResponseEntity<List<T>>type。因为JSON主体中产生的数据根据其规范需要是数组对象,而不是单个简单的string。有时可能会引起问题(例如Angular2中的Observables)。

区别:

返回String的JSON:"example"

返回List<String>的JSON:["example"]


3

添加@ResponseBody注释,这将在输出流中写入返回数据。


1
这对我不起作用。我有@PostMapping(value = "/some-url", produces = APPLICATION_JSON_UTF8_VALUE)
aliopi

0

这个问题使我发疯了:Spring是一种强大的工具,但是,如果没有丑陋的hack,将输出字符串写为JSON这样简单的事情似乎是不可能的。

我发现(在Kotlin中)侵入性最小,最透明的解决方案是使用控制器建议,并检查请求是否到达了一组特定的端点(通常是REST API,因为我们通常希望从此处返回所有答案作为JSON而不根据返回的数据是纯字符串(“不要进行JSON反序列化!”)还是其他方式(“进行JSON反序列化!”)对前端进行专业化处理。积极的一面是,控制器保持不变,没有被黑客入侵。

supports方法确保处理了所有由StringHttpMessageConverter(例如,处理返回纯字符串的所有控制器的输出的转换器)处理的请求,并且在该beforeBodyWrite方法中,我们控制在哪种情况下我们要中断并将输出转换为JSON (并相应地修改标题)。

@ControllerAdvice
class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> {
    
    override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
        converterType === StringHttpMessageConverter::class.java

    override fun beforeBodyWrite(
        body: Any?,
        returnType: MethodParameter,
        selectedContentType: MediaType,
        selectedConverterType: Class<out HttpMessageConverter<*>>,
        request: ServerHttpRequest,
        response: ServerHttpResponse
    ): Any? {
        return if (request.uri.path.contains("api")) {
            response.getHeaders().contentType = MediaType.APPLICATION_JSON
            ob.writeValueAsString(body)
        } else body
    }
}

我希望将来会得到一个简单的注释,在其中可以覆盖HttpMessageConverter应该用于输出的注释。


-5

将此注释添加到您的方法中

@RequestMapping(value = "/getString", method = RequestMethod.GET, produces = "application/json")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.