I am using spring annotation in my java code - with eclipse IDE
in my Controller i have this method:
#RequestMapping(value = "/some/link", produces = "application/json")
#ResponseBody
public AnyDto suggestMapping(#Valid #RequestBody(required = false) SomeDto dto) throws Exception {
///some code
return null;
}
How could i view the Full http request in eclipse expression window (during debug)
when i add #RequestBody to expression window i get an error ?
To view the request, you can add HttpServletRequest request to your method signature, e.g.:
public AnyDto suggestMapping(#Valid #RequestBody(required = false) SomeDto dto, HttpServletRequest request) throws Exception {
///some code
return null;
}
Spring then automatically 'autowires' HttpServletRequest request into the method code for you.
#ResponseBody is different - it simply takes the return type (AnyDto) and will set it as the HTTP response body (i.e. so it's unrelated to the request).
Related
The spring boot do not recognize my controllers only if i send more parameters on request. For example:
If i send normal GET request the spring boot recognize my controller:
http://localhost/idp/oauth/123/authorize
If i send GET request with extras parameters the spring boot do not recognize my controller:
http://localhost/idp/oauth/123/authorize?scope=public_profile
I need receive the request exactly for second example (with parameter scope), but the spring boot do not recognize the controller and redirect to /error.
code:
#Controller
#RequestMapping("/idp/oauth")
public class OAuthController {
#RequestMapping(value = "/{clientId}/authorize", method = RequestMethod.GET)
public String authorizeGet(
HttpServletRequest request,
HttpServletResponse response,
#PathVariable String clientId,
Model model) {
// ...
}
#RequestMapping(value = "/{clientId}/authorize", method = RequestMethod.POST)
public String authorizePost(
HttpServletRequest request,
HttpServletResponse response,
#PathVariable String clientId,
Model model) {
// ...
}
}
Since you are passing extra param with name "scope" Spring will search for #RequestParam in methods
It can't find any, thus the error
You need to modify your method to add all #RequestParam
You can also add optional fields if they are not mandatory with required = false
#RequestMapping(value = "/{clientId}/authorize", method = RequestMethod.GET)
public String authorizeGet(
HttpServletRequest request,
HttpServletResponse response,
#PathVariable String clientId,
#RequestParam(value = "scope") String scope,
#RequestParam(required = false, value = "optionalParam") String optionalParam,
Model model) {
// ...
}
You missed #RequestParam in the controller method definition.
More on #RequestParam
Since I'm using the CQRS pattern, I'm trying to create a single controller method that accepts every POST call with a command in its request body and send it.
I'm almost there, but I can't get the path variables.
I created a custom HandlerMapping
#Bean
public HandlerMapping requestMappingHandlerMapping() throws NoSuchMethodException {
for (final UrlEnum urlEnumItem : UrlEnum.values()) {
requestMappingHandlerMapping.registerMapping(new RequestMappingInfo(urlEnumItem.getCommandName(),
new PatternsRequestCondition(urlEnumItem.getUrl()),
null,
null,
null,
null,
null,
null),
commandController,
commandController.getClass().getDeclaredMethod("commandHandler", HttpServletRequest.class)
);
}
return requestMappingHandlerMapping;
}
and this is my controller method signature
#RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT}, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Object> commandHandler(final HttpServletRequest request) throws Exception {
// controller code here
}
If the url path is something like /api/test it works, but with something like /api/test/{idEntity} I don't have any PathVariable available in the request.
I tried everything like
String originalUrl = (String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
which returns the valued url (i.e. /api/test/1234), not the template, or adding
#PathVariable Map<String, Object> parameters
as a parameter in the method, which is empty.
Debugging the request object it seems there isn't anything useful to identify the path variables.
Maybe I should interrogate the HandlerMapping, but I can't have access to it in the controller method.
Is there a way to extract the pathVariables in the controller method?
It was an error in the configuration. I shouldn't have added the RequestMapping annotation to the controller method because it overrode my configuration.
Now I have
#RestController
public class CommandController extends AbstractController {
private final MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
#Override
protected ModelAndView handleRequestInternal(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
// controller code here
return new ModelAndView(mappingJackson2JsonView);
}
}
I implement a controller as the following:
#RequestMapping(value = "/export", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<Object> Export(HttpServletRequest req, HttpServletResponse response, String type,String text) {
........
}
When posting the text(form param) which the length is small(about 20k) from client, the controller works ok and can get form params(data and type).
But 'type' and 'text' are null in service side, when text(form param) is very long(more than 200k) from client.
Who know how to handle it.
Form params can be read from request as req.getParameter("type").
change your method as below since you are already using req and resp in the method signature
public #ResponseBody ResponseEntity<Object> Export(HttpServletRequest req, HttpServletResponse response){
String type = req.getParameter("type");
String text = req.getParameter("text");
}
You could use the Spring MVC annotation as follows.
public #ResponseBody void export(#PathVariable final String whatEver,
#RequestParam("type") final String type, #RequestParam("text") final String text,
final HttpServletRequest request)
My requirement is to get the json response with customized error message when a required #RequestParam is not sent to the request handler or invalid parameter(required is int but user is passing string) is sent to the request handler.
currently I am trying to use the #Exceptionhandler mechanism to handle these exceptions. But the respective exception handler methods not getting invoked.
Please see the code snippet:
#Controller
#RequestMapping("api/v1/getDetails")
public class Abc {
#RequestMapping
#ResponseBody
public Envelope<Object> retrieveTransactions(#RequestParam(required = false) Integer a,
#RequestParam int b, #RequestParam(required = false) boolean c,
HttpServletRequest req) {`
//implementation goes here
}
#ExceptionHandler(MissingServletRequestParameterException.class)
#ResponseBody
public Envelope<Object> missingParameterExceptionHandler(Exception exception,
HttpServletRequest request) {
Envelope<Object> envelope = null;
//error implementation
return envelope;
}
#ExceptionHandler(TypeMismatchException.class)
#ResponseBody
public Envelope<Object> typeMismatchExpcetionHandler(Exception exception, HttpServletRequest request) {
Envelope<Object> envelope = null;
//error implementation
return envelope;
}
Do I need to configure anything extra for exception handler? can anyone tell me where I am doing the wrong.
Consider identifying the parameter name in the RequestParameter annotation.
For example
#RequestParam(value="blammy", required=false)
I've never bothered figuring out how to handle type mismatch,
instead I've found it easier to accept all parameters as String and perform all verification myself (including type).
Also,
If you are accepting the HttpServletRequest as a parameter to your handler,
then there is no need to use #RequestParam annotations,
just get the parameter values directly from the request.
Finally,
consider org.springframework.web.context.request.WebRequest
or org.springframework.web.context.request.NativeWebRequest
instead of HttpServletRequest.
Have you tried to use MethodArgumentNotValidException or HttpMessageNotReadableException instead on your handlers?
And put required = true on your #RequestParam declaration to catch missing params exceptions
#RequestParam(required = true)
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;