I am new to Spring 3.1.0, and am trying to create an application, which can be exposed as a web application as well as web services.
For a POST where i am submitting a form object using the #ModelAttribute. I also want to expose this method which can consume the same object as XML, through any poster.
Shall i use both #ModelAttribute & #RequestBody together. I have already added the consumes property in the #RequestMapping annotation.
When you submit form, data comes in form-encoded manner, and when you use XML/JSON it comes as a string in body. You'd better place all your common logic to intermediate service layer and call it in your controllers. As a result it allows you to simply build REST services on top of existing HTML pages with forms:
public class Service {
public void registerUser(User user){
}
}
#RequestMapping("users")
public class FormController{
#Autowired private Service service;
#RequestMapping("register")
public ModelAndView registerUser(#ModelAttribute User user){
service.registerUser(user);
}
}
#RequestMapping("service/v1")
public class RESTController{
#Autowired private Service service;
#RequestMapping("users/register")
public ModelAndView registerUser(#RequestBody User user){
service.registerUser(user);
}
}
Actually, you can even put this in one controller.
Related
I am Planning to build a web application using Spring Boot as restful service.
my spring boot web restful application should be accessible by other application as well. In case if any one accessing the rest service from other application then my application should work as expected.
#Controller
public class GreetingController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
In above example if call is made from outside of application then the rest service should return JSON output.
One way we can have some variable to distinguish as request variable. But I do not want like that. Please share some standard way.
Appreciate your help.
Idiomatic way is to rely on Accept request header.
If requester presents Accept: application/json then return him JSON data (REST API).
If requester provides you with Accept: application/xhtml+xml return him HTML (web frontend).
Implementation-wise you should is to be done use #RequestMapping with consumes argument. You need two methods. If business logic for both paths is the same then in could be reused. Business logic should reside in another method or in separate #Service. Business logic on its own should not know, care or rely on transport protocol (HTTP), serialization of request response or presentation. Business logic should just work with POJOs and leave serialization to #Controller.
#Controller
#RequestMapping("/greeting")
public class GreetingController {
#RequestMapping(consumes="application/json")
#ResponseBody //required if you want to return POJO (spring will serialize it to response body)
public void rest() {
//return POJO, it will be serialized to JSON. or serialize pojo
directly and return response with manually set body and headers.
}
#RequestMapping(consumes="application/xhtml+xml")
public void html() {
//populate model, return string pointing to HTML to View
}
}
I suggest creating two controller classes, the second one using #RestController. Then, have two paths; the second could be "rs/greeting". This approach, which separates the Web and RESTful concerns, is much more extensible and doesn't require any weird headers that most clients don't want to deal with.
Before asking question first i describe the scenario. I have multiple servlet contexts. suppose /**book**/review url is corresponding to book-servlet.xml and /**report**/update corresponds to report-servlet.xml.
Here are two controllers
#Controller
#SessionAttributes(BookController.COMMAND_NAME)
public class BookController {
public static final String COMMAND_NAME = "login";
#GetMapping("/book/review")
public String show(ModelMap modelMap) {
modelMap.put(COMMAND_NAME, getBook());
return "redirects:" + "/report/update"; //it redirects to second controller method
}
}
#Controller
#SessionAttributes(ReportController.COMMAND_NAME)
public class ReportController {
public static final String COMMAND_NAME = "report";
#GetMapping("/report/update")
public String show(ModelMap modelMap) {
modelMap.put(COMMAND_NAME, getReport());
return "redirects:" + "/report/done";
}
}
Observe this two controller. When i put getBook() in model it stores this object in session after method excution since #SessionAttributes(BookController.COMMAND_NAME) is added above class definition. But, after redirection to /report/update (different servlet context) we are also trying to put getReport() in model. And after handler method excution spring should put the object in session as it does for first case.Unfortunately for second controller it doesn't store it in session.
My question is if the first controller method can successfully save it in session why the second controller can't? Or is it for servlet context switching / multiple get requests or something like this. Please i need to know the reason it behaves weirdly. I am now totally confused about #SessionAttributes. It should work same for both controllers.
After studying on this i found that it is wise to use RedirectAttributes for this type of redirect scenario. Cause ModelMap is intended for scenario where you use this ModelMap attributes to rendering a view. And FlashAttribute will survive after immediate redirection to another handler method and then be erased. So, i did my solution using RedirectAttrinute support from spring.
Let say we have an API endpoint configured using Spring MVC and Spring Security. We would like to be able to handle pairs of #RequestMapping and #Secured annotations where the only #Secured annotation values differ from pair to pair. This way, we would be able to return a different response body depending on security rules for the same request.
This may allow our code to be more maintainable by avoiding to check for security rules directly into the method body.
With a not working example, here is what we would like to do :
#Controller
#RequestMapping("/api")
public class Controller {
#Secured ({"ROLE_A"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomething(#PathVariable("uid") String uid) {
// Returns something for users having ROLE_A
}
#Secured ({"ROLE_B"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomethingDifferent(#PathVariable("uid") String uid) {
// Returns something different for users having ROLE_B
}
}
How can we achieve this ?
And if this can be done: How the priority should be managed for a user who has both ROLE_A and ROLE_B ?
Assuming you are using Spring 3.1 (or up) together with the RequestMappingHandlerMapping (and RequestMappingHandlerAdapter) you can extend the request mapping mechanism. You can do this by creating your own implementation of the RequestCondition interface and extend the RequestMappingHandlerMapping to construct this based on the #Secured annotation on your method.
You would need to override the 'getCustomMethodCondition' method on the RequestMappingHandlerMapping and based on the Method and the existence of the #Secured annotation construct your custom implementation of the RequestCondition. All that information is then taken into account when matching incoming requests to methods.
Related answers (although not specific for #Secured annotations but the mechanism is the same) is also to be found here or here
I don't think you can do this in spring-mvc, since both routes have exactly the same #RequestMapping (#Secured) is not taken into account by the route engine of spring-mvc. The easiest solution would be to do this:
#Secured ({"ROLE_A", "ROLE_B"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomething(#PathVariable("uid") String uid, Principal p) {
// Principal p gets injected by spring
// and you need to cast it to check access roles.
if (/* p.hasRole("ROLE_A") */) {
return "responseForA";
} else if (/* p.hasRole("ROLE_B") */) {
return "responseForB";
} else {
// This is not really needed since #Secured guarantees that you don't get other role.
return 403;
}
}
However, I would change your design, since the response is different per role, why not have 2 separate request mappings with slightly different URLs? If at some point you have users with role A and B at the same time, you can't let the user choose what response to get (think, for example, of the public and private profiles of LinkedIn)
in my exercise i have to develop a spring application which should be accessible through a WebGUI AND a REST service.
Now i browed through the examples of Spring MVC, there is this hello world tutorial on Spring MVC.
The controller looks like as follows:
#Controller
#RequestMapping("/welcome")
public class HelloController {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "Spring 3 MVC Hello World");
return "hello";
}
}
Then i looked through the Spring REST example which looks like this:
#Controller
#RequestMapping("/movie")
public class MovieController {
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public String getMovie(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return "list";
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String getDefaultMovie(ModelMap model) {
model.addAttribute("movie", "this is default movie");
return "list";
}
}
Now I am wondering, how do these two examples (Spring-mvc and Spring-rest) differ?
They both use the same annotations and work similar. Aren't that both just REST examples?
How can I provide a Rest-Interface to a Spring-MVC application?
regards
In order to provide rest interface to Spring MVC application, you can apply #RequestMapping annotation with a path name to each of the methods in controller, this creates a unique URL path for each of the rest services you would like to provide.
Meaning, the rest services are nothing but the methods in Spring MVC controller with #RequestMapping annotation.
If you would like to learn how Spring MVC supports Rest Based services, the below link might help:
http://blog.springsource.org/2009/03/08/rest-in-spring-3-mvc/#features
Both samples are about Spring Web MVC.
You should pay more attention to definitions, like what is REST
https://en.wikipedia.org/wiki/Representational_state_transfer
Representational State Transfer is intended to evoke an image of how a
well-designed Web application behaves: presented with a network of Web
pages (a virtual state-machine), the user progresses through an
application by selecting links (state transitions), resulting in the
next page (representing the next state of the application) being
transferred to the user and rendered for their use.
Spring Web MVC greatly facilitates developing REST web APIs and that's it.
Rememeber #ResponseBody as return type on method is going to be REST.
ofcourse returned object can be negotiated with either JSON or XML.
I want the client and server application to talk to each other using REST services. I have been trying to design this using Spring MVC. I am looking for something like this:
Client does a POST rest service call saveEmployee(employeeDTO, companyDTO)
Server has a similar POST method in its controller saveEmployee(employeeDTO, companyDTO)
Can this be done using Spring MVC?
Yes, this can be done. Here's a simple example (with Spring annotations) of a RESTful Controller:
#Controller
#RequestMapping("/someresource")
public class SomeController
{
#Autowired SomeService someService;
#RequestMapping(value="/{id}", method=RequestMethod.GET)
public String getResource(Model model, #PathVariable Integer id)
{
//get resource via someService and return to view
}
#RequestMapping(method=RequestMethod.POST)
public String saveResource(Model model, SomeResource someREsource)
{
//store resource via someService and return to view
}
#RequestMapping(value="/{id}", method=RequestMethod.PUT)
public String modifyResource(Model model, #PathVariable Integer id, SomeResource someResource)
{
//update resource with given identifier and given data via someService and return to view
}
#RequestMapping(value="/{id}", method=RequestMethod.DELETE)
public String deleteResource(Model model, #PathVariable Integer id)
{
//delete resource with given identifier via someService and return to view
}
}
Note that there are multiple ways of handling the incoming data from http-request (#RequestParam, #RequestBody, automatic mapping of post-parameters to a bean etc.). For longer and probably better explanations and tutorials, try googling for something like 'rest spring mvc' (without quotes).
Usually the clientside (browser) -stuff is done with JavaScript and AJAX, I'm a server-backend programmer and don't know lots about JavaScript, but there are lots of libraries available to help with it, for example see jQuery
See also:
REST in Spring 3 MVC
Yes, Rest is very easy to implement using spring MVC.
#RequestMapping(value="/saveEmploee.do",method = RequestMethod.POST)
#ResponseBody
public void saveEmployee(#RequestBody Class myclass){
//saving class.
//your class should be sent as JSON and will be deserialized by jackson
//bean which should be present in your Spring xml.
}