io.liuwei.web.StaticContentServlet.java Source code

Java tutorial

Introduction

Here is the source code for io.liuwei.web.StaticContentServlet.java

Source

/*******************************************************************************
 * Copyright (c) 2005, 2014 springside.github.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 *******************************************************************************/
package io.liuwei.web;

import io.liuwei.PropertyHolder;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springside.modules.web.Servlets;

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.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

/**
 * ??Servlet.
 * <p/>
 * ?,?Gzip.
 * ?org.springside.examples.showcase.cacheEhcacheMap???().
 * <p/>
 * ?
 * static-content/{contentPath}
 * static-content/{contentPath}?download=true
 *
 * @author calvin
 */
public class StaticContentServlet extends HttpServlet {

    private static final long serialVersionUID = -1855617048198368534L;

    /**
     * ?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;

    private ApplicationContext applicationContext;

    private String baseDir;

    /**
     * ???gzip?.
     */
    private static boolean checkAccetptGzip(HttpServletRequest request) {
        // Http1.1 header
        String acceptEncoding = request.getHeader("Accept-Encoding");

        return StringUtils.contains(acceptEncoding, "gzip");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // ??
        String contentPath = request.getPathInfo();
        if (StringUtils.isBlank(contentPath) || "/".equals(contentPath)) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "contentPath parameter is required.");
            return;
        }

        // ??.
        ContentInfo contentInfo = getContentInfo(contentPath);
        if (!contentInfo.file.exists()) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "file not found.");
            return;
        }

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

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

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

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

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

        // ?,?input file
        FileUtils.copyFile(contentInfo.file, output);
        output.flush();
    }

    /**
     * Gzip HeaderGZIPOutputStream.
     */
    private OutputStream buildGzipOutputStream(HttpServletResponse response) throws IOException {
        response.setHeader("Content-Encoding", "gzip");
        response.setHeader("Vary", "Accept-Encoding");
        return new GZIPOutputStream(response.getOutputStream());
    }

    /**
     * ?.
     */
    @Override
    public void init() throws ServletException {
        // ?applicationContext?.
        applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

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

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

        String realFilePath = getBaseDir() + contentPath;
        File file = new File(realFilePath);

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

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

        contentInfo.mimeType = mimetypesFileTypeMap.getContentType(contentInfo.fileName);

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

        return contentInfo;
    }

    private String getBaseDir() {
        if (baseDir == null) {
            baseDir = PropertyHolder.getUploadDir();
        }
        return baseDir;
    }

    /**
     * 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;
    }
}