MVC vzor

Tato část je o MVC. Jedná se o návrhový vzor, který odděluje data, prezentační logiku a business logiku. Jeho použití má spoustu výhod, jako je třeba lepší čitelnost kódu, údržba, testovatelost, snadnější práce v týmu, a tak podobně.

Komponenty MVC vzoru

MVC vzor se skládá ze tří komponent: Model, View a Controller. Následující tabulka je popisuje.

KomponentaPopis
ModelReprezentuje datovou část aplikace.
ViewZobrazuje data, reprezentovaná modelem.
ControllerPředstavuje rozhraní mezi modelem a view. Zpracovává příchozí requesty. Komunikuje s modelem (získává/aktualizuje/vytváří data) a vybírá view (stránku), která se pošle klientovi (stránce případně předává k zobrazení získaná data).

V kontextu servletů a JSP je většinou controller reprezentován servletem, view JSP stránkou a model může představovat třeba Java bean třída. Pokud například používáme nějaký framework, ORM nástroj, a tak podobně, tak to samozřejmě může být trochu jinak.

Funguje to tak, že servlety (controllery) přijímají ke zpracování requesty. Pokud například klient pošle request pro nějakou stránku, na které se mu mají v tabulce vypsat všechny položky z databáze, tak servlet, který je k tomu určený, získá položky z modelu (zavolá metodu nějaké třídy, která mu je vrátí) a předá je do JSP stránky (view) k zobrazení v tabulce.

MVC vzor

Ukázka použití MVC

Pro ukázku MVC vzoru si vytvoříme aplikaci, ve které bude mít uživatel možnost vytvářet, mazat a zobrazovat položky (textové poznámky). Aplikace bude obsahovat dvě stránky. Úvodní stránku, která uživatele v aplikaci jen přivítá, a stránku s položkami, na které si uživatel bude moci své položky prohlížet, mazat, nebo si případně vytvářet nové.

Založíme si nový Maven projekt a začneme tím, že si do souboru pom.xml kromě závislosti pro servlety přidáme také závislost pro JSTL. Budeme jej totiž v JSP stránkách používat.

  • src
    • main
      • java
      • resources
      • webapp
    • test
      • java
      • resources
  • target
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>io.github.jirkasa</groupId>
    <artifactId>mvc-vzor</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>mvc-vzor</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>17</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
</project>

Nejprve si vytvoříme stránku, která uživatele v aplikaci přivítá. V tomto případě je to jednoduché. Servlet (controller) jen nastaví stránku, která se má vyrenderovat. Nebude do ní předávat žádná data k zobrazení.

Jelikož nyní nechceme, aby k JSP stránkám měli uživatelé přímý přístup, tak je budeme ukládat do složky WEB-INF. K této složce totiž uživatelé přístup nemají. Vytvoříme tedy složku WEB-INF a v ní složku jsp, do které budeme JSP stránky ukládat. Uvnitř jsp složky vytvoříme stránku "Home.jsp" představující domovskou stránku. Následující ukázka ukazuje její kód. Jen zobrazuje uvítací text a odkaz na stránku s položkami.

  • src/main/webapp/WEB-INF/jsp
  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MVC Vzor</title>
</head>
<body>
    <p>Vítej ve webové aplikaci, kterou můžeš použít ke psaní poznámek.</p>
    <a href="./polozky">Pokračovat do aplikace</a>
</body>
</html>

Teď si vytvoříme servlet, který pojmenujeme jako HomeController. Bude sloužit jen k tomu, že zobrazí JSP stránku (vytvoří request dispatcher a předá request ke zpracování do JSP stránky). Servlety (controllery) budeme vytvářet v nějakém Java balíčku (např. io.github.jirkasa.controllers). Následující ukázka ukazuje kód servletu.

package io.github.jirkasa.controllers;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HomeController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Home.jsp");
        dispatcher.forward(req, res);
    }
}

