Vloženo:

Lekce 06 - Úkol 06 - Bezdomovci

Úkolem je vytvořit webovou aplikaci, která zobrazí seznam obličejů a umožní uživateli tipovat, který obličej patří bezdomovci a který univerzitnímu profesorovi. Po odeslání odpovědního formuláře aplikace vyhodnotí počet dosažených bodů (správně => 1 bod, špatně => 0 bodů). Inspirací pro tento úkol byly stránky https://www.proforhobo.com/.

Například takto:

Screenshot bezdomovců

Postup

Krok 1 - Seznam obrázků

Vložte do projektu do složky resources/static/images/obliceje všechny obrázky obličejů. Obličeje najdete v lekci 04 v podkladech nebo si sežeňte vlastní na internetu. Připravte si soubor index.html tak, aby se s využitím th:each zobrazily všechny obrázky z výše zmíněné složky. Atribut th:each potřebuje nějaký zdroj dat ze třídy HlavniController. Bude proto potřeba připravit seznam jmen obrázků. Jeden způsob, jak seznam naplnit, by bylo ruční vyplnění jmen souborů:

public class HlavniController {

    private List<String> souborySObliceji;

    public HlavniController() {
        souborySObliceji = new ArrayList<>();
        souborySObliceji.add("oblicej1.jpg");
        souborySObliceji.add("oblicej2.jpg");
        // a tak dale ...
    }

}

Ale to je jen pro lamy. Více profi je sestavit seznam jmen souborů automaticky (podle obsahu složky). Spring Framework na to má výbornou třídu ResourcePatternResolver.

public class HlavniController {

    private List<String> souborySObliceji;

    public HlavniController() throws IOException {
        ResourcePatternResolver prohledavacSlozek = new PathMatchingResourcePatternResolver();
        List<Resource> resources = Arrays.asList(prohledavacSlozek.getResources("classpath:/static/images/obliceje/*"));
        souborySObliceji = new ArrayList<>(resources.size());
        for (Resource prvek : resources) {
            souborySObliceji.add(prvek.getFilename());
        }
    }

}

Krok 2 - Formulář s tipovacími přepínači

Seznam obličejů bez formuláře by mohl být zapsaný schématicky zhruba takto:

<html>
<body>
    <ul>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
        <li>
            ... obrazek ...
        </li>
    </ul>
</body>
</html>

Připravte si soubor .css, kde budou jen ta stylovací pravidla, která používáte. (Není nutné dodržet do puntíku, ale rozhodně si tam nenechávejte celou tu velkou hromadu z výchozí šablony. U každého pravidla, které máte zapsané, byste měli vědět, co dělá. Nevíte-li, co pravidlo dělá nebo proč tam je, zlikvidujte ho.)

Po přidání formuláře <form> by to mohlo vypadat takto:

<html>
<body>
    <form method="post">
        <ul>
            <li>
                ... obrazek ...
                <label>
                    <input type="radio" name="odpoved0" value="true"/>
                    Bezdomovec
                </label>
                <label>
                    <input type="radio" name="odpoved0" value="false"/>
                    Profesor
                </label>
            </li>
            <li>
                ... obrazek ...
                <label>
                    <input type="radio" name="odpoved1" value="true"/>
                    Bezdomovec
                </label>
                <label>
                    <input type="radio" name="odpoved1" value="false"/>
                    Profesor
                </label>
            </li>
            <li>
                ... obrazek ...
                <label>
                    <input type="radio" name="odpoved2" value="true"/>
                    Bezdomovec
                </label>
                <label>
                    <input type="radio" name="odpoved2" value="false"/>
                    Profesor
                </label>
            </li>
            ... a tak dale ...
        </ul>

        <input type="submit" value="Odeslat"/>
    </form>
</body>
</html>

Přepínač (radio button) vyrobíte pomocí značky <input type="radio" name="nazevOdpovedniSkupiny"/>. Přepínače, které mají být navzájem výlučné (tj. lze mít zapnutý vždy jen jeden z nich), musejí patřit do stejné odpovědní skupiny a tedy musejí mít stejný atribut name.

Javová třída BezdomovciForm by potom mohla vypadat nějak takto:

public class BezdomovciForm {

    private boolean odpoved0;
    private boolean odpoved1;
    private boolean odpoved2;
    ... a tak dále ...

    public boolean getOdpoved0() { ... }
    public void setOdpoved0(boolean newValue) { ... }
    public boolean getOdpoved1() { ... }
    public void setOdpoved1(boolean newValue) { ... }
    ... a tak dále ...
}

