Spring MVC neden bir 404 ile yanıt veriyor ve "DispatcherServlet'te […] URI ile HTTP isteği için eşleşme bulunamadı" şeklinde rapor veriyor?


91

Tomcat üzerinde konuşlandırılmış bir Spring MVC uygulaması yazıyorum. Aşağıdaki minimal, eksiksiz ve doğrulanabilir örneğe bakın

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[] { "/*" };
    }
}

nerede SpringServletConfigolduğunu

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

Son olarak, @Controllerpakette bir tane varcom.example.controllers

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

Uygulamamın bağlam adı Example. Bir istek gönderdiğimde

http://localhost:8080/Example/home

uygulama bir HTTP Durumu 404 ile yanıt verir ve aşağıdakileri kaydeder

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'

Bir JSP kaynağım var, /WEB-INF/jsps/index.jspSpring MVC'nin denetleyicimi kullanarak isteği yerine getirmesini ve JSP'ye iletmesini bekledim, peki neden 404 ile yanıt veriyor?


Bu, bu uyarı mesajıyla ilgili sorular için kanonik bir gönderi olması amaçlanmıştır.

Yanıtlar:


100

Standart Spring MVC uygulamanız, DispatcherServletServlet konteynerinize kaydettiğiniz bir aracılığıyla tüm talepleri karşılayacaktır .

DispatcherServletOnun en bakar ApplicationContextve varsa, ApplicationContextbir kayıtlı ContextLoaderListenero kurulum kendi isteği sunma mantığı gereken özel fasulye için. Bu çekirdekler belgelerde açıklanmaktadır .

Muhtemelen en önemli, fasulye türü HandlerMappingharita

işleyicilere gelen istekler ve ayrıntıları HandlerMappinguygulamaya göre değişen bazı kriterlere göre ön ve son işlemcilerin (işleyici engelleyicileri) listesi . En popüler uygulama açıklamalı denetleyicileri destekler ancak başka uygulamalar da mevcuttur.

Bir JavadocHandlerMapping ileri uygulamaları davranması gerektiğini açıklamaktadır.

DispatcherServletBu türdeki tüm fasulye bulur ve bazı sırayla kaydeder (özelleştirilebilir). Bir istek sunarken, DispatcherServletbu HandlerMappingnesneler arasında döngüler oluşturur getHandlerve standart olarak temsil edilen gelen isteği işleyebilecek birini bulmak için her birini test eder HttpServletRequest. 4.3.x'ten itibaren bulamazsa , gördüğünüz uyarıyı günlüğe kaydeder.

Hiçbir haritalama URI ile HTTP isteğinde bulundu [/some/path]yılında DispatcherServletadı SomeName ile

ve ya bir atar NoHandlerFoundExceptionya da yanıtı 404 Bulunamadı durum koduyla hemen tamamlar.

Neden vermedi DispatcherServletbir bulmak HandlerMappingbenim isteği ele verebilir?

En yaygın HandlerMappinguygulama, fasulyelerin işleyiciler olarak RequestMappingHandlerMappingkaydedilmesidir @Controller(aslında @RequestMappingaçıklamalı yöntemler). Ya kendin (bu tip bir fasulye ilan edebilir @Beanveya <bean>veya başka bir mekanizma) ya da kullanabilirsiniz seçenekleri yerleşik . Bunlar:

  1. İle @Configurationsınıfınıza açıklama ekleyin @EnableWebMvc.
  2. <mvc:annotation-driven />XML yapılandırmanızda bir üye bildirin .

Yukarıdaki bağlantıda açıklandığı gibi, her ikisi de bir RequestMappingHandlerMappingfasulyeyi (ve bir sürü başka şeyi) kaydedecek . Ancak, HandlerMappingbir işleyici olmadan a pek kullanışlı değildir. RequestMappingHandlerMappingbazı @Controllerfasulye beklediğinden , bunları da @Beanbir Java yapılandırmasındaki yöntemler veya <bean>bir XML yapılandırmasındaki bildirimler yoluyla veya @Controllerher ikisinde de açıklamalı sınıfların bileşen taraması yoluyla bildirmeniz gerekir . Bu fasulyelerin mevcut olduğundan emin olun.

Uyarı mesajını ve bir 404 alıyorsanız ve yukarıdakilerin tümünü doğru şekilde yapılandırdıysanız , isteğinizi tespit edilen @RequestMappingek açıklamalı bir işleyici yöntemi tarafından işlenmeyen yanlış URI'ye gönderiyorsunuz demektir .

spring-webmvcKütüphane teklifler diğer yerleşik HandlerMappinguygulamalar. Örneğin BeanNameUrlHandlerMappingharitalar

URL'lerden eğik çizgiyle ("/") başlayan adlara kadar

ve her zaman kendi yazabilirsin. Açıkçası, gönderdiğiniz talebin kayıtlı HandlerMappingnesnenin işleyicilerinden en az biriyle eşleştiğinden emin olmanız gerekir .

Örtük veya açık herhangi kayıt sen yoksa HandlerMappingfasulye (veya eğer detectAllHandlerMappingsolduğunu true), DispatcherServletkayıtlarını bazı varsayılan . Bunlar sınıfla DispatcherServlet.propertiesaynı pakette tanımlanır DispatcherServlet. Bunlar BeanNameUrlHandlerMappingve DefaultAnnotationHandlerMapping(benzer RequestMappingHandlerMappingancak kullanımdan kaldırılmış).

Hata ayıklama

Spring MVC, üzerinden kaydedilen işleyicileri günlüğe kaydeder RequestMappingHandlerMapping. Örneğin, bir @Controllerbeğeni

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

INFO düzeyinde aşağıdakileri günlüğe kaydedecek

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

Bu, kaydedilen eşleştirmeyi tanımlar. İşleyici bulunamadığına dair uyarıyı gördüğünüzde, mesajdaki URI'yi burada listelenen eşlemeyle karşılaştırın. @RequestMappingİşleyiciyi seçmek için Spring MVC'de belirtilen tüm kısıtlamalar eşleşmelidir.

Diğer HandlerMappinguygulamalar, eşlemelerine ve karşılık gelen işleyicilerine ipucu vermesi gereken kendi ifadelerini günlüğe kaydeder.

Benzer şekilde, Bahar'ın hangi fasulyeleri kaydettiğini görmek için DEBUG düzeyinde Bahar günlüğünü etkinleştirin. Hangi açıklamalı sınıfları bulduğunu, hangi paketleri taradığını ve hangi çekirdekleri başlattığını rapor etmelidir. Beklediğiniz mevcut değilse, ApplicationContextyapılandırmanızı gözden geçirin .

Diğer yaygın hatalar

A DispatcherServlet, tipik bir Java EE'dir Servlet. Senin tipik ile Bunu kayıt <web.xml> <servlet-class>ve <servlet-mapping>beyan veya doğrudan aracılığıyla ServletContext#addServletbir yer WebApplicationInitializer, ya da her türlü mekanizma Bahar önyükleme kullanımları. Bu nedenle, Servlet belirtiminde belirtilen url eşleme mantığına güvenmeniz gerekir , Bölüm 12'ye bakın. Ayrıca bkz.

Bunu akılda tutarak, yaygın bir hata, DispatcherServletbir url eşlemesi ile kaydetmek, /*bir @RequestMappingeylemci yönteminden bir görünüm adı döndürmek ve bir JSP'nin işlenmesini beklemektir. Örneğin, bir işleyici yöntemi düşünün.

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

bir ile InternalResourceViewResolver

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

isteğin yoldaki bir JSP kaynağına iletilmesini bekleyebilirsiniz /WEB-INF/jsps/example-view-name.jsp. Bu olmayacak. Bunun yerine, bir bağlam adı varsayılarak Example, DisaptcherServletwill rapor

Hiçbir haritalama URI ile HTTP isteğinde bulundu [/Example/WEB-INF/jsps/example-view-name.jsp]yılında DispatcherServletadı 'memuru' ile

Çünkü DispatcherServleteşleştirilmiş /*ve /*(daha yüksek önceliğe sahip tam eşleme, hariç) her şeyi maçları, DispatcherServletişlemek için seçileceğini forwarddan JstlView(tarafından döndürülen InternalResourceViewResolver). Hemen hemen her durumda, DispatcherServletböyle bir talebi karşılayacak şekilde yapılandırılmayacaktır .

Bunun yerine, bu basit durumda, kayıt olmalıdır DispatcherServletTo /varsayılan servlet olarak işaretlemeyi. Varsayılan sunucu uygulaması, bir istek için son eşleşmedir. Bu, tipik sunucu uygulaması kapsayıcınızın , varsayılan sunucu uygulamasını denemeden önce *.jspJSP kaynağını (örneğin Tomcat sahip JspServlet) işlemek için eşlenen bir dahili Servlet uygulamasını seçmesine olanak tanır .

Örneğinizde gördüğünüz bu.


@EnableWebMvc ile dispatcherServlet zaten / 'a kayıtlı. "isteğin /WEB-INF/jsps/example-view-name.jsp yolundaki bir JSP kaynağına iletilmesini bekleyebilirsiniz. Bu olmayacak." O yoldaki bir JSP kaynağına yönlendirmesi için nasıl çalışmasını sağlarsınız? Bu temelde sorulan soru.
Tor

@Tor Kendi başına, @EnableWebMvcbir üzerinde @Configurationaçıklamalı sınıfta bunu yapmaz. Tek yaptığı, uygulama bağlamına bir dizi varsayılan Spring MVC işleyicisi / bağdaştırıcısı eklemesidir. Bir DispatcherServletservise kaydolmak /, Diğer yaygın hatalar bölümünde açıkladığım çeşitli şekillerde gerçekleştirilen tamamen ayrı bir işlemdir . Aktardığınız iki paragrafın altında sorulan soruya cevap veriyorum.
Sotirios Delimanolis

5

Daha önce açıklananlara ek olarak sorunumu çözdüm: `

@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 dosyası Spring Boot web uygulamasında işlenmiyor


2

Benim durumumda, 5.1.2 sürümü için ( Spring Boot v2.0.4.RELEASE kullanılırken ) Interceptors Spring belgelerini takip ediyordum ve WebConfigsınıfta, @EnableWebMvcuygulamamdaki başka bir şeyle çelişen ve statiği engelleyen ek açıklama vardı. varlıkların doğru bir şekilde çözülmemesi (yani istemciye CSS veya JS dosyası döndürülmemiş).

Farklı bir çok şey denedikten sonra denedim çıkarmadan@EnableWebMvc ve işe yaradı!

Düzenleme: Ek açıklamayı kaldırmanız gerektiğini söyleyen referans belgeler .@EnableWebMvc

Görünüşe göre en azından benim durumumda, Spring uygulamamı zaten yapılandırıyorum (her ne kadar kullanarak web.xmlveya başka bir statik dosya kullanarak olmasa da, kesinlikle programlı olarak), bu yüzden orada bir çakışma vardı.


1

Yapılandırma dosyanız üzerinde aşağıdaki değişiklikle kodunuzu değiştirmeyi deneyin. Bunun yerine Java yapılandırması kullanılır application.properties. configureDefaultServletHandlingYöntemde yapılandırmayı etkinleştirmeyi unutmayın .

WebMvcConfigurerAdaptersınıf kullanımdan kaldırıldı, bu yüzden WebMvcConfigurerarayüzü kullanıyoruz.

@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 kullanıyorum, aşağıdaki bağımlılıklara sahip olmalısınız 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'
}

0

Aynı hatanın başka bir nedeniyle karşılaştım. Bu, controller.java dosyanız için oluşturulmamış sınıf dosyalarından da kaynaklanıyor olabilir. Bunun bir sonucu olarak web.xml'de belirtilen dağıtıcı sunucu uygulaması, onu denetleyici sınıfındaki uygun yöntemle eşleyemez.

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

Eclipse altında Proje-> temiz -> Proje Oluştur seçeneğini seçin. Çalışma alanınızdaki yapıların altındaki denetleyici dosyası için sınıf dosyasının oluşturulup oluşturulmadığını kontrol edin.


0

Benim için, hedef sınıflarımın kaynakla aynı olmayan bir klasör modelinde oluşturulduğunu buldum. Bu muhtemelen tutulmada denetleyicilerimi içeren klasörler ekliyorum ve onları paket olarak eklemiyorum. Bu yüzden bahar yapılandırmasında yanlış yolu tanımladım.

Hedef sınıfım app altında sınıflar oluşturuyordu ve com.happy.app'e başvuruyordum

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

Com.happy.app için paketler (klasörler değil) ekledim ve dosyaları klasörlerden eclipse'deki paketlere taşıdım ve sorunu çözdüm.


0

Sunucunuzu temizleyin. Belki sunucuyu silin ve projeyi bir kez daha ekleyin ve Çalıştırın.

  1. Tomcat sunucusunu durdurun

  2. Sunucuya sağ tıklayın ve "Temizle" yi seçin

  3. Sunucuyu tekrar sağ tıklayın ve "Tomcat Çalışma Dizinini Temizle" yi seçin


0

Benim durumumda, ikincil java yapılandırma dosyalarının bir ana java yapılandırma dosyasına aktarılmasıyla uğraşıyordum. İkincil yapılandırma dosyalarını oluştururken ana yapılandırma sınıfının adını değiştirmiştim, ancak web.xml'deki adı güncelleyememiştim. Dolayısıyla, tomcat sunucumu her yeniden başlattığımda, Eclipse IDE konsolunda belirtilen eşleme işleyicileri görmüyordum ve ana sayfama gitmeye çalıştığımda şu hatayı görüyordum:

1 Kasım 2019 11:00:01 org.springframework.web.servlet.PageNotFound noHandlerFound UYARI: DispatcherServlet'te 'dispatcher' adlı URI [/ webapp / home / index] ile HTTP isteği için eşleme bulunamadı

Düzeltme, web.xml dosyasını güncelleyerek eski adı "WebConfig" yerine "MainConfig" olacak şekilde, ana java yapılandırma dosyasının en son adını yansıtacak şekilde yeniden adlandırmaktı (burada "MainConfig" keyfi ve sözcükler " Burada kullanılan Web "ve" Ana "bir sözdizimi gereksinimi değildir). MainConfig önemliydi, çünkü "WebController" için bileşen taraması yapan dosyaydı, web isteklerimi işleyen bahar mvc denetleyici sınıfım.

@ComponentScan(basePackageClasses={WebController.class})

web.xml şuna sahipti:

<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        com.lionheart.fourthed.config.WebConfig
    </param-value>
</init-param>

web.xml dosyası artık:

<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        com.lionheart.fourthed.config.MainConfig
    </param-value>
</init-param>

Şimdi konsol penceresinde eşlemeyi görüyorum:

BİLGİ: "{[/ home / index], yöntemler = [GET]}" genel org.springframework.web.servlet.ModelAndView com.lionheart.fourthed.controller.WebController.gotoIndex () ile eşlendi

Ve web sayfam yeniden yükleniyor.


-1

Aynı problemi yaşadım **No mapping found for HTTP request with URI [/some/path] in DispatcherServlet with name SomeName**

2 ila 4 gün boyunca analiz ettikten sonra temel nedeni buldum. Projeyi çalıştırdıktan sonra sınıf dosyaları oluşturulmadı. Proje sekmesine tıkladım.

Proje -> Projeyi Kapat -> OpenProject -> Temizle -> Proje oluştur

Kaynak kod için sınıf dosyaları oluşturuldu. Sorunumu çözdü. Sınıf dosyalarının oluşturulup oluşturulmadığını kontrol etmek için, lütfen proje klasörünüzdeki Derleme klasörünü kontrol edin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.