views:

720

answers:

3

I have web application, which was designed and always worked under root context ("/"). So all css, js and links started with "/" (for example "/css/style.css"). Now I need to move this web application to some different context (let's say /app1). It is easy to change server.xml configuration file and bring up web application in new context "app1" using [Context path=""] item. But web pages are broken because all links are now incorrect. They point to old root context ("/css/style.css") instead of new "app1" context. Is there any magic way to fix this problem without fixing each link by prefixing with some "context" variable? Used server - Tomcat 5. Application is written with Java and uses JSP, Struts2, Spring and UrlRewrite filter. More interesting is to hear real experience in fighting with such problems that theoretical debates. Thank you.

P.S. I do not see how UrlRewrite filter can help me because it will work only in 'app1' context. So requests to links like '/css/style.css' will not be passed to it.

+2  A: 

If you use URL rewriting to redirect ROOT to your application, won't that eliminate the ability to have a an application in ROOT? If so, what is gained by switching the context?

I think the general way to link resources is to either append a "context" variable and make the link absolute: ${pagecontext.request.contextpath}/css/style.css or just make the link relative: css/style.css

Unless you have specific reasons for being unable to modify the code, I would do a search/replace on the links and be done with it. You should have no more than three or four expressions to find, /css, /images, /javascript, etc.

Kevin
I use URL rewriting to have 'clear' urls. I do not see how UrlRewrite can help me. Suppose I have 2 apps in single Tomcat. Their contexts will be 'app1' and 'app2'. Both apps will have link to css in html like "/css/style.css". (Both wrong) How will UrlRewrite filter help me if it works in contexts 'app1' and 'app2' and will not be fired at all?
Denis
I completely understand way with adding 'context' variable. I do not like it because it is long and are not always simple (it is not static html site, it is JSP+Struts2). Relative links become very tricky as soon as you move a little deeper than first level pages. So I do not like it too.
Denis
The way to handle nested relative links is with the <base/> tag.
Kevin
+1  A: 

Make use of the HTML <base> tag in combination with ${pageContext.request.contextPath} and let all relative links be relative to it. This way you can place your webapp everywhere you want without worrying about the correct paths. Here's a basic example:

<!doctype html>
<html lang="en">
    <head>
        <base href="${pageContext.request.contextPath}">
        <link rel="stylesheet" type="text/css" href="css/style.css">
        <script type="text/javascript" src="js/script.js"></script>
    </head>
    <body>
        <ul>
            <li><a href="html/page.html">HTML page</a></li>
            <li><a href="jsp/page.jsp">JSP page</a></li>
        </ul>
    </body>
</html>

Note that you should not start the relative URL's with /, otherwise they will lead to the domain root, e.g. http://example.com/yourlink.

You only need to ensure that any CSS image paths inside the CSS file are relative to the CSS file itself and not to the root. Thus, use e.g. ../img/foo.jpg instead of /img/foo.jpg.

BalusC
A: 

You should always create urls via url re-writing, not only so that session info can be added to the url, if required, but also so that the context path can be added. You should create all urls as absolutely paths from the top of the application and then let url-rewriting handle adding the context-path to the front, as appropriate.

<c:url value="/css/site.css"/>

That will render /<context-path>/css/site.css or /<context-path>/css/site.css;jsessionid=134345434543 into a jsp file if they don't have cookies enabled. You can also use the c:url tag to render the url into a variable and then use that variable multiple times throughout your document. Just add a var="x" attribute to the tag and then ${x} will render the url into your doc. If you aren't using jsp to render your output, you'll need to find the appropriate mechanism for your view layer, but they will all have one. If you are rendering a url in java code, just take a look at the source code to the c:url tag and you'll see how it is done.

The one awkwardness is that CSS files (and js files) aren't processed, so urls in css and js files need to be relative paths or they will break whenever you change the context path. Most js already uses relative paths since library maintainers don't know what path you are going to install their library to. CSS backround images, on the other hand, are often specified as absolute urls, since the same CSS file may be included into html files at different levels of a file hierarchy. There is no easy fix for this that I am aware of other than to create appropriate symlinks such that the relative url always works or else serve up the problem CSS files via a JSP so that the urls can be rewritten as appropriate. I'm sure there are probably filters or apache modules you can run which will do the url replacement, but then you've still got to manually update your filter/module whenever you deploy to a new context path.