Vytvoříme si soubor web.xml a servlet si namapujeme na nějaké URL. Použijeme také element welcome-file-list, který jsme v tutoriálu zatím nepoužili. Ten slouží k nastavení hlavní stránky aplikace. Jeho podelementem je element welcome-file, pomocí kterého můžeme nastavit URL, které se má pro hlavní stránku použít. Pokud máme welcome-file elementů více, tak se použije první, pro který se najde stránka. Následující ukázka obsah našeho web.xml souboru ukazuje. Servlet mapujeme na "/home", ale používáme jej také jako hlavní stránku aplikace.

  • src/main/webapp/WEB-INF
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://Java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
id="WebApp_ID" version="3.0">
    <servlet>
        <servlet-name>HomeController</servlet-name>
        <servlet-class>io.github.jirkasa.controllers.HomeController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeController</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Protože jsme si servlet namapovali jako hlavní stránku, tak se vám spustí i po otevření http://localhost:8080/mvc-vzor/. Uvidíte tedy stránku, kterou ukazuje následující obrázek.

úvodní stránka aplikace

Teď začneme s tvorbou stránky s položkami. Jako první začneme vytvářet bean třídu (model), která bude představovat položku. Pro modely vytvoříme nový Java balíček (třeba io.github.jirkasa.models) a uvnitř něj třídu Item. Kód pro ni ukazuje následující ukázka. Jako vlastnosti má "id" (unikátní identifikátor položky), "text" (text položky) a "createdAt" (datum a čas vytvoření položky).

package io.github.jirkasa.models;

import java.io.Serializable;
import java.util.Date;

public class Item implements Serializable {
    private String id;
    private String text;
    private Date createdAt;

    public void setId(String id) { this.id = id; }
    public String getId() { return id; }
    
    public void setText(String text) { this.text = text; }
    public String getText() { return text; }
    
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
    public Date getCreatedAt() { return createdAt; }
}

Kromě toho, že třída Item bude reprezentovat položku, tak bude také obsahovat statické metody, s jejichž pomocí budeme moci vytvářet, získávat a mazat položky. Zatím si do ní přidáme jen metodu pro získání všech položek uživatele. Ještě jsme se v tutoriálu neučili, jak pracovat s databází, takže budeme data ukládat v session. V reálné aplikaci by to byl ale špatný nápad, protože po restartu aplikace by uživatel o data přišel. Navíc není dobré v session ukládat větší množství dat. Následující ukázka přidává do třídy Item statickou metodu getAll, která jako parametr přijímá session a vrací uživatelovy položky.

package io.github.jirkasa.models;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

import javax.servlet.http.HttpSession;

public class Item implements Serializable {
    private String id;
    private String text;
    private Date createdAt;

    public void setId(String id) { this.id = id; }
    public String getId() { return id; }
    
    public void setText(String text) { this.text = text; }
    public String getText() { return text; }
    
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
    public Date getCreatedAt() { return createdAt; }
    
    public static ArrayList<Item> getAll(HttpSession session) {
        ArrayList<Item> items = (ArrayList<Item>) session.getAttribute("items");
        
        if (items == null) return new ArrayList<Item>();
        return items;
    }
}

Teď si vytvoříme servlet (controller), který zavoláním metody getAll třídy Item získá uživatelovy položky a předá je k zobrazení na stránce. Můžeme jej pojmenovat jako ItemsController a umístit do Java balíčku pro controllery. Následující ukázka ukazuje jeho kód.

package io.github.jirkasa.controllers;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.github.jirkasa.models.Item;

public class ItemsController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        // získání všech položek uživatele
        ArrayList<Item> items = Item.getAll(req.getSession());
        
        // nastavení položek pro zobrazení na stránce
        req.setAttribute("items", items);
        
        // zobrazení stránky "Items.jsp"
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Items.jsp");
        dispatcher.forward(req, res);
    }
}

