Java 在网络应用程序中处理上下文的任何巧妙方法?

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

Any clever ways of handling the context in a web app?

javajspservletscontextpath

提问by Will Hartung

In Java, web apps are bundled in to WARs. By default, many servlet containers will use the WAR name as the context name for the application.

在 Java 中,Web 应用程序捆绑在 WAR 中。默认情况下,许多 servlet 容器将使用 WAR 名称作为应用程序的上下文名称。

Thus myapp.war gets deployed to http://example.com/myapp.

因此 myapp.war 被部署到http://example.com/myapp

The problem is that the webapp considers its "root" to be, well, "root", or simply "/", whereas HTML would consider the root of your application to be "/myapp".

问题是 webapp 认为它的“根”是“根”,或者只是“/”,而 HTML 会认为你的应用程序的根是“/myapp”。

The Servlet API and JSP have facilities to help manage this. For example, if, in a servlet, you do: response.sendRedirect("/mypage.jsp"), the container will prepend the context and create the url: http://example.com/myapp/mypage.jsp".

Servlet API 和 JSP 具有帮助管理此功能的工具。例如,如果在 servlet 中,您执行:response.sendRedirect("/mypage.jsp"),则容器将添加上下文并创建 url:http: //example.com/myapp/mypage.jsp"。

However, you can't do that with, say, the IMG tag in HTML. If you do <img src="/myimage.gif"/> you will likely get a 404, because what you really wanted was "/myapp/myimage.gif".

但是,您不能使用 HTML 中的 IMG 标记来做到这一点。如果你执行 <img src="/myimage.gif"/> 你可能会得到 404,因为你真正想要的是“/myapp/myimage.gif”。

Many frameworks have JSP tags that are context aware as well, and there are different ways of making correct URLs within JSP (none particularly elegantly).

许多框架都有上下文感知的 JSP 标记,并且在 JSP 中有不同的方法来制作正确的 URL(没有一种特别优雅)。

It's a nitty problem for coders to jump in an out of when to use an "App Relative" url, vs an absolute url.

对于编码人员来说,何时使用“应用程序相对”url 与绝对 url 相比是一个小问题。

Finally, there's the issue of Javascript code that needs to create URLs on the fly, and embedded URLs within CSS (for background images and the like).

最后,还有一个 Javascript 代码问题,需要动态创建 URL,并在 CSS 中嵌入 URL(用于背景图像等)。

I'm curious what techniques others use to mitigate and work around this issue. Many simply punt and hard code it, either to server root or to whatever context they happen to be using. I already know that answer, that's not what I'm looking for.

我很好奇其他人使用什么技术来缓解和解决这个问题。许多人只是简单地将其硬编码到服务器根目录或他们碰巧使用的任何上下文中。我已经知道那个答案了,这不是我要找的。

What do you do?

你做什么工作?

采纳答案by Vilmantas Baranauskas

You can use JSTL for creating urls.

您可以使用 JSTL 来创建 url。

For example, <c:url value="/images/header.jpg" />will prefix the context root.

例如,<c:url value="/images/header.jpg" />将前缀上下文根。

With CSS, this usually isn't an issue for me.

使用 CSS,这对我来说通常不是问题。

I have a web root structure like this:

我有一个像这样的网络根结构:

/css
/images

/CSS
/图像

In the CSS file, you then just need to use relative URLs (../images/header.jpg) and it doesn't need to be aware of the context root.

在 CSS 文件中,您只需要使用相对 URL (../images/header.jpg) 并且不需要知道上下文根。

As for JavaScript, what works for me is including some common JavaScript in the page header like this:

至于 JavaScript,对我有用的是在页面标题中包含一些常见的 JavaScript,如下所示:

<script type="text/javascript">
var CONTEXT_ROOT = '<%= request.getContextPath() %>';
</script>

Then you can use the context root in all your scripts (or, you can define a function to build paths - may be a bit more flexible).

然后您可以在所有脚本中使用上下文根(或者,您可以定义一个函数来构建路径 - 可能更灵活一些)。

Obviously this all depends on your using JSPs and JSTL, but I use JSF with Facelets and the techniques involved are similar - the only real difference is getting the context root in a different way.

显然,这完全取决于您使用 JSP 和 JSTL,但我将 JSF 与 Facelets 一起使用,所涉及的技术是相似的 - 唯一真正的区别是以不同的方式获取上下文根。

回答by Swati

I by nomeans claim that the following is an elegant issue. In fact, in hindsight, I wouldn't recommend this issue given the (most likely) performance hit.

绝不声称以下是一个优雅的问题。事实上,事后看来,考虑到(最有可能的)性能损失,我不推荐这个问题。

Our web app's JSPs were strictly XML raw data. This raw data was then sent into an XSL (server-side) which applied the right CSS tags, and spit out the XHTML.

