不太清楚Spring中,两个backend互相call,返回的值会被如何打包并通过何种协议(应该是http)进行传输。
@RequestBody: enabling automatic deserialization of the inbound HttpRequest body onto a Java object.
@ResponseBody: tells a controller that the object returned is automatically serialized into JSON and passed back into the HttpResponse object.
Other definition:
@RequestBody annotation binds the HTTPRequest body to the domain object. Spring framework automatically deserializes incoming HTTPRequest to the Java object using Http Message Converters. We pass the body of the request through a HttpMessageConverter to resolve the method argument depending on the content type of the request.
You shouldn’t need to configure the consumes or produces attribute at all. Spring will automatically serve JSON based on the following factors.
You should also follow Wim’s suggestion and define your controller with the @RestController annotation. This will save you from annotating each request method with @ResponseBody
怪不得我感觉即使我不用@ResponseBody也没用关系,应该是因为我用了@RestController
… Annotate the method with @ResponseBody, and the method parameter with @RequestBody, and it will work (no need for 2 methods).
所以我的理解是,有了@ResponseBody就不用@RequestMapping(consumes = {“application/json”}),也就是说有了@ResponseBody就不用@Produces(APPLICATION_JSON)这样,因为@Consumes(APPLICATION_JSON)和@RequestMapping(consumes = {“application/json”})是等价的
Explanation:
First, produces and consumes attributes are used to narrow the mapping types. By default the first HttpMessageConverter found, that matches the media type requested, will be used.
Second, client requests a media type by giving the media type in:
Third, produces
in combination with @ResponseBody
will produce the object in the requested media type (nice for GET requests, when you need to send something back to the client), and consumes
in combination with @RequestBody
will consume the object with the requested media type (nice for POST requests, when you need to get something from the client).
Four, when @ResponseBody not used, HttpMessageConverters are not used. Rather ViewResolvers kick in and produce a view (HTML, PDF…), and the return type should follow the rules that accompany ViewResolvers (check default view resolver and InternalResourceViewResolver for more).
You should always declare the @Produces and @Consumes annotations (either at the class level or method level) for the purpose of Content Negotiation and HTTP protocol correctness. Without these annotations, the result will be dependent on the client request and the default behavior of the server (which may be different across implementations), which leads to unpredictable and ambiguous results.
With these annotations, we advertise what media types we can produce and consume. On Retrieve (GET) requests, the client should send an Accept header with the media type of the resource they expect back. And on Create requests (PUT, POST), the client should send a Content-Type header telling the server what media type the data is that they are sending. If these headers don’t match what the server is advertised to handle, then the client will get error responses back telling them what the problem is; with a Retrieve request and a non-matching Accept header, the response will be a 406 Not Acceptable. With a Create request and a non-matching Content-Type header, the response will be a 415 Unsupported Media Type.
If your resource methods produce JSON as representation of your resources, they should be annotated with @Produces(MediaType.APPLICATION_JSON). As a result, the response will have a Content-Type header indicating the media type of the payload.
The media type defined in the @Produces annotation indicates the media type that will be produced by the MessageBodyWriter instances registered in the application. If your application uses Jackson, for example, the JacksonJsonProvider will be used to convert Java objects to JSON documents.
Why need @Produce since when comment out the @Produces annotation, it still returns JSON.
JAX-RS is an specification (just a definition) and Jersey is a JAX-RS implementation.
Coming to Jackson, It is just a JSON processor used to marshall and unmarshall objects from Java to JSON. Jersey uses Jackson internally to convert Java objects to JSON and vice versa.
Use one JSON provider that integrates with Jersey and it will provide you a MessageBodyWriter implementation. At time of writing, Jersey integrates with the following modules to provide JSON support:
https://technoless.wordpress.com/2013/04/02/spring-rest-vs-jersey-jax-rs/
https://dzone.com/articles/lets-compare-jax-rs-vs-spring-for-rest-endpoints
…
– @RequestBody (spring) vs method(String input) (jersey) ?
– @ResponseBody (spring) vs method return type (jersey)
– @ExceptionHandler (spring) vs @Provider and ExceptionMapper interface (jersey)
– @RequestMapping(produces = {“application/json”}) @Produces(“application/json”)
– @RequestMapping(consumes = {“application/json”}) @Consumes(“application/json”)
https://dzone.com/articles/lets-compare-jax-rs-vs-spring-for-rest-endpoints
总结: 2.1 & 2.3: 不管Service1返回的是List还是Response,service1所返回的response自动被deserialize了的感觉,只要service2在这里指定了返回类型
Service 1:
@Component
@Path("/base")
@Produces(APPLICATION_JSON)
@Consumes(APPLICATION_JSON)
@Api(value="its functionality", description="")
public class Service1 {
@GET
@Path("/myPath/path1")
@ApiOperation()
@ApiResponses()
public List<String> find(){
try {
List<String> infos = ...
return infos;
} catch (Exception e) {
return null;
}
}
// or:
public Response find(){
try {
List<String> infos = ...
return Response.status(Response.Status.OK).entity(infos).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e).build();
}
}
}
Service 2:
@Named
@Path("/base")
@Produces(APPLICATION_JSON)
@Consumes(APPLICATION_JSON)
public interface Client{
@GET
@Path("/myPath/path1")
List<String> find(){
}
// or:
Response find(){
}
}
@Component
public class Processor{
@Inject
private Client client;
public void process() {
List<String> infos = client.find();
// or:
Response response = client.find();
if (response.getStatus() != 200) {
Exception error = response.readEntity(Exception.class);
throw new Exception(error.getMessage());
}
List<String> infos = response.readEntity(List.class);
// is determined by the response type in cliet interface
}
}
returned type from service 1: List
received type of service 2: List
service1 Spring run log 返回204,code中service2 没法拿到status code,List为null
service2 返回200,code中service2 没法拿到status code,List为service1正确返回的List
returned type from service 1: List
received type of service 2: InBoundJarxResponse
service1 Spring run log 返回204,code中service2 拿到204,error为null
service1 返回200,code中service2 拿到200,List为service1正确返回的List
public void process() {
Response response = client.find();
if (response.getStatus() != 200) { // can get status: 200, 204... corresponding to real http status in service 1
Exception error = response.readEntity(Exception.class); // error is null
throw new Exception(error.getMessage());
}
List<String> infos = response.readEntity(List.class); // works normally
}
service2 也可以用 response.getStatus()得到service1返回的status,包括200, 204…是与service1一致的,即使service1返回的是null… 但error是null
returned type from service 1: OutBoundJarxResponse
received type of service 2: List
service1 Spring run log 返回500(不再是204),service2直接抛出是500,List断点到不了
service1 返回200,service2 没法拿到status code,List为service1正确返回的List
The returned type from service 1: OutBoundJarxResponse
The received type of service 2: InBoundJarxResponse
service1 Spring run log返回500(不再是204),code中service2 拿到500,error为service1正确返回的error
service1 返回200,code中service2 拿到200,List为service1正确返回的List
public void process() {
Response response = client.find();
if (response.getStatus() != 200) { // can get status, 200, 500... but is not 204, both in service 1 and service 2, the GET/POST status is just 500...
Exception error = response.readEntity(Exception.class); // error is not null, is the error bind into Jaxs Response
throw new Exception(error.getMessage());
}
List<String> infos = response.readEntity(List.class); // works normally
}
service2 也可以用 response.getStatus()得到service1返回的status,包括200, 500…是与service1你定义的一致的,比如除了200,剩下的都归为500,那么service1也不会有204出现在Spring的log里… 因此service 2也不会有除了500意外的error code。error不是null,是service bind进Response里的error。
综上,2.4最适合,又能拿到error message,又能拿到List,同时还能catch住service 1的500