Spring MVC가 404로 응답하고 "DispatcherServlet에서 URI […]를 사용하여 HTTP 요청에 대한 맵핑을 찾을 수 없음"으로보고하는 이유는 무엇입니까?

java spring spring-mvc servlets


Tomcat에 배포 된 Spring MVC 응용 프로그램을 작성 중입니다. 다음의 최소한의 완전하고 검증 가능한 예를 참조하십시오

public class Application extends AbstractAnnotationConfigDispatcherServletInitializer {
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { };
    }
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { SpringServletConfig.class };
    }
    protected String[] getServletMappings() {
        return new String[] { "/*" };
    }
}

SpringServletConfig 가있는 곳

@Configuration
@ComponentScan("com.example.controllers")
@EnableWebMvc
public class SpringServletConfig {
    @Bean
    public InternalResourceViewResolver resolver() {
        InternalResourceViewResolver vr = new InternalResourceViewResolver();
        vr.setPrefix("/WEB-INF/jsps/");
        vr.setSuffix(".jsp");
        return vr;
    }
}

마지막으로 com.example.controllers 패키지에 @Controller 가 있습니다.

@Controller
public class ExampleController {
    @RequestMapping(path = "/home", method = RequestMethod.GET)
    public String example() {
        return "index";
    }
}

내 응용 프로그램의 컨텍스트 이름은 Example 입니다. 요청을 보낼 때

http://localhost:8080/Example/home

애플리케이션이 HTTP 상태 404로 응답하고 다음을 기록합니다.

WARN  o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI `[/Example/WEB-INF/jsps/index.jsp]` in `DispatcherServlet` with name 'dispatcher'

/WEB-INF/jsps/index.jsp 에 JSP 리소스가 있습니다. Spring MVC가 컨트롤러를 사용하여 요청을 처리하고 JSP로 전달할 것으로 예상 했는데 왜 404로 응답합니까?


이 경고 메시지에 대한 질문에 대한 표준 게시물입니다.




Answer 1 Sotirios Delimanolis


표준 Spring MVC 애플리케이션은 서블릿 컨테이너에 등록한 DispatcherServlet 을 통해 모든 요청을 처리합니다 .

DispatcherServlet 그것에서 외모 ApplicationContext 하고, 가능한 경우 ApplicationContext 등록 ContextLoaderListener 는 설정의 요청을 제공하는 로직이 필요 특별한 콩합니다. 이 bean은 문서에 설명되어 있습니다 .

형의 거의 틀림없이 가장 중요한, 콩 HandlerMapping 지도

HandlerMapping 구현에 따라 세부 사항이 달라지는 일부 기준에 따라 핸들러에 대한 수신 요청 및 사전 및 사후 프로세서 (핸들러 인터셉터) 목록 . 가장 많이 사용되는 구현은 주석이 달린 컨트롤러를 지원하지만 다른 구현도 존재합니다.

HandlerMapping 의 javadoc은 구현이 작동하는 방법을 자세히 설명합니다.

DispatcherServlet 이 유형의 모든 콩을 발견하고 어떤 순서로 등록 (사용자 정의 할 수 있음). 요청을 처리하는 동안 DispatcherServlet 은 이러한 HandlerMapping 오브젝트를 반복 하고 getHandler 로 각 오브젝트를 테스트 하여 수신 요청을 처리 할 수있는 표준 HttpServletRequest 로 식별되는 오브젝트 를 찾습니다 . 4.3.x에서 현재로, 이 중 하나를 찾을 수없는 경우 , 그것은 경고 기록 이 표시되는지를

이름이 SomeName 인 DispatcherServlet 에서 URI [/some/path] 가 있는 HTTP 요청에 대한 맵핑을 찾을 수 없습니다.

그리고 하나 발생 NoHandlerFoundException 즉시 404 찾을 수 없음 상태 코드로 응답을 얻어냅니다.

DispatcherServlet 이 요청을 처리 할 수있는 HandlerMapping 을 찾지 못한 이유는 무엇 입니까?

가장 일반적인 HandlerMapping 구현은 RequestMappingHandlerMapping 이며 @Controller Bean을 핸들러 (실제로 @RequestMapping 어노테이션이있는 메소드) 로 등록하는 것을 처리합니다 . @Bean 또는 <bean> 또는 기타 메커니즘을 사용 하여이 유형의 Bean을 직접 선언 하거나 내장 옵션을 사용할 수 있습니다 . 이것들은:

  1. @EnableWebMvc@Configuration 클래스에 주석 을 답니다 .
  2. XML 구성에서 <mvc:annotation-driven /> 멤버를 선언 하십시오.

