简单 restful JSON POST,java 作为服务器,jquery 作为客户端
Simple restful JSON POST with java as server and jquery as client
在我问我的问题之前,我必须说我已经阅读了 20 多篇关于这个问题的问题和文章,其中 none 可以解决它。
我的问题是我在 java 中有一个 restful 服务器,如下所示:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final String stringRequest, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
而且我尝试了不同的方法来使用 jquery 将 json 发送到此服务器(但它们都会产生错误):
$.ajax({
url:"/downloadByCode",
type:"POST",
data: JSON.stringify({"name":"value"}) });
415 "errors message" : "Content type 'application/x-www-form
urlencoded;charset=UTF-8' not supported", "type" :
"HttpMediaTypeNotSupportedError"
所以我尝试通过添加 contentType 来修复它:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
400 "errors message" : "Could not instantiate JAXBContext for class
[class java.lang.String]: null; nested exception is
javax.xml.bind.JAXBException\n - with linked
exception:\n[java.lang.NullPointerException", "type"
:"HttpMessageConversionError"
我试图直接发送 json 对象而不是 JSON.stringify,它给出了相同的 400 错误。
我尝试向@requestMapping 添加不同的消费,但仍然没有成功。
我试图定义我自己的 class 而不是 JsonNode 但它没有改变任何东西。
有什么想法吗?
尝试@RequestBody final Map<String, String> stringRequest
您还需要在 @RequestMapping 上使用 consumes = "application/json"
,因为您在 AJAX 调用中有它
如果 spring 不喜欢您发送 ajax 的格式,您将获得 400 - 我过去在这方面遇到过很多麻烦,现在似乎更好除非必要,否则忽略 header 类型和内容类型
您可以尝试将响应作为 ResponseEntity 发回,而不是直接使用 HttpServletResponse。我的直觉是第二个参数,即 HttpServletRequest 参数,是导致问题的原因。我从来没有用过那个。我总是使用 spring mvc api 发回我的回复。
使用 Jersey api 你可以尝试:
@POST
public void downloadByCode(String stringRequest)
我认为您会在 stringRequest 中找到 post 的正文。
删除 downloadByCode
方法中的 @ResponseBody
将您的方法 downloadByCode() return 类型更改为 String,然后 return String
响应主体会自动将returned String 转换为JSON,然后适当地使用数据
我不太熟悉 java,但据我所知,您的 java 代码一定是这样的。
public class downloadByCode{
@GET
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response downloadByCode(@QueryParam("paramater1") final String parameter 1, @Context HttpServletRequest httpRequest) {
如果这没有帮助,您可以将您的代码保存在某个地方并共享它。
您可以将请求正文作为字符串,使用 org.springframework.http.HttpEntity<String>
作为请求类型,这里是您的代码作为基础的示例:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(final HttpEntity<String> request, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
但是,如果您打算将 return 结果作为字符串值,那么将字符串也用作 return 类型可能会更好,如下所示:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public String downloadByCode(HttpEntity<String> request) {
String requestBody = request.getBody();
String result;
// ...
// some processings here to create the result text
// ....
return result;
}
我使用 Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven 和 JDK >= 1.7 制作了简单的应用程序。
#clonning repository with sample
git clone git@github.com:mind-blowing/samples.git
#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text
#running application using maven spring-boot plugin
mvn spring-boot:run
应用程序启动后,您可以打开 http://localhost:8080,您将看到 html 页面,其中简单地使用 JQuery 发送 POST 请求,请求文本和响应将在 html 页面上可见,在控制器中我添加了两个处理程序,第一个使用 HttpEntity,第二个使用 POJO。
HTML 页面:index.html
项目:https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text
请尝试创建新的 class :
public class InputData{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
然后
public void downloadByCode(@RequestBody InputData stringRequest, final HttpServletResponse response)
和
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
查看您的错误,很明显您在 spring 配置中配置了 'Jaxb2RootElementHttpMessageConverter' 或类似的 XML 转换器。由于您已经注册了一个 XML 转换器,@RequestBody 和 @ResponseBody 将基于已注册的消息转换器工作。
因此,要解决您的问题,请使用 JSON 消息转换器,例如 'MappingJacksonHttpMessageConverter'。一旦你注册了一个 JSON 消息转换器,创建一个 bean class 来保存你的 json 数据并将它与 RequestBody 一起使用,如下所示:
// It has to meet the json structure you are mapping it with
public class YourInputData {
//properties with getters and setters
}
更新 1:
由于您定义了多个消息转换器,Spring 尝试使用默认情况下可用的第一个。为了使用特定的消息转换器(在本例中为 Jackson 转换器),您应该从客户端指定 'Accept' header,如下所示:
$.ajax({
headers: {
"Accept" : "application/json; charset=utf-8",
"Content-Type": "application/json; charset=utf-8"
}
data: "data",
success : function(response) {
...
} })
首先,如果你使用的是 maven,你应该为 jackson 添加依赖项
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
或者你可以下载jar包放到我们项目的class路径下(你也可以用其他的mapper)
那么您应该创建一个模型或 DTO class,您可以在其中映射您的 json
public class Data{
private String name;
pubilc Data(){}
//getter and setter
}
然后你控制器
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public Data downloadByCode(@RequestBody final Data data, final HttpServletResponse response)
{
//your code
return data;
}
AJAX 通话
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
(可选)您可以通过如下定义 bean 告诉对象映射器不要在缺少属性时失败来覆盖行为:
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return converter;
}
http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/
最后的答案是这个问题中许多answers/comments的组合,我将在这里总结它们:
1- 你必须确保在你的 spring 配置中有一个合适的 json 转换器,例如 MappingJacksonHttpMessageConverter
(感谢@java Anto)
2- 您必须创建一个与您的 json 对象具有相同结构的 POJO class(参见@Vinh Vo 的回答)
3- 你的 POJO class 不能是内联的 class 除非它是静态的 class。这意味着它应该有自己的 java 文件或者它应该是静态的。 (感谢@NTyler)
4- 如果您在对象映射器中适当地设置它,您的 POJO class 可能会遗漏部分 json 对象(参见@Aman Tuladhar 的回答)
5- 您的 ajax 调用需要 contentType:"application/json"
,您应该使用 JSON.stringify
发送数据
这是完美运行的最终代码:
public static class InputData
{
private String name
public String getName()
{
return name;
}
public void setName(final String name
{
this.name = name;
}
}
@RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final InputData request, final HttpServletResponse response)
{
try
{
String codes = request.getName();
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
这是 jquery Ajax 请求:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
在我问我的问题之前,我必须说我已经阅读了 20 多篇关于这个问题的问题和文章,其中 none 可以解决它。
我的问题是我在 java 中有一个 restful 服务器,如下所示:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final String stringRequest, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
而且我尝试了不同的方法来使用 jquery 将 json 发送到此服务器(但它们都会产生错误):
$.ajax({
url:"/downloadByCode",
type:"POST",
data: JSON.stringify({"name":"value"}) });
415 "errors message" : "Content type 'application/x-www-form urlencoded;charset=UTF-8' not supported", "type" : "HttpMediaTypeNotSupportedError"
所以我尝试通过添加 contentType 来修复它:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
400 "errors message" : "Could not instantiate JAXBContext for class [class java.lang.String]: null; nested exception is javax.xml.bind.JAXBException\n - with linked exception:\n[java.lang.NullPointerException", "type" :"HttpMessageConversionError"
我试图直接发送 json 对象而不是 JSON.stringify,它给出了相同的 400 错误。
我尝试向@requestMapping 添加不同的消费,但仍然没有成功。
我试图定义我自己的 class 而不是 JsonNode 但它没有改变任何东西。
有什么想法吗?
尝试@RequestBody final Map<String, String> stringRequest
您还需要在 @RequestMapping 上使用 consumes = "application/json"
,因为您在 AJAX 调用中有它
如果 spring 不喜欢您发送 ajax 的格式,您将获得 400 - 我过去在这方面遇到过很多麻烦,现在似乎更好除非必要,否则忽略 header 类型和内容类型
您可以尝试将响应作为 ResponseEntity 发回,而不是直接使用 HttpServletResponse。我的直觉是第二个参数,即 HttpServletRequest 参数,是导致问题的原因。我从来没有用过那个。我总是使用 spring mvc api 发回我的回复。
使用 Jersey api 你可以尝试: @POST public void downloadByCode(String stringRequest)
我认为您会在 stringRequest 中找到 post 的正文。
删除 downloadByCode
方法中的 @ResponseBody
将您的方法 downloadByCode() return 类型更改为 String,然后 return String
响应主体会自动将returned String 转换为JSON,然后适当地使用数据
我不太熟悉 java,但据我所知,您的 java 代码一定是这样的。
public class downloadByCode{
@GET
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response downloadByCode(@QueryParam("paramater1") final String parameter 1, @Context HttpServletRequest httpRequest) {
如果这没有帮助,您可以将您的代码保存在某个地方并共享它。
您可以将请求正文作为字符串,使用 org.springframework.http.HttpEntity<String>
作为请求类型,这里是您的代码作为基础的示例:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(final HttpEntity<String> request, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
但是,如果您打算将 return 结果作为字符串值,那么将字符串也用作 return 类型可能会更好,如下所示:
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public String downloadByCode(HttpEntity<String> request) {
String requestBody = request.getBody();
String result;
// ...
// some processings here to create the result text
// ....
return result;
}
我使用 Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven 和 JDK >= 1.7 制作了简单的应用程序。
#clonning repository with sample
git clone git@github.com:mind-blowing/samples.git
#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text
#running application using maven spring-boot plugin
mvn spring-boot:run
应用程序启动后,您可以打开 http://localhost:8080,您将看到 html 页面,其中简单地使用 JQuery 发送 POST 请求,请求文本和响应将在 html 页面上可见,在控制器中我添加了两个处理程序,第一个使用 HttpEntity,第二个使用 POJO。
HTML 页面:index.html
项目:https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text
请尝试创建新的 class :
public class InputData{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
然后
public void downloadByCode(@RequestBody InputData stringRequest, final HttpServletResponse response)
和
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
查看您的错误,很明显您在 spring 配置中配置了 'Jaxb2RootElementHttpMessageConverter' 或类似的 XML 转换器。由于您已经注册了一个 XML 转换器,@RequestBody 和 @ResponseBody 将基于已注册的消息转换器工作。
因此,要解决您的问题,请使用 JSON 消息转换器,例如 'MappingJacksonHttpMessageConverter'。一旦你注册了一个 JSON 消息转换器,创建一个 bean class 来保存你的 json 数据并将它与 RequestBody 一起使用,如下所示:
// It has to meet the json structure you are mapping it with
public class YourInputData {
//properties with getters and setters
}
更新 1:
由于您定义了多个消息转换器,Spring 尝试使用默认情况下可用的第一个。为了使用特定的消息转换器(在本例中为 Jackson 转换器),您应该从客户端指定 'Accept' header,如下所示:
$.ajax({
headers: {
"Accept" : "application/json; charset=utf-8",
"Content-Type": "application/json; charset=utf-8"
}
data: "data",
success : function(response) {
...
} })
首先,如果你使用的是 maven,你应该为 jackson 添加依赖项
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
或者你可以下载jar包放到我们项目的class路径下(你也可以用其他的mapper)
那么您应该创建一个模型或 DTO class,您可以在其中映射您的 json
public class Data{
private String name;
pubilc Data(){}
//getter and setter
}
然后你控制器
@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public Data downloadByCode(@RequestBody final Data data, final HttpServletResponse response)
{
//your code
return data;
}
AJAX 通话
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
(可选)您可以通过如下定义 bean 告诉对象映射器不要在缺少属性时失败来覆盖行为:
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return converter;
}
http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/
最后的答案是这个问题中许多answers/comments的组合,我将在这里总结它们:
1- 你必须确保在你的 spring 配置中有一个合适的 json 转换器,例如 MappingJacksonHttpMessageConverter
(感谢@java Anto)
2- 您必须创建一个与您的 json 对象具有相同结构的 POJO class(参见@Vinh Vo 的回答)
3- 你的 POJO class 不能是内联的 class 除非它是静态的 class。这意味着它应该有自己的 java 文件或者它应该是静态的。 (感谢@NTyler)
4- 如果您在对象映射器中适当地设置它,您的 POJO class 可能会遗漏部分 json 对象(参见@Aman Tuladhar 的回答)
5- 您的 ajax 调用需要 contentType:"application/json"
,您应该使用 JSON.stringify
这是完美运行的最终代码:
public static class InputData
{
private String name
public String getName()
{
return name;
}
public void setName(final String name
{
this.name = name;
}
}
@RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final InputData request, final HttpServletResponse response)
{
try
{
String codes = request.getName();
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
这是 jquery Ajax 请求:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });