6

I have a working url as this: localhost/info

@Controller
@RequestMapping("/info")
public class VersionController {

   @RequestMapping(value = "", method = RequestMethod.GET)
   public @ResponseBody
   Map get() {
      loadProperties();
      Map<String, String> m = new HashMap<String, String>();
      m.put("buildTimestamp", properties.getProperty("Application-Build-Timestamp"));
      m.put("version", properties.getProperty("Application-Version"));
      return m;
   }

}

and I would to register some other mappings at initializing of my application as this:

localhost/xxxx/info
localhost/yyyy/info
localhost/zzzz/info

All these urls will return same response as localhost/info

The xxxx, yyyy part of the application is changeable. I have to register custom mappings as

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("???").setViewName("???");
}

Bu this is only working for views.

Any idea for dynamic registration?

5
  • Is there a reason you can't use URLs of the form /affId/1313/info? Commented Mar 19, 2013 at 13:22
  • Yes because it was completely fictional. Actually the changing part is not id part. :( Commented Mar 19, 2013 at 13:28
  • 3
    describing a situation that bears no relationship to your actual problem doesn't help you, and wastes the time of anyone who tries to help you. Commented Mar 19, 2013 at 14:42
  • And if your current example isn't as completely fictional as your earlier example, @NilsH has given you a workable answer that should require less effort than registering a new HandlerMapping. Commented Mar 19, 2013 at 14:43
  • Actually I just wanted to learn programmatically registering beans as Costi Ciudatu has resolved perfectly. Anyway, thanks for your efforts. Commented Mar 19, 2013 at 15:35

6 Answers 6

5

I believe that simple example is worth more than 1000 words :) In SpringBoot it will look like...

Define your controller (example health endpoint):

public class HealthController extends AbstractController {

    @Override
    protected ModelAndView handleRequestInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) {
        return new ModelAndView(new MappingJacksonSingleView(), "health", Health.up().build());
    }

}

And create your configuration:

@Configuration
public class CustomHealthConfig {

    @Bean
    public HealthController healthController() {
        return new HealthController();
    }

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setOrder(Integer.MAX_VALUE - 2);
        mapping.setUrlMap(ImmutableMap.of("/health", healthController()));
        return mapping;
    }

}

Regarding the handler order - take a look about the reason here: Java configuration of SimpleUrlHandlerMapping (Spring boot)

The MappingJacksonSingleView is auxiliary class in order to return single json value for model and view:

public class MappingJacksonSingleView extends MappingJackson2JsonView {

    @Override
    @SuppressWarnings("unchecked")
    protected Object filterModel(Map<String, Object> model) {
        Object result = super.filterModel(model);
        if (!(result instanceof Map)) {
            return result;
        }

        Map map = (Map) result;
        if (map.size() == 1) {
            return map.values().toArray()[0];
        }
        return map;
    }

} 

Jackson single view source - this blog post: https://www.pascaldimassimo.com/2010/04/13/how-to-return-a-single-json-list-out-of-mappingjacksonjsonview/

Hope it helps!

Sign up to request clarification or add additional context in comments.

Comments

4

You can register a new HandlerMapping where you can add the handlers for your URL paths; the most convenient implementation would be SimpleUrlHandlerMapping.

If you want those handlers to be bean methods (like those annotated with @RequestMapping) you should define them as HandlerMethod wrappers so that the already registered RequestMappingHandlerAdapter will invoke them.

4 Comments

How to use SimpleUrlHandlerMapping? How to define them as HandlerMethod wrappers? A little example would make this answer much better.
Be careful when you register your own Handler mapping. By default, the new handler ignores all HandlerInterceptor instances.
When you say "by default" do you mean that there is a switch with which the interceptors can be enabled?
No, it’s not just a « switch ». You have to replug them manually and there is no automated/easy way to do it.
4

As of Spring 5.0.M2, Spring provides a functional web framework that allows you to create "controller"-like constructs programmatically.

What you would need to do in your case is create a proper RouterFunction for the URLs you need to handle, and then simply handle the request with the appropriate HandlerFunction.

Keep in mind however that these constructs are not part of Spring MVC, but part of Spring Reactive.

Check out this blog post for more details

2 Comments

Is there any way to use HandlerMethodArgumentResolvers somehow with functional endpoints?
Not that I am aware of
3

It is possible (now) to register request mapping by RequestMappingHandlerMapping.registerMapping() method.

Example:

@Autowired
RequestMappingHandlerMapping requestMappingHandlerMapping;

public void register(MyController myController) throws Exception {
    RequestMappingInfo mappingInfo = RequestMappingInfo.paths("xxxx/info").methods(RequestMethod.GET).build();
    Method method = myController.getClass().getMethod("info");
    requestMappingHandlerMapping.registerMapping(mappingInfo, myController, method);
}


2 Comments

can you explain it please?
Check out the documentation for the mentioned method for more details. Example I've posted just maps URL to an halndling method, nothing more. docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
0

You could register your own HandlerMapping by extending the RequestMappingHandlerMapping, e.g. override the registerHandlerMethod.

Comments

-5

It's not quite clear what you're trying to achieve, but maybe you can use @PathVariable in your @RequestMapping, something like:

@RequestMapping("/affId/{id}")
public void myMethod(@PathVariable("id") String id) {}

Edit: Original example has changed it appears, but you might be able to use PathVariable anyway.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.