위의 링크에서 설명했듯이 둘 다 RequestMappingHandlerMapping Bean (및 기타 여러 항목)을 등록합니다. 그러나 HandlerMapping 은 핸들러가 없으면별로 유용하지 않습니다. RequestMappingHandlerMapping 은 일부 @Controller Bean을 필요로하므로 Java 구성의 @Bean 메소드 또는 XML 구성의 <bean> 선언 또는 @Controller 어노테이션이있는 클래스 의 컴포넌트 스캔을 통해 이들을 선언해야 합니다. 이 콩이 있는지 확인하십시오.

경고 메시지와 404가 표시되고 위의 모든 사항을 올바르게 구성한 경우 요청을 잘못된 URI로 보내면 감지 된 @RequestMapping 어노테이션이있는 처리기 메소드에서 처리하지 않는 URI 입니다.

spring-webmvc 라이브러리 이벤트 다른 내장 된 HandlerMapping 구현. 예를 들어, BeanNameUrlHandlerMapping 맵핑합니다.

URL에서 슬래시 ( "/")로 시작하는 이름을 가진 Bean으로

그리고 당신은 항상 자신의 것을 쓸 수 있습니다. 분명히, 보내는 요청이 등록 된 HandlerMapping 객체의 핸들러 중 하나 이상과 일치하는지 확인해야합니다 .

HandlerMapping Bean을 내재적으로 또는 명시 적으로 등록하지 않은 경우 (또는 detectAllHandlerMappings true 인 경우 ) DispatcherServlet 은 일부 기본값을 등록합니다 . 이들은 DispatcherServlet 클래스 와 동일한 패키지의 DispatcherServlet.properties 에 정의되어 있습니다. 그들은이다 BeanNameUrlHandlerMapping DefaultAnnotationHandlerMapping (유사하다 RequestMappingHandlerMapping 하지만 사용되지 않음).

Debugging

Spring MVC는 RequestMappingHandlerMapping 을 통해 등록 된 핸들러를 기록 할 것이다 . 예를 들어 @Controller

@Controller
public class ExampleController {
    @RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
    public String example() {
        return "example-view-name";
    }
}

정보 수준에서 다음을 기록합니다.

Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()

등록 된 맵핑을 설명합니다. 핸들러를 찾을 수 없다는 경고가 표시되면 메시지의 URI를 여기에 나열된 맵핑과 비교하십시오. Spring MVC가 핸들러를 선택하려면 @RequestMapping 지정된 모든 제한 사항 이 일치해야합니다.

다른 HandlerMapping 구현은 맵핑 및 해당 핸들러에 암시해야하는 자체 명령문을 로깅합니다.

마찬가지로 DEBUG 레벨에서 Spring 로깅을 활성화하여 어떤 Bean이 스프링 레지스터인지 확인하십시오. 찾은 주석이 달린 클래스, 스캔 한 패키지 및 초기화 된 Bean을보고해야합니다. 예상 한 것이 없으면 ApplicationContext 구성 을 검토하십시오 .

다른 일반적인 실수

DispatcherServlet 은 단지 일반적인 자바 EE입니다 Servlet . 일반적인 <web.xml> <servlet-class><servlet-mapping> 선언으로 또는 WebApplicationInitializer ServletContext#addServlet 을 통해 또는 Spring 부트가 사용하는 메커니즘으로 직접 등록하십시오 . 따라서 서블릿 스펙에 지정된 URL 맵핑 로직 에 의존해야합니다 ( 12 장 참조).