Krok 3 - Vyhodnocení odpovědí a zobrazení výsledkové stránky

Bude třeba naprogramovat metodu reagující na odeslaný formulář (post) a v ní vypočítat výsledné score. Třeba takovouto:

@RequestMapping(value = "/", method = RequestMethod.POST)
public ModelAndView zpracujIndex(BezdomovciForm odpovedi)

Krok 4 - Seznam odpovědí

To, že třída BezdomovciForm má přehršel vlastností, není příliš elegantní ani dobře udržovatelné. V lekci jsme probírali seznamy (java.util.List), a tak je zde použijte. V javové třídě BezdomovciForm můžete místo osmi vlastností typu boolean nadeklarovat jen jednu vlastnost odpovedi typu List<Boolean>:

public class BezdomovciForm {

    private List<Boolean> odpovedi;

    public List<Boolean> getOdpovedi() {
        return odpovedi;
    }

    public void setOdpovedi(List<Boolean> newValue) {
        odpovedi = newValue;
    }
}

V Thymeleafu můžete vyjádřit práci se seznamy pomocí hranatých závorek:

<html>
<body>
    <form method="post">
        <ul>
            <li>
                ... obrazek ...
                <label>
                    <input type="radio" name="odpovedi[0]" value="true"/>
                    Bezdomovec
                </label>
                <label>
                    <input type="radio" name="odpovedi[0]" value="false"/>
                    Profesor
                </label>
            </li>
            <li>
                ... obrazek ...
                <label>
                    <input type="radio" name="odpovedi[1]" value="true"/>
                    Bezdomovec
                </label>
                <label>
                    <input type="radio" name="odpovedi[1]" value="false"/>
                    Profesor
                </label>
            </li>
            <li>
                ... obrazek ...
                <label>
                    <input type="radio" name="odpovedi[2]" value="true"/>
                    Bezdomovec
                </label>
                <label>
                    <input type="radio" name="odpovedi[2]" value="false"/>
                    Profesor
                </label>
            </li>
            ... a tak dale ...
        </ul>

        <input type="submit" value="Odeslat"/>
    </form>
</body>
</html>

Pokud použijete ve jméně skupiny hranaté závorky s číslem (<input name="jmenoSkupiny[CISLO]"/>), vloží se vám odeslaná odpověd v Javě sama do seznamu.

Tip: Pokud v Thymeleafu generujete řádky seznamu pomocí th:each="prvek : ${seznam}" a potřebujete (vyjma samotného prvku) i index, na kterém se v seznamu nachází, můžete použít rozšířenou syntax th:each="prvek, iterator : ${seznam}", kde z proměnné iterator lze získat vlastnost index. Tím pádem můžete zapsat třeba toto:

<span th:text="${iterator.index}">Číslo</span>
<span th:text="${prvek}">Název</span>

Krok 5 - Seznam správných odpovědí

Vymyslete, jak optimálně reprezentovat seznam správných odpovědí a jak ho naplnit. Zen by byl, pokud by celý program byl nezávislý na počtu fotek a jen a pouze přidáním nové fotky by se automaticky dalo rozhodnout, zda jde o fotku bezdomovce nebo profesora.

Tip: Šlo by to poznat třeba podle jména souboru s fotkou.

Odevzdání domácího úkolu

Nejprve appku/appky zbavte přeložených spustitelných souborů. Zařídíte to tak, že v IntelliJ IDEA vpravo zvolíte Maven Projects -> Lifecycle -> Clean. Úspěch se projeví tak, že v projektové složce zmizí podsložka target. Následně složku s projektem zabalte pomocí 7-Zipu pod jménem Ukol-CISLO-Vase_Jmeno.7z. (Případně lze použít prostý zip, například na Macu). Takto vytvořený archív nahrajte na Google Drive do Odevzdávárny.

Vytvořte snímek obrazovky spuštěného programu (webové stránky) a vložte jej do galerie Ukol CISLO ve skupině našeho kurzu na Facebooku.

Pokud byste chtěli odevzdat revizi úkolu (např. po opravě), zabalte ji a nahrajte ji na stejný Google Drive znovu, jen tentokrát se jménem Ukol-CISLO-Vase_Jmeno-verze2.7z.

Termín odevzdání je v neděli před další lekcí, nejpozději 23:59. Pokud úkol nebo revizi odevzdáte později, prosím pošlete svému opravujícímu kouči/lektorovi email nebo zprávu přes FB.