com.eryansky.common.web.servlet.StaticContentServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.eryansky.common.web.servlet.StaticContentServlet.java

Source

/**
 *  Copyright (c) 2012-2014 http://www.eryansky.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 */
package com.eryansky.common.web.servlet;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.eryansky.common.web.utils.WebUtils;

import javax.activation.MimetypesFileTypeMap;
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;

/**
 * ??Servlet.
 * <p/>
 * EhCache???, ?,?Gzip.
 * <p/>
 * ?
 * static-content?contentPath=img/logo.jpg
 * static-content?contentPath=img/logo.jpg&download=true   
 *
 * @author &Eryan eryanwcp@gmail.com
 */
public class StaticContentServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /** ?GzipMime. */
    private static final String[] GZIP_MIME_TYPES = { "text/html", "application/xhtml+xml", "text/plain",
            "text/css", "text/javascript", "application/x-javascript", "application/json" };

    /** ?Gzip??. */
    private static final int GZIP_MINI_LENGTH = 512;

    private MimetypesFileTypeMap mimetypesFileTypeMap;

    /**
     * Content?.
     */
    private Cache contentInfoCache;

    /**
     * ??.
     */
    @Override
    public void init() throws ServletException {
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        CacheManager ehcacheManager = (CacheManager) context.getBean("ehCacheManager");
        contentInfoCache = ehcacheManager.getCache("contentInfoCache");

        //?mimeTypes, css,.
        mimetypesFileTypeMap = new MimetypesFileTypeMap();
        mimetypesFileTypeMap.addMimeTypes("text/css css");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //??.
        String contentPath = request.getParameter("contentPath");
        ContentInfo contentInfo = getContentInfoFromCache(contentPath);

        //?EtagModifiedSince Header?, ??304,.
        if (!WebUtils.checkIfModifiedSince(request, response, contentInfo.lastModified)
                || !WebUtils.checkIfNoneMatchEtag(request, response, contentInfo.etag)) {
            return;
        }

        //Etag/
        WebUtils.setExpiresHeader(response, WebUtils.ONE_YEAR_SECONDS);
        WebUtils.setLastModifiedHeader(response, contentInfo.lastModified);
        WebUtils.setEtag(response, contentInfo.etag);

        //MIME
        response.setContentType(contentInfo.mimeType);

        //,Header
        if (request.getParameter("download") != null) {
            WebUtils.setDownloadableHeader(response, contentInfo.fileName);
        }

        //OutputStream
        OutputStream output;
        if (WebUtils.checkAccetptGzip(request) && contentInfo.needGzip) {
            //outputstream, http1.1 trunked??content-length.
            output = WebUtils.buildGzipOutputStream(response);
        } else {
            //outputstream, content-length.
            response.setContentLength(contentInfo.length);
            output = response.getOutputStream();
        }

        //?.
        FileInputStream input = new FileInputStream(contentInfo.file);
        try {
            //byte?OutputStream, ?4k.
            IOUtils.copy(input, output);
            output.flush();
        } finally {
            //??Input/Output Stream.
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(output);
        }
    }

    /**
     * ?Content?, ?.
     */
    private ContentInfo getContentInfoFromCache(String path) {
        Element element = contentInfoCache.get(path);
        if (element == null) {
            ContentInfo content = createContentInfo(path);
            element = new Element(content.contentPath, content);
            contentInfoCache.put(element);
        }
        return (ContentInfo) element.getObjectValue();
    }

    /**
     * Content?.
     */
    private ContentInfo createContentInfo(String contentPath) {
        ContentInfo contentInfo = new ContentInfo();

        String realFilePath = getServletContext().getRealPath(contentPath);
        File file = new File(realFilePath);

        contentInfo.contentPath = contentPath;
        contentInfo.file = file;
        contentInfo.fileName = file.getName();
        contentInfo.length = (int) file.length();

        contentInfo.lastModified = file.lastModified();
        contentInfo.etag = "W/\"" + contentInfo.lastModified + "\"";

        String mimeType = getServletContext().getMimeType(realFilePath);
        if (mimeType == null) {
            mimeType = "application/octet-stream";
        }
        contentInfo.mimeType = mimeType;

        if (contentInfo.length >= GZIP_MINI_LENGTH && ArrayUtils.contains(GZIP_MIME_TYPES, contentInfo.mimeType)) {
            contentInfo.needGzip = true;
        } else {
            contentInfo.needGzip = false;
        }

        return contentInfo;
    }

    /**
     * Content?.
     */
    static class ContentInfo {
        protected String contentPath;
        protected File file;
        protected String fileName;
        protected int length;
        protected String mimeType;
        protected long lastModified;
        protected String etag;
        protected boolean needGzip;
    }
}