Java SpringMVC-如何在Rest控制器中以JSON形式返回简单字符串
我的问题本质上是问题的后续问题Java SpringMVC-如何在Rest控制器中以JSON形式返回简单字符串,java,json,spring,rest,spring-mvc,Java,Json,Spring,Rest,Spring Mvc,我的问题本质上是问题的后续问题 @RestController public class TestController { @RequestMapping("/getString") public String getString() { return "Hello World"; } } 在上面的例子中,Spring会将“Hello World”添加到响应主体中。如何将字符串作为JSON响应返回?我知道我可以添加引号,但这感觉更像是一个黑客 请
@RestController
public class TestController
{
@RequestMapping("/getString")
public String getString()
{
return "Hello World";
}
}
在上面的例子中,Spring会将“Hello World”添加到响应主体中。如何将字符串作为JSON响应返回?我知道我可以添加引号,但这感觉更像是一个黑客
请提供任何例子来帮助解释这一概念
注意:我不希望直接将其写入HTTP响应正文,我希望以JSON格式返回字符串(我正在使用我的控制器)
它要求响应使用有效的JSON格式
格式)
返回
text/plain
(如中所示)或将字符串包装为某个对象
public class StringResponse {
private String response;
public StringResponse(String s) {
this.response = s;
}
// get/set omitted...
}
将响应类型设置为
MediaType.APPLICATION\u JSON\u VALUE
(=“APPLICATION/JSON”
)
你会得到一个JSON,看起来像
{ "response" : "your string value" }
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描述的包装类。在一个项目中,我们使用(maven)解决了这个问题。我们之所以选择它,是因为我们更喜欢返回一个简单的字符串,而不是一个包装器对象。如果您不想添加新的依赖项,可以很容易地使用内部助手类 用法示例:
@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);
}
}
最后说明:
从Spring 4.1.3开始提供,如果在以前的版本上运行,您可以使用extendMessageConverters
实现相同的技术,只需要稍微多做一点工作configureMessageConverters
- 这是许多其他可能方法中的一种,如果您的应用程序只返回JSON而不返回其他内容类型,那么最好跳过默认转换器并添加一个jackson转换器。另一种方法是添加默认转换器,但顺序不同,以便jackson转换器优先于字符串转换器。这应该允许控制器操作方法根据响应的媒体类型指定如何转换字符串
@RequestMapping
注释中添加生成=“application/json”
,如:
@RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")
提示:作为返回值,我建议使用ResponseEntity
type。因为JSON正文中生成的数据需要是一个数组或一个对象,而不是一个简单的字符串。有时可能会导致问题(例如,角度2的可观测值)
区别:
作为json返回字符串
:“示例”
作为json返回的
列表
:[“示例”]
添加@ResponseBody
注释,该注释将在输出流中写入返回数据。您可以使用属性响应
中的字符串
轻松返回json
,如下所示
@RestController
public class TestController {
@RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE)
public Map getString() {
return Collections.singletonMap("response", "Hello World");
}
}
我知道这个问题由来已久,但我也想提出以下建议: 其他响应之间的主要区别是hashmap返回
@GetMapping("...")
@ResponseBody
public Map<String, Object> endPointExample(...) {
Map<String, Object> rtn = new LinkedHashMap<>();
rtn.put("pic", image);
rtn.put("potato", "King Potato");
return rtn;
}
简单地说:
@GetMapping("/health")
public ResponseEntity<String> healthCheck() {
LOG.info("REST request health check");
return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK);
}
@GetMapping(“/health”)
公共响应健康检查(){
LOG.info(“REST请求健康检查”);
返回新的ResponseEntity(“{\“status\”:\“UP\”}”,HttpStatus.OK);
}
这个问题让我抓狂:Spring是一个如此强大的工具,然而,如果没有难看的黑客,编写JSON输出字符串这样简单的事情似乎是不可能的
我发现我的解决方案(在Kotlin中)侵入性最小、最透明,就是使用控制器建议并检查请求是否到达特定的端点集(RESTAPI通常是因为我们通常希望以JSON的形式返回所有答案,而不是根据返回的数据是纯字符串(“不要执行JSON反序列化!”)还是其他(“执行JSON反序列化!”)在前端进行专门化)积极的一面是控制器保持不变,没有黑客攻击
支持
方法确保由StringHttpMessageConverter
处理的所有请求(例如,处理返回纯字符串的所有控制器输出的转换器)在beforeBodyWrite
方法中,我们控制在何种情况下需要中断并将输出转换为JSON(并相应地修改标题)
@ControllerAdvice
类StringToJsonAdvice(val ob:ObjectMapper):ResponseBodyAdvice{
覆盖有趣的支持(returnType:MethodParameter,converterType:Class):布尔=
converterType==StringHttpMessageConverter::class.java
在bodywrite之前覆盖乐趣(
身体:有吗?,
returnType:MethodParameter,
selectedContentType:MediaType,
selectedConverterType:Class,
请求:ServerHttpRequest,
响应:ServerHttpResponse
):有吗{
返回if(request.uri.path.contains(“api”)){
response.getHeaders().contentType=MediaType.APPLICATION\u JSON
ob.writeValueAsString(正文)
}其他机构
}
}
我希望将来我们会得到一个简单的注释,在这个注释中我们可以覆盖输出应该使用的
HttpMessageConverter
。您可以返回Map或包含字符串的任何对象/实体,所以您的意思是希望字符串值序列化为JSON字符串?您还可以返回Collections.singletonMap(“响应”,“您的字符串值”)
在不创建包装类的情况下实现相同的结果。它不需要键和值。单个字符串或字符串数组都是有效的JSON。如果您不同意,也许可以解释为什么jsonlint网站接受这两个值作为有效的JSON。Sure is.JSON.org证实了这一点。包装是如何分类的
@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);
}
@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
}
}