是否可以在Spring MVC中动态设置RequestMappings?

got*_*ch4 11 spring-mvc

我已经使用Spring MVC三个月了.我正在考虑一种动态添加RequestMapping的好方法.这需要将控制器部件放入库中,然后以动态方式添加它们.无论如何,我能想到的唯一方法就是声明一个这样的控制器:

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

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

}
Run Code Online (Sandbox Code Playgroud)

哪个不好,因为基本上我没有使用Spring.然后我不能使用表单绑定,注释等.我想将requestMappings动态添加到可以像通常的MVC控制器一样注释的类的方法,并使用自动绑定,这样我就可以避免手动处理HttpServletRequest.

有任何想法吗?}

ska*_*man 24

Spring MVC使用HandlerMapping接口的实现来执行URL映射.通常开箱即用的那些是默认的实现,即SimpleUrlHandlerMapping,BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping.

如果你想实现自己的映射机制,这很容易做到 - 只需实现该接口(或者,更有可能,扩展AbstractUrlHandlerMapping),在上下文中将类声明为bean,并DispatcherServlet在请求时查阅它需要映射.

请注意,您可以HandlerMapping在一个上下文中拥有任意数量的实现.他们将被轮流咨询,直到其中一人有比赛.


mon*_*jbl 6

我知道这真的很旧,但我想我会扔掉这个以防万一其他人有同样的粗略经历,我试图使这项工作成功。我最终利用了 Spring 的两个特性:在上下文启动后动态注册 bean 的能力和对象afterPropertiesSet()上的方法RequestMappingHandlerMapping

RequestMappingHandlerMapping初始化时,它会扫描环境和创建地图所有的@RequestMappings表示它需要服务(大概是因为性能原因)。如果您动态注册带有 注释的 bean @Controller,它们将不会被选中。要重新触发此扫描,您只需afterPropertiesSet()在添加 bean 后调用。

在我的特定用例中,我@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());
Run Code Online (Sandbox Code Playgroud)

例如,您还可以这样做:

//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());
Run Code Online (Sandbox Code Playgroud)


Mic*_*ksa 6

以下构造在单个类中配置和实现处理程序方法。

它是动态的和静态映射的组合-所有MVC注释可用于像 @RequestParam @PathVariable@RequestBody等。

顺便说一句:@RestController注释从类中创建 bean 并添加@ResponseBody到每个处理程序方法中,因此不必手动完成。

@RestController
public class MyController {

    @Inject
    private RequestMappingHandlerMapping handlerMapping;

    /***
     * Register controller methods to various URLs.
     */
    @PostConstruct
    public void init() throws NoSuchMethodException {

        /**
         * When "GET /simpleHandler" is called, invoke, parametrizedHandler(String,
         * HttpServletRequest) method.
         */
        handlerMapping.registerMapping(
                RequestMappingInfo.paths("/simpleHandler").methods(RequestMethod.GET)
                .produces(MediaType.APPLICATION_JSON_VALUE).build(),
                this,
                // Method to be executed when above conditions apply, i.e.: when HTTP
                // method and URL are called)
                MyController.class.getDeclaredMethod("simpleHandler"));

        /**
         * When "GET /x/y/z/parametrizedHandler" is called invoke
         * parametrizedHandler(String, HttpServletRequest) method.
         */
        handlerMapping.registerMapping(
                RequestMappingInfo.paths("/x/y/z/parametrizedHandler").methods(RequestMethod.GET)
                .produces(MediaType.APPLICATION_JSON_VALUE).build(),
                this,
                // Method to be executed when above conditions apply, i.e.: when HTTP
                // method and URL are called)
                MyController.class.getDeclaredMethod("parametrizedHandler", String.class, HttpServletRequest.class));
    }

    // GET /simpleHandler
    public List<String> simpleHandler() {
        return Arrays.asList("simpleHandler called");
    }

    // GET /x/y/z/parametrizedHandler
    public ResponseEntity<List<String>> parametrizedHandler(
            @RequestParam(value = "param1", required = false) String param1,
            HttpServletRequest servletRequest) {
        return ResponseEntity.ok(Arrays.asList("parametrizedHandler called", param1));
    }
}
Run Code Online (Sandbox Code Playgroud)


now*_*y94 5

请看我的解决方案。它不会@RequestMapping在您的代码中创建动态,但提供了一个处理所有请求的HandlerMapping和。Controller如果运行该应用程序,您将收到 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我的自定义控制器

@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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我的自定义处理程序

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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


kay*_*e99 5

我花了很长时间尝试使它起作用,但最终设法找到一个返回a 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")
            );
  }

}
Run Code Online (Sandbox Code Playgroud)

控制器处理新映射的请求

@Controller
public class QueryController {

  public ResponseEntity<String> handleRequests() throws Exception {

    //Do clever stuff here

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

}
Run Code Online (Sandbox Code Playgroud)