2008-09-30 6 views
32

스프링 2.5와 주석을 사용하여 스프링 -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() { 
    ... 
    } 
} 

잘 작동합니다. 컨텍스트가 시작되면이 처리기에서 처리하는 URL이 발견되고 모든 것이 훌륭하게 작동합니다.

그러나 이것은하지 않습니다

@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) 

을 슈퍼 클래스와 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

에드

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

내가 할 필요가 무엇

12

벌금 CGLIB를 사용하는

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

이 강제 AspectJ를 함께

<tx:annotation-driven/> 

을 교체했다 작동 추가 맞다 dy 대신에 양상을하기 나믹 프락시 - CGLIB는 클래스를 확장하기 때문에 주석을 잃지 않지만 동적 프록시는 구현 된 인터페이스를 노출합니다.

+0

는주의 할 필요 CGLIB 오히려 더 이상 사용되지 않습니다. –

0

당신이 '프록시 대상 - 클래스 = "사실은"'DefaultAnnotationHandlerMapping#determineUrlsForHandler() 방법에 사용해야하는 진정한 이유는 그것이 @RequestMapping 주석을 찾기위한 ListableBeanFactory#findAnnotationOnBean를 사용한다 (이것은 프록시 문제에 대한 돌봐)하지만, 추가 @Controller 주석에 대한 조회는 AnnotationUtils#findAnnotation를 사용하여 수행됩니다 (않는하지 핸들 프록시 문제)는 다음 조금 주위에 주석을 이동해야하는 봄의 문서에서 언급 한 바와 같이, 당신의 스프링 MVC 컨트롤러의 인터페이스를 사용하려면

+0

버그가 있다는 것을 의미합니까? – Ruslan

10

: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping

인터페이스 메소드의 @RequestMapping 주석이 달린 컨트롤러 클래스와 작업 할 때 공통적 인 함정은 기능을 적용 할 때 컨트롤러 객체에 대한 프록시를 생성해야하는 공통점이 있습니다 (예 : ). @ 거래 방법). 일반적으로 컨트롤러에 대해 인터페이스를 도입하여 JDK 동적 프록시를 사용합니다. 이 을 작동 시키려면 @RequestMapping 주석을 으로 인터페이스로 이동해야합니다. 매핑 메커니즘은 프록시에 의해 노출 된 인터페이스 만 "볼"수 있습니다. 또는 컨트롤러 에 적용된 기능의 구성에서 proxy-target-class = "true" 을 활성화 할 수 있습니다 (Google 트랜잭션 시나리오 참조). 이렇게하면 은 인터페이스 기반 JDK 프록시 대신 CGLIB 기반 하위 클래스 프록시를 사용해야 함을 나타냅니다. 다양한 프록시에 대한 자세한 내용은 메커니즘을 참조하십시오.

불행히도 이것에 대한 구체적인 예는 없습니다. 이 작품처럼이 설정을 발견했다 :

@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 주석 (스프링 MVC 주석) 그리고 당신이 당신을 넣을 수 있습니다 중 하나를 선언하는 인터페이스입니다 @ 예를 들어 구체적인 클래스의 트랜잭션 또는 @Secured 주석. Spring이 매핑을 수행하는 방식 때문에 인터페이스에 넣어야하는 것은 @Controller 유형의 주석 일뿐입니다.

인터페이스를 사용하는 경우에만이 작업을 수행하면됩니다. CGLib 프록시가 만족 스럽다면 반드시 그렇게 할 필요는 없지만 JDK 동적 프록시를 사용하고 싶다면 어떤 방법이 될 수 있습니다.

2

내가 너무 늦기하지만 주석 기반 구성을 사용하는 경우 내가이 문제 이 사람이 쓰고 있어요 알고 ... 해결책은 다음과 같이 수 있습니다 :

@Configuration 
@ComponentScan("org.foo.controller.*") 
@EnableAspectJAutoProxy(proxyTargetClass=true) 
public class AppConfig { ...}