java/nekurak.net-web/src/java/cz/frantovo/nekurak/servlet/Fotky.java
author František Kučera <franta-hg@frantovo.cz>
Tue Mar 16 13:32:31 2010 +0100 (2010-03-16)
changeset 69 4964cf581166
parent 66 048531e09c09
child 145 0efefbf5f8b6
permissions -rw-r--r--
Hibernate: podniky budeme načítat včetně jejich fotek.
     1 package cz.frantovo.nekurak.servlet;
     2 
     3 import java.io.File;
     4 import java.io.FileInputStream;
     5 import java.io.IOException;
     6 import java.io.InputStream;
     7 import java.util.logging.Level;
     8 import java.util.logging.Logger;
     9 import java.util.regex.Pattern;
    10 import javax.servlet.ServletException;
    11 import javax.servlet.ServletOutputStream;
    12 import javax.servlet.http.HttpServlet;
    13 import javax.servlet.http.HttpServletRequest;
    14 import javax.servlet.http.HttpServletResponse;
    15 
    16 /**
    17  * <p>Servlet pro zpřístupnění fotek, které se nacházejí ve zvláštním adresáři.</p>
    18  *
    19  * <p>Má jeden inicializační parametr:</p>
    20  *  <ul>
    21  *     <li><code>adresar</code> – cesta k adresáři na disku, kde se nacházejí fotky.</li>
    22  *     <li>např. <code>/var/www/nekurak.net/fotky</code></li>
    23  *  </ul>
    24  *
    25  * <p>Očekává se struktura adresářů tohoto typu:</p>
    26  *  <ul>
    27  *	<li>Plné rozlišení: <code>/var/www/nekurak.net/fotky/original/1.jpg</code></li>
    28  *      <li>Náhled fotky:   <code>/var/www/nekurak.net/fotky/nahled/1.jpg</code></li>
    29  *  </ul>
    30  * <p>Lze ovlivnit konstantami níže.</p>
    31  *
    32  * <p>URL respektují fyzické umístění fotek na serveru (není např. ID v GET parametru stylem <code>/fotky?id=123</code>),
    33  * díky tomu je možné, aby fotky později servírovala přímo reverzní proxy a nemusely procházet přes naši aplikaci
    34  * (fotky jsou veřejné, není potřeba řešit autorizaci)</p>
    35  *
    36  * @author fiki
    37  */
    38 public class Fotky extends HttpServlet {
    39 
    40     /** Název inicializačního parametru */
    41     private static final String INIT_ADRESAR = "adresar";
    42     /** Název podadresáře obsahujícího fotku v plném rozlišení */
    43     public static final String PODADRESAR_ORIGINAL = "original";
    44     /** Název podadresáře obsahujícího výchozí náhled fotky */
    45     public static final String PODADRESAR_NAHLED = "nahled";
    46     public static final String PRIPONA = "jpg";
    47     private static final String LOMITKO = File.separator;
    48     /** Regulární výraz */
    49     private static final String VZOR_CESTY = "^" + LOMITKO + "(" + PODADRESAR_ORIGINAL + "|" + PODADRESAR_NAHLED + ")" + LOMITKO + "\\d+\\." + PRIPONA + "$";
    50     private static final String MIME_TYP = "image/jpeg";
    51     private File adresar;
    52     private static final Logger log = Logger.getLogger(Fotky.class.getSimpleName());
    53 
    54     @Override
    55     public void init() throws ServletException {
    56 	super.init();
    57 	String initAdresar = getServletConfig().getInitParameter(INIT_ADRESAR);
    58 	adresar = new File(initAdresar);
    59 	if (adresar.isDirectory()) {
    60 	    log.log(Level.INFO, "Servlet „Fotka“ byl úspěšně inicializován.");
    61 	    log.log(Level.INFO, "Adresář s fotkami: " + initAdresar);
    62 	    log.log(Level.INFO, "RegExp cesty: " + VZOR_CESTY);
    63 	} else {
    64 	    throw new ServletException("Servlet „Fotka“ se nepodařilo inicializovat. Cesta: " + initAdresar);
    65 	}
    66     }
    67 
    68     /**
    69      * @param pozadavek pouze GET (není důvod podporovat POST)
    70      * @param odpoved odešleme fotku s MIME typem podle konstanty, délkou a datem podle souboru.
    71      * @throws ServletException pokud je požadovaná cesta chybná (nevyhovuje vzoru)
    72      * @throws IOException
    73      */
    74     @Override
    75     protected void doGet(HttpServletRequest pozadavek, HttpServletResponse odpoved) throws ServletException, IOException {
    76 
    77 	String cesta = zkontrolujParametr(pozadavek.getPathInfo());
    78 	File soubor = new File(adresar, cesta);
    79 
    80 	if (soubor.isFile() && soubor.canRead()) {
    81 
    82 	    if (soubor.lastModified() > pozadavek.getDateHeader("If-Modified-Since")) {
    83 		/** Soubor se změnil nebo ho klient ještě nemá načtený. */
    84 		odpoved.setContentType(MIME_TYP);
    85 		odpoved.setContentLength((int) soubor.length());
    86 		odpoved.setDateHeader("Last-Modified", soubor.lastModified());
    87 
    88 		ServletOutputStream vystup = odpoved.getOutputStream();
    89 		InputStream vstup = new FileInputStream(soubor);
    90 
    91 		try {
    92 		    byte[] zasobnik = new byte[1024];
    93 		    int bajtuNacteno;
    94 		    while ((bajtuNacteno = vstup.read(zasobnik)) != -1) {
    95 			vystup.write(zasobnik, 0, bajtuNacteno);
    96 		    }
    97 		} catch (Exception e) {
    98 		    throw new ServletException("Chyba při odesílání obrázku klientovi.", e);
    99 		} finally {
   100 		    vstup.close();
   101 		    vystup.close();
   102 		}
   103 	    } else {
   104 		/** Soubor se od posledního načtení klientem nezměnil → není potřeba ho posílat znova. */
   105 		odpoved.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
   106 	    }
   107 
   108 	} else {
   109 	    /** Neexistující nebo nečitelný soubor → HTTP 404 chyba */
   110 	    odpoved.sendError(HttpServletResponse.SC_NOT_FOUND);
   111 	}
   112     }
   113 
   114     /**
   115      * @param cesta cesta požadovaná klientem: <code>request.getPathInfo()</code>
   116      * @throws ServletException pokud cesta nevyhovuje vzoru
   117      */
   118     private static String zkontrolujParametr(String cesta) throws ServletException {
   119 	if (Pattern.matches(VZOR_CESTY, cesta)) {
   120 	    /** cesta je v pořádku → pokračujeme */
   121 	    return cesta;
   122 	} else {
   123 	    /** Chybná cesta → HTTP 500 chyba */
   124 	    throw new ServletException("Chybná cesta k obrázku: " + cesta);
   125 	}
   126     }
   127 }