Pourquoi Spring MVC répond - il avec un 404 et signale "aucune correspondance trouvée pour la requête HTTP avec URI [...] dans DispatcherServlet"?

j'écris une application MVC de printemps, déployée sur Tomcat. Voir exemple minimal, complet et vérifiable :

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 est

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

enfin, j'ai un @Controller dans le paquet com.example.controllers

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

le nom de contexte de ma demande est Example . Quand j'envoie une demande à

http://localhost:8080/Example/home

L'application répond avec un statut HTTP 404 et enregistre ce qui suit

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'

j'ai une ressource JSP à /WEB-INF/jsps/index.jsp Je m'attendais à ce que Spring MVC utilise mon contrôleur pour traiter la requête et la transmettre au JSP, alors pourquoi répond-il avec un 404?


C'est censé être une représentation canonique de poste pour des questions à propos de ce message d'avertissement.

66
demandé sur Sotirios Delimanolis 2017-01-10 22:53:29

3 réponses

votre application standard printemps MVC répondra à toutes les demandes par le biais d'un DispatcherServlet que vous avez enregistré avec votre Servlet container.

le DispatcherServlet regarde son ApplicationContext et, si disponible, le ApplicationContext enregistré avec un ContextLoaderListener pour les haricots spéciaux dont il a besoin pour configurer sa logique de service de demande. ces haricots sont décrits dans la documentation .

Sans doute le plus important, haricots de type HandlerMapping carte

demandes reçues aux gestionnaires et une liste des pré-et post-processeurs (gestionnaire d'intercepteurs) en fonction de certains critères, dont les détails varie selon la mise en œuvre HandlerMapping . La mise en œuvre la plus populaire prend en charge les contrôleurs annotés mais d'autres implémentations existent comme bien.

le javadoc de HandlerMapping décrit plus en détail comment les mises en œuvre doivent se comporter.

Le DispatcherServlet trouve tous les haricots de ce type et les enregistre dans un certain ordre (peut être personnalisé). Lors de la signification d'une requête, les boucles DispatcherServlet à travers ces objets HandlerMapping et teste chacun d'eux avec getHandler pour trouver un qui puisse traiter la requête entrante, représentée comme la norme HttpServletRequest . Que de 4.3.x, si elle ne trouverez pas de , les journaux de l'avertissement que vous voyez

aucune correspondance trouvée pour les requêtes HTTP avec URI [/some/path] dans DispatcherServlet avec nom de domaine

et soit jette un NoHandlerFoundException ou immédiatement s'engage la réponse avec un 404 not Found code d'état.

pourquoi le DispatcherServlet trouver un HandlerMapping qui pourrait traiter ma demande?

la mise en oeuvre la plus courante HandlerMapping est RequestMappingHandlerMapping , qui gère l'enregistrement @Controller haricots comme handlers (en réalité leur @RequestMapping méthodes annotées). Vous pouvez soit déclarer un haricot de ce type vous-même (avec @Bean ou <bean> ou autre mécanisme) ou vous pouvez utiliser les options intégrées . Ce sont:

  1. annoter votre classe @Configuration avec @EnableWebMvc .
  2. déclare un membre <mvc:annotation-driven /> dans votre configuration XML.

comme le lien ci-dessus le décrit, tous les deux enregistreront un haricot RequestMappingHandlerMapping (et un tas d'autres choses). Cependant, un HandlerMapping n'est pas très utile sans un gestionnaire. RequestMappingHandlerMapping s'attend à certains "1519240920 haricots donc vous devez déclarer ceux aussi, à travers @Bean méthodes dans une configuration Java ou des déclarations <bean> dans une configuration XML ou par balayage de composants de classes annotées @Controller dans l'une ou l'autre de ces classes. assurez-vous que ces haricots sont présents.

si vous recevez le message d'avertissement et un 404 et que vous avez configuré tout ce qui précède correctement, alors vous envoyez votre demande à la mauvaise URI , une qui n'est pas traitée par un détecté @RequestMapping annoté méthode de gestionnaire.

la bibliothèque spring-webmvc offre d'autres implémentations HandlerMapping intégrées. Par exemple:, BeanNameUrlHandlerMapping cartes

de l'Url de haricots avec des noms qui commencent par une barre oblique ("/")

et vous pouvez toujours écrire votre propre. Évidemment, vous devrez vous assurer que la demande que vous envoyez correspond au moins à l'un des inscrits HandlerMapping handler's handlers.

si vous n'enregistrez pas implicitement ou explicitement des haricots HandlerMapping (ou si detectAllHandlerMappings est true ), le DispatcherServlet enregistre quelque par défaut . Celles-ci sont définies dans DispatcherServlet.properties dans le même colis que la classe DispatcherServlet . Ils sont BeanNameUrlHandlerMapping et DefaultAnnotationHandlerMapping (qui est similaire à RequestMappingHandlerMapping mais déprécié).

débogage

printemps MVC logera les conducteurs enregistrés par RequestMappingHandlerMapping . Par exemple, un @Controller comme

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

enregistrera ce qui suit au niveau INFO

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

décrit la cartographie enregistrée. Lorsque vous voyez l'avertissement qu'aucun handler n'a été trouvé, comparez L'URI dans le message à la cartographie listée ici. Toutes les restrictions spécifié dans le @RequestMapping doit correspondre à ressort MVC pour sélectionner le handler.

autres HandlerMapping implémentations enregistrer leurs propres déclarations qui devraient faire référence à leurs correspondances et leurs manipulateurs correspondants.

dans le même ordre d'idées, permettre la journalisation de printemps au niveau de débugage pour voir quels registres de printemps haricots. Il doit indiquer les classes annotées qu'il trouve, les paquets qu'il scanne, et les haricots qu'il initialise. Si l' ceux que vous attendiez ne sont pas présents, alors passez en revue votre configuration ApplicationContext .

autres erreurs courantes

A DispatcherServlet est juste un type Java EE Servlet . Vous l'enregistrez avec votre déclaration typique <web.xml> <servlet-class> et <servlet-mapping> , ou directement par ServletContext#addServlet dans un WebApplicationInitializer , ou avec n'importe quel mécanisme de botte de ressort utiliser. En tant que tel , vous devez vous en remettre à la URL mapping logique spécifiée dans la Servlet spécification , voir Chapitre 12. Voir aussi

avec cela à l'esprit, une erreur courante est d'enregistrer le DispatcherServlet avec un mappage d'url de /* , en retournant un nom de vue d'un @RequestMapping méthode handler, et s'attendre à ce qu'un JSP soit rendu. Par exemple, envisager une méthode de handler comme

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

avec un InternalResourceViewResolver

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

vous pourriez vous attendre à ce que la demande soit transmise à une ressource de JSP au chemin /WEB-INF/jsps/example-view-name.jsp . Cela n'arrivera pas. Au lieu de cela, en supposant un nom de contexte de Example , le DisaptcherServlet rapportera

Aucune correspondance trouvée pour la requête HTTP avec l'URI [/Example/WEB-INF/jsps/example-view-name.jsp] dans DispatcherServlet avec le nom de "répartiteur"

parce que le DispatcherServlet correspond à /* et /* correspond à tout (sauf les correspondances exactes, qui ont une priorité plus élevée), le DispatcherServlet serait choisi pour gérer le forward de la JstlView (retourné par le InternalResourceViewResolver ). dans presque tous les cas, le DispatcherServlet ne sera pas configuré pour traiter une telle requête .

au lieu de cela, dans ce cas simpliste, vous devriez enregistrer le DispatcherServlet à / , en le marquant comme le servlet par défaut. Le servlet par défaut est la dernière correspondance pour une requête. Cela permettra à votre conteneur de servlet typique de choisir une implémentation de Servlet interne, mappée à *.jsp , pour gérer la ressource JSP (par exemple, Tomcat a JspServlet ), avant d'essayer avec le servlet par défaut.

C'est ce que vous voyez dans votre exemple.

69
répondu Sotirios Delimanolis 2017-11-30 00:00:40

j'ai résolu mon problème lorsque, en plus de Décrit avant:

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

` de: fichier JSP ne rendant pas dans L'application Web de Botte de printemps

2
répondu Crimean.us 2017-05-23 12:34:50

je suis tombé sur une autre raison pour la même erreur. Cela pourrait aussi être dû aux fichiers de classe non générés pour votre contrôleur.fichier java. En conséquence de quoi le servlet de régulateur mentionné dans web.xml ne peut pas l'associer à la méthode appropriée dans la classe controller.

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

in eclipse under Project - > select clean - > Build Project.Vérifiez si le fichier de classe a été généré pour le fichier controller sous builds dans votre espace de travail.

0
répondu Anil N.P 2017-01-16 12:07:08