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:
Related
I want to consume both JSON & files in an API for my spring boot application (using Spring WebFlux). I tried multiple ways as was recommended over the internet (Article1, Article2, Article3), but it's not working for me. The API is not being hit and getting status 415 (Unsupported Media Type) from Postman.
Spring-Boot version : 2.5.3
Spring-Web/Webflux version : 5.3.9
Employee :
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Employee {
private String name;
private int age;
private int mobileNo;
private List<MultipartFile> files;
}
Controller :
#PostMapping(path = "employee", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public Mono<Response> processEmployeeDocs(#RequestPart Employee request, #RequestPart List<MultipartFile> files) {
Employee employee = new Employee(request.getName(), request.getAge(), request.getMobileNo(), files);
return employeeService.processDocs(employee);
}
Instead of using MultipartFile use FilePart to consume multipart content as per the spring docs
Below is the working code snippet
#PostMapping(path = "employees", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public Mono<ResponseEntity<Response>> processEmployeeDocs(#RequestPart Employee request, #RequestPart Flux<FilePart> files) {
log.info("processing request {}", request);
return files.flatMap(part -> part.transferTo(Paths.get("temp", File.separator, part.filename())))
.then(employeeService.processDocs(request))
.then(Mono.just(ResponseEntity.ok().build()));
}
The above code will save the files in "temp" directory. You can use those files for processing your logic.
Postman Request
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 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
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