V souboru web.xml servlet namapujeme na "/polozky", jak ukazuje následující ukázka.

  • src/main/webapp/WEB-INF
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://Java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
id="WebApp_ID" version="3.0">
    <servlet>
        <servlet-name>HomeController</servlet-name>
        <servlet-class>io.github.jirkasa.controllers.HomeController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeController</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>ItemsController</servlet-name>
        <servlet-class>io.github.jirkasa.controllers.ItemsController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ItemsController</servlet-name>
        <url-pattern>/polozky</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Servlet ItemsController zobrazuje stránku "Items.jsp". Vytvoříme ji tedy. Zatím v ní jen vypíšeme položky, které do ní servlet předává, nebo zobrazíme zprávu, že uživatel žádné položky momentálně vytvořené nemá. Následující ukázka kód stránky ukazuje. Myslím, že když se na něj podívate, tak pochopíte jak to funguje. Pro procházení položek se používá forEach tag z JSTL knihovny, o kterém jste si mohli přečíst v minulé části. Pro každou položku se v tabulce vytváří jeden řádek.

  • src/main/webapp/WEB-INF/jsp
  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MVC Vzor</title>
    
    <style>
        table, tr, th, td {
            border: 1px solid black;
            border-collapse: collapse;
        }
    </style>
</head>
<body>
    <table>
        <thead>
            <tr>
                <th colspan="3">Položky</th>
            </tr>
        </thead>
        <tbody>
            <c:choose>
                <c:when test="${fn:length(items) > 0}">
                    <c:forEach var="item" items="${items}">
                        <tr>
                            <td><fmt:formatDate value="${item.createdAt}" type="BOTH" /></td>
                            <td><c:out value="${item.text}" /></td>
                            <td><button>Smazat</button></td>
                        </tr>
                    </c:forEach>
                </c:when>
                <c:otherwise>
                    <tr>
                        <td colspan="3">Momentálně nemáš vytvořené žádné položky.</td>
                    </tr>
                </c:otherwise>
            </c:choose>
        </tbody>
    </table>
</body>
</html>

Po kliknutí na "Pokračovat do aplikace" na hlavní stránce nebo otevření http://localhost:8080/mvc-vzor/polozky by se vám stránka měla zobrazit. Zatím samozřejmě ještě nemáme vytvořené žádné položky.

prázdná stránka s položkami

Logiku pro zobrazování položek sice naprogramovanou máme, ale zatím ještě nemůžeme žádné položky vytvářet. To teď napravíme. Do stránky si přidáme formulář s inputem pro zadání textu položky a tlačítkem pro jeho odeslání. Formulář bude odkazovat na stejný servlet, který stránku poslal, ale odešle se metodou POST. Následující ukázka ukazuje upravený kód stránky.

  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MVC Vzor</title>
    
    <style>
        table, tr, th, td {
            border: 1px solid black;
            border-collapse: collapse;
        }
    </style>
</head>
<body>
    <table>
        <thead>
            <tr>
                <th colspan="3">Položky</th>
            </tr>
        </thead>
        <tbody>
            <c:choose>
                <c:when test="${fn:length(items) > 0}">
                    <c:forEach var="item" items="${items}">
                        <tr>
                            <td><fmt:formatDate value="${item.createdAt}" type="BOTH" /></td>
                            <td><c:out value="${item.text}" /></td>
                            <td><button>Smazat</button></td>
                        </tr>
                    </c:forEach>
                </c:when>
                <c:otherwise>
                    <tr>
                        <td colspan="3">Momentálně nemáš vytvořené žádné položky.</td>
                    </tr>
                </c:otherwise>
            </c:choose>
        </tbody>
    </table>
    <br>
    <form action="./polozky" method="POST">
        <input type="text" name="text" />
        <button>Přidat</button>
    </form>
</body>
</html>

V servletu ItemsController implementujeme metodu doPost, ve které budeme na odeslání formuláře reagovat. Než to ale uděláme, tak si do třídy Item přidáme metodu create pro vytvoření nové položky. Následující ukázka ji ukazuje.

package io.github.jirkasa.models;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;

import javax.servlet.http.HttpSession;

public class Item implements Serializable {
    private String id;
    private String text;
    private Date createdAt;

    public void setId(String id) { this.id = id; }
    public String getId() { return id; }
    
