Java 如何在另一个控制器中重写@RequestMapping?
我需要扩展一个现有的控制器,并为其添加一些功能。但是作为一个项目需求,我无法在原始控制器中触及,问题是这个控制器上有一个Java 如何在另一个控制器中重写@RequestMapping?,java,spring-mvc,Java,Spring Mvc,我需要扩展一个现有的控制器,并为其添加一些功能。但是作为一个项目需求,我无法在原始控制器中触及,问题是这个控制器上有一个@RequestMapping注释。所以我的问题是,我如何向新控制器而不是旧控制器发出请求,请求/someUrl 下面是一个示例,旨在澄清我所说的内容: 原控制器: @Controller public class HelloWorldController { @RequestMapping("/helloWorld") public String hello
@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";
}
}
新控制器:
@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的情况下覆盖原始映射?每个映射必须是唯一的。。无法否决现有的
@RequestMapping
但是您总是可以做一些变通方法: 像这样在请求中使用参数将创建一个新的
@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);
}
}
无法重写作为批注的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=42myhelloworld控制器将响应请求
顺便说一下。
控制器不应是动态内容提供程序。您需要一个@Service
实例。所以您可以一次实现控制器,然后使用多个服务实现。这是本文的主要思想
这是另一个解决办法,可能有危险,也可能没有危险
创建下面的类“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;
}
}
实施示例:
@Primary
@Controller
public class MyFoobar extends Foobar {
@Override
private String index() {
return "myView";
}
}
不确定注释是否会影响处理程序映射逻辑(您可以尝试一下)。如果没有,你可以映射到另一个URL并实现某种重写(例如通过)。我必须自己更正-Order
将不起作用,因为春季不允许重复映射(正如Jordi在回答中指出的)。不幸的是,当我尝试重写时,aproach spring抛出了一个模糊的UsMappingException。您是否尝试了具有新虚拟属性的第一个选项?@JordiCastilla我的理解是,除非这些方法具有相同的名称和签名,否则无法使用重写映射。那么,第二种选择将如何运作?