我在Spring启动时有一个示例Rest Controller:
@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
我正在使用json库:org.json
当我点击api /你好时,我得到一个例外说:
用于servlet [dispatcherServlet]的Servlet.service()与path的上下文 []引发异常[请求处理失败;嵌套异常是 java.lang.IllegalArgumentException:找不到返回的转换器 type of value:class org.json.JSONObject] with root cause
java.lang.IllegalArgumentException:找不到返回的转换器 type的值:class org.json.JSONObject
问题是什么?有人可以解释究竟发生了什么。我是SpringBoot的新手。
提前致谢:)
答案 0 :(得分:53)
当您使用spring boot web时,jackson依赖是隐式的,我们不必明确定义。如果使用eclipse,您可以在依赖关系层次结构选项卡中检查pom.xml中的jackson依赖项。
由于您使用@RestController
进行了注释,因此无需进行显式的json转换。只需返回一个POJO和jackson序列化器将负责转换为json。与@Controller一起使用时,它等同于使用@ResponseBody
。我们放置@ResponseBody
而不是@RestController
放置@Controller
而不是vanilla @ResponseBody
和 <div class="content">
<form onsubmit="return false">
<div id="speed">
<h3>How fast is your transfer speed?</h3>
<p>
<label for="internetSpeed">File Transfer Speed</label>
<input id="internetSpeed_p" type="button" value="+" onclick="internetSpeed.value = (parseInt(internetSpeed.value)+1).toFixed(2)">
<input id="internetSpeed" type="number" min="0" step="0.01" value="10" placeholder="File Transfer speed" autofocus>
<input id="internetSpeed_p" type="button" value="-" onclick="internetSpeed.value = (parseInt(internetSpeed.value)-1).toFixed(2)">
<select id="internetSpeedBase">
<option value="10^3">Kbps</option>
<option value="10^6" selected>Mbps</option>
<option value="10^9">Gbps</option>
</select>
</p>
<div>
<label class="collapse" for="_1">?</label>
<input id="_1" type="checkbox">
<div>
<p class="overhead-p"><label for="internetOverhead">Overhead</label>
<select id="internetOverhead">
<option value="1" selected>None</option>
<option value="0.99">1%</option>
<option value="0.95">5%</option>
<option value="0.9">10% (Typical TCP overhead)</option>
<option value="0.85">15%</option>
<option value="0.8">20%</option>
<option value="0.75">25%</option>
<option value="0.7">30%</option>
<option value="0.6">40%</option>
<option value="0.5">50%</option>
<option value="0.4">60%</option>
<option value="0.3">70%</option>
<option value="0.2">80%</option>
<option value="0.1">90%</option>
<option value="0.05">95%</option>
<option value="0.01">99%</option>
</select>
</p>
</div>
</div>
</div>
<div id="file">
<h3>What is the size of the file you want to transfer?</h3>
<p>
<label for="fileSize">File Size</label>
<input id="internetSpeed_p" type="button" value="+" onclick="fileSize.value = (parseInt(fileSize.value)+1).toFixed(2)">
<input type="number" id="fileSize" value="1" step="0.01" min="0">
<input id="internetSpeed_p" type="button" value="-" onclick="fileSize.value = (parseInt(fileSize.value)-1).toFixed(2)">
<select id="fileSizeBase">
<option value="2^10">KB </option>
<option value="2^20">MB </option>
<option value="2^30" selected>GB </option>
<option value="2^40">TB </option>
</select>
</p>
<p>
<button id="calculateButton" >Calculate</button>
</p>
</div>
</form>
<div id="results">
<div id="results_inner">
<p class="">It would take</p>
<p class="time">0</p>
<p class="">to transfer <span class="size"></span> </p>
<p class="">at <span class="speed"></span>/sec</p>
</div>
<hr>
</div>
默认情况下应用于该控制器中的所有资源。
请参阅此链接: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
您遇到的问题是因为返回的对象(JSONObject)没有某些属性的getter。并且您的目的不是序列化此JSONObject,而是序列化POJO。所以只需返回POJO。
请参阅此链接: https://stackoverflow.com/a/35822500/5039001
如果要返回json序列化字符串,则只返回字符串。在这种情况下,Spring将使用StringHttpMessageConverter而不是JSON转换器。
答案 1 :(得分:29)
您当前的方法不起作用的原因是因为默认使用Jackson来序列化和反序列化对象。但是,它不知道如何序列化JSONObject
。如果要创建动态JSON结构,可以使用Map
,例如:
@GetMapping
public Map<String, String> sayHello() {
HashMap<String, String> map = new HashMap<>();
map.put("key", "value");
map.put("foo", "bar");
map.put("aa", "bb");
return map;
}
这将导致以下JSON响应:
{ "key": "value", "foo": "bar", "aa": "bb" }
这有点受限,因为添加子对象可能会变得有点困难。杰克逊有自己的机制,使用ObjectNode
和ArrayNode
。要使用它,您必须在服务/控制器中自动装配ObjectMapper
。然后你可以使用:
@GetMapping
public ObjectNode sayHello() {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("key", "value");
objectNode.put("foo", "bar");
objectNode.put("number", 42);
return objectNode;
}
此方法允许您添加子对象,数组和使用所有各种类型。
答案 2 :(得分:24)
您可以按照@vagaasen的建议将响应返回为String
,也可以使用Spring提供的ResponseEntity
对象,如下所示。通过这种方式,您还可以返回Http status code
,这对于webservice调用更有帮助。
@RestController
@RequestMapping("/api")
public class MyRestController
{
@GetMapping(path = "/hello", produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> sayHello()
{
//Get data from service layer into entityList.
List<JSONObject> entities = new ArrayList<JSONObject>();
for (Entity n : entityList) {
JSONObject entity = new JSONObject();
entity.put("aa", "bb");
entities.add(entity);
}
return new ResponseEntity<Object>(entities, HttpStatus.OK);
}
}
答案 3 :(得分:7)
您也可以为此
使用散列图@GetMapping
public HashMap<String, Object> get() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", somePOJO);
return map;
}
答案 4 :(得分:3)
{{1}}
PS。仅适用于1个值
答案 5 :(得分:2)
针对API查询的更正确的创建DTO,例如EntityDTO:
df = pd.read_csv('https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-counties.csv',parse_dates=['date']) df.groupby(['state','date'])[['cases']].mean().reset_index()
但是如果您需要返回不同的Map参数,则可以使用下面的两个示例
2.要返回一个像map这样的参数:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) public List<EntityDto> getAll() { return entityService.getAllEntities(); }
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Object> getOneParameterMap() { return ResponseEntity.status(HttpStatus.CREATED).body( Collections.singletonMap("key", "value")); }
答案 6 :(得分:1)
如果您需要使用字符串返回JSON对象,那么以下方法应该起作用:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.ResponseEntity;
...
@RestController
@RequestMapping("/student")
public class StudentController {
@GetMapping
@RequestMapping("/")
public ResponseEntity<JsonNode> get() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree("{\"id\": \"132\", \"name\": \"Alice\"}");
return ResponseEntity.ok(json);
}
...
}
答案 7 :(得分:0)
使用ResponseEntity<ResponseBean>
在这里,您可以根据需要使用ResponseBean或Any java bean返回api响应,这是最佳实践。我已使用Enum进行响应。它将返回状态代码和API的状态消息。
@GetMapping(path = "/login")
public ResponseEntity<ServiceStatus> restApiExample(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
loginService.login(username, password, request);
return new ResponseEntity<ServiceStatus>(ServiceStatus.LOGIN_SUCCESS,
HttpStatus.ACCEPTED);
}
用于响应ServiceStatus或(ResponseBody)
public enum ServiceStatus {
LOGIN_SUCCESS(0, "Login success"),
private final int id;
private final String message;
//Enum constructor
ServiceStatus(int id, String message) {
this.id = id;
this.message = message;
}
public int getId() {
return id;
}
public String getMessage() {
return message;
}
}
Spring REST API应该具有以下响应键
您将在下面得到最终答复
{
"StatusCode" : "0",
"Message":"Login success"
}
您可以根据需要使用ResponseBody(java POJO,ENUM等)。