Přejít k navigační liště

Zdroják » Různé » Java na webovém serveru: Komentáře a integrace s Texy

Java na webovém serveru: Komentáře a integrace s Texy

Články Různé

Možnost vkládat komentáře, resp. schopnost přijímat od uživatelů formátovaný text, to je vlastnost, bez které se neobejde skoro žádný web. V dnešním díle přidáme do naší aplikace podporu komentářů a ukážeme si, jak je kontrolovat, aby nám do nich potenciální útočník nemohl podstrčit žádná závadná data, která by narušila naši stránku. Kromě XHTML a prostého textu umožníme čtenářům psát komentáře ještě v jednom formátu – Texy.

Naše aplikace obsahuje (nebo spíš bude obsahovat) databázi hospod a jiných podobných podniků, a tak by bylo dobré, kdyby je návštěvníci mohli komentovat a napsat, jak se jim tam líbilo. Web je postavený na XHTML (nebo HTML) a tak se přímo nabízí tenhle formát použít i pro zadávání komentářů. Někteří uživatelé ho ale neovládají, a tak je dobré jim dát i jinou možnost – psaní v prostém textu (což bude většině lidí stačit) nebo Texy. Texy! je dílo Davida Grudla a slouží k snadnému zápisu formátovaného textu (i když mně osobně přijde přirozenější psát ostré závorky)

Přejdeme rovnou k věci a jako obvykle si stáhneme aktuální zdrojové kódy aplikace z Mercurialu:

$ hg pull
$ hg up "14. díl"

Případně je můžete stáhnout jako bzip2 archiv přes web.

Proces zpracování komentáře

Při odesílání si uživatel může vybrat, v jakém formátu komentář posílá (v další verzi bychom mohli přidat automatickou detekci). Tím se nám proces rozděluje na tři větve – v prostém textu alespoň přidáme na konce řádků <br/>, aby se řádky neslily v jeden nekonečný nepřehledný tok textu (když už si uživatel dal práci a napsal několik odstavců). V případě Texy předáme vstupní text externí službě. A do XHTML pak doplníme odstavce, pokud je uživatel nezadal sám. Pak se cesty opět spojují a komentář odešleme k validaci. Ta je důležitá, aby nám na stránku někdo nevložil škodlivý kód (javascript injection) nebo třeba příliš velké písmo nebo neuzavřenou HTML značku, která by narušila naši stránku.

Napojení na Texy

Jelikož je knihovna Texy napsaná v PHP a my používáme Javu, musíme nějak vyřešit propojení těchto dvou světů. Existuje sice i port Texy do Javy, ale vzhledem k tomu, že chybí formální specifikace Texy, rozhodl jsem se použít originální PHP implementaci. Vytvořil jsem velice jednoduché „API“ – pomocí HTTP POST odešleme prostý text na URL http://nekurak.net/texy/http/ a jako odpověď dostaneme XHTML. Implementace rozhraní na straně Javy:

public class Texy {
    /** TODO: parametrizovatelnost */
    private static final String URL_SLUZBY = "http://nekurak.net/texy/http/";
    private static final Logger log = Logger.getLogger(Texy.class.getSimpleName());
    public String preved(String text) throws TexyVyjimka {
    OutputStreamWriter wr = null;
    BufferedReader rd = null;
    try {
        URL url = new URL(URL_SLUZBY);
        URLConnection spojeni = url.openConnection();
        spojeni.setDoOutput(true);
        /** Odešleme data */
        wr = new OutputStreamWriter(spojeni.getOutputStream());
        wr.write(URLEncoder.encode(text, "UTF-8"));
        wr.flush();
        /** Přijmeme odpověď */
        rd = new BufferedReader(new InputStreamReader(spojeni.getInputStream()));
        StringBuffer vysledek = new StringBuffer();
        String radka;
        while ((radka = rd.readLine()) != null) {
        vysledek.append(radka);
        }
        return vysledek.toString();
    } catch (Exception e) {
        throw new TexyVyjimka("Chyba při zpracovávání textu: " + text, e);
    } finally {
        try {
        wr.close();
        } catch (IOException e) {
        log.log(Level.WARNING, "Selhalo zavírání OutputStreamWriteru", e);
        }
        try {
        rd.close();
        } catch (IOException e) {
        log.log(Level.WARNING, "Selhalo zavírání BufferedReaderu", e);
        }
    }
    }
}

