Spring MVC-如何返回简单的字符串作为 JSON 在休息控制器

我的问题本质上是 这个问题的后续。

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

在上面的代码中,Spring 将在响应主体中添加“ Hello World”。如何返回一个 String 作为 JSON 响应?我知道我可以加引号,但那更像是黑客行为。

请提供任何例子来帮助解释这个概念。

注意: 我不想直接写到 HTTP 响应主体中,我想以 JSON 格式返回 String (我使用的是 Controller) 使用 RestyGWT,它要求响应为有效的 JSON 格式)。

477949 次浏览

返回 text/plain(如在 只从 SpringMVC3控制器返回字符串消息中)或者包装您的 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)

你会得到一个 JSON,看起来像

{  "response" : "your string value" }

JSON 本质上是 PHP 或 JAVA 上下文中的一个 String。这意味着可以响应返回有效 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 所描述的包装器类。

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

示例用法:

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

只需注销默认的 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.removeIf(c -> c instanceof StringHttpMessageConverter);
}
}

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

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


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

最后注意事项:

  • 自 Spring4.1.3以来,extendMessageConverters就可以使用了,如果在以前的版本上运行,那么可以使用 configureMessageConverters实现相同的技术,只是需要多做一点工作。
  • 这是许多其他可能方法中的一种,如果应用程序只返回 JSON 而不返回其他内容类型,那么最好跳过默认转换器并添加一个 jackson 转换器。另一种方法是添加默认转换器,但是顺序不同,这样杰克逊转换器优先于字符串1。这应该允许控制器操作方法根据响应的媒体类型来规定它们希望 String 如何转换。

@RequestMapping注释中添加 produces = "application/json",如下所示:

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

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

区别:

返回 String作为 json: "example"

返回 List<String>作为 json: ["example"]

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

在属性 response中,可以很容易地返回 JSONString,如下所示

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

我知道这个问题已经过时了,但是我也愿意为此做出贡献:

其他响应之间的主要区别是散列表返回。

@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"}

简单来说:

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

这个问题让我抓狂: Spring 是一个如此强大的工具,然而,如果没有丑陋的技巧,像编写 JSON 这样简单的输出 String 似乎是不可能的。

我的解决方案(在 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

简单和直接发送任何对象或返回简单列表

@GetMapping("/response2")
@ResponseStatus(HttpStatus.CONFLICT)
@ResponseBody List<String> Response2() {
List<String> response = new ArrayList<>(Arrays.asList("Response2"));
        

return response;
        

}

我已经添加了 HttpStatus.CONFLICT作为随机响应,以显示如何通过 RequestBody也是 HttpStatus

{Postman Response