In our spring rest controller we would like to use the same mappings with different kind of parameters.
To do this we created additional functions differentiated by mapping params. By doing so we are duplicating the number of functions. To avoid this I would like to use different controllers that should be loaded based on params values.
The question is can we
#RequestMapping(value = "/v1")
#RestController
public class Controller {
#PostMapping(value = "/event-calendar", params = {"externalToken", "event_type"})
public ResponseEntity createEntityOfTypeToken(#RequestHeader(name = "X-Application-Authentication") String externalToken,
#RequestParam(value = "event_type") String eventType) {
MyEntity entity = service.createEntityOfType(
userService.getTokenService(externalToken).getDeviceSerialNumber());
return new ResponseEntity<>(entity, HttpStatus.OK);
}
#PostMapping(value = "/event-calendar", params = {"serialId", "event_type"})
public ResponseEntity createEntityOfTypeSerial(#RequestParam(value = "serialId") String serialId,
#RequestParam(value = "event_type") String eventType) {
MyEntity entity = service.createEntityOfType(serialId);
return new ResponseEntity<>(entity, HttpStatus.OK);
}
}
Please refer
create two method for same url pattern with different arguments
Spring - is possible to give same url in request mapping of post method?
P.S. not enough points to comment
Related
I am writing a feign client
#RequestMapping(
path = "/TrackingServlet?CompanyName=Test&UserName=&BranchCode=",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<String> getInfo(
#RequestParam("DocumentNumbers") String bill);
when it is invoked the url becomes /TrackingServlet?CompanyName=Test&UserName&BranchCode
eliminating the = symbol, but the API needs it in that format, since its a third party API we cannot modify it.
Also tried
#RequestMapping(
path = "/TrackingServlet?CompanyName=Test&UserName=",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE
)
ResponseEntity<String> getInfo(
#RequestParam("DocumentNumbers") String bill,
#RequestParam(name = "BranchCode", required = true) String BranchCode);
default ResponseEntity<String> getInfo(String bill) {
return getInfo(bill, "");
}
this will not even have the param BranchCode
I am using org.springframework.cloud:spring-cloud-starter-openfeign:2.1.1.RELEASE
Spring boot version 2.1.4.RELEASE
is there anyway or workarounds for keeping empty params in urls as it is ?
If your URL is http://localhost:8080/trackingServlet/testing?userName=pratik
Use feign client:
#FeignClient(name = "tracking-servlet-service")
public interface TestFeignClient {
#GetMapping("/trackingServlet/testing")
public String getQueryParam(#RequestParam("userName") String name);
}
If you have 2 or more parameter then you can add same in #RequestParam
E.g
URL http://localhost:8080/trackingServlet/testing?userName=pratik&companyName=Test
#FeignClient(name = "tracking-servlet-service")
public interface TestFeignClient {
#GetMapping("/trackingServlet/testing")
public String getQueryParam(#RequestParam("userName") String name,
#RequestParam("companyName") String companyName);
}
I am trying to write a feign client to make calls to retrieve data from a server where the api accepts a list of identical named query parameters to determine how much data is being asked. Here is an example url I am trying to hit:
http://some-server/some-endpoint/{id}?include=profile&include=account&include=address&include=email
So far for my feign client I'm attempting to set it up this way:
#FeignClient("some-server")
public interface SomeServerClient {
#RequestMapping(method = RequestMethod.GET,
value = "/customers/api/customers/{id}",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
Map<Object, Object> queryById(
#PathVariable long id,
#RequestParam("include[]") String ... include);
default Map<Object, Object> queryById(long id) {
return queryById(id,"profile", "account", "address", "email");
}
However this doesn't appear t format the request in the way desired, so my question is how can I set up my feign client to submit its request to the url as shown in the example above?
use #RequestParam("include") List<String> includes, example:
client:
#FeignClient(value = "foo-client")
public interface FooClient {
#GetMapping("/foo")
Foo getFoo(#RequestParam("include") List<String> includes);
}
controller:
#RestController
public class FooController {
#GetMapping("/foo")
public Foo getFoo(#RequestParam("include") List<String> includes) {
return new Foo(includes);
}
}
usage:
List<String> includes = new ArrayList<>();
includes.add("foo");
includes.add("bar");
Foo foo = fooClient.getFoo(includes);
url:
http://some-server/foo?include=foo&include=bar
I have a controller annotated with #RestController and it implements an interface:
public interface ContratEndpoint {
String ROOT = "/api/contrats";
String GET_CONTRAT = "";
String GET_CONTRAT_PER_PK = "/{idContrat}";
#RequestMapping(value = GET_CONTRAT)
Contrat getContrat(#RequestParam(value = "contratId")Long contratId);
#RequestMapping(value = GET_CONTRAT_PER_ID)
ExtContrat getContratById(#PathVariable("idContrat") Long idContrat);
}
The controller:
#RestController
#RequestMapping(value = ContratEndpoint.ROOT)
public class ContratController implements ContratEndpoint {
//Injecting Services....
#Resource
private Mapper mapper;
#Override
public Contrat getContrat(Long contratId) {
return mapper.map(contratService.get(contratId),Contrat.class);
}
#Override
public ExtContrat getContratById(#PathVariable("idContrat") Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
.The above Code works just fine.
. But For the first inherited method , I didn't have to annotate arguments with #RequestParam and it worked just fine.
As for the second method I tried at first :
#Override
public ExtContrat getContratById(Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
. I expected the same behaviour Like the first Method, But i was wrong and the code ended up firing an IllegalArgumentException because of the check in ligne Preconditions.checkArgument(idContrat!=null).
My question is what is so specific about #PathVariable that i've missed ?
Or is it just something is wrong with my approach?
Thanks.
There is difference between Request param and path variable,seee below post that you can confirm with your uri the cause for the exception :
#PathVariable is to obtain some placeholder from the uri (Spring call it an URI Template) — see Spring Reference Chapter 16.3.2.2 URI Template Patterns
#RequestParam is to obtain an parameter — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
Assume this Url http://localhost:8080/SomeApp/user/1234/invoices?date=12-05-2013 (to get the invoices for user 1234 for today)
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}
I have created a liferay portlet application using Spring, thymeleaf and AngularJS. For communication between AngularJS and spring I need to create some rest calls which I have created using #ResourceMapping like as shown below. The application is working fine but the problem is that I don't know how to make GET, DELETE, PUT http REST calls since #ResourceMapping is not allowing to specify any methods.
#ResourceMapping(value="getUserDetail")
public void userDetail(#RequestParam long userId, ResourceResponse response) throws Exception {
Users users = new Users(userId);
// some logic
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
JSON_MAPPER.writeValue(response.getPortletOutputStream(), users);
}
When I used #RequestMapping instead of #ResourceMapping like as shown below
#RequestMapping(value="getUserDetail", method=RequestMethod.GET)
#ResponseBody
public void userDetail(#RequestParam long userId, ResourceResponse response) throws Exception {
System.out.println("Got detail request for user with id {} "+ userId);
// UserDetail userDetail = this.userService.getPortalUserDetail(userId);
List<String> users = new ArrayList<String>();
users.add("Manu");
users.add("Lissie");
users.add("John");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
JSON_MAPPER.writeValue(response.getPortletOutputStream(), users);
}
I have got
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping': Initialization of bean failed; nested exception is java.lang.IllegalStateException: Mode mappings conflict between method and type level: [getUserDetail] versus [view]
Can anyone please tell me some solution for this
How to create different types of http calls using #ResourceMapping
Can we use #RequestMapping instead of #ResourceMapping in Liferay Spring portlet for REST calls
How can we create resource based REST urls like getUser/12/mumbai
How can we send REST json as body instead of Request Param
Mode mappings conflict exception
The question doesn't show it, but your controller probably has #RequestMapping("view") annotation. This type level mapping is in conflict with the method level mappings. You should remove #RequestMapping annotation on the controller class.
Request mapping examples
#Controller
public class SampleRESTFullController {
// Simple GET
#RequestMapping(value = "/helloSample", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody List<HelloSample> helloSample() { ... }
// GET with path variable
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.GET)
public #ResponseBody HelloSample helloSample(#PathVariable("sampleId") Long sampleId) { ... }
// POST with #RequestBody
#RequestMapping(value = "/helloSample", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody HelloSample createSample(#RequestBody HelloSample helloSample) { ... }
// PUT with path variable and #RequestBody
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.NO_CONTENT)
void update(#PathVariable("sampleId") long sampleId, #RequestBody HelloSample helloSample) { ... }
// DELETE
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.NO_CONTENT)
void delete(#PathVariable("sampleId") long sampleId) { ... }
}
I took the examples from Using RESTFul services with Liferay blog post. It answers all your questions and presents tons of examples. Pay attention to Spring configuration, which makes the RESTful services possible (especially the view resolver and message converter).
1. How to create different types of http calls using #ResourceMapping
If you want to a REST Api with Complete Actions (GET, POST, PUT, DELETE) you need to use #RequestMapping.
2. Can we use #RequestMapping instead of #ResourceMapping in Liferay Spring portlet for REST calls
You should be able to use.
3. How can we create resource based REST urls like getUser/12/mumbai
#RequestMapping(value="getUser/{userId}/mumbai", method=RequestMethod.GET)
#ResponseBody
public List<String> userDetail(#RequestParam("userId") long userId) throws Exception {
System.out.println("Got detail request for user with id {} "+ userId);
//UserDetail userDetail = this.userService.getPortalUserDetail(userId);
List<String> users = new ArrayList<String>();
users.add("Manu");
users.add("Lissie");
users.add("John");
return users;
}
4. How can we send REST json as body instead of Request Param
You can use #RequestBody
#RequestMapping(value="saveUser/{userId}", method=RequestMethod.GET)
#ResponseStatus(HttpStatus.CREATED)
public void userDetail(#RequestParam("userId") long userId, #RequestBody User user) throws Exception {
// Logic
}
How to create different types of http calls using #ResourceMapping
Here are some examples that may help you, that's how i use #RequestMapping:
// GET
#RequestMapping(value = "/api/something", method = RequestMethod.GET)
#ResponseBody
public boolean getSomething() {
return "something";
}
// GET with param
#RequestMapping(value = "/api/something/{id}", method = RequestMethod.GET)
#ResponseBody
public boolean getSomething(#PathVariable("id") Long id) {
return id;
}
Instead of RequestMethod.GET you can use RequestMethod.POST,RequestMethod.PUT,RequestMethod.DELETE and so on...
How can we send REST json as body instead of Request Param
Here is a code snippet that i currently use with an AngularJS FrontEnd for user registration. It works just fine and i use #RequestMapping:
#ResponseBody
#RequestMapping(value = "/auth/register", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> register(#RequestBody User user) {
user = userService.initUser(user);
Authentication authentication = securityUserDetailsService.register(user);
if (authentication != null) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
User authUser = securityUserDetailsService.getAuthenticatedUser();
return new ResponseEntity<>(authUser, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
In order to consume JSON you do:
RequestMapping(value = "/whatever", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
In order to produce (return) JSON you do:
RequestMapping(value = "/whatever", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
Also since you use Spring i think you should take a look at Spring Data and Spring Data Rest. This way you can expose your business models as RESTful endpoints.
How can we create resource based REST urls like getUser/12/mumbai
So in order to expose this endpoint getUser/12/mumbai that's what you should do:
// mumbai hardcoded
#RequestMapping(value = "/getUser/{id}/mumbai", method = RequestMethod.GET)
#ResponseBody
public User getUser(#PathVariable("id") Long id) {
// go get the user ...
return user;
}
// mumbai as a param
#RequestMapping(value = "/getUser/{id}/{prop}", method = RequestMethod.GET)
#ResponseBody
public User getUser(#PathVariable("id") Long id, #PathVariable("prop") String prop) {
// go get the user ...
return user;
}
Lastly can you please try to change
public void userDetail (...
to this
public ResponseEntity<userDetail > (...
There are following methods to use rest app with angular js
#RequestMapping(value = "/saveuser", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#RequestMapping(value = "/getemployee", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#RequestMapping(value = "/editCountry", method = RequestMethod.PUT)
#RequestMapping(value = "/deleteCountry", method = RequestMethod.DELETE)
and use following javascript to communicate with spring controller
var formData = {
"userName" : 'Vasim',
"password" : '123456',
"roleName" : 'Admin'
};
var response = $http.post('add', formData);
response.success(function(data, status, headers, config) {
$scope.message = data;
});
var formData = {
"userName" : 'Vasim',
"password" : '123456',
"roleName" : 'Admin'
};
var response = $http.put('edit', formData);
response.success(function(data, status, headers, config) {
$scope.message = data;
});
$scope.delete= function(employeeId) {
$http['delete']('delete', {
params : {
'employeeId' : employeeId
}
}).
success(function(data) {
$scope.msg = data;
});
$http.get('get',{params:{
'id':id
}
}).success(function(data) {
$scope.employees = data;
Am developing an application using Spring boot.I tried with all representations verbs like GET, POST , DELETE all are working fine too. By using PUT method, it's not supporting in spring boot. Whether I need to add any new configuration.
Put method works only the request not have any parameters. If i add any query parameter or form data it doesnt work. Kindly any expertize will help me to solve this issue.
#RequestMapping("/student/info")
#RequestMapping(method = RequestMethod.PUT)
public #ResponseBody String updateStudent(#RequestParam(value = "stdName")String stdName){
LOG.info(stdName);
return "ok";
}
Request method 'PUT' not supported
This code will work fine. You must specify request mapping in class level or in function
level.
#RequestMapping(value = "/student/info", method = RequestMethod.PUT)
public #ResponseBody String updateStudent(#RequestBody Student student){
LOG.info(student.toString());
return "ok";
}
Have you tried the following Request Mapping:
#RequestMapping(value = "/student/info", method = RequestMethod.PUT)
There's no need to separate the value and the Request Method for the URI.
Since Spring 4.3 you can use #PutMapping("url") : https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/PutMapping.html
In this case it will be:
#PutMapping("/student/info")
public #ResponseBody String updateStudent(#RequestParam(value = "stdName")String stdName){
LOG.info(stdName);
return "ok";
}
I meet the same issue with spring boot 1.5.*,I fixed it by follow:
#RequestMapping(value = "/nick", method = RequestMethod.PUT)
public Result updateNick(String nick) {
return resultOk();
}
Add this bean
#Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory(){
#Override
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
connector.setParseBodyMethods("POST,PUT,DELETE");
}
};
}
see also
https://stackoverflow.com/a/25383378/4639921
https://stackoverflow.com/a/47300174/4639921
you can add #RestController annotation before your class.
#RestController
#RequestMapping(value = "/v1/range")
public class RangeRestController {
}