我们的 Web 应用程序的 JSP 是严格的 XML 原始数据。然后将此原始数据发送到 XSL(服务器端),该 XSL 应用正确的 CSS 标签,并输出 XHTML。

We had a single template.xsl which would be inherited by the multiple XSL files that we had for different components of the website. Our paths were all defined in an XSL file called paths.xml:

我们有一个 template.xsl,它将被我们为网站的不同组件拥有的多个 XSL 文件继承。我们的路径都定义在一个名为 path.xml 的 XSL 文件中:

<?xml version="1.0" encoding="UTF-8"?>
<paths>
    <path name="account" parent="home">Account/</path>
    <path name="css">css/</path>
    <path name="home">servlet/</path>
    <path name="icons" parent="images">icons/</path>
    <path name="images">images/</path>
    <path name="js">js/</path>
</paths>

An internal link would be in the XML as follows:

内部链接将在 XML 中,如下所示:

<ilink name="link to icons" type="icons">link to icons</ilink>

This would get processed by our XSL:

这将由我们的 XSL 处理:

<xsl:template match="ilink">
    <xsl:variable name="temp">
        <xsl:value-of select="$rootpath" />
        <xsl:call-template name="paths">
            <xsl:with-param name="path-name"><xsl:value-of select="@type" /></xsl:with-param>
        </xsl:call-template>
        <xsl:value-of select="@file" />
    </xsl:variable>
        <a href="{$temp}" title="{@name}" ><xsl:value-of select="." /></a>
</xsl:template>

$rootPathwas passed onto each file with ${applicationScope.contextPath}The idea behind us using XML instead of just hard-coding it in a JSP/Java file was we didn't want to have to recompile.

$rootPath被传递到每个文件${applicationScope.contextPath}我们使用XML,而不是仅仅把它硬编码在JSP / Java的文件是我们不想重新编译背后的想法。

Again, the solution isn't a good one at all...but we did use it once!

同样,该解决方案根本不是一个好的解决方案……但我们确实使用过一次!

Edit: Actually, the complexity in our issue arose because we weren't able to use JSPs for our entire view. Why wouldn't someone just use ${applicationScope.contextPath}to retrieve the context path? It worked fine for us then.

编辑:实际上,我们问题的复杂性出现了,因为我们无法在整个视图中使用 JSP。为什么有人不只是${applicationScope.contextPath}用来检索上下文路径?那时对我们来说效果很好。

回答by kosoant