Na straně serveru (PHP) je implementace tohoto rozhraní velice snadná, ale v Javě kvůli ní musíme psát víc kódu než je nutné (ošetřování chyb, řešení nízkoúrovňových operací). Texy funkcionalita je zapouzdřena ve třídě cz.frantovo.nekurak.ext.Texy, takže v budoucnu můžeme snadno přepsat rozhraní na SOAP webové služby či XML-RPC – nebo použít nativní implementaci Texy v Javě (port odkazovaný výše). Případně můžete v komentářích navrhnout, jak byste tuto úlohu řešili pomocí REST API, ale nemyslím si, že by to v tomto případě bylo vhodné.

XML schéma – XSD

Ať už uživatel zadal text pomocí Texy nebo jako prostý text, klíčová je nakonec validace výsledného XHTML.

Pro kontrolu povolených značek (a vůbec formátování) použijeme XML Schéma. Díky tomu nebudeme muset moc programovat a pouze deklarujeme, jaké značky případně atributy jsou povolené. Vytvořené schéma je velmi jednoduché – povoluje jen odstavce, tučné a skloněné písmo a ruční zalomení řádku. Další značky a atributy si můžete podle potřeby přidat do schématu v souboru komentář.xsd. Např. povolit odkazy nebo odrážky.

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="div">
    <xs:complexType>
        <xs:choice minOccurs="1" maxOccurs="unbounded">
        <xs:element name="p">
            <xs:complexType mixed="true">
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element name="em" type="xs:string"/>
                <xs:element name="strong" type="xs:string"/>
                <xs:element name="br"/>
            </xs:choice>
            </xs:complexType>
        </xs:element>
        </xs:choice>
    </xs:complexType>
    </xs:element>
</xs:schema>

Jelikož každé XML musí mít kořenový element, použili jsme <div/>. Mohli bychom si vymyslet i vlastní kořenovou značku a vůbec celý formát, ale podobnost s XHTML se nám hodí – uživatelé se nemusí učit novou syntaxi a my nemusíme dělat další konverzi při vypisování na stránku.

Podpora XSD v Netbeans

V Netbeans existuje pěkný plugin pro vizuální návrh XML schématu. Ve výchozí instalaci ho pravděpodobně nemáte dostupný, ale dá se to snadno napravit – stačí si přidat vývojářské úložiště zásuvných modulů  – jeho URL je:

http://updates.netbeans.org/netbeans/updates/6.8/uc/m1/dev/catalog.xml.gz

a doinstalovat si „XML Schema and WSDL“.

Validace v Javě

Kód, který se stará o kontrolu XML oproti schématu se nachází v metodě zkontroluj() třídy Komentare (v modulu nekurak.net-lib).

public static Document zkontroluj(String komentar) throws KomentarovaVyjimka {
    try {
    URL soubor = Komentare.class.getClassLoader().getResource("cz/frantovo/nekurak/util/komentář.xsd");
    SchemaFactory tovarnaSchemat = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = tovarnaSchemat.newSchema(soubor);
    DocumentBuilderFactory tovarnaDB = DocumentBuilderFactory.newInstance();
    tovarnaDB.setSchema(schema);
    DocumentBuilder db = tovarnaDB.newDocumentBuilder();
    db.setErrorHandler(new ErrorHandler() {
        public void warning(SAXParseException e) throws SAXException {
        throw e;
        }
        public void error(SAXParseException e) throws SAXException {
        throw e;
        }
        public void fatalError(SAXParseException e) throws SAXException {
        throw e;
        }
    });
    Document dokument = db.parse(new ByteArrayInputStream(komentar.getBytes("UTF-8")));
    return dokument;
    } catch (Exception e) {
    throw new KomentarovaVyjimka("Neplatný komentář: " + komentar, e);
    }
}

Pomocí vlastního ErrorHandleru můžeme zjistit, v čem přesně dokument nevyhovuje a sdělit to uživali, aby věděl, co má opravit. V případě platného XML vrací metoda zkontroluj() DOM (který zatím k ničemu nevyužíváme) a v případě chyby vyhazuje výjimku – ta v sobě obsahuje informaci, které elementy jsou chybné, ale v ne příliš čitelné podobě.

Validace v Linuxu

Správnost XML dokumentů si můžeme kontrolovat i bez Javy a nějakých složitých IDE, stačí nám k tomu příkazová řádka a nástroj xmllint. V linuxových distribucích jako je Debian nebo Ubuntu si ho nainstalujeme pomocí:

$ aptitude install libxml2-utils

A kontrolu provádíme jednoduše příkazem:

