乐趣区

Spring-Boot整合JSP遇到的问题解决思路

虽然 Spring Boot 默认已经不支持 JSP 了,但是本着学习至上的原则,在多方查资料的情况下,进行了一番整合操作。

1 Maven 依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- JSP 渲染引擎 -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <!-- 如果是外部 tomcat 部署的话,provided 属性需要开启 -->
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>

    <!-- JSTL -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2 Controller 代码

@Controller
public class JspOnSpringBootController {

    // 从 application.yml 中读取配置,如取不到默认值为 Hello Jsp
    @Value("${application.hello:Hello Jsp}")
    private String hello = "Hello Jsp";

    /**
     * 默认页 <br/>
     * @RequestMapping("/") 和 @RequestMapping 是有区别的
     * 如果不写参数,则为全局默认页,加入输入 404 页面,也会自动访问到这个页面。* 如果加了参数“/”,则只认为是根页面。* 可以通过 localhost:7070 或者 localhost:7070/index 访问该方法
     */
    @RequestMapping(value = {"/","/index"})
    public String index(Model model) {
        // 直接返回字符串,框架默认会去 spring.view.prefix 目录下的(index 拼接 spring.view.suffix)页面
        // 本例为 /WEB-INF/jsp/index.jsp
        model.addAttribute("name", "Landy");
        model.addAttribute("hello", hello);

        return "index";
    }

}

3 application.properties 配置

#service 端口(Dev)server.port=7070

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

application.hello = hello jsp on spring boot

4 Jsp 页面代码

<html>
<head>
    <title>JSP on Spring Boot</title>
</head>
<body>
    <h1 style="color: red">${name}, ${hello}</h1>

</body>
</html>

5 运行

按理说,以上完成后就可以运行顺利看到页面结果了,但是如果直接运行 SpringApplication 的 main 方法是不能看到结果的,报 404.

经过网上一番寻找发现其根本原因,可以参见文章为什么整合 jsp 后必须通过 spring-boot:run 方式启动查看具体原因。

以下三种方式均可正常运行。

5.1 spring-boot:run 启动

使用命令 maven clean spring-boot:run 或者使用 idea 的 maven 插件运行均可。

访问地址:http://localhost:7070/index

5.2 打成 war 包

  1. 设置 pom.xml 文件 packaging 属性应该为 war。

    <groupId>org.landy</groupId>
    <artifactId>spring-boot-lesson-4</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
  2. 执行打包命令 maven clean package
  3. 执行运行 war 包命令 java -jar war 包名称

  1. 访问地址:http://localhost:7070/index

5.3 外部 tomcat 部署方法

  1. 确保 <scope>provided</scope> 没有被注释。

    Spring Boot 内嵌的 Servlet API 运行时由 tomcat 提供,需要在运行时剔除。

  2. 修改 SpringBootLesson4Application 类,需要继承 org.springframework.boot.web.support.SpringBootServletInitializer, 然后实现其 configure 方法,具体内容为 return builder.sources(本类类名.class);(注意,这里不能是 this,this 是一个类的实例,而 xxx.class 是类的模板)。

    外部容器部署的话,就不能依赖于 Application 的 main 方法启动了,而是要依赖于类似 servlet 的 web.xml 的方式来启动 Spring 的应用上下文了。此时需要继承 SpringBootServletInitializer 并实现 configure 方法。

  3. 打包:maven clean package
  4. 放在 tomcat 下的 webapp 目录, 重命名即可。

  1. 访问地址:http://localhost:8080/jsp-in-spring-boot

    以上三种方式都可以成功访问到以下页面。

6 问题说明

在外部 tomcat 部署的时候,必须继承 SpringBootServletInitializer 类,如果没有继承则会报 404 错误,如下页面所示,

本文事例代码共有两处,

  • 未继承 SpringBootServletInitializer 类的工程参见地址:https://github.com/landy8530/…
  • 继承了 SpringBootServletInitializer 类的工程参见地址:https://github.com/landy8530/…
退出移动版