原创

SpringBoot支持JSP教程

项目背景

一些前端还是JSP的老项目,需要改造为springboot,所以需要springboot能支持JSP。

项目结构

afei-demo
    ├──src/main                                           
    ├   ├──java 
    ├   ├   ├──com.afei.test.demo
    ├   ├   ├   ├──controller 
    ├   ├   ├   ├──service  
    ├   ├   ├   ├──mapper
    ├   ├   ├   ├──Application.java  springboot项目main方法所在的主类             
    ├   ├──resources            
    ├   ├   ├──css 存放css文件的地方
    ├   ├   ├──images 存放.jpg,.png等图片资源的地方
    ├   ├   ├──js 存放js文件的地方
    ├   ├   ├──application.properties springboot配置文件
    ├   ├──webapp    
    ├   ├   ├──WEB-INF/jsp 这个路径和视图配置中的spring.mvc.view.prefix要对应
    ├   ├   ├   ├──index.jsp 
    ├   ├   ├   ├──monitor 监控相关jsp页面
    ├   ├   ├   ├──warning 告警相关jsp页面

依赖组件

springboot支持JSP的主要依赖组件如下:

  • spring-boot-starter-web版本为1.5.9.RELEASE;

  • jstl版本为1.2;

  • tomcat-embed-jasper版本为8.5.23;

  • spring-boot-maven-plugin版本为1.4.2.RELEASE;

核心POM

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--springboot tomcat jsp 支持开启 start-->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <version>8.5.23</version>
    </dependency>
    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!--springboot tomcat jsp 支持开启 end-->
</dependencies>

插件配置

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <!--springboot-maven不能使用1.5.9.RELEASE版本, 否则会导致WEB-INF下的jsp资源无法访问-->
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.4.2.RELEASE</version>
            <configuration><!--指定springboot的main方法类,否则会由于某些测试类中也有main方法而导致构建失败-->
                <mainClass>com.yyfax.fdfsfront.Application</mainClass>
            </configuration>
            <executions>
                <execution> <goals> <goal>repackage</goal> </goals> </execution>
            </executions>
        </plugin>

        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>

    </plugins>

    <resources>
        <!-- 打包时将jsp文件拷贝到META-INF目录下-->
        <resource>
            <!-- 指定resources插件处理哪个目录下的资源文件 -->
            <directory>src/main/webapp</directory>
            <!--注意此次必须要放在此目录下才能被访问到-->
            <targetPath>META-INF/resources</targetPath>
            <includes>
                <include>**/**</include>
            </includes>
        </resource>
        <resource>
            <directory>${project.basedir}/lib</directory>
            <targetPath>BOOT-INF/lib/</targetPath>
            <includes>
                <include>**/*.jar</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/**</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>

</build>

再次强调,spring-boot-maven-plugin的版本是1.4.2.RELEASE,而spring-boot-starter-web的版本是1.5.9.RELEASE。否则会导致即使能成功构建JAR包,也无法访问JSP资源。这里坑浪费了我不少时间!

静态资源

resources标签下的配置非常重要,其作用是将webapp目录下所有的资源(主要是JSP资源,因为css,js,图片等资源放在resoures目录下)拷贝到最终springboot的JAR包中的META-INF/resources目录下。

  • 为什么是/META-INF/resources目录?

这个与springboot的配置spring.resources.static-locations有关,其默认赋值在源码ResourceProperties.java中,由源码可知,classpath:/META-INF/resources/是其中一个默认的静态资源存放路径:

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {

    private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" };

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/" };

    private static final String[] RESOURCE_LOCATIONS;

    static {
        RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length
                + SERVLET_RESOURCE_LOCATIONS.length];
        System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0,
                SERVLET_RESOURCE_LOCATIONS.length);
        System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS,
                SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length);
    }

    /**
     * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
     * /resources/, /static/, /public/] plus context:/ (the root of the servlet context).
     */
    private String[] staticLocations = RESOURCE_LOCATIONS;
    ... ...
}

至于其他的css,图片,js等静态资源文件,放到resources目录下即可,并结合如下核心代码:

@Configuration
@Slf4j
public class FdfsWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Bean
    public SecurityInterceptor getSecurityInterceptor() {
        return new SecurityInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 除了login登陆访问路径和error页面,其他都要经过SecurityInterceptor拦截器(SecurityInterceptor extends HandlerInterceptorAdapter)
        InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor());
        // 排除配置
        addInterceptor.excludePathPatterns("/error");
        addInterceptor.excludePathPatterns("/login**");
        // 拦截配置
        addInterceptor.addPathPatterns("/**");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 配置welcome默认首页
        registry.addViewController("/").setViewName("forward:/main/index.shtml");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }

    @Bean
    public ServletRegistrationBean servletRegistrationBean(DispatcherServlet dispatcherServlet) {
        ServletRegistrationBean bean = new ServletRegistrationBean(dispatcherServlet);
        // RequestMapping路径都以.shtml结尾,例如:http://localhost/main/login.shtml
        bean.addUrlMappings("*.shtml");
        // 其他文件该是什么后缀就是什么后缀
        bean.addUrlMappings("*.html");
        bean.addUrlMappings("*.css");
        bean.addUrlMappings("*.js");
        bean.addUrlMappings("*.png");
        bean.addUrlMappings("*.gif");
        bean.addUrlMappings("*.ico");
        bean.addUrlMappings("*.jpeg");
        bean.addUrlMappings("*.jpg");
        return bean;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 这里的配置很重要,由于我们把css,图片,js等静态资源文件放在resources目录下,所以必须增加这些ResourceHandler,才能访问到这些资源
        registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/favicon.ico");
        registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css/");
        registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/");
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
        registry.addResourceHandler("/500.html").addResourceLocations("classpath:/500.html");
        registry.addResourceHandler("/index.jsp").addResourceLocations("classpath:/index.jsp");
        super.addResourceHandlers(registry);
    }

}

视图配置

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

这里的配置要非常注意,以笔者这两个配置为例,如果我在controller中return new ModelAndView("main/index");,那么它访问的资源路径是/WEB-INF/jsp/main/index.jsp(prefix+ModelAndView+suffix)。这里强烈建议spring.mvc.view.prefix的配置以/结尾,即配置/WEB-INF/jsp/而不要配置/WEB-INF/jsp。否则如果return new ModelAndView("main/index");就会抛出如下错误:

File [/WEB-INF/jspmain/index.jsp] not found
  • 总结

  1. 配置为/WEB-INF/jsp/,那么return new ModelAndView("/main/index");return new ModelAndView("main/index");都可以访问。

  2. 配置为/WEB-INF/jsp,那么只有return new ModelAndView("/main/index");才可以访问。

正文到此结束
本文目录