Java 在 /* 上映射全局前端控制器 servlet 时如何访问静态资源

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/870150/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:28:09  来源:igfitidea点击:

How to access static resources when mapping a global front controller servlet on /*

javaservletsresources

提问by Rahul Garg

I've mapped the Spring MVC dispatcher as a global front controller servlet on /*.

我已将 Spring MVC 调度程序映射为/*.

<servlet>       
  <servlet-name>home</servlet-name>         
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>     
</servlet>  
<servlet-mapping>       
  <servlet-name>home</servlet-name>         
  <url-pattern>/*</url-pattern>     
</servlet-mapping>

However, this mapping stops the access to static files like CSS, JS, images etc which are all in the /res/folder.

但是,此映射会阻止对文件/res/夹中所有静态文件(如 CSS、JS、图像等)的访问。

How can I access them anyway?

我怎样才能访问它们?

采纳答案by Gandalf

I've run into this also and never found a great solution. I ended up mapping my servlet one level higher in the URL hierarchy:

我也遇到过这个问题,但从未找到很好的解决方案。我最终将我的 servlet 映射到 URL 层次结构中更高的一层:

<servlet-mapping>       
  <servlet-name>home</servlet-name>             
  <url-pattern>/app/*</url-pattern>     
</servlet-mapping>

And now everything at the base context (and in your /res directory) can be served up by your container.

现在,您的容器可以提供基本上下文(以及您的 /res 目录中)中的所有内容。

回答by alamar

I'd recommend trying to use a Filter instead of a default servlet whenever possible.

我建议尽可能尝试使用过滤器而不是默认的 servlet。

Other two possibilities:

其他两种可能:

Write a FileServlet yourself. You'll find plenty examples, it should just open the file by URL and write its contents into output stream. Then, use it to serve static file request.

自己编写一个 FileServlet。你会发现很多例子,它应该只是通过 URL 打开文件并将其内容写入输出流。然后,使用它来服务静态文件请求。

Instantiate a FileServlet class used by Google App Engine and call service(request, response) on that FileServlet when you need to serve the static file at a given URL.

实例化 Google App Engine 使用的 FileServlet 类,并在您需要在给定 URL 处提供静态文件时调用该 FileServlet 上的 service(request, response) 。

You can map /res/* to YourFileServlet or whatever to exclude it from DispatcherServlets' handling, or call it directly from DispatcherServlet.

您可以将 /res/* 映射到 YourFileServlet 或其他任何内容以将其从 DispatcherServlets 的处理中排除,或者直接从 DispatcherServlet 调用它。

And, I have to ask, what does Spring documentation say about this collision? I've never used it.

而且,我不得不问,Spring 文档对这种碰撞有什么看法?我从来没有用过。

回答by Gandalf

If you use Tomcat, you can map resources to the default servlet:

如果使用 Tomcat,则可以将资源映射到默认 servlet:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

and access your resources with url http://{context path}/static/res/...

并使用 url http://{context path}/static/res/... 访问您的资源

Also works with Jetty, not sure about other servlet containers.

也适用于 Jetty,不确定其他 servlet 容器。

回答by Nick Johnson

'Static' files in App Engine aren't directly accessible by your app. You either need to upload them twice, or serve the static files yourself, rather than using a static handler.

您的应用无法直接访问 App Engine 中的“静态”文件。您要么需要上传两次,要么自己提供静态文件,而不是使用静态处理程序。

回答by Bill

The reason for the collision seems to be because, by default, the context root, "/", is to be handled by org.apache.catalina.servlets.DefaultServlet. This servlet is intended to handle requests for static resources.

冲突的原因似乎是因为,默认情况下,上下文根“/”将由 org.apache.catalina.servlets.DefaultServlet 处理。此 servlet 旨在处理对静态资源的请求。

If you decide to bump it out of the way with your own servlet, with the intent of handling dynamic requests, that top-level servlet must also carry out any tasks accomplished by catalina's original "DefaultServlet" handler.

如果您决定使用自己的 servlet 来处理动态请求,那么顶级 servlet 还必须执行由 catalina 的原始“DefaultServlet”处理程序完成的任何任务。

If you read through the tomcat docs, they make mention that True Apache (httpd) is better than Apache Tomcat for handling static content, since it is purpose built to do just that. My guess is because Tomcat by default uses org.apache.catalina.servlets.DefaultServlet to handle static requests. Since it's all wrapped up in a JVM, and Tomcat is intended to as a Servlet/JSP container, they probably didn't write that class as a super-optimized static content handler. It's there. It gets the job done. Good enough.

如果您通读 tomcat 文档,他们会提到 True Apache (httpd) 在处理静态内容方面比 Apache Tomcat 更好,因为它是专门为此而构建的。我的猜测是因为 Tomcat 默认使用 org.apache.catalina.servlets.DefaultServlet 来处理静态请求。由于它们都包含在 JVM 中,并且 Tomcat 旨在作为 Servlet/JSP 容器,因此他们可能没有将该类编写为超级优化的静态内容处理程序。在那。它完成了工作。够好了。

But that's the thing that handles static content and it lives at "/". So if you put anything else there, and that thing doesn't handle static requests, WHOOPS, there goes your static resources.

但这就是处理静态内容的东西,它位于“/”。因此,如果您将其他任何东西放在那里,而那个东西不处理静态请求,那么您的静态资源就会消失。

I've been searching high and low for the same answer and the answer I'm getting everywhere is "if you don't want it to do that, don't do that".

我一直在寻找相同的答案,而我到处都得到的答案是“如果你不希望它这样做,就不要那样做”。

So long story short, your configuration is displacing the default static resource handler with something that isn't a static resource handler at all. You'll need to try a different configuration to get the results you're looking for (as will I).

长话短说,您的配置正在用根本不是静态资源处理程序的东西替换默认的静态资源处理程序。您需要尝试不同的配置来获得您想要的结果(我也会这样做)。

回答by casey

What you do is add a welcome file in your web.xml

你要做的是在你的 web.xml 中添加一个欢迎文件

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

And then add this to your servlet mappings so that when someone goes to the root of your application, they get sent to index.html internally and then the mapping will internally send them to the servlet you map it to

然后将其添加到您的 servlet 映射中,以便当有人访问您的应用程序的根目录时,他们会在内部被发送到 index.html,然后映射将在内部将它们发送到您将其映射到的 servlet

<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/main</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>MainActions</servlet-name>
    <url-pattern>/index.html</url-pattern>
</servlet-mapping>

End result: You visit /Application, but you are presented with /Application/MainActions servlet without disrupting any other root requests.

最终结果:您访问 /Application,但您会看到 /Application/MainActions servlet,而不会中断任何其他根请求。

Get it? So your app still sits at a sub url, but automatically gets presented when the user goes to the root of your site. This allows you to have the /images/bob.img still go to the regular place, but '/' is your app.

得到它?因此,您的应用程序仍然位于子 url 处,但是当用户转到您网站的根目录时会自动呈现。这允许您将 /images/bob.img 仍然放在常规位置,但 '/' 是您的应用程序。

回答by MStodd

Add the folders which you don't want to trigger servlet processing to the <static-files>section of your appengine-web.xml file.

将您不想触发 servlet 处理的文件夹添加到<static-files>appengine-web.xml 文件的部分。

I just did this and looks like things are starting to work ok. Here's my structure:

我刚刚这样做了,看起来事情开始正常了。这是我的结构:

/

/

/pages/<.jsp files>

/pages/<.jsp 文件>

/css

/css

I added "/pages/**" and "/css/**" to the <static-files>section and I can now forward to a .jsp file from inside a servlet doGet without causing an infinite loop.

我在该<static-files>部分添加了“/pages/**”和“/css/**”,现在我可以从 servlet doGet 内部转发到 .jsp 文件,而不会导致无限循环。

回答by BalusC

Map the controller servlet on a more specific url-patternlike /pages/*, put the static content in a specific folder like /staticand create a Filterlistening on /*which transparently continues the chain for any static content and dispatches requests to the controller servlet for other content.

将控制器 servlet 映射到更具体的url-pattern/pages/*,将静态内容放在特定的文件夹中,/static并创建一个Filter监听/*,透明地继续任何静态内容的链,并将请求分派到控制器 servlet 以获取其他内容。

In a nutshell:

简而言之:

<filter>
    <filter-name>filter</filter-name>
    <filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>controller</servlet-name>
    <servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>controller</servlet-name>
    <url-pattern>/pages/*</url-pattern>
</servlet-mapping>

with the following in filter's doFilter():

在过滤器中具有以下内容doFilter()

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/static")) {
    chain.doFilter(request, response); // Goes to default servlet.
} else {
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

No, this does not end up with /pagesin browser address bar. It's fully transparent. You can if necessary make "/static"and/or "/pages"an init-paramof the filter.

不,这不会/pages在浏览器地址栏中结束。它是完全透明的。如有必要,可以补充"/static"和/或"/pages"一个init-param过滤器。

回答by logixplayer

The best way to handle this is using some kind of URL re-writing. In this way, you can have clean restful URLs, and NOT with any extensions i.e abc.com/welcom/register as opposed to abc.com/welcome/resister.html

处理此问题的最佳方法是使用某种 URL 重写。通过这种方式,您可以拥有干净的宁静 URL,而不是任何扩展名,即 abc.com/welcom/register,而不是 abc.com/welcome/resister.html

I use Tuckey URLwhich is pretty cool.

我使用非常酷的Tuckey URL

It's got instructions on how to set up your web app.I have set it up with my Spring MVC web app. Of course, everything was fine until I wanted to use annotations for Spring 3 validations like @Emailor @Nullfor domain objects.

它有关于如何设置您的 Web 应用程序的说明。我已经使用我的 Spring MVC Web 应用程序进行了设置。当然,一切都很好,直到我想用注解春3个验证样@Email@Null域对象。

When I add the Spring mvc directives:

当我添加 Spring mvc 指令时:

< mvc:annotation-driven  /> 
< mvc:default-servlet-handler />

.. it breaks the good ol Tuckey code. Apparently, < mvc:default-servlet-handler />replaces Tuckey, which I'm still trying to solve.

.. 它破坏了好的 ol Tuckey 代码。显然,< mvc:default-servlet-handler />取代了我仍在努力解决的塔基。

回答by digitaljoel

As of 3.0.4 you should be able to use mvc:resourcesin combination with mvc:default-servlet-handleras described in the spring documentation to achieve this.

从 3.0.4 开始,您应该能够按照 spring 文档中的描述mvc:resources结合使用mvc:default-servlet-handler来实现这一点。

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-static-resources