SpringBoot支持JSP访问,启动报错java.lang.NoClassDefFoundError: javax/servlet/ServletContext

时间:2023-01-19 21:13:24

SpringBoot支持JSP简介

前言:

这篇文章中, 我们将使用IntelliJ IDEA开发一个带有Spring Boot所提供的内嵌tomcat的Spring MVC 应用程序示例。 示例源码是官网下载下来。记录一下所踩过的坑。有什么疑问可以在评论区提问,谢谢。

环境:

JDK1.8

IntelliJ IDEA/Eclipse

Maven

Spring Boot 1.5.6


Spring Boot与Apache Maven 3.2兼容。
Maven 依赖
spring-boot-starter-parent:  
提供了依赖关系管理,可以省略已存在依赖的版本标签。
并声明一个或多个“启动器”的依赖关系。Spring Boot还提供了一个可选的 Maven插件来创建可执行的jar。

spring-boot-starter-parent是使用Spring Boot的好方法,但它可能不适合所有的时间。有时您可能需要从不同的父POM

继承,或者您可能不喜欢我们的默认设置。请参见 第13.2.2节“使用不带父POM的Spring Boot”作为使用import 范围的替代解

决方案

spring-boot-starter-web: 包括了创建一个web应用程序的所有依赖。 这将避免列出不同的Spring常见的项目的版本(译注:项Web项目可能需要添加大量的依赖)。

spring-boot-starter-tomcat:默认情况下,启用一个内嵌的Apache Tomcat 7实例。 我们使用了我们定义的版本重写了这一点。 如果你需要部署War包在其他独立版本的Tomcat服务器上也可以标明。

tomcat-embed-jasper: 提供.jsp文件加载。

项目介绍:

首先,去官网翻阅了一下文档找到如下介绍,已经翻译过来,如下:SpringBoot支持JSP访问,启动报错java.lang.NoClassDefFoundError: javax/servlet/ServletContext

使用SpringBoot时对JSP有一些限制,然后官网有一个JSP示例,试着跑起来,目前官网推荐的springboot版本是1.5.6,

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>

其它依赖:

<!-- JSP文件需要的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- Provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope><!--由JDK或者容器提供-->
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope><!--在IntellijIDEA中为provided时不会加入到Classpath中,这是IDEA的BUG->
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

然后试着去执行官网的JSP示例,使用的开发工具是IntellJ IDEA遇到了几个问题,如下介绍:

1、运行项目遇到了如下错误:

Caused by: java.lang.IllegalStateException: Failed to introspect annotated methods on class 
org.springframework.boot.web.support.SpringBootServletInitializer

at org.springframework.core.type.StandardAnnotationMetadata.
getAnnotatedMethods(StandardAnnotationMetadata.java:163) ~[spring-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.
retrieveBeanMethodMetadata(ConfigurationClassParser.java:380) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.
doProcessConfigurationClass(ConfigurationClassParser.java:314) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.
processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.
parse(ConfigurationClassParser.java:198) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.
parse(ConfigurationClassParser.java:167) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 17 common frames omitted

Caused by: java.lang.NoClassDefFoundError: javax/servlet/ServletContext
at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_111]
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) ~[na:1.8.0_111]
at java.lang.Class.getDeclaredMethods(Class.java:1975) ~[na:1.8.0_111]
at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods
(StandardAnnotationMetadata.java:152) ~[spring-core-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 22 common frames omitted

Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContext
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_111]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_111]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_111]
... 26 common frames omitted

google一番,查到了一些原因。

注意:

在Intellij IDEA中所有 scope 为 provided 的依赖都是不会被加入到 classpath 中的,目前该bug尚未被修复((bug report)。

如果你的web应用是部署到容器中的,那么这个bug不会影响使用,因为web应用中provided的依赖在容器运行时会被提供。

如果你做spring Boot开发,有带provided的依赖时,直接在IntellIJ IDEA中运行项目会导致ClassNotFound异常。

所以当jar需要被加入到classpath中需要注释<scope>provided</scope>,或者更改为:<scope>compile</scope>

Intellij Idea下运行Spring Boot关于provided依赖不加入classpath的bug与解决方案。其实这个错误有多种解决方案,下面就简单介绍一下最简单的解决方案:

SpringBoot支持JSP访问,启动报错java.lang.NoClassDefFoundError: javax/servlet/ServletContext

插件赖如下:

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
如运行报错,指定版本<version>version number</version>版本号显示红色说明插件相关文件没有下载下来或者没有下载完整。找到maven repository删除之前不完整或者文件夹即可,重新下载。这样就完美解决了之前的问题。

指定Application的working directory:

如上述还是不能访问jsp文件,或者报错404,原因如下,继续如下操作,指定working directory

问题:
在使用Intellij idea 时,如果配置文件放在project根目录下或者其他位置,往往会出现找不到配置文件的问题,而eclipse却不会出现这种问题。
解决方: 导致此问题的原因是因为Intellij idea 默认的根目录project的目录,而不是要运行的module目录。 
选择Edit Configurations–》Configuration–》Working directory,选择当前的module或者$MODULE_DIR$,即可解决。详情如下图: 


 SpringBoot支持JSP访问,启动报错java.lang.NoClassDefFoundError: javax/servlet/ServletContext

注意:

spring-boot-starter-web包括spring-boot-starter-tomcat。你可以在这里查看

spring-boot-starter-tomcat包括tomcat-embed-core。你可以在这里查看

但是,似乎tomcat-embed-core不包括tomcat-embed-jasper。其实是tomcat-embed-jasper谁包括依赖tomcat-embed-core在这里检查

无论如何,tomcat-embed-jasper标记为provided,所以表示您期望JDK或容器在运行时提供依赖关系。此范围仅适用于编译和测试类路径,不可传递。

总而言之,spring-boot-starter-web包括tomcat嵌入式的依赖关系,但它不包括jasper嵌入依赖关系,所以应该是单独声明的原因。

如有人遇到一样的问题,麻烦在评论区评论一下,谢谢。以上问题都是在使用IntelliJ IDEA的情况下所发生的错误及解决方案。项目也在eclipse运行过,没有以上问题出现。