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.jsp
Spring MVC가 내 컨트롤러를 사용하여 요청을 처리하고 JSP로 전달 하는 데 JSP 리소스가 있는데 왜 404로 응답합니까?
이것은이 경고 메시지에 대한 질문에 대한 표준 게시물입니다.
답변
표준 Spring MVC 애플리케이션은 DispatcherServlet
Servlet 컨테이너에 등록한를 통해 모든 요청을 처리합니다 .
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>
또는 기타 메커니즘을 사용 하여) 내장 옵션을 사용할 수 있습니다 . 이것들은:
- 당신의 주석
@Configuration
과 클래스를@EnableWebMvc
. <mvc:annotation-driven />
XML 구성에서 멤버를 선언 하십시오.
위의 링크에서 설명했듯이 두 가지 모두 RequestMappingHandlerMapping
빈 (및 기타 여러 가지)을 등록합니다. 그러나 HandlerMapping
핸들러 없이는별로 유용하지 않습니다. RequestMappingHandlerMapping
일부 @Controller
bean을 예상 하므로 @Bean
Java 구성의 메소드 또는 <bean>
XML 구성의 선언을 통해 또는 @Controller
둘 중 하나에서 주석 이 달린 클래스 의 구성 요소 스캔을 통해이를 선언 해야합니다. 이 콩이 있는지 확인하십시오.
경고 메시지와 404가 표시되고 위의 모든 사항을 올바르게 구성한 경우 감지 된 주석 처리기 메서드에서 처리하지 않는 잘못된 URI로 요청을 보내는 것@RequestMapping
입니다.
spring-webmvc
라이브러리 이벤트 다른 내장 HandlerMapping
구현. 예 : BeanNameUrlHandlerMapping
지도
URL에서 슬래시 ( “/”)로 시작하는 이름을 가진 Bean으로
언제든지 직접 작성할 수 있습니다. 당연히 보내려는 요청이 등록 된 HandlerMapping
객체의 핸들러 중 하나 이상과 일치하는지 확인해야합니다 .
암시 적 또는 명시 적으로 등록하지 당신이 경우 HandlerMapping
콩 (또는 경우 detectAllHandlerMappings
이다 true
)의 DispatcherServlet
레지스터 일부 기본값을 . 이들은 클래스 DispatcherServlet.properties
와 동일한 패키지에 정의되어 DispatcherServlet
있습니다. 그들은이다 BeanNameUrlHandlerMapping
와 DefaultAnnotationHandlerMapping
(과 유사하다 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#addServlet
A의 WebApplicationInitializer
, 또는 어떤 메커니즘 봄 부팅 용도로. 따라서 서블릿 사양에 지정된 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;
}
요청 이 경로의 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
에를 /
기본 서블릿으로 표시. 기본 서블릿은 요청에 대한 마지막 일치입니다. 이렇게하면 일반적인 서블릿 컨테이너가 기본 서블릿으로 시도하기 전에 *.jsp
JSP 리소스 (예 : 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>
답변
내 경우, 나는 다음이었다 버전 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에 대한 패키지 (폴더 아님)를 추가하고 파일을 폴더에서 이클립스의 패키지로 이동하여 문제를 해결했습니다.
답변
서버를 청소하십시오. 서버를 삭제하고 프로젝트를 다시 추가하고 실행하십시오.
-
Tomcat 서버 중지
-
서버를 마우스 오른쪽 버튼으로 클릭하고 “Clean”을 선택합니다.
-
서버를 다시 마우스 오른쪽 단추로 클릭하고 “Tomcat 작업 디렉토리 정리”를 선택하십시오.