xmllint --schema komentář.xsd komentář.xml

Pokud jsme nikde neudělali chybu, program nám odpoví výpisem XML souboru a hláškou komentář.xml validates. To se nám může hodit pro různé ladění nebo dávkové testování XML dokumentů na disku.

Validace při výstupu v JSP

Tak, jak jsme aplikaci vytvořili, teď závisí její bezpečnost na kvalitě dat v databázi. Pokud zajistíme, že se do ní bude zapisovat jen přes aplikaci (tzn. zkontrolované komentáře) nebo že do ní nikdo nezanese ručně chyby, můžeme aplikaci nechat tak, jak je. Pokud ale chceme vyšší bezpečnost, je lepší kontrolovat validitu komentářů i při jejich vypisování a nespoléhat se na kvalitu dat v databázi.

K tomu můžeme použít vlastní JSTL funkci nkfn:zkontrolujKomentar(). Pomocí tohoto kódu vypíšeme platné komentáře s formátováním a neplatné bez něj – escapované:

<c:out value="${k.komentar}" escapeXml="${!nkfn:zkontrolujKomentar(k.komentar)}" />

Další možností je, nevypsat chybné komentáře vůbec a zobrazit místo nich hlášku. Tento kód najdete v mercurialu v historii verzí souboru komentareVypis.tag. Jestli kontrolovat data jen na vstupu nebo i na výstupu, je z velké části kompromis mezi bezpečností a výkonem. S nastavením můžete experimentovat a vyzkoušet si, jestli se zapnutá validace vůbec na výkonu nějak viditelně projeví.

Závěr

Dnes jme do naší aplikace doplnili podporu komentářů a ukázali jsme si ještě jeden způsob, jak lze provázat aplikace – byť ne tak sofistikovaný jako webové služby, REST nebo jiné standardnější postupy. Také jsme nakousli téma XML a jeho validace v Javě. Jen připomínám, že aplikaci si můžete vyzkoušet na adrese nekuřák.net a jméno a heslo je: zdrojak.root.cz/hes­lo – pokud si nechcete zakládat vlastní účet.

Odkazy

  • Texy! – PHP knihovna pro snadné formátování textu.
  • JTexy – její port do jazyka Java.
  • XML schémata  – stránka Jiřího Koska o XML schématech.
  • Libxml2 – XML parser a sada nástrojů napsaná v C.
  • Relax NG – další způsob definice XML dokumentů.
  • Schematron  – totéž, ale trochu jinak.

Komentáře

Subscribe
Upozornit na
guest
30 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
harvie

Proč u svatého Stallmana rvete to do texy a zpátky přes DNS resolver, všechny možné síťové vrstvy a webový server? Normální člověk by si udělal php-cli skript (ne. opravdu nemyslím php-cgi), který by pak z javy spouštěl a data do něj rval pípou, nebo by šlo z javy spustit php fastcgi a nějak to tahat přes něj.
Asi za to může celá ta tendence všechno přesouvat na web a dělat jako že umět psát opravdové programy už není potřeba… (ale pak musí stejně přijít opravdoví chlapi s pravděpodobně většími platy a programovat operační systémy, servery, databáze, prohlížeče a programovací jazyky pro všechny ty programátory webů, kteří se toho bojí)
Jinak pokuď už chcete zkoušet různá harakiri, tak mrkněte na tohle:
http://php-java-bridge.sourceforge.net/
http://www.zend.com/en/products/server-ce/
ale opakuji, že bych do podobných sebevražd nešel…

tom

A v cem je problem? Tohle bylo asi nejjednodussi nastavit a hlavne si to muze vyzkouset kazdy. Pokud budes chtit rychlost, proste si naimplementujes navrhnuty interface jinym zpusobem. Autor, ale timto ukazal pouziti nekolika technologii, ktere pravdepodobne bude ctenar v budoucnu pouzivat.

snowracer

Ve Quercu se mi podařilo rozchodit jen starou verzi Texy pro PHP4 a to ještě jen špatně s nutností několika úprav.
Výborně naopak funguje PHP/Java bridge pomocí JSR 223. Jen nedoporučuji používat přímo na aplikačním serveru. Lépe vytvořit jednoduchý Texy-miniserver komunikovat nativními zprávami s ním.

lolek

java na webovém serveru, to jako vážně?! to dneska ještě někdo dělá?

jehovista

Provokace, nebo neznalost?

jerzy.burzek

