任何聪明的处理方式的背景下,在一个网络应用程序?
-
02-07-2019 - |
题
在爪哇,网络应用程序的被捆绑在战争。默认情况下,许多小的容器将使用战争的名称方面应用程序的名称。
因此myapp。战争获取部署到 http://example.com/myapp.
问题是,网络应用程序考虑其"根本"是的,好了,"根本",或简单地"/",而HTML会考虑的根本的应用程序"/myapp".
Servlet API和JSP有设施,以帮助管理这一点。例如,如果在一个servlet,你这样做:响应。sendRedirect("/我的页面.jsp"),容器将在前面加上下文而创建的网址: http://example.com/myapp/mypage.jsp".
但是,你不能这样做,说,IMG tag in HTML。如果你不做 <img src="/myimage.gif" /> ,你可能会得到404,因为你真正想要的是"/myapp/myimage.gif".
许多框架有JSP标签方面认识到,有不同的方式作出正确的网址内JSP(没有特别优雅).
这是一个基本问题的程序员跳出时使用"的应用程序相对的"url,与一个绝对的网址。
最后,还有一问题的Javascript code,需要建立网址上飞行和嵌入式网址内CSS(背景图像等)。
我很好奇有什么技术的其他人使用到减轻和解决这个问题。很多人只是平底船和硬代码,无论是根服务器或任何背景下,他们碰巧是使用。我已经知道答案,那不是我要找的。
你是做什么的?
解决方案
您可以使用JSTL创建网址。
例如,<c:url value="/images/header.jpg" />
将为上下文根添加前缀。
使用CSS,这对我来说通常不是问题。
我有这样的网络根结构:
/ CSS结果 /图像
在CSS文件中,您只需要使用相对URL(../ images / header.jpg),而不需要知道上下文根。
对于JavaScript,对我有用的是在页眉中包含一些常见的JavaScript,如下所示:
<script type="text/javascript">
var CONTEXT_ROOT = '<%= request.getContextPath() %>';
</script>
然后你可以在所有脚本中使用上下文根(或者,你可以定义一个函数来构建路径 - 可能会更灵活一些)。
显然这一切都取决于你使用的JSP和JSTL,但是我将JSF与Facelets结合使用,所涉及的技术是相似的 - 唯一真正的区别在于以不同的方式获取上下文根。
其他提示
HTML网页,我只是设置HTML <base>
标记。每一个相对的链接(即不开始与方案或者 /
)将成为相对于它。没有清洁的方式来抓住它立即通过 HttpServletRequest
, 所以我们需要一点帮助的JSTL在这里。
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="req" value="${pageContext.request}" />
<c:set var="url">${req.requestURL}</c:set>
<c:set var="uri">${req.requestURI}</c:set>
<!DOCTYPE html>
<html lang="en">
<head>
<base href="${fn:substring(url, 0, fn:length(url) - fn:length(uri))}${req.contextPath}/" />
<link rel="stylesheet" href="css/default.css">
<script src="js/default.js"></script>
</head>
<body>
<img src="img/logo.png" />
<a href="other.jsp">link</a>
</body>
</html>
这又是一个警告:锚(的 #identifier
URL)将会变得相对于基本路径。如果你有任何的他们,你想要让它相对于请求URL(URI)代替。因此,改变喜欢
<a href="#identifier">jump</a>
要
<a href="${uri}#identifier">jump</a>
在JS,你只可以访问 <base>
元素从DOM只要你想转换一个相对URL到一个绝对的网址。
var base = document.getElementsByTagName("base")[0].href;
或如果你做jQuery
var base = $("base").attr("href");
在CSS,图像的网址是相对于该网址的样式表本身。因此,只是下降的影像在一些文件夹中的相对来的样式表本身。E.g。
/css/style.css
/css/images/foo.png
和引用如下
background-image: url('images/foo.png');
如果你不喜欢下降的影像在一些文件夹在同一水平CSS文件夹
/css/style.css
/images/foo.png
然后使用 ../
去到共同的父的文件夹
background-image: url('../images/foo.png');
参见:
我同意 tardate 。 我也过滤了过滤器,并在项目 UrlRewriteFilter 中找到了解决方案。 简单的配置如下:
<rule>
<from>^.+/resources/(.*)$</from>
<to>/resources/$1</to>
</rule>
有助于将* / resources路径的所有请求转发到/ resources pass(包括上下文路径前缀)。因此,我可以将所有图片和 CSS 文件放在资源文件夹下,并继续在我的样式中使用相对URL作为背景图片和其他案例。
Servlet API和JSP都有 帮助管理这个的设施。对于 例如,如果在servlet中执行: response.sendRedirect是(QUOT <!>; <!> /mypage.jsp QUOT), 容器将在上下文之前 并创建网址: http://example.com/myapp/mypage.jsp <!>“。
啊,也许,也许不是 - 这取决于你的容器和servlet规范!
来自 Servlet 2.3:公开的新功能 :
最后,经过长时间的辩论 一组专家,Servlet API 2.3 已经一劳永逸地澄清了 什么发生在一个 res.sendRedirect(<!> quot; /index.html <!> quot;)调用 对于在a中执行的servlet 非根上下文。问题是 Servlet API 2.2需要不完整 路径如<!> quot; /index.html <!> quot;成为 由servlet容器翻译 走进一条完整的道路,但不说 如何处理上下文路径。如果 servlet拨打电话 路径上的上下文<!> quot; / contextpath,<!> quot; 应该重定向URI翻译 相对于容器根 ( http:// server:port / index.html )或 上下文根 ( http:// server:port / contextpath / index.html )? 为了最大程度的便携性,它是 定义行为的必要性; 经过长时间的辩论,专家们 选择翻译相对于 容器根。对于那些想要的人 上下文相对,你可以前置 从getContextPath()输出到你的 URI。
所以不,2.3你的路径不自动翻译为包含上下文路径。
我已经使用帮助程序类来生成img标记等。这个帮助程序类使用应用程序的contextPath处理前缀路径。 (这很有效,但我真的不喜欢它。如果有人有更好的选择,请告诉我。)
对于css文件中的路径等,我使用 Ant构建脚本,它在生产环境中使用site.production.css作为site.css,在开发环境中使用site.development.css。
或者我有时会使用一个Ant脚本替换@token @ 令牌,并为不同的环境提供适当的数据。在这种情况下,@ contextPAth @ token将被替换为正确的上下文路径。
一种选择是使用<!> quot; flat <!> quot;应用程序结构和相关URL尽可能。
按<!>“flat <!>”;我的意思是你的应用程序根目录下没有子目录,也许只有几个静态内容目录为<!> quot; images / <!> quot;。您的所有JSP,操作URL,servlet都直接位于根目录下。
这并不能完全解决您的问题,但会大大简化。
Vilmantas在这里说的是正确的词:相对的URL。
您在IMG中需要做的就是使用
<img src="myimage.gif"/>
而不是
<img src="/myimage.gif"/>
并且它将与应用程序上下文相关(因为浏览器正在解释要转到的URL)
除特殊情况外,我建议不要以这种方式使用绝对URL。永远。当另一个webapp 指向您的webapp中的某些内容时,绝对URL很适合。在内部 - 当一个资源指向同一上下文中的第二个资源时 - 资源应该知道它所在的位置,因此它应该能够表达第二个资源的相对路径。
当然,您将编写模块化组件,这些组件不知道包含它们的资源。例如:
/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" />
那么,email.jsp
如何知道sendmail.jsp
的相对路径?很明显,链接将在/myapp/browse/profile.jsp
中断,或者在/myapp/home.jsp
上断开。答案是,将所有URL保存在同一个平面文件路径空间中。也就是说,在/myapp/
之后,每个URL都应该没有斜杠。
这很容易实现,只要您在URL和生成内容的实际文件之间有某种映射。 (例如,在Spring中,使用DispatcherServlet将URL映射到JSP文件或视图。)
有特殊情况。例如如果您在Javascript中编写浏览器端应用程序,那么维护平坦的文件路径空间会变得更加困难。在这种情况下,或者在其他特殊情况下,或者只是在您有个人偏好的情况下,使用<%= request.getContextPath() %>
创建绝对路径并不是一件大事。
你可以使用的请求。getContextPath()建立绝对的网址并不难编码于一个特定的上下文。作为一个较早的回答表明,对于JavaScript你只是设置一个变量在JSP(或最好在一个模板)和前缀为的上下文。
这不起作用CSS图像的更换除非你想要的动态生成了一个CSS文件,这可能会导致其他问题。但既然你知道你的CSS文件是在关系到你的图像,你可以摆脱相对的网址。
由于某些原因,我已经有麻烦即处理相对的网址和已回落到使用的表达JavaScript变量设置的上下文。我只是拆我的即图像的替代品进入他们自己的文件和使用即宏拉在正确的。这不是一个大问题因为我已经不得不这样做,以处理与透明的Png无论如何。这不是很漂亮,但它的工作。
我已经使用了大部分这些技术(保存XSLT架构)。
我认为问题的关键(和共识)是拥有一个可能有多个目录的网站。
如果您的目录深度(缺少更好的术语)是不变的,那么您可以依赖CSS之类的相对URL。
介意,布局不必完全平坦,只是一致。
例如,我们已经完成了/ css,/ js,/ common,/ admin,/ user等层次结构。将适当的页面和资源放在适当的目录中。拥有这样的结构可以很好地处理基于容器的身份验证。
我还将* .css和* .js映射到JSP servlet,并使它们动态化,以便我可以动态构建它们。
我只是希望有一些我可能错过的东西。
我通过否表示声称以下是一个优雅的问题。事实上,事后看来,鉴于(最有可能)性能影响,我不会推荐这个问题。
我们的网络应用程序的JSP是严格的XML原始数据。然后将这些原始数据发送到XSL(服务器端),该XSL应用正确的CSS标签,并吐出XHTML。
我们有一个template.xsl,它将由我们为网站的不同组件提供的多个XSL文件继承。我们的路径都在名为paths.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>
内部链接将在XML中如下:
<ilink name="link to icons" type="icons">link to icons</ilink>
这将由我们的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>
使用$rootPath
将 ${applicationScope.contextPath}
传递到每个文件上我们使用XML而不是仅仅在JSP / Java文件中对其进行硬编码的想法是我们不想重新编译的。
同样,解决方案根本不是一个好的...但我们确实使用过一次!
编辑:实际上,我们的问题很复杂,因为我们无法在整个视图中使用JSP。为什么没有人只使用<=>来检索上下文路径?那时它对我们来说很好。
当创建一个网站,从头开始,我侧@会-目的是为一致和可预测的网址结构,这样你可以坚持相对的参考文献。
但是,事情可能会变得真的很混乱,如果你正在更新一个网站,最初建的工作直接在网站根"/"(相当常见的用于简单的JSP网站),以正式的 Java EE 包装(其上下文根会一路下根)。
这可能意味着一个很大的代码变化。
如果你想要避免或推迟的代码变化,但仍然确保正确的上下文中根引用的一种技术,我已经试验使用servlet过滤器。滤波器,可能落入一个现有的切尔西不改变任何事(除了web.xml),并将重任何网址提出HTML到正确的道路,也确保重定向是正确引用。
一个例子网站和可用的代码可在这里: EnforceContextRootFilter-1.0-src.zip NB:实际映的规则是实现为regex在servlet类并提供相当一般捕获所有的-但你可能需要修改用于特殊情况。
顺便说一句,我分叉的一个稍微不同的问题解决 迁移现有的码的基础,从"/"非根环境的路径
我倾向于将一个属性作为我的核心JavaScript库的一部分。我认为这不是完美的,但我认为这是我能够实现的最佳目标。
首先,我有一个模块,它是我的应用核心的一部分,始终可用
(function (APP) {
var ctx;
APP.setContext = function (val) {
// protect rogue JS from setting the context.
if (ctx) {
return;
}
val = val || val.trim();
// Don't allow a double slash for a context.
if (val.charAt(0) === '/' && val.charAt(1) === '/') {
return;
}
// Context must both start and end in /.
if (val.length === 0 || val === '/') {
val = '/';
} else {
if (val.charAt(0) !== '/') {
val = '/' + val;
}
if (val.slice(-1) !== '/') {
val += '/';
}
}
ctx = val;
};
APP.getContext = function () {
return ctx || '/';
};
APP.getUrl = function (val) {
if (val && val.length > 0) {
return APP.getContext() + (val.charAt(0) === '/' ? val.substring(1) : val);
}
return APP.getContext();
};
})(window.APP = window.APP || {});
然后我使用带有通用标头的apache磁贴,它总是包含以下内容:
<script type="text/javascript">
APP.setContext('${pageContext.request['contextPath']}');
// If preferred use JSTL cor, but it must be available and declared.
//APP.setContext('<c:url value='/'/>');
</script>
现在我已经初始化了上下文,我可以在任何地方使用getUrl(path)
(js文件或jsp / html),这将返回上下文中给定输入字符串的绝对路径。
请注意,以下两者都是有意的。 getUrl
将始终返回绝对路径,因为相对路径不需要您首先了解上下文。
var path = APP.getUrl("/some/path");
var path2 = APP.getUrl("some/path");
这是最好的方法: 上下文重定向过滤器 必须在匹配前的扩展点应用过滤器,因此使用注释@PreMatching。
实现此接口的过滤器必须使用@Provider进行注释,以便由JAX-RS运行时发现。还可以发现容器请求过滤器实例并将其动态绑定到特定资源方法。
用示例代码解释: