No mapping for GET……

本文探讨了SpringMVC框架下处理静态HTML页面的方法。通过分析DispatcherServlet与ViewResolver的配置,解决静态页面访问问题,并对比了JSP与HTML的处理差异。介绍了如何通过修改Tomcat的web.xml文件或使用Spring的DefaultServletHandlerConfigurer实现静态资源的正确访问。
摘要由CSDN通过智能技术生成

很久没有玩spring mvc了。这次一玩,出问题了。

我发现对于静态页面(*.html),dispatcher servlet处理不了,会报No mapping for GET/url的错误。

我先把环境说一下:

AppInitializer.java
配置dispatcher servlet:

package com.ocean.config;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class AppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();

        webApplicationContext.register(AppConfig.class);

        webApplicationContext.refresh();

        DispatcherServlet dispatcherServlet = new DispatcherServlet(webApplicationContext);
        ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcherServlet", dispatcherServlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/");
    }
}

AppConfig.java
spring的配置类:

package com.ocean.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@ComponentScan(basePackages = "com.ocean")
public class AppConfig {

    @Bean
    public ViewResolver viewResolver(){
       InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
       internalResourceViewResolver.setPrefix("/WEB-INF/");
       internalResourceViewResolver.setSuffix(".html");

       return internalResourceViewResolver;
    }

}

我想得到静态页面的视图,所以后缀配了.html。

DummyController.java

一个controller:

package com.ocean.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/dummy")
public class DummyController {


    @GetMapping("/home")
    public String home(){
        return "home";
    }

}

当我发出http://localhost:8088/spring_source_war/dummy/home的请求时,报了404的错误,控制台的打印是:

No mapping for GET /spring_source_war/WEB-INF/home.html

home.html我当然写了。为什么会找不到呢?

那我换成jsp怎么样:

 internalResourceViewResolver.setSuffix(".jsp");

这时就能访问WEB-INF下的home.jsp了。

dispatcher serlvet从controller那里拿到了modelAndView,然后它要借助ViewResolver来向用户返回视图。但为什么只有jsp可以?

你会觉得jsp是要从controller那里拿数据返回的视图,而html页面是直接可以访问的,那我就跳过controller直接访问静态页面:

package com.ocean.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;



@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.ocean.controller")
public class AppConfig implements WebMvcConfigurer {

    @Bean
    public ViewResolver viewResolver(){
       InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
       internalResourceViewResolver.setPrefix("/WEB-INF/");
       internalResourceViewResolver.setSuffix(".html");

       return internalResourceViewResolver;
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/straight_home").setViewName("/home");
    }


}

AppInitializer中加上webApplicationContext.setServletContext(servletContext);

(在调用refresh方法前加,不然tomcat启动的时候会报找不到servletCxt的错误)。

请求:http://localhost:8088/spring_source_war/straight_home

依旧是No mapping for GET /spring_source_war/WEB-INF/home.html

我们翻翻tomcat的conf目录下的web.xml

 <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>


    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

tomcat自己有专门处理jsp页面的servlet。

要不我们加一个*.html的url-pattern吧。

 <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

竟然成功了。


不过人家的serlvet是处理jsp的,我们这么做不太好。那应该有专门处理静态页面的servlet吧。

 <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

这个DefaultServlet是处理静态页面的,我们把它映射的url改为*.html。

    <!-- The mapping for the default servlet -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

这么做也是可以的。

不过改之前,它的url-pattern是/,不是拦截所有的请求吗,*.html不是它的子集吗?

因为还有一个老大哥servlet,我们的dispatcher servlet,它的映射url也是/。

registration.addMapping("/");

DefaultServlet的优先级是最低的,所以说,Dispatcher Servlet直接替代了DefaultServlet。

这样逻辑就清楚了。

我们不动tomcat的web.xml。

在mvc的配置类直接启用DefaultServlet。

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

public class DefaultServletHandlerConfigurer
extends Object

Configures a request handler for serving static resources by forwarding the request to the Servlet container’s “default” Servlet. This is intended to be used when the Spring MVC DispatcherServlet is mapped to “/” thus overriding the Servlet container’s default handling of static resources.
Since this handler is configured at the lowest precedence, effectively it allows all other handler mappings to handle the request, and if none of them do, this handler can forward it to the “default” Servlet.

文档解释的情况和我这里遇到的情况是一样的。

注册了default servlet handler之后,静态页面也能访问了。这样又没有动tomcat的web.xml,方式还是很优雅的。


对于静态资源,spring有更优雅的方式处理。我们注释掉对default servlet handler的注册:

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

然后使用ResourceHttpRequestHandler来处理静态资源。

   @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/resource/**")
                    .addResourceLocations("/resource/");

    }

我们把resource什么什么的路径全部映射到resource文件夹下。这个文件夹的位置为:webapp/resource

webapp/resource 这个文件夹下,我放一个test.html

这时的请求路径为:

http://localhost:8088/spring_source_war/resource/test.html

我们得到了正确的响应。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值