如何在另一个控制器中覆盖@RequestMapping?

我需要扩展现有的控制器并为其添加一些function。 但是作为一个项目要求我无法触及原始控制器,问题是该控制器上有一个@RequestMapping注释。 所以我的问题是如何向/someUrl请求我的新控制器而不是旧控制器。

这是一个例子,只是为了澄清我在说什么:

原控制器:

 @Controller public class HelloWorldController { @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", "Hello World!"); return "helloWorld"; } } 

新控制器:

 @Controller public class MyHelloWorldController { @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", "Hello World from my new controller"); // a lot of new logic return "helloWorld"; } } 

如何在不编辑HelloWorldController情况下覆盖原始映射?

无法覆盖作为注释的URL映射。 如果两个或更多控制器配置了相同的请求URL和请求方法,您将收到错误。

你可以做的是扩展请求映射:

 @Controller public class MyHelloWorldController { @RequestMapping("/helloWorld", params = { "type=42" }) public String helloWorld(Model model) { model.addAttribute("message", "Hello World from my new controller"); return "helloWorld"; } } 

示例:现在,如果您调用yourhost / helloWorld?type = 42 MyHelloWorldController将响应请求


顺便一提。 控制器不应该是动态内容提供者。 你需要一个@Service实例。 因此,您可以实现一次Controller并使用多个Service实现。 这是Spring MVC和DI的主要思想

 @Controller public class HelloWorldController { @Autowired private MessageService _messageService; // -> new MessageServiceImpl1() or new MessageServiceImpl2() ... @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", messageService.getMessage()); return "helloWorld"; } } 

每个映射必须是唯一的。 。 没有办法否决现有的@RequestMapping


你可以随时做一些解决方法:

在请求中使用param将创建一个与现有的不同的@RequestMapping

 @RequestMapping("/helloWorld/{someDataId}", method = RequestMethod.GET) public String helloWorld(@PathVariable("someDataId") final long id, Model model) { /* your code here */ } 

或者创建另一个扩展现有的@Controller

 public class YourController extends BaseController { @Override @RequestMapping("/helloWorld") public void renderDashboard(Model model){ // Call to default functionallity (if you want...) super.renderDashboard(patientId, map); } } 

这是另一种解决方法,可能有危险,也可能没有危险。

创建下面的类“MyRequestMappingHandler”,然后在MvcConfig中将其连接起来

 @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { return new MyRequestMappingHandler(); } 

RequestMappingHandlerMapping: *这不是生产代码 – 由您决定*

 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.aop.support.AopUtils; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MyRequestMappingHandler extends RequestMappingHandlerMapping { @Override protected RequestMappingInfo getMappingForMethod(Method method, Class handlerType) { RequestMappingInfo mappingForMethod = super.getMappingForMethod(method, handlerType); // Check if this class extends a super. and that super is annotated with @Controller. Class superClass = handlerType.getSuperclass(); if (superClass.isAnnotationPresent(Controller.class)) { // We have a super class controller. if (handlerType.isAnnotationPresent(Primary.class)) { // We have a @Primary on the child. return mappingForMethod; } } else { // We do not have a super class, therefore we need to look for other implementations of this class. Map controllerBeans = getApplicationContext().getBeansWithAnnotation(Controller.class); List> classesExtendingHandler = controllerBeans.entrySet().stream().filter(e -> AopUtils.getTargetClass(e.getValue()).getSuperclass().getName().equalsIgnoreCase(handlerType .getName()) && !AopUtils.getTargetClass(e.getValue()).getName().equalsIgnoreCase(handlerType.getName())) .collect(Collectors.toList()); if (classesExtendingHandler == null || classesExtendingHandler.isEmpty()) { // No classes extend this handler, therefore it is the only one. return mappingForMethod; } else { // Classes extend this handler, // If this handler is marked with @Primary and no others are then return info; List> classesWithPrimary = classesExtendingHandler .stream() .filter(e -> e.getValue().getClass().isAnnotationPresent(Primary.class) && !AopUtils.getTargetClass(e.getValue().getClass()).getName().equalsIgnoreCase (handlerType.getName())) .collect(Collectors.toList()); if (classesWithPrimary == null || classesWithPrimary.isEmpty()) { // No classes are marked with primary. return null; } else { // One or more classes are marked with @Primary, if (classesWithPrimary.size() == 1 && AopUtils.getTargetClass(classesWithPrimary.get(0).getValue ()).getClass().getName().equalsIgnoreCase(handlerType.getName())) { // We have only one and it is this one, return it. return mappingForMethod; } else if (classesWithPrimary.size() == 1 && !AopUtils.getTargetClass(classesWithPrimary.get(0) .getValue()).getClass().getName().equalsIgnoreCase(handlerType.getName())) { // Nothing. } else { // nothing. } } } } // If it does, and it is marked with @Primary, then return info. // else If it does not extend a super with @Controller and there are no children, then return info; return null; } } 

这允许你做的是,扩展一个@Controller类,并用@Primary标记它,并覆盖该类的方法,你的新类现在将在spring启动时加载而不是炸掉“多个bean /请求映射等“

“超级”控制器示例:

 @Controller public class Foobar { @RequestMapping(method = "GET") private String index() { return "view"; } } 

实施示例:

 @Primary @Controller public class MyFoobar extends Foobar { @Override private String index() { return "myView"; } }