I've used helper classesto generate img tags etc. This helper class takes care of prefixing pathswith the application's contextPath. (This works, but I don't really like it. If anyone has any better alternatives, please tell.)

我使用了辅助类来生成 img 标签等。这个辅助类负责使用应用程序的 contextPath为路径添加前缀。(这有效,但我不太喜欢它。如果有人有更好的选择,请告诉。)

For paths in css files etc. I use an Ant build scriptthat uses a site.production.css for site.css in production environment and site.development.css in development encironment.

对于 css 文件中的路径等。我使用Ant 构建脚本,该脚本在生产环境中使用 site.production.css 用于 site.css,在开发环境中使用 site.development.css。

Alternatively I sometimes use an Ant script that replaces @token@tokens with proper data for different environents. In this case @contextPAth@ token would be replaced with the correct context path.

或者,我有时使用 Ant 脚本将 @token@令牌替换为不同环境的适当数据。在这种情况下,@contextPAth@ 令牌将被替换为正确的上下文路径。

回答by Vilmantas Baranauskas

One option is to use "flat" application structure and relative URLs whenever possible.

一种选择是尽可能使用“平面”应用程序结构和相对 URL。

By "flat" I mean that there are no subdirectories under your application root, maybe just few directories for static content as "images/". All your JSP's, action URLs, servlets go directly under the root.

“平面”是指您的应用程序根目录下没有子目录,可能只有几个静态内容目录为“images/”。您所有的 JSP、操作 URL、servlet 都直接位于根目录下。

This doesn't completely solve your problem but simplifies it greatly.

这并不能完全解决您的问题,而是大大简化了它。

回答by Scott Stanchfield

Vilmantas said the right word here: relative URLs.

Vilmantas 在这里用了正确的词:相对 URL。

All you need to do in your IMG is to use

您需要在 IMG 中做的就是使用

<img src="myimage.gif"/>

instead of

代替

<img src="/myimage.gif"/>

and it'll be relative to the app context (as the browser is interpreting the URL to go to)

它将与应用程序上下文相关(因为浏览器正在解释要转到的 URL)

回答by Travis Wilson

Except for special cases, I'd recommend against using absolute URLs this way. Ever. Absolute URLs are good for when another webappis pointing at something in your webapp. Internally -- when one resource is pointing at a second resource in the same context -- the resource should know where it lives, so it should be able to express a relative path to the second resource.

除了特殊情况,我建议不要以这种方式使用绝对 URL。曾经。当另一个 web 应用程序指向您的 web 应用程序中的某些内容时,绝对 URL 很有用。在内部——当一个资源指向同一上下文中的第二个资源时——资源应该知道它的位置,所以它应该能够表达到第二个资源的相对路径。

Of course, you'll write modular components, which don't know the resource that's including them. For example:

当然,您将编写模块化组件,这些组件不知道包含它们的资源。例如:

/myapp/user/email.jsp:
Email: <a href="../sendmail.jsp">${user.email}</a>

/myapp/browse/profile.jsp:
<jsp:include page="../user/email.jsp" />

/myapp/home.jsp:
<jsp:include page="../user/email.jsp" />

So, how does email.jspknow the relative path of sendmail.jsp? Clearly the link will break on either /myapp/browse/profile.jspor it will break on /myapp/home.jsp. The answer is, keep all your URLs in the same flat filepath space. That is, every URL should have no slashes after /myapp/.

那么,如何email.jsp知道 的相对路径sendmail.jsp呢?显然,链接将在任何一个上断开,或者/myapp/browse/profile.jsp将在 上断开/myapp/home.jsp。答案是,将所有 URL 保存在同一个平面文件路径空间中。也就是说,每个 URL 后都不应有斜杠/myapp/

This is pretty easy to accomplish, as long as you have some kind of mapping between URLs and the actual files that generate the content. (e.g. in Spring, use DispatcherServlet to map URLs to JSP files or to views.)

这很容易实现,只要您在 URL 和生成内容的实际文件之间有某种映射。(例如,在 Spring 中,使用 DispatcherServlet 将 URL 映射到 JSP 文件或视图。)

There are special cases. e.g. if you're writing a browser-side application in Javascript, then it gets harder to maintain a flat filepath space. In that case, or in other special cases, or just if you have a personal preference, it's not really a big deal to use <%= request.getContextPath() %>to create an absolute path.

有特殊情况。例如,如果您正在使用 Javascript 编写浏览器端应用程序,那么维护平面文件路径空间将变得更加困难。在这种情况下,或者在其他特殊情况下,或者只是如果您有个人偏好,使用<%= request.getContextPath() %>创建绝对路径并不是什么大问题。

回答by Brian Deterling

You can use request.getContextPath() to build absolute URLs that aren't hard-coded to a specific context. As an earlier answer indicated, for JavaScript you just set a variable at the top of your JSP (or preferably in a template) and prefix that as the context.

您可以使用 request.getContextPath() 构建未硬编​​码到特定上下文的绝对 URL。正如之前的回答所指出的,对于 JavaScript,您只需在 JSP 的顶部(或最好在模板中)设置一个变量,并将其作为上下文的前缀。

That doesn't work for CSS image replacement unless you want to dynamically generate a CSS file, which can cause other issues. But since you know where your CSS file is in relation to your images, you can get away with relative URLs.

这不适用于 CSS 图像替换,除非您想动态生成 CSS 文件,否则会导致其他问题。但是由于您知道 CSS 文件与图像的相关位置,因此您可以使用相对 URL。

For some reason, I've had trouble with IE handling relative URLs and had to fall back to using expressions with a JavaScript variable set to the context. I just split my IE image replacements off into their own file and used IE macros to pull in the correct ones. It wasn't a big deal because I already had to do that to deal with transparent PNGs anyway. It's not pretty, but it works.

出于某种原因,我在 IE 处理相对 URL 时遇到了麻烦,不得不回退到使用将 JavaScript 变量设置为上下文的表达式。我只是将我的 IE 图像替换拆分到他们自己的文件中,并使用 IE 宏来提取正确的。这没什么大不了的,因为无论如何我都必须这样做才能处理透明的PNG。它不漂亮,但它有效。

回答by Will Hartung

I've used most of these techniques (save the XSLT architecture).

我已经使用了大部分这些技术(除了 XSLT 体系结构)。

I think the crux (and consensus) of the problem is having a site with potentially multiple directories.

我认为问题的症结(和共识)是有一个可能有多个目录的站点。

If your directory depth (for lack of a better term) is constant, then you can rely on relative urls in things like CSS.

如果您的目录深度(因为没有更好的术语)是恒定的,那么您可以依赖 CSS 之类的相对 url。

Mind, the layout doesn't have to be completely flat, just consistent.

请注意,布局不必完全平坦,只需保持一致即可。

For example, we've done hierarchies like /css, /js, /common, /admin, /user. Putting appropriate pages and resources in the proper directories. Having a structure like this works very well with Container based authentication.

例如,我们已经完成了像 /css、/js、/common、/admin、/user 这样的层次结构。将适当的页面和资源放在适当的目录中。拥有这样的结构非常适合基于容器的身份验证。

I've also mapped *.css and *.js to the JSP servlet, and made them dynamic so I can build them on the fly.

我还将 *.css 和 *.js 映射到 JSP servlet,并使它们动态化,以便我可以即时构建它们。

I was just hoping there was something else I may have missed.

我只是希望还有其他我可能错过的东西。

回答by tardate

When creating a site from scratch, I side with @Will - aim for a consistent and predictable url structure so that you can stick with relative references.

从头开始创建站点时,我支持 @Will - 旨在实现一致且可预测的 url 结构,以便您可以坚持使用相对引用。

But things can get really messy if you are updating a site that was originally built to work directly under the site root "/" (pretty common for simple JSP sites) to formal Java EEpackaging (where context root will be some path under the root).

但是,如果您将最初构建为直接在站点根目录“/”(对于简单的 JSP 站点非常常见)下工作的站点更新为正式的Java EE打包(其中上下文根将是根目录下的某个路径),事情会变得非常混乱)。

