I was alwyas wondering what is the best way of referring to resources like javascript, css, images on the .jsp files. What should be natural is using absolute paths, but this was not an option in my situation since I didn't want my application to be application context dependent. Another option is to use relative paths everywhere and keep some standards of url structure to make these relative urls work. E.g. when opening a page using MVC we point the address using UrlResolvers, these URLs could be resembling this one: http://my.host.com/application/dispatcher/module/action
In my JSP pages I couls assume the URL structure and point the resource with relative path (let's assume there is an /images folder in web application root folder):
<img src="../../images/logo.gif" />
It's a outbraining solution in my opinion.
The solution that is mentioned the most often is to use ;<c:url value="/images/logo.gif"> tag.
I works, I can't say otherwise, but... I'm lazy and quickly I become tired of filling those damn <c:url> tags
So, the solution that finally brought smile on my face was... a filter. Actually, there is out of the box solution provided by Spring similar to mine- ResourceServlet... I had some problems deploying it to access image resources though.
My filter recognizes 3 types of resources: images, css, js. I have assumed that these resources are always available in the corresponding folders of web application root. Filter simply checks if requested url matches resource location. If it finds images/ css/ or js/ string in the url then it includes a corresponding resource in the response.
My filter implementation looks like this:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* This filter makes .jsp design related to image/css/js resource a lot easier. It translates all accesses to these resources no matter
* where are they called from. Basically it allows to use relative path everywhere on the sites e.g.:
* instead of calling:
* <code><img src="<c:url value=" />"/></code>
* simple code can be user:
* <code><img src="images/logo.gif" /></code>
*
* Remember, that relative path must be user, since /images will not be passed to this filter at all.
*
* @author Bartosz Jankiewicz
*/
public class ResourcesFilter implements Filter
{
private FilterConfig config;
@Override
public void destroy()
{
}
@Override
public void doFilter( ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException
{
if ( request instanceof HttpServletRequest)
{
String url = ( (HttpServletRequest) request).getRequestURI();
String path = decodeResourcePath( url);
if( path != null)
{
File file = new File( path);
if( !file.exists())
{
((HttpServletResponse) response).sendError( HttpServletResponse.SC_NOT_FOUND);
return;
}
String contentType = this.config.getServletContext().getMimeType( file.getName());
doInclude( file, contentType, (HttpServletResponse) response);
return;
}
}
filterChain.doFilter( request, response);
}
private String decodeResourcePath( String url)
{
if ( url.contains( "images/"))
{
String imagePath = "/" + url.substring( url.indexOf( "images/"));
return this.config.getServletContext().getRealPath( imagePath);
}
if ( url.contains( "/css/") || url.startsWith( "css/"))
{
String resourcePath = "/" + url.substring( url.indexOf( "css/"));
return this.config.getServletContext().getRealPath( resourcePath);
}
if ( url.contains( "/js/") || url.startsWith( "js/"))
{
String resourcePath = "/" + url.substring( url.indexOf( "js/"));
return this.config.getServletContext().getRealPath( resourcePath);
}
return null;
}
private void doInclude( File file, String contentType, HttpServletResponse response) throws IOException
{
response.setContentType( contentType);
response.setContentLength((int)file.length());
// Open the file and output streams
FileInputStream in = new FileInputStream( file);
OutputStream out = response.getOutputStream();
// Copy the contents of the file to the output stream
byte[] buf = new byte[1024];
int count = 0;
while ( ( count = in.read( buf)) >= 0)
{
out.write( buf, 0, count);
}
in.close();
out.close();
}
@Override
public void init( FilterConfig config) throws ServletException
{
this.config = config;
}
}
Happy Java coding :)
Cheers,
Bartosz
No comments:
Post a Comment