2011-04-22 59 views
10

我一直在使用Spring MVC三個月。我正在考慮一個動態添加RequestMapping的好方法。這是由於必須將控制器部件放入庫中,然後將其添加到媒體庫中。無論如何,我能想到的唯一辦法是宣佈這樣的控制器:是否可以在Spring MVC中動態設置RequestMappings?

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

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

} 

這是沒有好處,因爲基本上我沒有使用Spring。然後我不能使用形式結合,註釋等。我想動態添加到requestMappings可能被註釋等通常MVC控制器,具有自動綁定的類的方法,使我能避免手動處理的HttpServletRequest。

任何想法? }

回答

23

Spring MVC使用HandlerMapping接口的實現執行URL映射。通常開箱即用的那些是默認的實現,即SimpleUrlHandlerMappingBeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping

如果你想實現你自己的映射機制,這很容易做 - 只需實現該接口(或者更可能的話,擴展AbstractUrlHandlerMapping),在你的上下文中將該類聲明爲一個bean,請求需要映射時,請參考DispatcherServlet

注意,你在一個上下文喜歡,你可以有很多HandlerMapping實現。他們將被輪流徵詢,直到他們中的一個進行比賽。

+0

感謝斯卡夫,你總要給偉大的祕訣。無論如何,我如何通過代碼操作上下文,我的意思是,是否有一種方法來動態添加HandlerMapping bean或其他bean? – gotch4 2011-04-23 09:01:17

+0

@ gotch4:你不需要動態添加一個'HandlerMapping'。你配置一個*自定義的'HandlerMapping',然後動態地添加映射到它。既然你自己寫了'HandlerMapping',那麼這個工作是由你自己決定的。 – skaffman 2011-04-23 09:12:53

2

我知道這是真的老了,但我想我萬一別人折騰這有相同的坎坷經歷我也努力使這項工作。我最終利用了Spring的兩個特性:在上下文啓動後動態註冊bean的能力以及RequestMappingHandlerMapping對象上的afterPropertiesSet()方法。

當初始化RequestMappingHandlerMapping時,它會掃描上下文並創建它需要服務的所有@RequestMapping的映射(推測可能是出於性能原因)。如果您動態註冊使用@Controller註釋的bean,它們將不會被選中。要重新掃描此掃描,只需在添加完豆後調用afterPropertiesSet()即可。

在我的具體使用情況下,我實例化的新@Controller對象在一個單獨的Spring上下文和它們連接到我的WebMvc方面需要。如何對象沒有爲這雖然事情的細節,所有你需要的是一個對象的引用:

//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()); 

例如,你也可以這樣做:

//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()); 
3

請大家看我的解決辦法。它不會在你的代碼創建動態@RequestMapping,但提供了一個HandlerMappingController處理所有請求。如果您運行該應用程序,您將在json中獲得hello world消息。

應用類:

@SpringBootApplication 
public class Application { 
    public static void main(String[] args) { 
    SpringApplication.run(Application.class, args); 
    } 

    @Bean 
    public MyCustomHandler myCustomHandler(MyCustomController myCustomController) { 
    MyCustomHandler myCustomHandler = new MyCustomHandler(myCustomController); 
    myCustomHandler.setOrder(Ordered.HIGHEST_PRECEDENCE); 
    return myCustomHandler; 
    } 
} 

MyCustomController

@Component 
public class MyCustomController extends AbstractController { 

    @Override 
    protected ModelAndView handleRequestInternal(HttpServletRequest request, 
     HttpServletResponse response) throws Exception { 
    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); 
    response.getWriter().println("{\"hello\":\"world\"}"); 
    return null; 
    } 
} 

MyCustomHandler

public class MyCustomHandler extends AbstractHandlerMapping { 

    private MyCustomController myCustomController; 

    public MyCustomHandler(MyCustomController myCustomController) { 
    this.myCustomController = myCustomController; 
    } 

    @Override 
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception { 
    return myCustomController; 
    } 
} 

https://github.com/nowszy94/spring-mvc-dynamic-controller

1

我花了很長時間試圖讓這個工作,但最終設法找到一個解決方案,返回ResponseEntity而不是舊的ModelAndView。此解決方案還具有避免與Application Context進行任何明確交互的額外好處。

端點服務

@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 
public class QueryController { 

    public ResponseEntity<String> handleRequests() throws Exception { 

    //Do clever stuff here 

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

} 
+0

你可以在addMapping被調用時添加什麼時候? – Tiago 2018-02-04 10:42:33

+0

它可以從任何你喜歡的地方調用。就我而言,我的應用程序發佈到一個單獨的端點來解析新的請求,並最終調用'addMapping' – kaybee99 2018-02-05 09:38:43

相關問題