skor borec, co si precital clanok o „pomalosti java 1.1“ z 12.3.1998 a zbuchal uz 3 webshopy v php v celkovom objeme 12.4kB zdrojoveho kodu, co ho nepochybne radi medzi odbornikov :-)

Flasi

A k tomu má nejspíš dojem, že java na webovém serveru = java na webu = java applet ve stránce. :-)

lolek

dojmy a pojmy z mé osoby o které absolutně nic nevíte nechme stranou. zkuste mi napsat, kdy a proč bych měl použít na web javu místo ruby/php/pythonu? v čem spočívájí výrazné výhody?

jehovista

Zkusime to jinak: Jaka je vyrazna nevyhoda Java EE?

Radek Miček

Velmi špatná architektura, viz
http://www.springsource.org/about
Java EE chce být univerzální, ale není, zato je ale složitá. Podobně jsou na tom i další technologie, třeba XML nebo MS LINQ to SQL.

blizzboz

zložitá je len pre toho kto má v hlave nasraté, my ostatní sa neustále vzdelávame. a čo je prosím ťa zložité na LINQ to SQL ?

x

nemam ziaden vyhraneny nazor ani na php ani na javu … len ak by bol nejaky priklad na nejaku komplikovanejsiu webaplikaciu v jave… lebo zatial co si pamatam resp. nepamatam ziadnu stranku v jsp, ktora by dokazala odpovedat … ako to povedat … svizne… Neviem ci to je teda sposobene javou alebo len zlou konektivitou serverov – i ked tie by sa dali pomocou pingu odmerat a odpocitat.
Nemusi to byt ziadna wikipedia ani facebook, len nieco co je navstevovane a nieco jednoznacne vykonava okrem vracania statickeho textu.

Přezdívka

java na webu neznamena pouze jsp, jsp je v podstate mrtva vec

Palo

Java bude rychlejsie ako PHP.

Ondra

je dost, např. LinkedIn.com.
Facebook.com zvažoval Javu jako jednu z alternativ k ukrutně pomalému PHP, nakonec začali překládádat PHP kód do C++ a kompilovat do binárek.

Radek Miček

Váš údiv je zcela na místě. Psát v dnešní době novou aplikaci v Javě je sebemrskačství.

dívka

Proč? (no flame plz.)

Radek Miček

Protože existují lepší jazyky s lepšími knihovnami.
Porovnávám podle následujících kritérií: znovupoužitelnost, přehlednost, typová kontrola, možnost paralelismu.

Radek Miček

Třeba Haskell, F#. Pro JVM třeba Clojure, Scala.

Satai

Ve Scalle jsou psane nektere komponenty (ne frontend) Twitteru, Novell ve Scale (framework Lift) implementoval Pulse, FourSquare take pouziva Scalu i Lift.
To ale samozrejme ani zdaleka neznamena, ze je Java vzdy spatna volba. Ma vyzrale knihovny a ekosystem (trebas Apache odvedl uzasny kus prace), komu nevyhovuje aktualni podoba Java EE „podle Sunu“, tak muze sahnout po Springu, neni problem, pokud mate penize, sehnat slusne programatory, jsou k dispozici knihy, navody, IDEs, servery pro CI…

KapitánRUM

Prosím o vyšší četnost těchto článku!
Jsou výborné, děkuji.

KapitánRUM

Myslím samozřejmě o Java na straně serveru ;-)

lopata

u výpisů zdrojového kódu není obarvena syntaxe a vůbec je to nějaké „smrsklé“, u tohoto – http://zdrojak.root.cz/clanky/happstack-cast-treti/ je to v pořádku, Opera 10.53 win, takže asi chyba redakce/autora.

Martin Malý

Opraveno, díky za upozornění.

Ondra

Hoj,
rád bych podotknul, že JTexy je ve vývoji… tj. rozhodně nepřeparsuje vše.
Není čas… Pokud by se někdo chtěl přidat, jen uvítám :)
Ondra

Ondra

Vytvořil jsem Texy Docker image. https://github.com/OndraZizka/texy-docker/

A potom ho používám víceméně stejně.

        HttpURLConnection conn = (HttpURLConnection) this.url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "text/texy");
        //conn.setRequestProperty("Content-Length", ""+);

        conn.setDoInput(true);
        conn.setDoOutput(true);
        BufferedInputStream bis = new BufferedInputStream(texyMarkupStream);

        try (OutputStream requestBodyStream = conn.getOutputStream()) {
            IOUtils.copy(texyMarkupStream, requestBodyStream);
        }

        return conn.getInputStream();

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.