I'm trying to send an Ajax request to a Spring MVC controller and map it to a Java class accordingly:
public class Person implements Serializable {
private MutableLong Id = new MutableLong();
#NotEmpty
#Size(min = 1, max = 50)
String FirstName=null;
#NotEmpty
#Size(min = 1, max = 50)
String LastName=null;
public Person(){}
public long getId(){
return this.Id.longValue();
}
//getters and setters
}
then I have JavaScript which sends the AJAX request:
function loadXMLDoc(){
if(window.ActiveXObject)
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
else if(window.XMLHttpRequest)
{
xmlHttp=new XMLHttpRequest();
}
xmlHttp.onreadystatechange=handleStateChange;
xmlHttp.open("POST","/authenticate.dlp", true);
xmlHttp.setRequestHeader('Content-Type', 'application/json');
param = '{\"FirstName\"=\"test\",\"LastName\"=\"test2\"}';
xmlHttp.send(param);
}
and then the controller itself:
#RequestMapping(value="/authenticate.dlp",method = RequestMethod.POST)
#ResponseBody
public String getAjax(#RequestBody Person person){
Set<ConstraintViolation<Person>> failures = validator.validate(person);
if(!failures.isEmpty())
//......
}
It looks like no response from the server. If I'm using Fiddler, I see the following response from the server:
The server refused this request
because the request entity is in a
format not supported by the requested
resource for the requested method ().
What am I doing wrong?
There are two possible reasons:
You forget <mvc:annotation-driven />. It automatically configures HTTP message converters for use with #RequestBody/#ResponseBody
You don't have Jackson JSON Processor in the classpath. Spring requires it to bind application/json to #RequestBody
Just a couple of other helpful links...check out this Spring blog post:
http://blog.springsource.com/2010/07/22/spring-mvc-3-showcase/
And the examples which make use of #ResponseBody:
https://src.springframework.org/svn/spring-samples/mvc-showcase/
There's also ResponseEntity:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/http/ResponseEntity.html
#RequestMapping("/ajax/helloworld")
public ResponseEntity<String> helloworld() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<String>("Hello World", headers, HttpStatus.OK);
}
Where instead of "Hello World" you could return a marshalled object.
This is not exactly an answer to your question, but have you looked at DWR before? It makes JS to Java RPC super-easy. http://directwebremoting.org/dwr/index.html
Related
I am building and testing a simple Spring Boot API REST tutorial.
I have faced with an issue that I am trying to understand. I am getting an HTTP 406 (NOT ACCEPTABLE) when calling POST method to create and persist a new entity.
Problem is the entity is persisted but the response to the client is not what should be expected (HTTP 201 CREATED with URI in this case).
Tutorial and TutorialDto classes have the exact same attributes. Here is the definition:
public class TutorialDto {
private long id;
private String title;
private String description;
private boolean published;
...
}
Here is my POST method in #RestController class:
#PostMapping("/tutorial")
public ResponseEntity.BodyBuilder createTutorial(#RequestBody final TutorialDto tutorialDto) {
final TutorialDto createdTutorial = tutorialService.add(tutorialDto);
return ResponseEntity.created(URI.create(String.format("tutorial/%d", createdTutorial.getId())));
}
And here is the #Service method to create the entity:
#Transactional
public TutorialDto add(final TutorialDto tutorialDto) {
final Tutorial createdTutorial = tutorialRepository.save(modelmapper.map(tutorialDto, Tutorial.class));
return Optional.of(modelmapper.map(createdTutorial, TutorialDto.class))
.orElseThrow(() -> new TutorialCreationException(
String.format("Tutorial: %s could not be created", tutorialDto.getTitle()))
);
}
This is the request body:
{
"title": "tutorial",
"description": "This is the first created tutorial"
}
And this is the response body:
{
"timestamp": "2022-04-16T00:40:36.626+00:00",
"status": 406,
"error": "Not Acceptable",
"path": "/api/v1/tutorial"
}
I am getting the HTTP 406 response at the end of the controller method, after returning the "ResponseEntity.created".
Thanks in advance.
Looks like you are using wrong usage of ResponseEntity.BodyBuilder. Here is an example
Hence, your controller code should look something like this:
#PostMapping("/tutorial")
public ResponseEntity createTutorial(#RequestBody final TutorialDto tutorialDto) {
final TutorialDto createdTutorial = tutorialService.add(tutorialDto);
return ResponseEntity.created(URI.create(String.format("tutorial/%d", createdTutorial.getId()))).body(createdTutorial);
}
I am trying to make a post request using json but in postman the request is successful only if I make the request like this: email#example.com. If I make a request using the standard JSON format {"email":"email#example.com"} I get "invalid email id". I should mention that content type application/json header is checked in postman, and I am making the request in body/raw.
I have tried messing with #RequestBody/#RequestParam annotations, using consumes = "application/json" but I am unsuccessful and I couldn't find a similar issue after lots of googling either.
my controller:
#RestController
public class UserController {
#Autowired
private UserService userService;
#PostMapping(value = "/forgot-password", consumes = "application/json")
public String forgotPassword(#RequestBody String email) {
String response = userService.forgotPassword(email);
if (!response.startsWith("Invalid")) {
response = "http://localhost:8080/reset-password?token=" + response;
}
return response;
}
user service:
public String forgotPassword(String email) {
Optional<User> userOptional = Optional
.ofNullable(userRepository.findByEmail(email));
if (!userOptional.isPresent()) {
return "Invalid email id.";
}
User user = userOptional.get();
user.setToken(generateToken());
user.setTokenCreationDate(LocalDateTime.now());
user = userRepository.save(user);
return user.getToken();
}
Simply put, the #RequestBody annotation maps the HttpRequest body to a transfer or domain object.You need to put object instead of String
Your endpoint should be like Below.
#PostMapping(value = "/forgot-password", consumes = "application/json")
public String forgotPassword(#RequestBody EmailDto email) {
String response = userService.forgotPassword(email.getEmail);
// ...
return response;
}
Your DTO should be like below
public class EmailDto {
private String email;
//Getters and Setters
}
You should have Email model with string property email.
public EmailPayload {
String email;
.....
Then it will work (it will fit json you provided).
Ofcouse class name can be different, only thing that must match is email property, then in your Controller your #RequestBody will be this class, and not String you have now.
I seem to be butting heads with a limiter somewhere. One of my Spring-Boot REST endpoint (POST) parameters (surveyResults) is looking for a string of JSON:
private static final String SURVEY_RESULTS_ENDPOINT = "/survey/results";
#PostMapping(
value = SURVEY_RESULTS_ENDPOINT,
produces = { "application/hal+json", "application/json" }
)
#ApiOperation(value = "Save one survey results")
public Resource<SurveyResult> createSurveyResults(
#ApiParam(value = "who/what process created this record", required = true) #Valid
#RequestParam(value = "recordCreatedBy", required = true) String createdBy,
#ApiParam(value = "was an issue identified", required = true)
#RequestParam(value = "hadFailure", required = true) Boolean hadFailure,
#ApiParam(value = "JSON representation of the results", required = true)
#RequestParam(value = "surveyResults", required = true) String surveyResult
) ...
If I post to this with about 1500 characters, it works. Somewhere just over that and it will fail with a HTTP 400 error bad request. The whole payload is less than 2K with the other parameters.
I just moved from Wildfly to a new server setup. My company is adopting continuous deployment to cloud servers so i don't have much control nor visibility to this new load balanced server. The server is "server": "openresty/1.13.6.2" - any idea what limit I am running into?
Please use #RequestBody instead of #RequestParam.
#RequestBody annotation maps the HTTP request's body to an object. #RequestParam maps the request parameter in the request, which is in the URL and not in the body.
Most browsers have a limitation to the number of characters supported in a request parameter, and you just hit that limit.
What I would suggest is to create a POJO that looks like this
public class Body {
private String createdBy;
private Boolean hadFailure;
private String surveyResult;
// getters and setters
}
Now your controller will be simpler
#PostMapping(
value = SURVEY_RESULTS_ENDPOINT,
produces = { "application/hal+json", "application/json" }
)
public Resource<SurveyResult> createSurveyResults(#RequestBody Body body) {
}
Wherever you are posting, you will have to now post a JSON (Content-Type = application/json) that looks like the following
{ "createdBy" : "foo", "hadFailure" : false, "surveyResult" : "the foo bar"}
I have a rest java webservice using a PUT method for updating an employee.
The web service should take a list of files and a json containig the infos to be updated.
The method has the following signature
#RequestMapping(value = "/employees/{employeeId}", method = RequestMethod.PUT, consumes =
MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> updateEmployee(
#RequestPart EmployeeUserUpdateDto employeeDto,
#PathVariable("employeeId") int employeeId,
#RequestPart MultipartFile[] uploadedFiles, BindingResult bindingResult)
When i test this request with postman like follows it says that my json is not present:
PS : I have a similar post request for adding an employee, working just fine with the same configuration , the sole diffrence between the 2 requests is the pathvariable and PUT not POST
add over method : #ResponseBody
You can get multipart request in dto wrapper like this:
#PutMapping("/upload-poc")
ResponseEntity<?> uploadFileWithData(#ModelAttribute TestModel model){
log.info("File Exist: {}",model.getImage().get(0).getOriginalFilename());
log.info("Data: {}", model);
return new ResponseEntity<>(HttpStatus.OK);
}
#Getter
#Setter
#ToString
class TestModel{
private List<MultipartFile> images;
//#NotNull(message = "Name must be provided")
#Size(min = 2, max = 6)
private String name;
private Long id;
}
I am uploading 3 files in one request.
Here is the post man request sample:
I am trying to return response as JSON. After searching I found solution to add headers = "Accept=application/json" in RequestMapping. But still it is not working .
It is throwing error HTTP Status 406 "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers."
Here is my controller code :
#RestController
public class EmployeeController {
private EmployeeService employeeService;
#Autowired(required = true)
#Qualifier(value = "employeeService")
public void setEmployeeService(EmployeeService employeeService){
this.employeeService = employeeService;
}
#RequestMapping(value = "/test",method = RequestMethod.GET)
public String test(){
return "{\"name\":\"xyz\"}";
}
#RequestMapping(value = "/employees",method = RequestMethod.GET,headers = "Accept=application/json")
public List<Employee> listEmployees(){
List<Employee> employees = this.employeeService.getEmployees();
return employees;
}
}
Where am I doing wrong?
The simple way to generate JSON, XML response is #ResponseBody annotation.
#RequestMapping(value =" /jsonPostSingle", method = RequestMethod.GET)
#ResponseBody
public PostModel generateJSONPostsingle(#ModelAttribute("postModel") PostModel postModel) {
if(postModel.getPostId() == 1) {
postModel.setTitle("post title for id 1");
} else {
postModel.setTitle("default post title");
}
return postModel;
}
This way you will be able to map your request to model class using #ModelAttribute.
Follow the complete tutorial Spring MVC : JSON response using #ResponseBody
I understand that you're trying to send a response from GET request of /employees.
if you are using Spring 3.1, try to use
#RequestMapping(value = "/employees",method = RequestMethod.GET, produces = "application/json")
instead of adding headers = "Accept=application/json"
More info:
if you want to specify type of data that will send with a request, you can use consumes attribute
example:
#RequestMapping(value="/foo", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
this will consumes and response with JSON type only
check this link about spring update http://spring.io/blog/2011/06/13/spring-3-1-m2-spring-mvc-enhancements/
Hope it helps