이를 염두에두고 일반적인 실수는 DispatcherServlet/* 의 URL 맵핑 으로 등록하고 @RequestMapping 핸들러 메소드 에서보기 이름을 리턴 하며 JSP가 렌더링 될 것으로 예상하는 것입니다. 예를 들어 다음과 같은 핸들러 메소드를 고려하십시오.

@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
    return "example-view-name";
}

InternalResourceViewResolver

@Bean
public InternalResourceViewResolver resolver() {
    InternalResourceViewResolver vr = new InternalResourceViewResolver();
    vr.setPrefix("/WEB-INF/jsps/");
    vr.setSuffix(".jsp");
    return vr;
}

/WEB-INF/jsps/example-view-name.jsp 경로에서 요청 이 JSP 자원 으로 전달 될 것으로 예상 할 수 있습니다 . 이런 일은 일어나지 않을 것입니다. 대신 컨텍스트 이름이 Example 이라고 가정 하면 DisaptcherServlet

이름이 'dispatcher'인 DispatcherServlet 에서 URI [/Example/WEB-INF/jsps/example-view-name.jsp] 를 사용하는 HTTP 요청에 대한 맵핑을 찾을 수 없습니다.

때문에 DispatcherServlet 이이 매핑됩니다 /*/* (더 높은 우선 순위가 정확히 일치 제외) 일치의 모든의 DispatcherServlet 은 을 처리하기 위해 선택 될 forward 로부터 JstlView (에 의해 반환되는 InternalResourceViewResolver ). 거의 모든 경우에 DispatcherServlet 은 이러한 요청을 처리하도록 구성되지 않습니다 .

대신이 간단한 경우에는 DispatcherServlet/ 에 등록 하여 기본 서블릿으로 표시해야합니다. 기본 서블릿은 요청에 대한 마지막 일치입니다. 이를 통해 일반적인 서블릿 컨테이너 는 기본 서블릿을 사용하기 전에 *.jsp 에 맵핑 된 내부 서블릿 구현을 선택 하여 JSP 자원 (예 : Tomcat에 JspServlet 이 있음 ) 을 처리 할 수 ​​있습니다 .

그것이 당신의 예에서보고있는 것입니다.




Answer 2 RoutesMaps.com


앞에서 설명한 것 외에도 문제를 해결했습니다.

@Bean
public InternalResourceViewResolver resolver() {
    InternalResourceViewResolver vr = new InternalResourceViewResolver();
    vr.setPrefix("/WEB-INF/jsps/");
    vr.setSuffix(".jsp");
    return vr;
}

added tomcat-embed-jasper:

<dependency>
       <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
       <scope>provided</scope>
</dependency>

`from : JSP 파일이 Spring Boot 웹 애플리케이션에서 렌더링되지 않습니다




Answer 3 Acapulco


내 경우, 나는 다음이었다 버전 5.1.2에 대한 인터셉터 봄 문서 (사용하는 동안 봄 부팅 v2.0.4.RELEASE )와 WebConfig 의 클래스는 주석했다 @EnableWebMvc 듯했다 내 응용 프로그램에서 뭔가와 충돌 할 정적 자산이 올바르게 확인되지 않도록합니다 (예 : CSS 또는 JS 파일이 클라이언트에 반환되지 않음).

많은 다른 것들을 시도한 후에 @EnableWebMvc제거 하려고 시도했지만 효과 가 있었습니다 !

편집 : @EnableWebMvc 주석을 제거해야한다고 말하는 참조 문서 는 다음과 같습니다 .

분명히 내 경우에는 적어도 이미 Spring 응용 프로그램을 구성하고 있습니다 ( web.xml 또는 다른 정적 파일 을 사용하지는 않지만 프로그래밍 방식으로 확실합니다). 그래서 충돌이 발생했습니다.




Answer 4 Anil N.P


나는 같은 오류에 대한 또 다른 이유를 발견했습니다. controller.java 파일에 대해 생성되지 않은 클래스 파일 때문일 수도 있습니다. 그 결과 web.xml에 언급 된 디스패처 서블릿이이를 컨트롤러 클래스의 적절한 메소드에 맵핑 할 수 없습니다.

@Controller
Class Controller{
@RequestMapping(value="/abc.html")//abc is the requesting page
public void method()
{.....}
}

프로젝트-> 클린-> 프로젝트 빌드에서 일식에서 작업 영역의 빌드에서 컨트롤러 파일에 대해 클래스 파일이 생성되었는지 확인하십시오.




Answer 5 Roy


나를 위해 대상 클래스가 소스와 동일하지 않은 폴더 패턴으로 생성되었다는 것을 알았습니다. 이것은 일식으로 컨트롤러를 포함하기위한 폴더를 추가하고 패키지로 추가하지 않습니다. 그래서 스프링 설정에서 잘못된 경로를 정의하게되었습니다.

내 대상 클래스는 앱에서 클래스를 생성하고 있었고 com.happy.app를 참조하고있었습니다.

<context:annotation-config />
<context:component-scan
    base-package="com.happy.app"></context:component-scan> 

com.happy.app에 대한 패키지 (폴더가 아닌)를 추가하고 파일을 폴더에서 Eclipse의 패키지로 옮겼으며 문제가 해결되었습니다.