2008-09-30 2 views
32

Я использую Spring 2.5 и аннотации для настройки моего веб-контекста spring-mvc. К сожалению, я не могу заставить работать. Я не уверен, что это ошибка (похоже, это так) или если есть основное недоразумение о том, как работает подклассы аннотаций и интерфейса.Проблема Spring-MVC с использованием @Controller на контроллере, реализующем интерфейс

Например,

@Controller 
@RequestMapping("url-mapping-here") 
public class Foo { 
    @RequestMapping(method=RequestMethod.GET) 
    public void showForm() { 
    ... 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm() { 
    ... 
    } 
} 

работает отлично. Когда контекст запускается, ссылки, обработанные этим обработчиком, обнаруживаются, и все работает отлично.

Это, однако, не делает:

@Controller 
@RequestMapping("url-mapping-here") 
public class Foo implements Bar { 
    @RequestMapping(method=RequestMethod.GET) 
    public void showForm() { 
    ... 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm() { 
    ... 
    } 
} 

При попытке подтянуть URL, я получаю следующую неприятную трассировки стека:

javax.servlet.ServletException: No adapter for handler [[email protected]]: Does your handler implement a supported interface like Controller? 
    org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1091) 
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:874) 
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809) 
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) 
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:627) 

Однако, если я изменю Bar быть абстрактным суперкласс и Foo расширять его, то он работает снова.

@Controller 
@RequestMapping("url-mapping-here") 
public class Foo extends Bar { 
    @RequestMapping(method=RequestMethod.GET) 
    public void showForm() { 
    ... 
    } 
    @RequestMapping(method=RequestMethod.POST) 
    public String processForm() { 
    ... 
    } 
} 

Это похоже на ошибку. Аннотации @Controller должны быть достаточными, чтобы отметить это как контроллер, и я должен иметь возможность реализовать один или несколько интерфейсов в моем контроллере, не делая ничего другого. Есть идеи?

ответ

5

Нет сомнений в том, что аннотации и наследование могут быть немного сложными, но я думаю, что это должно сработать. Попробуйте явно добавить AnnotationMethodHandlerAdapter в свой контекст сервлета.

http://static.springframework.org/spring/docs/2.5.x/reference/mvc.html#mvc-ann-setup

Если это не работает, немного больше информации было бы полезно. В частности, являются ли два метода аннотированных контроллеров интерфейсом? Предполагается ли, что Foo является RegistrationController?

12

Ed является правильным, добавление

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> 
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> 

работает отлично

12

Что мне нужно сделать, это заменить

<tx:annotation-driven/> 

с

<tx:annotation-driven proxy-target-class="true"/> 

Это заставляет AspectJ использовать CGLIB для выполнения аспектов вместо dy namic proxies - CGLIB не теряет аннотации, так как расширяет класс, тогда как динамические прокси просто выставляют реализованный интерфейс.

+0

Необходимо, чтобы отметить, что CGLIB довольно устарела. – 2015-07-28 15:44:53

0

Истинная причина вам нужно использовать «прокси-целевой класс =„истинный“» в DefaultAnnotationHandlerMapping#determineUrlsForHandler() методы: хотя он использует ListableBeanFactory#findAnnotationOnBean для поиска в @RequestMapping аннотации (и это заботится о каких-либо вопросах по доверенности), дополнительный поиск для @Controller аннотаций осуществляется с помощью AnnotationUtils#findAnnotation (который не занимается вопросами прокси)

+0

Вы имеете в виду, что есть ошибка? – Ruslan 2017-07-19 11:04:40

10

Если вы хотите использовать интерфейсы для контроллеров Spring MVC, то вам нужно переместить аннотации вокруг немного, как указано в Весенних документы: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping

Использование @RequestMapping On Interface Methods Общепринятая ошибка, когда , работающий с классами аннотированных контроллеров, возникает при применении функции , которая требует создания прокси-объекта для объекта-контроллера (например, @Transactional методы). Обычно вы используете интерфейс для контроллера, чтобы использовать динамические прокси JDK. Чтобы выполнить эту работу , вы должны переместить аннотации @RequestMapping на интерфейс как , так как механизм отображения может «видеть» интерфейс, открытый прокси. В качестве альтернативы вы можете активировать proxy-target-class = "true" в конфигурации для функций, применяемых к контроллеру (в нашем сценарии транзакций). При этом указывает, что прокси-классы подкласса на основе CGLIB следует использовать вместо прокси-серверов JDK на основе интерфейса. Для получения дополнительной информации о различных механизмах проксирования см. Раздел 8.6 «Механизмы проксирования».

К сожалению, это не дает конкретного примера этого. Я нашел настройки, как это работает:

@Controller 
@RequestMapping(value = "/secure/exhibitor") 
public interface ExhibitorController { 

    @RequestMapping(value = "/{id}") 
    void exhibitor(@PathVariable("id") Long id); 
} 

@Controller 
public class ExhibitorControllerImpl implements ExhibitorController { 

    @Secured({"ROLE_EXHIBITOR"}) 
    @Transactional(readOnly = true) 
    @Override 
    public void exhibitor(final Long id) { 

    } 
} 

Так что у вас здесь есть интерфейс, который объявляет @Controller, @PathVariable и @RequestMapping аннотаций (аннотации Spring MVC), а затем вы можете положить ваш @ Транзакционные или @ Необработанные аннотации, например, для конкретного класса. Это только аннотации типа @Controller, которые вам нужно наложить на интерфейс из-за того, как Spring делает свои сопоставления.

Обратите внимание, что вам нужно сделать это, только если вы используете интерфейс. Вам не обязательно делать это, если вы довольны прокси-серверами CGLib, но если по какой-то причине вы хотите использовать динамические прокси-серверы JDK, это может быть путь.

2

Я знаю, что это слишком поздно, но я пишу это для тех, кто имеет эту проблему , если вы используете конфигурацию аннотаций на основе ... решение может быть таким:

@Configuration 
@ComponentScan("org.foo.controller.*") 
@EnableAspectJAutoProxy(proxyTargetClass=true) 
public class AppConfig { ...} 
Смежные вопросы