I have a controller with method, which returns PagedResource, which looks like this:
#RequestMapping(value = "search/within", method = RequestMethod.POST)
public #ResponseBody PagedResources within(#RequestBody GeoJsonBody body,
Pageable pageable, PersistentEntityResourceAssembler asm) {
// GET PAGE
return pagedResourcesAssembler.toResource(page, asm);
}
Now, I want to add that method as a link to the root resource, so I do the following:
public RepositoryLinksResource process(RepositoryLinksResource repositoryLinksResource) {
repositoryLinksResource.add(linkTo(methodOn(ShipController.class).within(null, null, null)).withRel("within"));
return repositoryLinksResource;
}
Which works and I get my link, however it add that link without pagination parameters. So it look like this:
"within": {
"href": "http://127.0.0.1:5000/search/within"
},
and I want to turn it into:
"within": {
"href": "http://127.0.0.1:5000/search/within{?page, size}"
},
This previous question on stackoverflow suggests that after fixing the corresponding issue on GitHub it should work by default, however, it doesn't.
What am I doing wrong ?
Automatic Creation of Paginated Links with PagedResourcesAssembler
I had success using PagedResourcesAssembler. Let's say your entity is called
MyEntity. Your within method should return HttpEntity<PagedResources<MyEntity>>.
Your within method should look something similar to the example shown below.
#RequestMapping(value = "search/within", method = RequestMethod.POST)
#ResponseBody
public HttpEntity<PagedResources<MyEntity>>
within(#RequestBody GeoJsonBody body,Pageable pageable,
PagedResourcesAssembler assembler) {
// GET PAGE
Page<MyEntity> page = callToSomeMethod(pageable);
return new ResponseEntity<>(assembler.toResource(page), HttpStatus.OK);
}
Here is a simple example. In this example, the response looked like the one shown below,
{
"_embedded": {
"bookList": [
{
"id": "df3372ef-a0a2-4569-982a-78c708d1f609",
"title": "Tales of Terror",
"author": "Edgar Allan Poe"
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/books?page=0&size=20"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
Manual Creation of Paginated Self Link
If you're interested in creating the paginated link manually, here's the code snippet you can use,
Page<MyEntity> page = callToSomeMethod(pageable);
ControllerLinkBuilder ctrlBldr =
linkTo(methodOn(ShipController.class).within(body, pageable, asm));
UriComponentsBuilder builder = ctrlBldr.toUriComponentsBuilder();
int pageNumber = page.getPageable().getPageNumber();
int pageSize = page.getPageable().getPageSize();
int maxPageSize = 2000;
builder.replaceQueryParam("page", pageNumber);
builder.replaceQueryParam("size", pageSize <= maxPageSize ?
page.getPageable().getPageSize() : maxPageSize);
Link selfLink =
new Link(new UriTemplate(builder.build().toString()), "self");
Related
I am a newbie in WebClient. I want to consume a rest service and replace some value and return the result.
this is the response I get from rest service:
[
{
"type": "somthing",
"details": {
"d1": "va1",
"d2": "va2",
"d3": "va3"
}
},
{
.....
},
...
]
This is the result I want to return to the user. (the new value is something that I get from the user, so I have it as a parameter.)
[
{
"type": "somthing",
"details": {
"d1": "va1",
"d2": "va2",
**"d3": "Replace with new value"**
}
},
{
.....
},
...
]
Flux<Item> items= webClient.get()
.uri("------URL------")
.retrieve()
.bodyToFlux(Item.class)
Above code correctly return items from the rest service and traditionally I can use collectList().block() to get a List and replace the value inside the object and return it.
I feel that it is an old-fashion way. Is there any better way to handle this situation by using WebClient functionality?
Thanks to #michalk I used map and it worked.
Flux<Item> items= webClient.get()
.uri("------URL------")
.retrieve()
.bodyToFlux(Item.class)..map(item-> {
item.getDetails().setDThree(request.getValue);
return item;
});
I am working on a Spring boot project, it produces strange behaviors, for ex:
I have two APIs as follow
Controller file
#GetMapping("/list/employees")
public ResponseEntity<List<Employee>> getEmployees(){
List<Employee> list = employeeService.getAllEmployees();
return new ResponseEntity<List<Employee>>(list, new HttpHeaders(), HttpStatus.OK );
}
#GetMapping("employee/{id}")
public ResponseEntity<Employee> getEmployeeById(#PathVariable("id") long id) throws RuntimeException{
Employee employee = employeeService.getEmployee(id);
return new ResponseEntity<Employee>(employee,new HttpHeaders(),HttpStatus.OK);
}
Service file
/* return all employees */
public List<Employee> getAllEmployees(){
List<Employee> listEmployee = employeeRepo.findAll();
if(listEmployee.size()>0){
return listEmployee;
}else{
return new ArrayList<Employee>();
}
}
/*
RETURN SINGLE EMPLOYEE BY ID
*/
public Employee getEmployee(long id) throws RuntimeException{
Optional<Employee> employee = employeeRepo.findById(id);
if(employee.isPresent()){
return employee.get();
}else{
new RuntimeException("Record not found");
}
return null;
}
But running them in Postman gives weird output, for ex:
Correct behavior of second API returning single employee
http://127.0.0.1:8080/employee/3
{
"id": 3,
"firstName": "Caption",
"lastName": "America",
"email": "cap#marvel.com"
}
Incorrect behavior of the same API (I am typing the wrong path this time)
http://127.0.0.1:8080/employees/3
The API path is wrong (employees/3)
{
"firstName": "Caption",
"lastName": "America",
"email": "cap#marvel.com",
"_links": {
"self": {
"href": "http://127.0.0.1:8080/employees/3"
},
"employee": {
"href": "http://127.0.0.1:8080/employees/3"
}
}
}
same behavior with the root URI, I have not triggered any action with home URI but still gives output like in the above API.
what can be the reason for these unwanted API calls?
Looks like you have Spring Data Rest on your class path. It will automatically wire paths based on the repositories. That second response is a HATEOAS response.
A simple test would be to check maven/gradle. If you see spring-data-rest, comment it out and try again.
There is no unwanted API calls. That is the way HATEOS response is represented as stated in the documentation:
The fundamental idea of hypermedia is to enrich the representation of a resource with hypermedia elements. The simplest form of that are links. They indicate a client that it can navigate to a certain resource. The semantics of a related resource are defined in a so-called link relation.
As suggested above, try to look for spring boot hateos dependency and comment or remove that, then it should revert back to normal REST JSON response.
If you are using maven, look for :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
if you are using gradle, look for :
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
I am working on an app written in java and angular. The request goes from angular with params and I need to read the params in the rest services. The angular piece is fixed (I cannot change it), but I can update the java code as needed.
My issue: I cannot read the params in my java services method. The value is always null.
angular code:
alert("params : "+JSON.stringify(params, null, 2));
return $http.get(url, {
params: params
}).success(function (data) {
// success criteria
});
The params looks like this based on the alert statement:
{
"start": 0,
"end": 100,
"type": "asdf",
"name": null,
"values": [],
"locs": [],
"test1": "Val"
}
My java code looks like this:
#GET
#Path("valuesList")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_XML)
public String getValues(#RequestParam("type")String type) throws Exception {
System.out.println("type ================"+type);
}
The type is null. I want to read all the values, but for now I am just using the type for testing. I also tried various #Consumes values, but nothing helps.
I think I need to change the #RequestParam, but not sure to what though. Thanks for any pointers.
Just wanted to post the solution - I had to update the #RequestParam to #QueryParam. The updated method call is below
public String getValues(#QueryParam("type")String type) throws Exception {
System.out.println("type ================"+type);
}
I am developing Spring MVC 4 Dynamic web module application.
In my application I have simple CRUD operations.
Get requests are working fine but POST and PUT are not working at all.
I am getting this error:
HTTP Status 400 - The request sent by the client was syntactically incorrect.
This is my controller code for GET:
#RequestMapping(value = "/getCustomreById/{id}", method = RequestMethod.GET)
public ResponseEntity<CustomerDetails> getCustomer(
#PathVariable("id") String id) {
System.out.println(id);
if (id != null)
return new ResponseEntity<CustomerDetails>(
serv.getCustomerById(id), HttpStatus.OK);
else
return new ResponseEntity<CustomerDetails>(
serv.getCustomerById("1"), HttpStatus.OK);
}
and for POST :
#RequestMapping(value = "/addCustomer", method = RequestMethod.POST)
public int AddCustomer(#RequestBody CustomerDetails customer) {
return serv.addCustomer(customer);
}
POST Request :
{
"customerName": "Sid",
"customerEmail": "sid#gmail.com",
"customerAddress": [{
"address1": "123 Street",
"address2": " ",
"zipCode": "400065",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"region": "Gateway of India"
}]
}
I read on stackoverflow on this question that I need to add multipart reosolver but even aafter adding that I am getting same error.
Assuming you just need to send int id as response, add #ResponseBody to the method
#RequestMapping(value = "/addCustomer", method = RequestMethod.POST)
#ResponseBody
public int AddCustomer(#RequestBody CustomerDetails customer) {
return serv.addCustomer(customer);
}
Otherwise return ResponseEntity as you are doing for GET
return new ResponseEntity<Integer>(serv.addCustomer(customer), HttpStatus.OK);
Adding #ResponseBody will work for this question
For some reason unknown to me, when making a request to my Spring controller it is returning an invalid JSON value. I'm using Jackson to map my JSON object. This is the data being returned when I make the request:
{} &&
{
"registros": [
{
"id": 251,
"matricula": "32849923",
"dadoPessoal": {
"nome": "Testando",
"email": "tiare#terra.com.br",
"telefone": "1235324812",
"celular": "123832911",
"foto": null,
"salario": 3829
},
"status": true,
"nascimento": {
"dataNascimento": 1417485600000,
"nascionalidade": "Brasil",
"localNascimento": "SP"
},
"documentoPessoal": {
"rg": "8329892332",
"orgaoEmissor": "SSP/SP",
"dataEmissao": 1417485600000,
"cpf": "016.015.XXX-XX",
"tituloEleitor": "adw91021",
"zonaDeVoto": "91aa",
"sessaoVoto": "2a",
"enderecoVoto": "adw"
},
"dataAdmissao": 1361674800000,
"dataDesligamento": null,
"version": 0
}
],
"total": 1
}
The problem here is that somehow invalid characters "{} &&" are being added to the beginning of the JSON. What I'm not understanding is how? Its adding these values that are not defined anywhere in my Spring method.
My Request Mapping:
#Override
#RequestMapping(value = { "/", "" }, method = RequestMethod.GET)
public ModelAndView index() {
ModelAndView view = new ModelAndView(VIEW_INDEX);
view.addObject("registros", service.findAll());
view.addObject("total", service.findAll().size());
return view;
}
The Jackson configuration:
/**
* #return MappingJacksonJsonView
*/
#Bean
public MappingJacksonJsonView mappingJacksonJsonView() {
MappingJacksonJsonView mappingJacksonJsonView = new MappingJacksonJsonView();
mappingJacksonJsonView.setContentType("application/json");
mappingJacksonJsonView.setObjectMapper(this.objectMapper());
mappingJacksonJsonView.setEncoding(JsonEncoding.UTF8);
mappingJacksonJsonView.setPrefixJson(true);
return mappingJacksonJsonView;
}
/**
* #return ContentNegotiatingViewResolver
*/
#Bean
public ContentNegotiatingViewResolver contentNegotiatingViewResolver() {
List<ViewResolver> viewResolvers = new ArrayList<ViewResolver>();
// Tiles
viewResolvers.add(this.tileViewResolver());
// Views
List<View> defaultViews = new ArrayList<View>();
defaultViews.add(this.mappingJacksonJsonView());
ContentNegotiatingViewResolver contentNegotiatingViewResolver = new ContentNegotiatingViewResolver();
contentNegotiatingViewResolver.setViewResolvers(viewResolvers);
contentNegotiatingViewResolver.setDefaultViews(defaultViews);
contentNegotiatingViewResolver.setOrder(0);
return contentNegotiatingViewResolver;
}
Thanks you all. I found the error!!
When i started to read the javadoc i found this:
"Indicates whether the JSON output by this view should be prefixed with "{} && ". Default is false."
springsource docs