    public void setText(String text) { this.text = text; }
    public String getText() { return text; }
    
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
    public Date getCreatedAt() { return createdAt; }
    
    public static ArrayList<Item> getAll(HttpSession session) {
        ArrayList<Item> items = (ArrayList<Item>) session.getAttribute("items");
        
        if (items == null) return new ArrayList<Item>();
        return items;
    }
    
    public static Item create(HttpSession session, String text) {
        ArrayList<Item> items = (ArrayList<Item>) session.getAttribute("items");
        
        if (items == null) {
            items = new ArrayList<Item>();
            session.setAttribute("items", items);
        }
        
        Item item = new Item();
        item.setId(UUID.randomUUID().toString());
        item.setText(text);
        item.setCreatedAt(new Date());
        
        items.add(item);
        
        return item;
    }
}

Teď v servletu ItemsController vytvoříme metodu doPost a metodu create třídy Item v ní pro vytvoření nové položky použijeme. Poté znova vyrenderujeme stránku s položkami. Jelikož tuto operaci děláme i v metodě doGet, tak na to vytvoříme samostatnou metodu. Následující ukázka ukazuje upravený kód.

package io.github.jirkasa.controllers;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.github.jirkasa.models.Item;

public class ItemsController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        renderItemsPage(req, res);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        // je potřeba nastavit kódování, abychom data z formuláře získali ve správném formátu
        req.setCharacterEncoding("UTF-8");
        
        // vytvoření nové položky podle textu z formuláře
        String text = req.getParameter("text");
        Item.create(req.getSession(), text);
        
        renderItemsPage(req, res);
    }
    
    // zobrazuje stránku "Items.jsp"
    private void renderItemsPage(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        ArrayList<Item> items = Item.getAll(req.getSession());
                
        req.setAttribute("items", items);

        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Items.jsp");
        dispatcher.forward(req, res);
    }
}

Můžete si pár položek zkusit přidat. Zobrazí se vám na stránce v tabulce.

stránka s položkami

Nyní nám již zbývá jen přidat funkcionalitu pro mazání položek. To si zkusíme udělat přes JavaScript, jelikož pro mazání budeme používat HTTP metodu DELETE, kterou HTML formuláře nepodporují. Začneme tím, že pro mazání položek přidáme do třídy Item statickou metodu deleteById, která smaže položku podle předaného identifikátoru. Ukazuje ji následující ukázka. Jako návratový typ má hodnotu boolean, která určuje, zda se položka smazala nebo ne.

package io.github.jirkasa.models;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.UUID;

import javax.servlet.http.HttpSession;

public class Item implements Serializable {
    private String id;
    private String text;
    private Date createdAt;

    public void setId(String id) { this.id = id; }
    public String getId() { return id; }
    
    public void setText(String text) { this.text = text; }
    public String getText() { return text; }
    
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
    public Date getCreatedAt() { return createdAt; }
    
    public static ArrayList<Item> getAll(HttpSession session) {
        ArrayList<Item> items = (ArrayList<Item>) session.getAttribute("items");
        
        if (items == null) return new ArrayList<Item>();
        return items;
    }
    
    public static Item create(HttpSession session, String text) {
        ArrayList<Item> items = (ArrayList<Item>) session.getAttribute("items");
        
        if (items == null) {
            items = new ArrayList<Item>();
            session.setAttribute("items", items);
        }
        
        Item item = new Item();
        item.setId(UUID.randomUUID().toString());
        item.setText(text);
        item.setCreatedAt(new Date());
        
        items.add(item);
        
        return item;
    }
    
    public static boolean deleteById(HttpSession session, String id) {
    	ArrayList<Item> items = (ArrayList<Item>) session.getAttribute("items");
    	
    	if (items == null) return false;
    	
    	int itemIdx = -1;
    	for (int i = 0; i < items.size(); i++) {
    		if (items.get(i).id.equals(id)) {
    			itemIdx = i;
    			break;
    		}
    	}
    	
    	if (itemIdx == -1) return false;
    	
    	items.remove(itemIdx);
    	return true;
    }
}