That can mean a lot of code changes.

这可能意味着要进行大量代码更改。

If you want to avoid or postpone the code changes, but still ensure correct context root referencing, a technique I've tested is to use servlet filters. The filter can be dropped into an existing proejct without changing anything (except web.xml), and will remap any url references in the outbound HTML to the correct path, and also ensure redirects are correctly referenced.

如果您想避免或推迟代码更改,但仍要确保正确的上下文根引用,我测试过的一种技术是使用 servlet 过滤器。过滤器可以在不更改任何内容(web.xml 除外)的情况下放入现有项目,并将出站 HTML 中的任何 url 引用重新映射到正确的路径,并确保正确引用重定向。

An example site and usable code available here: EnforceContextRootFilter-1.0-src.zipNB: the actual mapping rules are implemented as regex in the servlet class and provide a pretty general catch-all - but you may need to modify for particular circumstances.

此处提供了一个示例站点和可用代码:EnforceContextRootFilter-1.0-src.zip注意:实际映射规则在 servlet 类中作为正则表达式实现,并提供了一个非常通用的包罗万象 - 但您可能需要针对特定​​情况进行修改。

btw, I forked a slightly different question to address migrating existing code base from "/" to a non-root context-path

顺便说一句,我提出了一个稍微不同的问题来解决将现有代码库从“/”迁移到非根上下文路径的问题

回答by tardate

The Servlet API and JSP have facilities to help manage this. For example, if, in a servlet, you do: response.sendRedirect("/mypage.jsp"), the container will prepend the context and create the url: http://example.com/myapp/mypage.jsp".

Servlet API 和 JSP 具有帮助管理此功能的工具。例如,如果在 servlet 中,您执行:response.sendRedirect("/mypage.jsp"),则容器将添加上下文并创建 url:http: //example.com/myapp/mypage.jsp"。

Ah, maybe, maybe not - it depends on your container and the servlet spec!

啊,也许,也许不是 - 这取决于您的容器和 servlet 规范!

From Servlet 2.3: New features exposed:

Servlet 2.3 开始:公开的新功能

And finally, after a lengthy debate by a group of experts, Servlet API 2.3 has clarified once and for all exactly what happens on a res.sendRedirect("/index.html") call for a servlet executing within a non-root context. The issue is that Servlet API 2.2 requires an incomplete path like "/index.html" to be translated by the servlet container into a complete path, but doesn't say how context paths are handled. If the servlet making the call is in a context at the path "/contextpath," should the redirect URI translate relative to the container root (http://server:port/index.html) or the context root (http://server:port/contextpath/index.html)? For maximum portability, it's imperative to define the behavior; after lengthy debate, the experts chose to translate relative to the container root. For those who want context relative, you can prepend the output from getContextPath() to your URI.

最后,经过一组专家的长时间辩论,Servlet API 2.3 一劳永逸地澄清了在 res.sendRedirect("/index.html") 调用在非根上下文中执行的 servlet 时会发生什么。问题是 Servlet API 2.2 需要像“/index.html”这样的不完整路径由 servlet 容器转换为完整路径,但没有说明如何处理上下文路径。如果进行调用的 servlet 位于路径“/contextpath”的上下文中,重定向 URI 是否应该相对于容器根 ( http://server:port/index.html) 或上下文根 ( http://服务器:端口/上下文路径/index.html)?为了获得最大的可移植性,必须定义行为;经过长时间的争论,专家们选择了相对于容器根的翻译。对于那些想要上下文相关的人,您可以将 getContextPath() 的输出添加到您的 URI。

So no, with 2.3 your paths are notautomatically translated to include the context path.

所以不,在 2.3 中,您的路径不会自动转换为包含上下文路径。