Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在另一个控制器中重写@RequestMapping?_Java_Spring Mvc - Fatal编程技术网

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=42
myhelloworld控制器将响应请求


顺便说一下。 控制器不应是动态内容提供程序。您需要一个
@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我的理解是,除非这些方法具有相同的名称和签名,否则无法使用重写映射。那么,第二种选择将如何运作?