Teď můžeme do servletu ItemsController přidat metodu doDelete, která z query parametru získá id položky, která se má odstranit, a použitím metody deleteById třídy User ji odstraní. Následující ukázka ji ukazuje.

package io.github.jirkasa.controllers;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.github.jirkasa.models.Item;

public class ItemsController extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        renderItemsPage(req, res);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        // je potřeba nastavit kódování, abychom data z formuláře získali ve správném formátu
        req.setCharacterEncoding("UTF-8");
        
        // vytvoření nové položky podle textu z formuláře
        String text = req.getParameter("text");
        Item.create(req.getSession(), text);
        
        renderItemsPage(req, res);
    }
    
    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        String itemId = req.getParameter("itemId");
        
        // smazání položky podle ID
        boolean success = Item.deleteById(req.getSession(), itemId);
        
        // nastavení status kódu, který se pošle klientovi
        if (success) {
            // položka se smazala
            res.setStatus(200);
        } else {
            // položka se nesmazala (nenašla se)
            res.setStatus(404);
        }
    }

    // zobrazuje stránku "Items.jsp"
    private void renderItemsPage(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        ArrayList<Item> items = Item.getAll(req.getSession());
                
        req.setAttribute("items", items);

        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Items.jsp");
        dispatcher.forward(req, res);
    }
}

Jak jsem psal, tak mazání položek budeme provádět přes JavaScript. Ve složce webapp si tedy vytvoříme JavaScript soubor, který pojmenujeme třeba jako "ItemsPage.js". Tento soubor bude obsahovat funkci, kterou budeme moci volat pro smazání položky. Následující ukázka obsah tohoto JavaScript souboru ukazuje. Pokud JavaScriptu příliš nerozumíte, tak nevadí, tento tutoriál je o servletech. Stačí vám vědět, že když tuto funkci zavoláte, tak se pošle HTTP request pro smazání položky a stránka se znovu načte.

  • src/main/webapp
async function deleteItemById(itemId) {
    try {
        // odeslání requestu pro smázání položky
        await fetch(`./polozky?itemId=${itemId}`, {
            method: "DELETE"
        });
        // obnovení stránky
        location.href = location.href;
    } catch(err) {
        console.log(err);
    }
}

Script si na stránku napojíme a u tlačítka pro smazání položky nastavíme onclick atribut, pomocí kterého zavoláme funkci pro smazání položky, když se na tlačítko klikne. Následující ukázka ukazuje upravenou stránku.

  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>MVC Vzor</title>
    
    <style>
        table, tr, th, td {
            border: 1px solid black;
            border-collapse: collapse;
        }
    </style>
</head>
<body>
    <table>
        <thead>
            <tr>
                <th colspan="3">Položky</th>
            </tr>
        </thead>
        <tbody>
            <c:choose>
                <c:when test="${fn:length(items) > 0}">
                    <c:forEach var="item" items="${items}">
                        <tr>
                            <td><fmt:formatDate value="${item.createdAt}" type="BOTH" /></td>
                            <td><c:out value="${item.text}" /></td>
                            <td><button onclick="deleteItemById('${item.id}')">Smazat</button></td>
                        </tr>
                    </c:forEach>
                </c:when>
                <c:otherwise>
                    <tr>
                        <td colspan="3">Momentálně nemáš vytvořené žádné položky.</td>
                    </tr>
                </c:otherwise>
            </c:choose>
        </tbody>
    </table>
    <br>
    <form action="./polozky" method="POST">
        <input type="text" name="text" />
        <button>Přidat</button>
    </form>
    <script src="./ItemsPage.js"></script>
</body>
</html>

Teď již máme možnost položky i mazat. Naše aplikace je tedy hotová.

Na závěr této části bych chtěl jen zmínit, že aplikace, kterou jsme si v této části naprogramovali není úplně ideální. V praxi by se to určitě dalo naprogramovat o dost lépe. Myslím si ale, že podstatu MVC vzoru ilustruje celkem dobře a o to nám v této části šlo.