Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to dynamically set RequestMappings in Spring MVC?

Tags:

spring-mvc

I've been using Spring MVC for three months now. I was considering a good way to dynamically add RequestMapping. This comes from the necessity to put controller parts in a library and then add them dinamically. Anyway, the only way I can think of is to declare a controller like this:

@Controller
@RequestMapping("/mypage")
public class MyController {

@RequestMapping(method = RequestMethod.GET)
    public ModelAndView mainHandler(HttpServletRequest req) {
        return handleTheRest(req);
    }

}

Which is no good because basically I'm not using Spring. Then I cannot use form binding, annotations etc.. I'd like to add requestMappings dynamically to methods of classes that could be annotated like usual MVC controllers, with autobinding, so that I could avoid processing HttpServletRequest manually.

Any ideas? }

like image 868
gotch4 Avatar asked Apr 22 '11 18:04

gotch4


People also ask

What is the use of @RequestMapping in Spring MVC?

One of the most important annotations in spring is the @RequestMapping Annotation which is used to map HTTP requests to handler methods of MVC and REST controllers. In Spring MVC applications, the DispatcherServlet (Front Controller) is responsible for routing incoming HTTP requests to handler methods of controllers.

What is difference between RestController and RequestMapping?

In case of @RestController the parameter value depicts the component name or bean name, whereas in @RequestMapping the value parameter is used to specify the path. Both are used for different purpose. If you want to specify request URI path on controller class name use @RequestMapping annotation with @RestController .

What is the difference between RequestMapping and GetMapping?

@RequestMapping is used at the class level while @GetMapping is used to connect the methods. This is also an important Spring MVC interview question to knowing how and when to use both RequestMapping and GetMapping is crucial for Java developers.

What will happen if handler methods @RequestMapping?

Using @RequestMapping With HTTP Methods In the code snippet above, the method element of the @RequestMapping annotations indicates the HTTP method type of the HTTP request. All the handler methods will handle requests coming to the same URL ( /home), but will depend on the HTTP method being used.


3 Answers

Spring MVC performs URL mappings using implementations of the HandlerMapping interface. The ones usually used out of the box are the default implementations, namely SimpleUrlHandlerMapping, BeanNameUrlHandlerMapping and DefaultAnnotationHandlerMapping.

If you want to implement your own mapping mechanism, this is fairly easy to do - just implement that interface (or, perhaps more likely, extend AbstractUrlHandlerMapping), declare the class as a bean in your context, and it will be consulted by DispatcherServlet when a request needs to be mapped.

Note that you can have as many HandlerMapping implementations as you like in the one context. They will be consulted in turn until one of them has a match.

like image 154
skaffman Avatar answered Sep 28 '22 05:09

skaffman


I know this is really old but I figured I toss this in in case anyone else has the same rough experience I did trying to make this work. I ended up taking advantage of two features of Spring: the ability to dynamically register beans after the context is started and the afterPropertiesSet() method on the RequestMappingHandlerMapping object.

When RequestMappingHandlerMapping is initialized, it scans the context and creates a map of all @RequestMappings that it needs to serve (presumably for performance reasons). If you dynamically register beans annotated with @Controller, they will not be picked them up. To retrigger this scan, you just need to call afterPropertiesSet() after you've added your beans.

In my particular use case, I instantiated the new @Controller objects in a separate Spring context and needed to wire them into my WebMvc context. The particulars of how the objects don't matter for this though, all you need is an object reference:

//register all @Controller beans from separateContext into webappContext
separateContext.getBeansWithAnnotation(Controller.class)
   .forEach((k, v) -> webappContext.getBeanFactory().registerSingleton(k, v));

//find all RequestMappingHandlerMappings in webappContext and refresh them
webappContext.getBeansOfType(RequestMappingHandlerMapping.class)
   .forEach((k, v) -> v.afterPropertiesSet());

For example, you could also do this:

//class annotated with @Controller
MyController controller = new MyController

//register new controller object
webappContext.getBeanFactory().registerSingleton("myController", controller);

//find all RequestMappingHandlerMappings in webappContext and refresh them
webappContext.getBeansOfType(RequestMappingHandlerMapping.class)
   .forEach((k, v) -> v.afterPropertiesSet());
like image 36
monitorjbl Avatar answered Sep 28 '22 03:09

monitorjbl


I spent a long time trying to get this to work, but finally managed to find a solution that returns a ResponseEntity instead of the older ModelAndView. This solution also has the added benefit of avoiding any explicit interaction with Application Context.

Endpoint Service

@Service
public class EndpointService {

  @Autowired
  private QueryController queryController;

  @Autowired
  private RequestMappingHandlerMapping requestMappingHandlerMapping;

  public void addMapping(String urlPath) throws NoSuchMethodException {

    RequestMappingInfo requestMappingInfo = RequestMappingInfo
            .paths(urlPath)
            .methods(RequestMethod.GET)
            .produces(MediaType.APPLICATION_JSON_VALUE)
            .build();

    requestMappingHandlerMapping.
            registerMapping(requestMappingInfo, queryController,
                    QueryController.class.getDeclaredMethod("handleRequests")
            );
  }

}

Controller to handle newly mapped requests

@Controller
public class QueryController {

  public ResponseEntity<String> handleRequests() throws Exception {

    //Do clever stuff here

    return new ResponseEntity<>(HttpStatus.OK);
  }

}
like image 35
kaybee99 Avatar answered Sep 28 '22 05:09

kaybee99