Spring #ResponseStatus returns empty response - java

In my Spring API I wanted to handle responses from operations like create, put and delete with Spring's annotation #ResponseStatus. Every endpoint works correctly but they always return empty response.
Why response from annotated endpoints is empty?
Controller:
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;
#RestController
#RequestMapping(value = "/v1/portfolios")
public class PortfolioController {
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void create(#RequestBody Portfolio resource) {
repo.save(resource);
}
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.OK)
public void delete(#PathVariable("id") String id) {
repo.removeById(id);
}
}

Why response from annotated endpoints is empty?
Because your methods return void (means without body). Status code - it's not a body.
You can try this to return response with message explicity:
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public ResponseEntity<String> delete(#PathVariable("id") String id) {
repo.removeById(id);
return new ResponseEntity<>("Your message here", HttpStatus.OK);
}
Instead of ResponseEntity<String> you can put ResponseEntity<YourCustomObject>and then return new ResponseEntity<>(yourCustomObject instance, HttpStatus.OK); It will be conver into JSON during response.
You also can make this:
#ResponseStatus(value = HttpStatus.OK, reason = "Some reason")
and in this case you will return something like this:
{
"timestamp": 1504007793776,
"status": 200,
"error": "OK",
"message": "Some reason",
"path": "/yourPath"
}

Related

How do I execute two Mappings at once in SpringBoot by calling only the first mapping first?

#PostMapping(value = "/save")
public String saveRequest(#RequestBody Request request) {
requestRepo.save(request);
return "Saved...";
}
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
httpServletResponse.setHeader("Location", "https://www.google.com");
httpServletResponse.setStatus(302);
}
Is there a way to execute the second mapping automatically after executing the first mapping?
Or a way to mix/make this better?
EDIT: updated redirect mapping method
#PostMapping(value = "/yourEndpointFromWhichToBeRedirected")
public String saveRequest(#RequestBody Request request) {
requestRepo.save(request);
return "redirect:/endpointToWhichToBeRedirectedTo";
}

Spring http request validation with anotations

I am trying to implement validation of incoming http request in spring boot app.
I was following these instructions:
https://www.yawintutor.com/how-to-validate-request-body-in-spring-boot/
but I don't get response like stated in article.
I am getting exception in my console though: DefaultHandlerExceptionResolver: ... DefaultMessageSourceResolvable: default message [must be a well-formed email address]]
Process is stopped based on set constraint (email formating, obviously), but I don't get http response messages, just Bad Request.
This is my controller:
#RestController
#Validated
#RequestMapping(path = "/user", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController {
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> createUser(#Valid #RequestBody User user) {
User createdUser = userService.createUser(user);
return ResponseEntity.ok(user);
}
}
And this is entity :
#Entity
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Email
private String email;
}
What am I missing?
First of all I'd like to mention that for me the provided link (https://www.yawintutor.com/how-to-validate-request-body-in-spring-boot/) didn't work somehow...
Now to your question. As I see it, in order to archive this you'd have to create a validator first and then you could continue with something line this (not your example but it should help):
#RequestMapping(value = "/validation", method = RequestMethod.POST)
public ResponseEntity<?> acceptData(#Valid #RequestBody Data data, Errors errors,
#RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language) {
stringValueValidator.validate(language, data, errors);
if (errors.hasErrors()) {
return new ResponseEntity<>(createErrorString(errors), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
}
Use #ControllerAdvice and create your own response Object for representing not valid arguments. Example below will return all not valid arguments with its messages.
#ControllerAdvice
public class ExceptionHandlerClass extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> validationList = ex.getBindingResult().getFieldErrors().stream().map(fieldError->fieldError.getDefaultMessage()).collect(Collectors.toList());
return new ResponseEntity<>(new ExceptionObject(false,validationList), status);
} }

How to get parameters from RequestBody in Spring REST controller method

