Spring controller - logging request and response body - java

I have a spring application which exchanges JSON with the mobile.
Spring controller looks like this:
#RequestMapping(value = "/register", method = RequestMethod.POST, headers = {"Content-type=application/json"})
public String register(#RequestBody #Valid UserRegistrationRequest urf, BindingResult bindingResult) {
return toJson(someResponse);
}
I wonder, what is the best way to log http request body and response body?
At the moment, I have custom json message converter and it logs a request body, before creating a bean out of json. and I use CustomTraceInterceptor to log a response body. Unfortunately, CustomTraceInterceptor doesn't allow to log request body.
Any advice for better solutions would be highly appreciated!
Thank you in advance.

Extend HandlerInterceptorAdapter, and override postHandle. Which has request and response injected into it.
You can also use new HttpServletResponseWrapper((HttpServletResponse) response) which has a more friendly api, and spring probably has even nicer wrapper as well ...

Related

In Web Client, returning ResponseEntity containing both Body and Http Status Code(both success and failure) JAVA spring boot

I am writing an blocking web client. I want to return both body(class) and http status code in ResponseEntity object to be used in some method. Can you please help with this. I am new to Java and already tried approaches many mentioned on internet.
You can use ResponseEntity class!
For e.g. Assume you want to return your Model/Pojo as below
Model class -> MyResponse (Has fields, getter/setters,toString etc) you want to respond along with HTTP code
Code snippet
#GetMapping("/getresponse) //Or any mapping
public ResponseEntity getResponse()
{
MyResponse response=new MyResponse();
return new ResponseEntity>(response,HttpStatus.OK);
}

how to write a rest controller to consume restful web services json request

How to Consume a Json Request,Coming from some other Application like ".Net" and i want to Consume that into my Java Application .
How to Consume this with Controller in Spring MVC .
Thanks
Shashank
If I'am able to understand your question then you are asking about how to Post JsonRequest to RestController, for that I'm attaching a code snippet and hope it helps.
Step1: Create a Model Class of that JSON Request.
Step2: Mark #RequestBody Annotation with Controller method to get that type of Object in Method argument.
#RequestMapping(value = "/getRequest", method = { RequestMethod.POST },
produces = {"application/json"})
public #ResponseBody Object getResponse(#RequestBody JsonRequest request) {
sysout("Json Body: "+request.toString());
}
you are basically asking how controllers work !! a controller's job is to handle any (JSON or ...) request to its services.
I suggest you read some articles about spring MVC and controllers to understand how it works.
https://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration
https://www.in28minutes.com/spring-mvc-tutorial-for-beginners

POST doesn't work Spring java

I have an web application and I'm trying to creat a simple POSt method that will have a value inside the body request:
#RequestMapping(value = "/cachettl", method = RequestMethod.POST)
#CrossOrigin(origins = "http://localhost:3000")
public #ResponseBody String updateTtl(#RequestBody long ttl) {
/////Code
}
My request which I call from some rest client is:
POST
http://localhost:8080/cachettl
Body:
{
"ttl": 5
}
In the response I get 403 error "THE TYPE OF THE RESPONSE BODY IS UNKNOWN
The server did not provide the mandatory "Content-type" header."
Why is that happening? I mention that other GET requests are working perfectly.
Thanks!
Edit:
When I tried it with postman the error message I got is "Invalid CORS request".
Spring application just doesn't know how to parse your message's body.
You should provide "header" for your POST request to tell Spring how to parse it.
"Content-type: application/json" in your case.
You can read more about http methods here: https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data
Updated:
Just in case of debug, remove useless annotations to test only POST mechanism. Also, change types of arg and return type. And try to use case-sensitive header.
#RequestMapping(value = "/cachettl", method = RequestMethod.POST)
public void updateTtl(#RequestBody String ttl) {
System.out.println("i'm working");
}
Since the error is about the response type, you should consider adding a produces attribute, i.e :
#RequestMapping(value = "/cachettl", method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
Since you are also consuming JSON, adding a consumes attribute won't hurt either :
#RequestMapping(value = "/cachettl", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE, produces=MediaType.APPLICATION_JSON_VALUE)
The error message is slightly misleading. Your server code is not being hit due an authentication error.
Since you say spring-security is not in play then I suspect you're being bounced by a CORS violation maybe due to a request method restriction. The response body generated by this failure (if any at all) is automatic and will not be of the application/json type hence the client failure. I suspect if you hit the endpoint with something that doesn't care for CORS such as curl then it will work.
Does your browser REST client allow you to introspect the CORS preflight requests to see what it's asking for?

