我需要扩展现有的控制器并为其添加一些功能。但是作为项目要求我无法触及原始控制器,问题是该控制器上有一个@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
的情况下覆盖原始地图?
答案 0 :(得分:12)
无法覆盖作为注释的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 and 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";
}
}
答案 1 :(得分:3)
每个映射必须是唯一的。。没有办法否决现有的@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);
}
}
扩展现有的:{/ p>
{{1}}
答案 2 :(得分:3)
这是另一种解决方法,可能有危险,也可能没有危险。
创建以下类" 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<String, Object> controllerBeans = getApplicationContext().getBeansWithAnnotation(Controller.class);
List<Map.Entry<String, Object>> 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<Map.Entry<String, Object>> 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启动时加载,而不是炸掉& #34;多个bean /请求映射等&#34;
&#34; super&#34;的例子控制器:
@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";
}
}