In a Spring Boot application I have the following method signature in a Controller:
#PostMapping(value="/borrow")
public ResponseEntity<Void> postBorrowBook(#RequestBody String personId,
#RequestBody String bookId) {
LOG.info(RESTController.class.getName() + ".postBorrowBook() method called.");
...
return new ResponseEntity<Void>(HttpStatus.OK);
}
I want to get the values of the two parameters from the RequestBody.
Can anyone let me know how this be done if the request I am making is JSON as follows:
{"personId":"207","bookId":"5"}
I am currently receiving:
{
"timestamp": "2018-06-17T20:59:37.330+0000",
"status": 400,
"error": "Bad Request",
"message": "Required request body is missing: public org.springframework.http.ResponseEntity<java.lang.Void> com.city2018.webapps.code.controller.RESTController.postBorrowBook(java.lang.String,java.lang.String)",
"path": "/rest/borrow/"
}
I already have the following working in a similar scenario for simple non-REST requests:
#RequestMapping(value="/borrow", method=RequestMethod.POST)
public String postBorrowBook(#RequestParam("personId") String personId,
#RequestParam("bookId") String bookId,
Model model) {
LOG.info(PersonController.class.getName() + ".postBorrowBook() method called.");
You can declare a POJO with 2 fields (personId and bookId) and change your signature as follow:
#PostMapping(value="/borrow")
public ResponseEntity<Void> postBorrowBook(#RequestBody RequestDTO requestBody) {
requestBody.getPersonId();
requestBody.getBookId();
...
}
First you should define a POJO class as:
public class BorrowBookEntity{
public String personId;
public String bookId;
}
Then you rely on spring to get the value as:
#PostMapping("/request")
public ResponseEntity<Void> postController(
#RequestBody BorrowBookEntity borrowBookEntity) {
...
You can also try another .
e.g. #RequestBodyParam
#RequestMapping(value = "/saveData", headers="Content-Type=application/json", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<Boolean> saveData(#RequestBodyParam String source,#RequestBodyParam JsonDto json) throws MyException {
...
}
https://github.com/LambdaExpression/RequestBodyParam

Why does this action parameter not get picked up?

I am trying to map /my/route/id to an action but the parameter id keeps coming in as null. Does anyone know what I'm doing wrong?
Controller mapping code:
#Controller
#RequestMapping("/admin/alias")
public class AliasesController {
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public #ResponseBody SampleAliasMaskModel index(Integer id) {
Code issuing the request
$('select[name=aliasMask]', ctx).change(function () {
var val = parseInt($(this).val(), 10);
if (val === -1)
return maskSelected(null);
if (!_.isNaN(val))
$.getJSON('alias/'+val, {}, function(mask){
maskSelected(mask);
});
})
The request itself:
If spring isn't compiled with debug information you have to specify the name of the Pathvariable as annotation parameter.
Like this:
#Controller
#RequestMapping("/admin/alias")
public class AliasesController {
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public #ResponseBody SampleAliasMaskModel index(#PathVariable("id") Integer id) {
Maybe that's the reason.

Return only string message from Spring MVC 3 Controller

Can any one tell me how I can return string message from controller?
If i just return a string from a controller method then spring mvc treating it as a jsp view name.
Annotate your method in controller with #ResponseBody:
#RequestMapping(value="/controller", method=GET)
#ResponseBody
public String foo() {
return "Response!";
}
From: 15.3.2.6 Mapping the response body with the #ResponseBody annotation:
The #ResponseBody annotation [...] can be put on a method and indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name).
With Spring 4, if your Controller is annotated with #RestController instead of #Controller, you don't need the #ResponseBody annotation.
The code would be
#RestController
public class FooController {
#RequestMapping(value="/controller", method=GET)
public String foo() {
return "Response!";
}
}
You can find the Javadoc for #RestController here
Although, #Tomasz is absolutely right there is another way:
#RequestMapping(value="/controller", method=GET)
public void foo(HttpServletResponse res) {
try {
PrintWriter out = res.getWriter();
out.println("Hello, world!");
out.close();
} catch (IOException ex) {
...
}
}
but the first method is preferable. You can use this method if you want to return response with custom content type or return binary type (file, etc...);
This is just a note for those who might find this question later, but you don't have to pull in the response to change the content type. Here's an example below to do just that:
#RequestMapping(method = RequestMethod.GET, value="/controller")
public ResponseEntity<byte[]> displayUploadedFile()
{
HttpHeaders headers = new HttpHeaders();
String disposition = INLINE;
String fileName = "";
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//Load your attachment here
if (Arrays.equals(Constants.HEADER_BYTES_PDF, contentBytes)) {
headers.setContentType(MediaType.valueOf("application/pdf"));
fileName += ".pdf";
}
if (Arrays.equals(Constants.HEADER_BYTES_TIFF_BIG_ENDIAN, contentBytes)
|| Arrays.equals(Constantsr.HEADER_BYTES_TIFF_LITTLE_ENDIAN, contentBytes)) {
headers.setContentType(MediaType.valueOf("image/tiff"));
fileName += ".tif";
}
if (Arrays.equals(Constants.HEADER_BYTES_JPEG, contentBytes)) {
headers.setContentType(MediaType.IMAGE_JPEG);
fileName += ".jpg";
}
//Handle other types if necessary
headers.add("Content-Disposition", , disposition + ";filename=" + fileName);
return new ResponseEntity<byte[]>(uploadedBytes, headers, HttpStatus.OK);
}
What about:
PrintWriter out = response.getWriter();
out.println("THE_STRING_TO_SEND_AS_RESPONSE");
return null;
This woks for me.
For outputing String as text/plain use:
#RequestMapping(value="/foo", method=RequestMethod.GET, produces="text/plain")
#ResponseBody
public String foo() {
return "bar";
}
#Controller
public class HelloController {
#RequestMapping(value = "/", method = RequestMethod.GET)
ResponseEntity<String> sayHello() {
return ResponseEntity.ok("Hello");
}
}
Simplest solution:
Just add quotes, I really don't know why it's not auto-implemented by Spring boot when response type defined as application/json, but it works great.
#PostMapping("/create")
public String foo()
{
String result = "something"
return "\"" + result + "\"";
}
There are two possible solution
Use #Controller and #ResponseBody, to combine HTML page and the string message for different functions
#Controller
#RequestMapping({ "/user/registration"})
public class RegistrationController {
#GetMapping
public String showRegistrationForm(Model model) {
model.addAttribute("user", new UserDto());
return "registration"; //Returns the registration.html
}
#PostMapping
#ResponseBody
public String registerUserAccount(#Valid final UserDto accountDto, final HttpServletRequest request) {
LOGGER.debug("Registering user account with information: {}", accountDto);
return "Successfully registered" // Returns the string
}
Use #RestController to return String message. In this case, you cannot have functions which returns HTML page.
#RestController
#RequestMapping({ "/user/registration"})
public class RegistrationController {
#PostMapping
public String registerUserAccount(#Valid #RequestBody final UserDto accountDto, final HttpServletRequest request) {
LOGGER.debug("Registering user account with information: {}", accountDto);
return "Successfully registered" // Returns the string
}
#ResponseBody
#RequestMapping(value="/get-text", produces="text/plain")
public String myMethod() {
return "Response!";
}
You see that #ResponseBody ?
It's telling that the method returns some text and not to interpret
it as a view etc.
You see that produces="text/plain" ?
It's just a good practice as it tells what will be returned from the
method :)

Categories

Resources