1 package cz.frantovo.nekurak.servlet;
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;
17 * <p>Servlet pro zpřístupnění fotek, které se nacházejí ve zvláštním adresáři.</p>
19 * <p>Má jeden inicializační parametr:</p>
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>
25 * <p>Očekává se struktura adresářů tohoto typu:</p>
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>
30 * <p>Lze ovlivnit konstantami níže.</p>
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>
38 public class Fotky extends HttpServlet {
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";
52 private static final Logger log = Logger.getLogger(Fotky.class.getSimpleName());
55 public void init() throws ServletException {
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: {0}", initAdresar);
62 log.log(Level.INFO, "RegExp cesty: {0}", VZOR_CESTY);
64 throw new ServletException("Servlet „Fotka“ se nepodařilo inicializovat. Cesta: " + initAdresar);
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)
75 protected void doGet(HttpServletRequest pozadavek, HttpServletResponse odpoved) throws ServletException, IOException {
77 String cesta = zkontrolujParametr(pozadavek.getPathInfo());
78 File soubor = new File(adresar, cesta);
80 if (soubor.isFile() && soubor.canRead()) {
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());
88 ServletOutputStream vystup = odpoved.getOutputStream();
89 InputStream vstup = new FileInputStream(soubor);
92 byte[] zasobnik = new byte[1024];
94 while ((bajtuNacteno = vstup.read(zasobnik)) != -1) {
95 vystup.write(zasobnik, 0, bajtuNacteno);
97 } catch (Exception e) {
98 throw new ServletException("Chyba při odesílání obrázku klientovi.", e);
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);
109 /** Neexistující nebo nečitelný soubor → HTTP 404 chyba */
110 odpoved.sendError(HttpServletResponse.SC_NOT_FOUND);
115 * @param cesta cesta požadovaná klientem: <code>request.getPathInfo()</code>
116 * @throws ServletException pokud cesta nevyhovuje vzoru
118 private static String zkontrolujParametr(String cesta) throws ServletException {
119 if (Pattern.matches(VZOR_CESTY, cesta)) {
120 /** cesta je v pořádku → pokračujeme */
123 /** Chybná cesta → HTTP 500 chyba */
124 throw new ServletException("Chybná cesta k obrázku: " + cesta);