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

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

마지막으로 @Controller패키지에com.example.controllers

@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.jspSpring MVC가 내 컨트롤러를 사용하여 요청을 처리하고 JSP로 전달 하는 데 JSP 리소스가 있는데 왜 404로 응답합니까?


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



답변

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

DispatcherServlet의에서 외모 ApplicationContext와는 가능한 경우 ApplicationContext에 등록 ContextLoaderListener이 설정의 요청을 제공하는 로직이 필요 특별한 콩을 위해. 이러한 빈은 문서에 설명되어 있습니다 .

틀림없이 가장 중요한 유형 HandlerMapping맵의 빈

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

의 javadoc는HandlerMapping 더는 구현이 행동해야하는 방법에 대해 설명합니다.

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

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

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

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

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

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

위의 링크에서 설명했듯이 두 가지 모두 RequestMappingHandlerMapping빈 (및 기타 여러 가지)을 등록합니다. 그러나 HandlerMapping핸들러 없이는별로 유용하지 않습니다. RequestMappingHandlerMapping일부 @Controllerbean을 예상 하므로 @BeanJava 구성의 메소드 또는 <bean>XML 구성의 선언을 통해 또는 @Controller둘 중 하나에서 주석 이 달린 클래스 의 구성 요소 스캔을 통해이를 선언 해야합니다. 이 콩이 있는지 확인하십시오.

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

spring-webmvc라이브러리 이벤트 다른 내장 HandlerMapping구현. 예 : BeanNameUrlHandlerMapping지도

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

언제든지 직접 작성할 수 있습니다. 당연히 보내려는 요청이 등록 된 HandlerMapping객체의 핸들러 중 하나 이상과 일치하는지 확인해야합니다 .

암시 적 또는 명시 적으로 등록하지 당신이 경우 HandlerMapping콩 (또는 경우 detectAllHandlerMappings이다 true)의 DispatcherServlet레지스터 일부 기본값을 . 이들은 클래스 DispatcherServlet.properties와 동일한 패키지에 정의되어 DispatcherServlet있습니다. 그들은이다 BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping(과 유사하다 RequestMappingHandlerMapping하지만 사용되지 않음).

디버깅

Spring MVC는 RequestMappingHandlerMapping. 예를 들어, @Controller좋아요

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

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

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

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

다른 HandlerMapping구현은 매핑 및 해당 핸들러에 대한 힌트를 제공해야하는 자체 문을 기록합니다.

마찬가지로, DEBUG 수준에서 Spring 로깅을 활성화하여 Spring이 등록하는 Bean을 확인하십시오. 찾은 주석이 달린 클래스, 스캔하는 패키지 및 초기화하는 Bean을보고해야합니다. 예상 한 항목이 없으면 ApplicationContext구성 을 검토하십시오 .

기타 일반적인 실수

A DispatcherServlet는 일반적인 Java EE Servlet입니다. 전형적인으로 당신은 그것을 등록 <web.xml> <servlet-class><servlet-mapping>신고, 직접을 통해 ServletContext#addServletA의 WebApplicationInitializer, 또는 어떤 메커니즘 봄 부팅 용도로. 따라서 서블릿 사양에 지정된 URL 매핑 논리 에 의존해야합니다 ( 12 장 참조).

이를 염두에두고를 DispatcherServletURL 매핑 으로 등록하고 핸들러 메서드 /*에서 뷰 이름을 반환 @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;
}

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

URI [/Example/WEB-INF/jsps/example-view-name.jsp]DispatcherServlet‘dispatcher’인 HTTP 요청에 대한 매핑을 찾을 수 없습니다.

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

대신,이 단순한 경우에, 당신은 등록해야 DispatcherServlet에를 /기본 서블릿으로 표시. 기본 서블릿은 요청에 대한 마지막 일치입니다. 이렇게하면 일반적인 서블릿 컨테이너가 기본 서블릿으로 시도하기 전에 *.jspJSP 리소스 (예 : Tomcat has JspServlet) 를 처리하기 위해에 매핑 된 내부 서블릿 구현을 선택할 수 있습니다 .

그것이 귀하의 예에서 보는 것입니다.


답변

이전에 설명한 것 외에도 내 문제를 해결했습니다 .`

@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 : Spring Boot 웹 애플리케이션에서 렌더링되지 않는 JSP 파일


답변

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

다른 많은 것들을 시도 후, 나는 시도 제거@EnableWebMvc하고 일했다!

편집 : 주석을 제거해야한다는 참조 문서 가 있습니다.@EnableWebMvc

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


답변

구성 파일에서 다음 변경 사항으로 코드를 수정하십시오. 대신 Java 구성이 사용됩니다 application.properties. configureDefaultServletHandling방법 에서 구성을 활성화하는 것을 잊지 마십시오 .

WebMvcConfigurerAdapter클래스는 더 이상 사용되지 않으므로 WebMvcConfigurer인터페이스 를 사용 합니다.

@Configuration
@EnableWebMvc
@ComponentScan
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

나는 gradle을 사용하며 다음과 같은 종속성이 있어야합니다 pom.xml.

dependencies {

    compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.3.0.RELEASE'
    compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.0.35'
}


답변

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

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

프로젝트 아래의 이클립스에서 클린-> 프로젝트 빌드를 선택하십시오. 작업 공간의 빌드에서 컨트롤러 파일에 대해 클래스 파일이 생성되었는지 확인하십시오.


답변

저에게는 대상 클래스가 소스와 동일하지 않은 폴더 패턴으로 생성되었음을 알았습니다. 이것은 아마도 이클립스에서 내 컨트롤러를 포함하는 폴더를 추가하고 패키지로 추가하지 않을 것입니다. 그래서 나는 스프링 구성에서 잘못된 경로를 정의했습니다.

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

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

com.happy.app에 대한 패키지 (폴더 아님)를 추가하고 파일을 폴더에서 이클립스의 패키지로 이동하여 문제를 해결했습니다.


답변

서버를 청소하십시오. 서버를 삭제하고 프로젝트를 다시 추가하고 실행하십시오.

  1. Tomcat 서버 중지

  2. 서버를 마우스 오른쪽 버튼으로 클릭하고 “Clean”을 선택합니다.

  3. 서버를 다시 마우스 오른쪽 단추로 클릭하고 “Tomcat 작업 디렉토리 정리”를 선택하십시오.