Multipart Request with MultipartFile as Optional Field - Spring MVC

I am using Spring MVC on a J2EE Web application.
I have created a method that bounds the request body to a model like the above
#RequestMapping(value = "/", method = RequestMethod.POST, produces = "application/json")
public AModel createEntity(#Valid #ModelAttribute MyInsertForm myInsertForm) {
// coding..
}
Everything are working great and when i include a property of type MultipartFile in the MyEntityForm, then i have to make the request with content type "multipart/form-data".
Also, everything are working great with this scenario too.
The problem i am facing is that i would like to have the MultipartFile property as optional.
When a client request include a file my method works great but when a client request does not include a file spring throws a
HTTP Status 500 - Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream ended unexpectedly
Is there any way to solve this issue without creating two methods on my controller (one with a MultipartFile and another without)?
I had the same issue and just adding the required=false worked for me; because, I don't send a file all the time. Please find the sample code below,
#RequestMapping(value = "/", method = RequestMethod.POST, produces = "application/json")
public AModel createEntity(#Valid #ModelAttribute MyInsertForm myInsertForm, #RequestParam(value ="file", required=false) MultipartFile file) {
// coding..
}
Give a try by adding
(required=false)
to multipart property in method signature.
When you wish to send one or more files using HTTP, you have to use multipart request. This means that the body of the request will be like the above,
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="text"
text default
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------9051914041544843365972754266
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
When you wish to send only data (and not files) you can send them as json, key-value pairs etc.
Spring framework uses the #ModelAttribute annotation when you wish to map a multipart request to an object.
When you have a normal key-value request, you use the #RequestBody annotation.
Thus, you can't have the MultipartFile optional, because you have to use different annotations. Using two different methods, one per request type, solves the issue. Example,
#RequestMapping(value = "/withFile", method = RequestMethod.POST, produces = "application/json")
public ReturnModel updateFile(#ModelAttribute RequestModel rm) {
// do something.
}
#RequestMapping(value = "/noFile", method = RequestMethod.PUT, produces = "application/json")
public ReturnModel updateJson(#RequestBody RequestModel rm) {
// do something else.
}

Spring MVC - creating an httprequest with java for a controller

here is one controller i got on my web application:
#RequestMapping(value = "/createAccount", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
#ResponseBody
public ResponseDTO createAccount(#RequestBody PlayerAccountDTO playerAccountDTO,
HttpServletRequest request) {
this.playerService.createAccount(playerAccountDTO);
return new ResponseDTO();
}
This controller is being called via ajax using post and passing a json and jackson mapper takes care for it to arrive as a POJO (Nice!)
What i would like to do now is:
In a different web application i would like to call with http post request passing PlayerAccountDTO to this exact controller and ofcourse recieve the ResponseDTO.
I would like that to be as simple as possible.
Is it possible to achieve that? here is my wishfull solution (a service on a different web app):
public ResponseDTO createAccountOnADifferentWebApp() {
PlayerAccountDTO dto = new PlayerAccountDTO(...);
ResponseDTO result = httpRequestPost(url, dto, ResponseDTO.class);
return result;
}
Your web server doesn't receive a PlayerAccountDTO object. It receives an HTTP request with a body that (likely) contains a JSON object. The Spring web application tries to deserialize that JSON into a PlayerAccountDTO object which it passes to your handler method.
So what you want to do is use an HTTP client which serializes your PlayerAcocuntDTO on the client side into some JSON which you send in an HTTP request.
Check out RestTemplate which is a Spring HTTP client and uses the same HttpMessageConverter objects that Spring uses to serialize and deserialize objects in #ResponseBody annotated methods and #RequestBody annotated parameters.
You can do it using commons-http-client library

Categories

Resources