Java 为什么 WEB-INF 文件夹内的 jsp 文件有效,但放在 WEB-INF 下的文件夹下却无效?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25904298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why jsp files inside WEB-INF folder works , but placed under a folder under WEB-INF doesn't?
提问by sofs1
When my jsp files are inside WEB-INF folder (as /WEB-INF/file.jsp) , I can access them from localhost: 8080/ProjectCtxtRoot/, but I can't access them, if they are placed in /WEB-INF/jsp/file.jsp?
当我的 jsp 文件在 WEB-INF 文件夹(如 /WEB-INF/file.jsp)中时,我可以从本地主机访问它们:8080/ProjectCtxtRoot/,但是如果它们被放置在 /WEB- INF/jsp/file.jsp?
I changed the path in welcome-list tag in web.xml as follows
我将 web.xml 中的welcome-list 标签中的路径更改如下
<welcome-file-list>
<welcome-file>/JSP/fileName.jsp</welcome-file>
</welcome-file-list>
I also changed the dispatcher-servlet.xml as follows
我还更改了 dispatcher-servlet.xml 如下
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
Still it doesn't work. Url used for above case are
还是不行。用于上述情况的网址是
localhost:8080/ContextRoot/jsp/
localhost:8080/ContextRoot/jsp/fileName.jsp
localhost:8080/ContextRoot/jsp/fileName
and it doesn't work for any of the above urls.
它不适用于上述任何网址。
But it was working when
但它在工作时
<welcome-file-list>
<welcome-file>/fileName.jsp</welcome-file>
</welcome-file-list>
dispatcher-servlet.xml as follows
dispatcher-servlet.xml 如下
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/"
p:suffix=".jsp" />
Url used for above case is localhost:8080/ContextRoot/ and it works.
用于上述案例的 URL 是 localhost:8080/ContextRoot/ 并且它可以工作。
I use tomcat v 7.0 server. I refresh my project in Eclipse IDE, then clean it, build it, build war using mvn clean install, then choose the war from tomcat manager homepage and deploy it. I do this each time.
我使用 tomcat v 7.0 服务器。我在 Eclipse IDE 中刷新我的项目,然后清理它,构建它,使用 mvn clean install 构建战争,然后从 tomcat 管理器主页选择战争并部署它。我每次都这样做。
This is how the diapatcher-servlet.xml looks all through the process. I just change particular section as above said
这就是 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>
This is how my web.xml looks like
这是我的 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>
Ok. It works when I moved the entire jsp folder from /webapp/WEB-INF/jsp/fileName.jsp to /webapp/jsp/fileName.jsp. I would like to know 1. why it works now? 2. Is this the correct way to do things? 3. It works when the url is localhost:8080/CtxtRoot/jsp/or localhost:8080/CtxtRoot/jsp/search.jsp, but it doesn't work for localhost:8080/AnnaUnivResults/jsp/search. Why is it so?
好的。当我将整个 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无效。为什么会这样?
采纳答案by msknapp
I think there are a couple problems here:
我认为这里有几个问题:
- You are confused about the paths with spring MVC
- You are not configuring your web xml correctly
- 您对 Spring MVC 的路径感到困惑
- 您没有正确配置您的 web xml
Unfortunately I can't cover every detail for you, a lot of spring is configurable, so my explanation is just going to cover the most basic scenario. If somebody finds a mistake please tell and I will fix it.
不幸的是,我无法为您涵盖所有细节,很多 spring 是可配置的,因此我的解释仅涵盖最基本的场景。如果有人发现错误,请告诉我,我会修复它。
For the paths, it might help to think of things step by step.
对于路径,一步一步地思考可能会有所帮助。
- You request the url from your browser, The browser looks at the protocol, host, and port, and uses a DNS to find the appropriate IP address to connect with.
- A connection is established between your browser and the host. The host looks for a process running on the port you specified, and if a TCP connection is allowed by any security systems in place, the request is streamed to the process running on that port, the web server.
- The web server makes decisions based on what's after the port, specifically, it determines what the web application context is by looking at the path it was given. Once it determines the application context root, it knows which web application should handle that request. The decision is based on how you configure the web server, you could have a web application handle requests with no context root, or a specific context root. For example, if you requested
localhost:8080/CtxtRoot/jsp/
, you could have one web application on the server whose context root is "CtxtRoot", and it would handle that request. Alternatively, you could have an application that has "" for a context, and it could handle that request. It depends on how you configure the server, by default Tomcat will use the war name as a context root. - The web application receives the request. While it knows the full URL requested, it only makes decisions based on everything after the context root. So for example, with the request to
localhost:8080/CtxtRoot/jsp/
, the web application would route things based on 'jsp' as the path. - The web application has a filter chain that it submits the request to first. If a filter's pattern matches the request, that filter can evaluate the request. It might block the request, handle the request, or pass it on. I won't say much more because your question doesn't involve filters.
- The web app looks for a resource whose pattern matches the request, it considers servlets first, and then static resources. The url part that comes AFTER the context is what it tries to match, so if the request was for
localhost:8080/CtxtRoot/jsp/
, and the context root was 'CtxtRoot', then the web application is comparing '/jsp/' to all of the servlet mappings. Requests for static resources in WEB-INF will always be refused, but servlets and filters can and do return data from WEB-INF. - I'm going to proceed assuming the request was sent to the spring DispatcherServlet, it receives the request, and considers everything after the servlet path. Spring's DispatcherServlet looks for a Controller whose path matches the path after the servlet path. The servlet path is basically what you put in the servlet mapping in your web xml. Let me give an example, let's say you have a web app whose context is 'app', and it has a spring MVC servlet whose servlet mapping is '/mvc', and a controller that handles the path 'sales', then you could reach that controller with
http://localhost:8080/app/mvc/sales
. - If the DispatcherServlet cannot find a Controller, I believe it treats the incoming request as if it was returned by a controller, so if the sub-path is 'sales', then it would pass that as an argument to the view resolver. If it can't find it, then the server returns a not found error.
- Typically the Controller returns a string when it's done, which is the path to a resource. It could return 'popular' as a string. Spring then forwards this to the ViewResolver, and I will assume you're using the InternalResourceViewResolver. It will look at the prefix and suffix, and basically wrap those around what it was given. So if the prefix is '/WEB-INF/views/', the suffix is '.jsp', and the argument is 'popular', then it will look for a resource at '/WEB-INF/views/popular.jsp'. It is literally just concatenating those strings to make a path. The path is ALWAYS relative to the web application root here. If the path produced is a jsp file, it will be interpreted before being returned.
- Then it is finally returned to the user.
- 您从浏览器请求 url,浏览器查看协议、主机和端口,并使用 DNS 查找要连接的适当 IP 地址。
- 在您的浏览器和主机之间建立连接。主机查找在您指定的端口上运行的进程,如果任何安全系统允许 TCP 连接,则请求将流式传输到在该端口上运行的进程,即 Web 服务器。
- 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 映射中的内容。让我举个例子,假设你有一个 web 应用,它的上下文是“app”,它有一个 spring MVC servlet,它的 servlet 映射是“/mvc”,还有一个处理路径“sales”的控制器,那么你可以使用 到达该控制器
http://localhost:8080/app/mvc/sales
。 - 如果 DispatcherServlet 找不到控制器,我相信它会将传入的请求视为由控制器返回,因此如果子路径是“sales”,那么它会将其作为参数传递给视图解析器。如果找不到,则服务器返回未找到错误。
- 通常,控制器在完成时返回一个字符串,它是资源的路径。它可以将 'popular' 作为字符串返回。Spring 然后将其转发给 ViewResolver,我假设您正在使用 InternalResourceViewResolver。它将查看前缀和后缀,并基本上将它们包裹在给出的内容周围。所以如果前缀是'/WEB-INF/views/',后缀是'.jsp',参数是'popular',那么它会在'/WEB-INF/views/popular.jsp'寻找资源'。它实际上只是连接这些字符串以形成路径。该路径始终相对于此处的 Web 应用程序根目录。如果生成的路径是一个jsp文件,在返回之前会被解释。
- 然后最终返回给用户。
From your example you were requesting localhost:8080/ContextRoot/jsp/fileName, so it looks like 'CtxRoot' is the context root, your servlet's path is '/', so it should pass whatever is after that to a controller. By the time the DispatcherServlet receives the request, it is searching for a controller that handles 'jsp' as a path. Since you had none, it decided to treat that as a resource path. It used the view resolver and formed the path /WEB-INF/jsp/jsp/fileName.jsp, which obviously does not exist.
在您的示例中,您请求的是 localhost:8080/ContextRoot/jsp/fileName,因此看起来“CtxRoot”是上下文根,您的 servlet 的路径是“/”,因此它应该将之后的任何内容传递给控制器。当 DispatcherServlet 收到请求时,它正在搜索将“jsp”作为路径处理的控制器。由于您没有,它决定将其视为资源路径。它使用视图解析器并形成路径/WEB-INF/jsp/jsp/fileName.jsp,该路径显然不存在。
Let's assume that you had instead requested localhost:8080/ContextRoot/fileName, the request would reach the DispatcherServlet, it would find no Controller that handles 'fileName' as a path, and hence would treat it as a resource. It would form the path /WEB-INF/jsp/fileName.jsp, and that would return the result.
假设您改为请求 localhost:8080/ContextRoot/fileName,该请求将到达 DispatcherServlet,它将找不到将“fileName”作为路径处理的控制器,因此会将其视为资源。它将形成路径/WEB-INF/jsp/fileName.jsp,并返回结果。
However, your web xml was not configured to initialize spring. So your web application was actually treating every one of your requests as if they were for a resource relative to the web application root. I believe that if you had made that request with Spring properly initialized, it might have worked.
但是,您的 web xml 未配置为初始化 spring。因此,您的 Web 应用程序实际上将您的每个请求都视为针对与 Web 应用程序根目录相关的资源。我相信,如果您在正确初始化 Spring 的情况下提出该请求,它可能会奏效。
Here is a good example of how to do it:
这是一个很好的例子,说明如何做到这一点:
http://www.mkyong.com/spring3/spring-3-mvc-hello-world-example/
http://www.mkyong.com/spring3/spring-3-mvc-hello-world-example/
notice that his web xml has a ContextLoaderListener, which is commented out in yours, and it's essential for initializing spring in a web app. I also see the comment in your dispatcher with the path /src/main/resources, but all paths in web xml are supposed to be relative to the web application root. At runtime, the web server has no knowledge of your project, and 'src' is not a directory in your web app's root. Also note that you can have a different application context for your MVC stuff than your main spring context, and this is common.
请注意,他的 web xml 有一个 ContextLoaderListener,在您的注释中已注释掉,并且对于在 web 应用程序中初始化 spring 至关重要。我还在您的调度程序中看到了路径为 /src/main/resources 的注释,但是 web xml 中的所有路径都应该是相对于 web 应用程序根目录的。在运行时,Web 服务器不知道您的项目,并且 'src' 不是您的 Web 应用程序根目录中的目录。另请注意,您的 MVC 内容可以具有与主 spring 上下文不同的应用程序上下文,这很常见。
I think if you do these things it will work:
我认为如果你做这些事情它会起作用:
- Move your jsp to /WEB-INF/jsp/fileName.jsp
- Update your app context so '/WEB-INF/jsp/' is the prefix, and '.jsp' is the suffix.
- Add the context loader listener to your web xml, and set the contextConfigLocation path relative to the app context root. For example, it could be /WEB-INF/appContext.xml
make a request to
localhost:8080/CtxtRoot/fileName
- 将您的 jsp 移动到 /WEB-INF/jsp/fileName.jsp
- 更新您的应用程序上下文,因此“/WEB-INF/jsp/”是前缀,“.jsp”是后缀。
- 将上下文加载器侦听器添加到您的 Web xml,并设置相对于应用程序上下文根的 contextConfigLocation 路径。例如,它可以是 /WEB-INF/appContext.xml
提出请求
本地主机:8080/CtxtRoot/文件名
Also, you kept talking about the welcome-file, but you were giving full paths to resources. The welcome file only comes into play if the user makes a request to the root of a directory, like this:
此外,您一直在谈论欢迎文件,但您提供了资源的完整路径。仅当用户向目录的根目录发出请求时,欢迎文件才会起作用,如下所示:
localhost:8080/CtxtRoot/
That request would be forwarded to the welcome-file. I think the only time you tried that, the jsp happened to be in your app's root, and was configured as the welcome file, so it worked. While it "worked", it did NOT actually use spring to return that.
该请求将被转发到欢迎文件。我认为您唯一尝试过的时候,jsp 恰好在您的应用程序的根目录中,并且被配置为欢迎文件,因此它起作用了。虽然它“有效”,但它实际上并没有使用弹簧来返回它。
Good luck to you.
祝你好运。
回答by lotr22
Everything outside WEB-INF is publicly available no authentication is applied on that(we can apply by defining scurity constraint in web.xml ), but all resources inside WEB-INF is secured. You can keep static pages outside WEB-INF and dynamic pages like profiles, accounts inside WEB-INF. Please cross check i might be wrong.
WEB-INF 之外的所有内容都是公开可用的,没有对其应用身份验证(我们可以通过在 web.xml 中定义安全约束来应用),但是 WEB-INF 中的所有资源都是安全的。您可以将静态页面保留在 WEB-INF 之外,将动态页面(如个人资料、帐户)保留在 WEB-INF 中。请交叉检查我可能是错的。