为啥 WEB-INF 文件夹中的 jsp 文件有效,但放在 WEB-INF 下的文件夹下无效?
Posted
技术标签:
【中文标题】为啥 WEB-INF 文件夹中的 jsp 文件有效,但放在 WEB-INF 下的文件夹下无效?【英文标题】:Why jsp files inside WEB-INF folder works , but placed under a folder under WEB-INF doesn't?为什么 WEB-INF 文件夹中的 jsp 文件有效,但放在 WEB-INF 下的文件夹下无效? 【发布时间】:2014-11-12 07:12:08 【问题描述】:当我的 jsp 文件在 WEB-INF 文件夹中(如 /WEB-INF/file.jsp)时,我可以从 localhost:8080/ProjectCtxtRoot/ 访问它们,但如果它们被放置在/WEB-INF/jsp/file.jsp?
我将web.xml中welcome-list标签中的路径更改如下
<welcome-file-list>
<welcome-file>/JSP/fileName.jsp</welcome-file>
</welcome-file-list>
我还把dispatcher-servlet.xml改成如下
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
还是不行。用于上述情况的网址是
localhost:8080/ContextRoot/jsp/
localhost:8080/ContextRoot/jsp/fileName.jsp
localhost:8080/ContextRoot/jsp/fileName
它不适用于上述任何网址。
但是当它工作时
<welcome-file-list>
<welcome-file>/fileName.jsp</welcome-file>
</welcome-file-list>
dispatcher-servlet.xml如下
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/"
p:suffix=".jsp" />
用于上述情况的 URL 是 localhost:8080/ContextRoot/ 并且它有效。
我使用 tomcat v 7.0 服务器。我在 Eclipse IDE 中刷新我的项目,然后清理它,构建它,使用 mvn clean install 构建战争,然后从 tomcat 管理器主页中选择战争并部署它。我每次都这样做。
这就是 diapatcher-servlet.xml 在整个过程中的样子。我只是如上所述更改特定部分
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.projectName.www" />
<!-- Factory bean that creates the Mongo instance -->
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<property name="host" value="localhost" />
</bean>
<!-- MongoTemplate for connecting and quering the documents in the database -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo" />
<constructor-arg name="databaseName" value="tableName" />
</bean>
<!-- Use this post processor to translate any MongoExceptions thrown in @Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<!-- <bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver"/>
<bean class=
"org.springframework.web.servlet.view.tiles2.TilesConfigurer"> -->
<!-- <property name="definitions">
<list>
<value>/WEB-INF/views/views.xml</value>
</list>
</property>
</bean> -->
</beans>
这就是我的 web.xml 的样子
<web-app>
<!-- <display-name>Archetype Created Web Application</display-name> -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- <init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/src/main/webapp/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</context-param>
<!-- <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> -->
<welcome-file-list>
<welcome-file>/fileName.jsp</welcome-file>
</welcome-file-list>
</web-app>
好的。当我将整个 jsp 文件夹从 /webapp/WEB-INF/jsp/fileName.jsp 移动到 /webapp/jsp/fileName.jsp 时,它可以工作。我想知道 1. 为什么现在有效? 2. 这是正确的做事方式吗? 3.当url为localhost:8080/CtxtRoot/jsp/或localhost:8080/CtxtRoot/jsp/search.jsp时有效,但对于localhost:8080/AnnaUnivResults/jsp/search无效。为什么会这样?
【问题讨论】:
我认为这里的大写实际上可能会有所不同,因为 spring 正在将内容解释为文件路径。 请留言说明当欢迎文件有小写 jsp 时第一个示例是否有效。 A<welcome-file>
与 Spring ViewResolver
完全无关。您的问题目前到处都是。您必须明确您的上下文路径以及您在每种情况下发送的确切 HTTP 请求。如果请求由 Spring 的 DispatcherServlet
处理,您还需要显示处理程序。
@msknapp 将“jsp”设为小写不起作用。
我认为您需要解释一下您是如何运行该应用的,您的网络应用服务器的配置文件可能与您帖子底部附近的一些问题有关。
【参考方案1】:
我认为这里有几个问题:
-
你对使用 spring MVC 的路径感到困惑
您没有正确配置 Web xml
很遗憾,我无法为您介绍所有细节,很多 spring 是可配置的,所以我的解释只是涵盖最基本的场景。如果有人发现错误,请告诉我,我会改正的。
对于路径,逐步思考可能会有所帮助。
-
您从浏览器请求 url,浏览器查看协议、主机和端口,并使用 DNS 查找要连接的适当 IP 地址。
在您的浏览器和主机之间建立了连接。主机查找在您指定的端口上运行的进程,如果任何安全系统允许 TCP 连接,则请求将流式传输到在该端口上运行的进程,即网络服务器。
Web 服务器根据端口之后的内容做出决定,具体而言,它通过查看给定路径来确定 Web 应用程序上下文是什么。一旦确定了应用程序上下文根,它就知道应该由哪个 Web 应用程序处理该请求。该决定取决于您如何配置 Web 服务器,您可以让 Web 应用程序处理没有上下文根或特定上下文根的请求。例如,如果您请求
localhost:8080/CtxtRoot/jsp/
,您可以在服务器上拥有一个上下文根为“CtxtRoot”的Web 应用程序,它会处理该请求。或者,您可以拥有一个具有“”作为上下文的应用程序,它可以处理该请求。这取决于您如何配置服务器,默认情况下 Tomcat 将使用战争名称作为上下文根。
Web 应用程序接收请求。虽然它知道请求的完整 URL,但它只根据上下文根之后的所有内容做出决定。例如,对于localhost:8080/CtxtRoot/jsp/
的请求,Web 应用程序将基于“jsp”作为路径来路由。
Web 应用程序有一个过滤器链,它首先将请求提交到该过滤器链。如果过滤器的模式与请求匹配,则该过滤器可以评估请求。它可能会阻止请求、处理请求或传递它。我不会多说,因为你的问题不涉及过滤器。
Web 应用程序查找模式与请求匹配的资源,它首先考虑 servlet,然后是静态资源。上下文之后的 url 部分是它试图匹配的内容,所以如果请求是针对 localhost:8080/CtxtRoot/jsp/
的,并且上下文根是“CtxtRoot”,那么 Web 应用程序会将“/jsp/”与所有 servlet 进行比较映射。在 WEB-INF 中对静态资源的请求总是会被拒绝,但是 servlet 和过滤器可以并且确实从 WEB-INF 返回数据。
我将继续假设请求已发送到 Spring DispatcherServlet,它接收请求,并考虑 servlet 路径之后的所有内容。 Spring 的 DispatcherServlet 查找其路径与 servlet 路径之后的路径匹配的 Controller。 servlet 路径基本上就是您在 web xml 中的 servlet 映射中放置的内容。举个例子,假设你有一个上下文是'app'的web应用程序,它有一个spring MVC servlet,它的servlet映射是'/mvc',还有一个处理路径'sales'的控制器,那么你可以使用http://localhost:8080/app/mvc/sales
到达该控制器。
如果 DispatcherServlet 找不到控制器,我相信它会将传入的请求视为由控制器返回,因此如果子路径是“销售”,那么它会将其作为参数传递给视图解析器.如果找不到,则服务器返回未找到错误。
通常,控制器在完成后会返回一个字符串,它是资源的路径。它可以将“流行”作为字符串返回。然后 Spring 将其转发给 ViewResolver,我假设您使用的是 InternalResourceViewResolver。它将查看前缀和后缀,并基本上将它们包装在给出的内容周围。所以如果前缀是'/WEB-INF/views/',后缀是'.jsp',参数是'popular',那么它会在'/WEB-INF/views/popular.jsp处寻找资源'。它实际上只是将这些字符串连接起来形成一条路径。该路径始终相对于此处的 Web 应用程序根目录。如果生成的路径是jsp文件,在返回之前会先进行解释。
然后最终返回给用户。
从您的示例中,您请求的是 localhost:8080/ContextRoot/jsp/fileName,因此看起来“CtxRoot”是上下文根,您的 servlet 的路径是“/”,因此它应该将之后的任何内容传递给控制器.当 DispatcherServlet 收到请求时,它正在搜索将“jsp”作为路径处理的控制器。由于您没有,它决定将其视为资源路径。它使用视图解析器,形成路径/WEB-INF/jsp/jsp/fileName.jsp,显然不存在。
假设您改为请求 localhost:8080/ContextRoot/fileName,该请求将到达 DispatcherServlet,它将找不到将“fileName”作为路径处理的控制器,因此会将其视为资源。它将形成路径 /WEB-INF/jsp/fileName.jsp,并返回结果。
但是,您的 web xml 未配置为初始化 spring。因此,您的 Web 应用程序实际上将您的每一个请求都视为针对相对于 Web 应用程序根的资源的请求。我相信,如果您在正确初始化 Spring 的情况下发出该请求,它可能会奏效。
这是一个很好的例子:
http://www.mkyong.com/spring3/spring-3-mvc-hello-world-example/
请注意,他的 web xml 有一个 ContextLoaderListener,它在你的注释中被注释掉了,它对于在 web 应用程序中初始化 spring 是必不可少的。我还在您的调度程序中看到了带有路径 /src/main/resources 的注释,但是 web xml 中的所有路径都应该是相对于 web 应用程序根目录的。在运行时,Web 服务器不知道您的项目,并且“src”不是您的 Web 应用根目录中的目录。另请注意,您的 MVC 内容可以使用与主 spring 上下文不同的应用程序上下文,这很常见。
我认为如果你做这些事情会奏效:
-
将您的 jsp 移动到 /WEB-INF/jsp/fileName.jsp
更新您的应用上下文,将“/WEB-INF/jsp/”作为前缀,“.jsp”作为后缀。
将上下文加载器侦听器添加到您的 Web xml,并设置相对于应用上下文根的 contextConfigLocation 路径。例如,它可以是 /WEB-INF/appContext.xml
向
发出请求localhost:8080/CtxtRoot/文件名
此外,您一直在谈论欢迎文件,但您提供的是资源的完整路径。欢迎文件只有在用户向根目录发出请求时才会发挥作用,如下所示:
localhost:8080/CtxtRoot/
该请求将被转发到欢迎文件。我认为您唯一尝试过的时候,jsp 恰好位于您的应用程序的根目录中,并且被配置为欢迎文件,所以它起作用了。虽然它“有效”,但它实际上并没有使用 spring 来返回它。
祝你好运。
【讨论】:
伙计,非常感谢您花时间和精力来解释这一点。你点燃了一个春天的文盲。很好解释。我有几个问题 1) 项目的根以及战争总是 '/' 吗? 2) 如何在 tomcat 服务器中更改应用程序的上下文根? (只是出于好奇) 3)从您的整体工作流程解释来看,URL 是否总是先命中 dispatcher-servlet.xml 然后再进入 web.xml? (这是一个正确的说法,如果不是,请改写/正确答案) 4) 我可以在 dispatcher-servlet.xml 中同时使用 UrlBasedViewResolver 和 InternalResourceViewResolver(因为我使用的是 Apache 磁贴)吗? 5)您在第 6 点中提到“servlet 路径基本上就是您在 web xml 中的 servlet 映射中放置的内容。让我举个例子,假设您有一个上下文为 'app' 的 web 应用程序,它有一个 spring其 servlet 映射为 '/mvc' 的 MVC servlet。”,“spring MVC servlet 其 servlet 映射为 '/mvc'”是什么意思?您能否为您解释 /mvc 的案例提供代码。 @msknapp 我已根据您的解释更改了代码。但我仍然面临修复它的问题。当你写答案时,我还在项目中引入了瓷砖功能。这是新问题***.com/questions/25947668/… 请帮助(教)我。你是唯一一个现在澄清我的问题的人。非常感谢。 解释应该是这样的——msknapp 显然对主题有知识和理解;不仅仅是做什么,而是它是如何工作的。业界对示例作为文档的痴迷的一个问题是,它没有足够的解释来说明事情是如何工作的,而不是仅仅“做这个,那个就会发生”。【参考方案2】:WEB-INF 之外的所有内容都是公开可用的,没有对其应用身份验证(我们可以通过在 web.xml 中定义安全约束来应用),但 WEB-INF 内的所有资源都是安全的。您可以将静态页面保留在 WEB-INF 之外,将动态页面(如配置文件、帐户)保留在 WEB-INF 中。 请交叉检查我可能是错的。
【讨论】:
通常你会是对的,但是由于他使用的是Spring MVC,所以spring能够在web-inf中显示jsp文件,并且实际上在他们的示例中做了很多。 Spring 有一个过滤器来拦截请求,并确定从哪里获取视图。他的视图解析器被配置为从 web-inf 中获取它,这非常好,因为访问是通过过滤器来的,换句话说,不是通过 http 请求直接访问的。 OP 没有访问过WEB-INF
之外的任何内容。以上是关于为啥 WEB-INF 文件夹中的 jsp 文件有效,但放在 WEB-INF 下的文件夹下无效?的主要内容,如果未能解决你的问题,请参考以下文章
eclipse WEB-INF下文件夹中的jsp文件无法运行
JSP 中的问题:按钮 Click() 上的转发(当目标 jsp 在 web-inf 文件夹下时)
如何隐藏 WEB-INF 文件夹中的 JSP 文件? [复制]