2015-04-20 11 views
13

Potrzebuję rozszerzyć istniejący kontroler i dodać do niego trochę funkcji. Ale jako wymaganie projektu nie mogę dotknąć oryginalnego kontrolera, problem polega na tym, że ten kontroler ma na sobie adnotację @RequestMapping. Tak więc moje pytanie brzmi: jak mogę zgłaszać prośby do /someUrl, aby przejść do mojego nowego kontrolera zamiast starego.Jak przesłonić @RequestMapping w innym kontrolerze?

tutaj jest przykład tylko w celu wyjaśnienia tego, co mówię:

oryginalny kontroler:

@Controller 
public class HelloWorldController { 

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

nowy Kontroler:

@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"; 
    } 
} 

jak mogę zastąpić oryginalne odwzorowanie bez edycja HelloWorldController?

+0

Nie jestem pewien, czy [' Order'] (http://docs.spring.io /spring-framework/docs/3.2.3.RELEASE/javadoc-api/org/springframework/core/annotation/Order.html) adnotacja wpłynie na logikę mapowania handlerów (możesz spróbować). Jeśli nie, możesz odwzorować na inny adres URL i zaimplementować coś w rodzaju przepisywania (np. Za pomocą [URLRewriteFilter] (http://tuckey.org/urlrewrite/)). –

+0

Muszę się poprawić - "Zamówienie" nie będzie działać, ponieważ duplikowanie map nie jest dozwolone na wiosnę (jak zauważył Jordi w swojej odpowiedzi). –

Odpowiedz

9

Url mapującą adnotacji nie może być pominięte. Otrzymasz błąd, jeśli skonfigurujesz dwa lub więcej kontrolerów za pomocą tego samego adresu URL żądania i metody żądania.

Co można zrobić, to wydłużyć mapowania żądanie:

@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"; 
    } 

} 

Przykład: Teraz jeśli zadzwonisz yourhost/helloworld type = 42MyHelloWorldController wola odpowiedź prośba


By? droga. Kontroler nie powinien być dynamicznym dostawcą treści. Potrzebujesz instancji @Service. Dzięki temu można wdrożyć kontroler raz i korzystać z wielu implementacji usług. Jest to główna idea 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"; 
    } 

} 
3

Każde odwzorowanie musi być unikalne.. Nie ma sposobu, aby uchylić istniejący @RequestMapping.



ALE Zawsze można zrobić kilka obejścia:

użyć param we wniosku jak ten stworzy nowy @RequestMapping że będzie różnić się od istniejącego.

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

lub tworzenie innej @Controller rozszerzenie istniejącego:

public class YourController extends BaseController { 

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

Niestety, gdy próbuję przesłonić aproach wiosna rzuca wyjątek AmbiguousMappingException. –

+0

Czy wypróbowałeś pierwszą opcję z nowym atrybutem * wirtualnym *? –

+2

@JordiCastilla Moim zrozumieniem jest to, że nie można użyć mapowania Zastąp, chyba że metody mają tę samą nazwę i podpis. Jak działa wtedy druga opcja? –

2

Oto kolejny obejście, które mogą lub nie mogą być niebezpieczne.

Utwórz poniżej klasy "MyRequestMappingHandler", a następnie podłączyć go w swojej MvcConfig

@Bean 
public RequestMappingHandlerMapping requestMappingHandlerMapping() { 

    return new MyRequestMappingHandler(); 
} 

RequestMappingHandlerMapping: * TO NIE JEST KOD PRODUKCJI - do you *

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; 
    } 
} 

co to pozwala to zrobić, rozszerzyć klasę @Controller i oznaczyć ją jako @Primary, i zastąpić metodę na tej klasie, twoja nowa klasa zostanie załadowana, gdy wiosną rozpocznie się zamiast wysadzać w powietrze "wiele fasoli/reques" t mapowania etc”

przykładem "super" Kontroler:

@Controller 
public class Foobar { 

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

} 

przykładem realizacji:

@Primary 
@Controller 
public class MyFoobar extends Foobar { 

    @Override 
    private String index() { 
     return "myView"; 
    } 

} 
Powiązane problemy