Spring Boot #RestController endpoints and Spring Data Rest projections - java

I'm currently developing a Spring Boot application that exposes endpoints using #RestController and #RequestMapping annotations.
I recently discovered the concept of the projections as defined in Spring Data Rest (#Projection-annotated interfaces and #RepositoryRestResource-annotated JPA repositories) and I'd like to apply this concept to my existing services.
As I understand this post Spring Boot Projection with RestController, (please correct me if I'm wrong), #RestController and #RepositoryRestResource classes both define endpoints. So these annotations seem quite incompatible.
Is there a Spring component which can simply apply the projections concept to the #RestController endpoints ?
Is there a way to manually reroute requests from a endpoint to another ? (for example, using #RestController endpoints as some sort of proxy which performs controls or other operations before rerouting the request to the #RepositoryRestResource endpoints)
EDIT: I add a glimpse of the final code I'd like to have in the end.
#RestController
public class MyController {
#RequestMapping(value = "/elements/{id}", method = RequestMethod.GET)
public ResponseEntity<Element> getElements(
#PathVariable("id") Integer elementId,
#RequestParam("projection") String projection,
#RequestHeader(value = "someHeader") String header{
// [manual controls on the header then call to a service which returns the result]
}
}
#Entity
public class Element {
private Integer id;
private String shortField;
private String longField;
private List<SubElement> subElements;
// [Getters & setters]
}
#Projection(name = "light", types = {Element.class})
interface ElementLight {
public Integer getId();
public String getShortField();
}
If I call /elements/4, I'd get the complete Element having id = 4.
If I call /elements/4?projection=light, I'd get only the id and the short field of the Element having id = 4.

This answer gives some detail about how to create projection instances of your entities - https://stackoverflow.com/a/29386907/5371736
So depending on your projection parameter you could generate the given projections.
Hope this is what you are looking for.

Related

Spring MVC/WebAPI equivalent of C# RoutePrefix

I'm used to developing in C# Web API where as well as routing attributes for individual endpoints I can also add a prefix for the controller, e,g,
[RoutePrefix("/MyController")]
However I'm developing in Java Spring Boot and although I can map individual endpoints, I can't find a way to add a prefix for all.
Is this possible?
On spring-boot you can use the #RequestMapping("/MyController") annotation at the class level.
#RequestMapping("/MyController")
public class MyController {
#GetMapping(value = "/helloWord") // this will become /MyController/helloWord
public String helloWorld() {
return "Hello World";
}
}

Spring Security + MVC : same #RequestMapping, different #Secured

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)

Spring 3.1.0 mvc binding modelattribute along with requestbody

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.

#RequestMapping does not work on type and method in Spring 2.5

I have been reading on Spring 3.2 lately and I am now trying the following code using Spring 2.5. From what I have read this should mean that it should map profile/tags/me. However it doesn't. It just throws a No mapping found for HTTP request with URI .... What is wrong with the code, or didn't Spring 2.5 work like it does in Spring 3?
Problem when using Spring 2.5
#Controller
#RequestMapping("/profile/tags")
public class ProfileController { ... }
And this is the method inside ProfileController class:
#RequestMapping(value = "/me", method = RequestMethod.GET)
public String show(#RequestParam final long id, final ModelMap model) { ... }
According to Spring documentation, I imagine you're missing the required configuration to receive the request parameter, if you mean to receive this request parameter:
#RequestMapping(value = "/me/{id}", method = RequestMethod.GET)
public String show(#RequestParam("id") final long id, final ModelMap model) { ... }
Or you should remove RequestParam.
Update for Spring 2.5
Additionally, since you're using Spring 2.5, make sure that you've configured your DispatcherServlet in the expected way; Sections 13.11, subsections 1, 2, and 3. In summary:
DispatcherServlet should be told to load annotated RequestMappings.
DispatcherServlet should be told to load Controller annotations.
Not sure but maybe you need to refine the paths you use for the request mappings.
Hope this helps.

How to design a Spring MVC REST service?

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.
}

Categories

Resources