franta-hg@64: package cz.frantovo.nekurak.servlet;
franta-hg@64:
franta-hg@64: import java.io.File;
franta-hg@64: import java.io.FileInputStream;
franta-hg@64: import java.io.IOException;
franta-hg@64: import java.io.InputStream;
franta-hg@64: import java.util.logging.Level;
franta-hg@64: import java.util.logging.Logger;
franta-hg@64: import java.util.regex.Pattern;
franta-hg@64: import javax.servlet.ServletException;
franta-hg@64: import javax.servlet.ServletOutputStream;
franta-hg@64: import javax.servlet.http.HttpServlet;
franta-hg@64: import javax.servlet.http.HttpServletRequest;
franta-hg@64: import javax.servlet.http.HttpServletResponse;
franta-hg@64:
franta-hg@64: /**
franta-hg@65: *
Servlet pro zpřístupnění fotek, které se nacházejí ve zvláštním adresáři.
franta-hg@64: *
franta-hg@65: * Má jeden inicializační parametr:
franta-hg@65: *
franta-hg@65: * adresar
– cesta k adresáři na disku, kde se nacházejí fotky.
franta-hg@65: * - např.
/var/www/nekurak.net/fotky
franta-hg@65: *
franta-hg@64: *
franta-hg@65: * Očekává se struktura adresářů tohoto typu:
franta-hg@65: *
franta-hg@65: * - Plné rozlišení:
/var/www/nekurak.net/fotky/original/1.jpg
franta-hg@65: * - Náhled fotky:
/var/www/nekurak.net/fotky/nahled/1.jpg
franta-hg@65: *
franta-hg@65: * Lze ovlivnit konstantami níže.
franta-hg@65: *
franta-hg@65: * URL respektují fyzické umístění fotek na serveru (není např. ID v GET parametru stylem /fotky?id=123
),
franta-hg@65: * 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
franta-hg@65: * (fotky jsou veřejné, není potřeba řešit autorizaci)
franta-hg@65: *
franta-hg@64: * @author fiki
franta-hg@64: */
franta-hg@64: public class Fotky extends HttpServlet {
franta-hg@64:
franta-hg@64: /** Název inicializačního parametru */
franta-hg@64: private static final String INIT_ADRESAR = "adresar";
franta-hg@64: /** Název podadresáře obsahujícího fotku v plném rozlišení */
franta-hg@66: public static final String PODADRESAR_ORIGINAL = "original";
franta-hg@64: /** Název podadresáře obsahujícího výchozí náhled fotky */
franta-hg@66: public static final String PODADRESAR_NAHLED = "nahled";
franta-hg@66: public static final String PRIPONA = "jpg";
franta-hg@64: private static final String LOMITKO = File.separator;
franta-hg@64: /** Regulární výraz */
franta-hg@64: private static final String VZOR_CESTY = "^" + LOMITKO + "(" + PODADRESAR_ORIGINAL + "|" + PODADRESAR_NAHLED + ")" + LOMITKO + "\\d+\\." + PRIPONA + "$";
franta-hg@64: private static final String MIME_TYP = "image/jpeg";
franta-hg@64: private File adresar;
franta-hg@64: private static final Logger log = Logger.getLogger(Fotky.class.getSimpleName());
franta-hg@64:
franta-hg@64: @Override
franta-hg@64: public void init() throws ServletException {
franta-hg@64: super.init();
franta-hg@64: String initAdresar = getServletConfig().getInitParameter(INIT_ADRESAR);
franta-hg@64: adresar = new File(initAdresar);
franta-hg@64: if (adresar.isDirectory()) {
franta-hg@64: log.log(Level.INFO, "Servlet „Fotka“ byl úspěšně inicializován.");
franta-hg@64: log.log(Level.INFO, "Adresář s fotkami: " + initAdresar);
franta-hg@64: log.log(Level.INFO, "RegExp cesty: " + VZOR_CESTY);
franta-hg@64: } else {
franta-hg@64: throw new ServletException("Servlet „Fotka“ se nepodařilo inicializovat. Cesta: " + initAdresar);
franta-hg@64: }
franta-hg@64: }
franta-hg@64:
franta-hg@64: /**
franta-hg@64: * @param pozadavek pouze GET (není důvod podporovat POST)
franta-hg@65: * @param odpoved odešleme fotku s MIME typem podle konstanty, délkou a datem podle souboru.
franta-hg@65: * @throws ServletException pokud je požadovaná cesta chybná (nevyhovuje vzoru)
franta-hg@64: * @throws IOException
franta-hg@64: */
franta-hg@64: @Override
franta-hg@64: protected void doGet(HttpServletRequest pozadavek, HttpServletResponse odpoved) throws ServletException, IOException {
franta-hg@64:
franta-hg@64: String cesta = zkontrolujParametr(pozadavek.getPathInfo());
franta-hg@64: File soubor = new File(adresar, cesta);
franta-hg@64:
franta-hg@64: if (soubor.isFile() && soubor.canRead()) {
franta-hg@64:
franta-hg@64: if (soubor.lastModified() > pozadavek.getDateHeader("If-Modified-Since")) {
franta-hg@64: /** Soubor se změnil nebo ho klient ještě nemá načtený. */
franta-hg@64: odpoved.setContentType(MIME_TYP);
franta-hg@64: odpoved.setContentLength((int) soubor.length());
franta-hg@64: odpoved.setDateHeader("Last-Modified", soubor.lastModified());
franta-hg@64:
franta-hg@69: ServletOutputStream vystup = odpoved.getOutputStream();
franta-hg@69: InputStream vstup = new FileInputStream(soubor);
franta-hg@64:
franta-hg@64: try {
franta-hg@69: byte[] zasobnik = new byte[1024];
franta-hg@64: int bajtuNacteno;
franta-hg@69: while ((bajtuNacteno = vstup.read(zasobnik)) != -1) {
franta-hg@69: vystup.write(zasobnik, 0, bajtuNacteno);
franta-hg@64: }
franta-hg@64: } catch (Exception e) {
franta-hg@64: throw new ServletException("Chyba při odesílání obrázku klientovi.", e);
franta-hg@64: } finally {
franta-hg@69: vstup.close();
franta-hg@69: vystup.close();
franta-hg@64: }
franta-hg@64: } else {
franta-hg@64: /** Soubor se od posledního načtení klientem nezměnil → není potřeba ho posílat znova. */
franta-hg@64: odpoved.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
franta-hg@64: }
franta-hg@64:
franta-hg@64: } else {
franta-hg@64: /** Neexistující nebo nečitelný soubor → HTTP 404 chyba */
franta-hg@64: odpoved.sendError(HttpServletResponse.SC_NOT_FOUND);
franta-hg@64: }
franta-hg@64: }
franta-hg@64:
franta-hg@64: /**
franta-hg@65: * @param cesta cesta požadovaná klientem: request.getPathInfo()
franta-hg@64: * @throws ServletException pokud cesta nevyhovuje vzoru
franta-hg@64: */
franta-hg@64: private static String zkontrolujParametr(String cesta) throws ServletException {
franta-hg@64: if (Pattern.matches(VZOR_CESTY, cesta)) {
franta-hg@64: /** cesta je v pořádku → pokračujeme */
franta-hg@64: return cesta;
franta-hg@64: } else {
franta-hg@64: /** Chybná cesta → HTTP 500 chyba */
franta-hg@64: throw new ServletException("Chybná cesta k obrázku: " + cesta);
franta-hg@64: }
franta-hg@64: }
franta-hg@64: }