Question
How can I develop a servlet that serves static content in a web application deployed on both Tomcat and Jetty containers?
Answer
In this guide, we will create a simple servlet to serve static content such as images, CSS, and JavaScript files effectively across Tomcat and Jetty web containers. This servlet will accommodate custom URL routing and leverage caching mechanisms like If-Modified-Since headers for optimized performance.
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
public class StaticContentServlet extends HttpServlet {
private String staticPath;
@Override
public void init() throws ServletException {
staticPath = getServletContext().getRealPath("/static");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
File file = new File(staticPath, request.getPathInfo());
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// Handle If-Modified-Since
long lastModified = file.lastModified();
response.setDateHeader("Last-Modified", lastModified);
if (request.getDateHeader("If-Modified-Since") == lastModified) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
response.setContentType(getServletContext().getMimeType(file.getName()));
response.setContentLength((int) file.length());
try (FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
}
}
Causes
- Tomcat and Jetty have different behaviors regarding static file handling, causing compatibility issues.
- Need for custom URL patterns to route requests properly to the main servlet and static files.
Solutions
- Create a dedicated servlet for static content serving.
- Implement caching support with If-Modified-Since for efficient loading.
- Optionally include gzip encoding and ETags for compressing responses and supporting cache validation.
Common Mistakes
Mistake: Forgetting to map the servlet correctly in web.xml.
Solution: Ensure correct servlet mappings are defined for both the main and static content servlets.
Mistake: Not checking for file existence before reading.
Solution: Always verify if the requested file exists to avoid server errors.
Mistake: Ignoring cache headers leading to unnecessary file transfers.
Solution: Implement cache control using If-Modified-Since and Last-Modified headers.
Helpers
- Java servlet
- serve static content servlet
- Tomcat Jetty static content
- If-Modified-Since header
- gzip encoding servlet