Práce s databází

Naprostá většina webových aplikací potřebuje nějakou databázi. V první části tutoriálu jste si mohli nainstalovat MySQL databázy. V této části se dozvíte, jak se k ní můžete připojit a pracovat s ní. Pokud jste si teda namísto MySQL nenainstalovali nějakou jinou databázi. Práce s jinými relačními databázemi je ale hodně podobná. Takže pokud chcete používat jinou databázi, tak samozřejmě můžete.

Nebudeme tu rozebírat databáze do hloubky a ani si vysvětlovat, jak funguje dotazovací jazyk SQL. Pokud je pro vás práce s databázemi úplně nová, tak se budete muset SQL naučit někde jinde. Zde si akorát ukážeme, jak se můžeme k databázi připojit pomocí JDBC a pracovat s ní v servletech.

Co je JDBC

Nejvíce nízkoúrovňová cesta jak přistupovat k databázím v Javě je přes JDBC API (Java Database Connectivity). Výhodou je, že nemusíme stahovat žádné knihovny třetích stran, protože JDBC je k dispozici přímo v JDK/JRE. Jediné co potřebujeme, je JDBC driver pro specifickou databázi, ke které se připojujeme.

Kromě JDBC existují také třeba různé ORM (Object Relational Mapping) nástroje (implementace JPA, což je technologie z Javy EE), které nám s databází umožňují pracovat na vyšší úrovni a usnadňují nám mapování položek z databáze na objekty. Ty JDBC používají. Příkladem je například Hibernate. Pro reálné projekty určitě nějaký ORM nástroj použít doporučuji. V této části nám jde jen o to, vůbec se k databázi připojit a zkusit si s ní pracovat.

Ukázka práce s databází

Abychom si ukázali, jak v servletech můžeme pracovat s databází, tak si vytvoříme aplikaci, ve které si uživatel bude moci vytvářet, prohlížet, editovat a mazat kontakty.

Začneme tím, že si vytvoříme databázi a v ní tabulku "kontakty". Jak to udělat pro MySQL popisuje následující slider.

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 1

    Spustíme si MySQL klienta příkazového řádku.

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 2

    Po spuštění zadáme heslo, které jsme při instalaci MySQL serveru nastavili.

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 3

    Pokud bylo heslo správné, tak jsme se úspěšně přihlásili.

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 4

    Vytvoříme databázi, kterou můžeme pojmenovat jako "kontakty_app" příkazem "CREATE DATABASE kontakty_app;".

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 5

    Vytvořenou databázi začneme používat příkazem "USE kontakty_app;".

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 6

    Vytvoříme tabulku "kontakty" příkazem, který si můžete zkopírovat z ukázky níže (pro vložení můžete použít pravé tlačítko myši).

  • Vytvoření databáze s tabulkou kontakty v MySQL - část 7

    Pokud se nám tabulka úspěšně vytvořila, tak si můžeme zobrazit její popis příkazem "DESC kontakty".

CREATE TABLE kontakty
(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    jmeno VARCHAR(255) NOT NULL,
    prijmeni VARCHAR(255) NOT NULL,
    telefon VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

Vytvořili jsme si databázi s tabulkou, do které budeme ukládat kontakty. Jako sloupce jsme jí nastavili id, což bude jedinečné číslo pro každou položku v tabulce, a sloupce jmeno, prijmeni a telefon. Můžeme se pustit do samotné tvorby aplikace.

Založíme si nový Maven projekt, který můžeme pojmenovat třeba jako "kontakty". Kromě závislosti pro servlety si do souboru pom.xml přidáme také závislost pro JSTL, jelikož ji budeme 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>kontakty</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>kontakty</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>

Můžeme začít například tím, že si vytvoříme servlet a JSP stránku pro hlavní stránku aplikace. Následující ukázky je ukazují. Servlet pouze předá příchozí request pro zpracování do JSP stránky a ta jen zobrazí pár odkazů na další stránky aplikace, které později vytvoříme. JSP stránku můžeme pojmenovat třeba jako "Home.jsp" a umístit ji do složky WEB-INF/jsp, kterou vytvoříme, jelikož necheme aby k ní uživatelé měli přímý přístup.

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 HomeServlet 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);
    }
}
  • 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>Práce s databází</title>
</head>
<body>
    <p>Vítej v aplikaci. Co chceš udělat?</p>
    <ul>
        <li><a href="./kontakty">Zobrazit kontakty</a></li>
        <li><a href="./vytvorit-kontakt">Vytvořit nový kontakt</a></li>
        <li><a href="./odstranit-kontakt">Odstranit kontakt</a></li>
    </ul>
</body>
</html>

Ve složce WEB-INF vytvoříme soubor web.xml a náš vytvořený servlet namapujeme na "/home". Také jej použijeme jako domovskou 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>HomeServlet</servlet-name>
        <servlet-class>HomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeServlet</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Po spuštění aplikace a navštívení http://localhost:8080/kontakty/ by jste měli vidět stránku, kterou ukazuje následující obrázek.

hlavní stránka aplikace

Teď bude pravděpodobně nejlepší začít s tvorbou stránky pro přidání nového kontaktu, abychom si do databáze vůbec mohli nějaké kontakty přidat. Následující ukázky pro ni ukazují servlet a JSP stránku. JSP stránka se jmenuje "CreateContact.jsp" a nachází se na ní formulář pro vytvoření nového kontaktu. Do servletu pro jeho zpracování potom přidáme metodu doPost.

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 CreateContactServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/CreateContact.jsp");
        dispatcher.forward(req, res);
    }
}
  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Práce s databází</title>
</head>
<body>
    <a href="./">Zpět</a>
    <br><br>
    <form action="./vytvorit-kontakt" method="POST">
        <label for="jmeno">Jméno:</label> <input type="text" id="jmeno" name="jmeno" />
        <br><br>
        <label for="prijmeni">Příjmení:</label> <input type="text" id="prijmeni" name="prijmeni" />
        <br><br>
        <label for="telefon">Telefon:</label> <input type="text" id="telefon" name="telefon" />
        <br><br>
        <button>Vytvořit</button>
    </form>
</body>
</html>

V souboru web.xml servlet namapujeme na "/vytvorit-kontakt".

  • 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>HomeServlet</servlet-name>
        <servlet-class>HomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeServlet</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>CreateContactServlet</servlet-name>
        <servlet-class>CreateContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CreateContactServlet</servlet-name>
        <url-pattern>/vytvorit-kontakt</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Po restartu aplikace a otevření odkazu "Vytvořit nový kontakt" na hlavní stránce by se vám měla zobrazit stránka s formulářem pro vytvoření nového kontaktu.

stránka pro vytvoření nového kontaktu

Abychom mohli stránku pro vytvoření kontaktu dokončit, tak se v naší aplikaci potřebujeme připojit k databázi. Je více cest jak to udělat. My si vyzkoušíme nakonfigurovat připojení k databázi pomocí souboru context.xml. Jedná se o konfigurační soubor používaný v servletových kontejnerech (zejména v Tomcatu), který slouží ke konfiguraci webové aplikace. Můžeme v něm nadefinovat připojení k databází, proměnné prostředí, a tak podobně. Může být užitečný pro nastavení aplikace v různých prostředích (např. vývojovém a produkčním).

Soubor context.xml můžeme vytvořit ve složce META-INF, kterou můžeme založit ve složce webapp, stejně jako složku WEB-INF. Kořenovým elementem souboru context.xml je element Context. Do tohoto elementu můžeme přidat element Resource, který slouží ke konfiguraci datového zdroje. Následující ukázka ukazuje soubor context.xml pro náš projekt.

  • src/main/webapp/META-INF
  • src/main/webapp/META-INF
<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/kontakty" auth="Container" type="javax.sql.DataSource"
        maxActive="20" maxIdle="5" maxWaitMillis="10000"
        username="root" password="admin"
        driverClassName="com.mysql.cj.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/kontakty_app"/>
</Context>

Elementu Resource jsme v souboru context.xml nastavili spoustu atributů. Následující seznam popisuje, k čemu tyto atributy slouží:

  • name - nastavuje unikátní jméno datového zdroje v kontejneru servletů (Tomcatu)
  • auth - určuje metodu autentizace pro přístup k datovému zdroji
  • type - specifikuje typ datového zdroje (v našem případě bude typu javax.sql.DataSource)
  • maxActive - určuje maximální počet aktivních připojení k datovému zdroji
  • maxIdle - určuje maximální počet nečinných (nevyužívaných) připojení k datovému zdroji
  • maxWaitMillis - určuje maximální dobu v milisekundách, po kterou je vlákno ochotno čekat na připojení k databázi
  • username - specifikuje uživatelské jméno pro přihlášení k databázi
  • password - specifikuje heslo pro přihlášení k databázi (vy zadejte samozřejmě svoje, pokud nemáte heslo "admin")
  • driverClassName - specifikuje název třídy JDBC ovladače pro databázi, ke které se připojujeme
  • url - nastavuje URL adresu databáze, ke které se připojujeme (obsahuje port a název databáze; port je defaultně 3306, pokud jste jej neměnili)

Pomocí atributu driverClassName jsme nastavili JDBC driver, který se má použít pro přistupování k MySQL databázi. Budeme si jej muset přidat jako závislost do souboru pom.xml. Pokud používate nějakou jinou databázi, tak si musíte najít jiný driver. Soubor pom.xml s přidanou závislostí pro JDBC driver k MySQL databázi ukazuje následující ukázka.

<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>kontakty</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>kontakty</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>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.2.0</version>
        </dependency>
    </dependencies>
</project>

Teď když máme připojení k databázi přichystané, můžeme začít třeba tím, že si vytvoříme jednoduchou třídu, která bude reprezentovat kontakt. Bude obsahovat jen vlastnosti, které se budou jmenovat stejně jako sloupce tabulky, kterou jsme si vytvořili v databázi, a jejich gettery a settery. Můžeme ji pojmenovat jako "Kontakt". Následující ukázka ukazuje její kód.

public class Kontakt {
    private int id;
    private String jmeno;
    private String prijmeni;
    private String telefon;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getJmeno() {
        return jmeno;
    }
    public void setJmeno(String jmeno) {
        this.jmeno = jmeno;
    }
    public String getPrijmeni() {
        return prijmeni;
    }
    public void setPrijmeni(String prijmeni) {
        this.prijmeni = prijmeni;
    }
    public String getTelefon() {
        return telefon;
    }
    public void setTelefon(String telefon) {
        this.telefon = telefon;
    }
}

Pro komunikaci s databází za účelem získání, měnění, mazání a tvorby kontaktů si založíme třídu jménem KontaktDBUtil. Jako parametr bude v konstruktoru přijímat objekt typu javax.sql.DataSource. Z tohoto objektu získáme pomocí metody getConnection připojení k databázi, které potom můžeme používat. Později si přidáme metody, kde jej využijeme. Protože je potřeba po použití připojení k databázi provést jeho uzavření, tak třída bude také obsahovat metodu close, kterou vždy zavoláme, až budeme s její prací hotovi. Připojení k databázi se ve skutečnosti nezavírá, ale vrací se do poolu, kde čeká na další použití. Proto jsme v souboru context.xml definovali maximální počet aktivních a neaktivních připojení.

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

public class KontaktDBUtil {
    private Connection conn;
    
    public KontaktDBUtil(DataSource dataSource) {
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public void close() {
        try {
            conn.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
    }
}

Jako první si do třídy KontaktDBUtil přidáme metodu pro vytvoření nového kontaktu. Bude přijímat instanci třídy Kontakt, podle které v databázi vytvoří novou položku. Následující ukázka tuto metodu ukazuje. Vytváříme v ní objekt typu PreparedStatement, kterému předáváme SQL kód, který chceme spustit. Namísto vkládání hodnot přímo do řetězce se SQL kódem používáme otazníky. Až poté na jednotlivá místa pomocí metody setString nastavujeme hodnoty. To děláme kvůli tomu, abychom zabránili SQL Injection útokům. Uživatel by totiž mohl do SQL kódu vložit hodnotu, která by obsahovala SQL kód a tento kód by se potom spustil. Mohl by například jako hodnotu použít řetězec "; DROP TABLE kontakty;" a tím by nám smazal celou tabulku kontakty. Po vytvoření statement objektu náš SQL kód spustíme zavoláním execute metody a protože je potřeba statement objekt uzavřít, zavoláme také metodu close.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.sql.DataSource;

public class KontaktDBUtil {
    private Connection conn;
    
    public KontaktDBUtil(DataSource dataSource) {
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public void add(Kontakt kontakt) {
        try {
            PreparedStatement statement = conn.prepareStatement("INSERT INTO kontakty (jmeno, prijmeni, telefon) VALUES (?, ?, ?)");
            
            statement.setString(1, kontakt.getJmeno());
            statement.setString(2, kontakt.getPrijmeni());
            statement.setString(3, kontakt.getTelefon());
            
            statement.execute();
            
            statement.close();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public void close() {
        try {
            conn.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
    }
}

Naši nově vytvořenou třídu KontaktDBUtil můžeme použít v servletu CreateContactServlet, kde nám zbývá implementovat metodu doPost. Než to ale uděláme, tak si ještě vytvoříme JSP stránku, která bude sloužit k zobrazování zpráv. V servletu budeme moci nastavit zprávu a na stránce ji poté zobrazit. Můžeme ji pojmenovat třeba jako "Message.jsp". Kód pro ni ukazuje následující ukázka. Kromě zprávy budeme také nastavovat URL pro odkaz "Pokračovat", který se na stránce nachází.

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

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Práce s databází</title>
</head>
<body>
    <p>${zprava}</p>
    <br>
    <a href="${odkaz}">Pokračovat</a>
</body>
</html>

Teď přidáme do servletu CreateContactServlet metodu doPost, ve které budeme reagovat na odeslaný formulář a pomocí třídy KontaktDBUtil vytvářet v databázi nový kontakt. Poté pošleme stránku se zprávou, že se kontakt úspěšně vytvořil. V následující ukázce si můžete kód metody doPost prohlédnout. Jelikož k vytvoření instance třídy KontaktDBUtil potřebujeme objekt typu DataSource, tak si jej v servletu definujeme jako vlastnost.

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;
import javax.sql.DataSource;

public class CreateContactServlet extends HttpServlet {
    private DataSource dataSource;
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/CreateContact.jsp");
        dispatcher.forward(req, res);
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        
        Kontakt kontakt = new Kontakt();
        kontakt.setJmeno(req.getParameter("jmeno"));
        kontakt.setPrijmeni(req.getParameter("prijmeni"));
        kontakt.setTelefon(req.getParameter("telefon"));
        
        System.out.println(dataSource);
        
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        dbUtil.add(kontakt);
        dbUtil.close();
        
        req.setAttribute("zprava", "Kontakt byl vytvořen.");
        req.setAttribute("odkaz", "./");
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Message.jsp");
        dispatcher.forward(req, res);
    }
}

Nastavení DataSource objektu necháme na Tomcatu. Použijeme na vlastnost dataSource anotaci @Resource a tím mu řekneme, aby ji nastavil. Abychom ale mohli tuto anotaci použít, potřebujeme si do souboru pom.xml přidat závislost pro anotace. Následující ukázka ukazuje upravený soubor.

<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>kontakty</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>kontakty</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>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.2.0</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
</project>

Teď můžeme anotaci @Resource použít. Jako parametr jí nastavujeme název datového zdroje, který jsme specifikovali v souboru context.xml. Následující ukázka ukazuje dokončený servlet CreateContactServlet.

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class CreateContactServlet extends HttpServlet {
    @Resource(name="jdbc/kontakty")
    private DataSource dataSource;
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/CreateContact.jsp");
        dispatcher.forward(req, res);
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        
        Kontakt kontakt = new Kontakt();
        kontakt.setJmeno(req.getParameter("jmeno"));
        kontakt.setPrijmeni(req.getParameter("prijmeni"));
        kontakt.setTelefon(req.getParameter("telefon"));
        
        System.out.println(dataSource);
        
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        dbUtil.add(kontakt);
        dbUtil.close();
        
        req.setAttribute("zprava", "Kontakt byl vytvořen.");
        req.setAttribute("odkaz", "./");
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Message.jsp");
        dispatcher.forward(req, res);
    }
}

Nyní by formulář na stránce pro vytvoření kontaktu měl fungovat. Po jeho odeslání se vám v databázi vytvoří nová položka a zobrazí se vám stránka se zprávou, že byl kontakt úspěšně vytvořen.

stránka, oznamující že byl kontakt vytvořen

V aplikaci si vytvořené kontakty zatím nemáme možnost zobrazit. Pustíme se tedy do tvorby stránky, kde se nám do tabulky vypíší všechny vytvořené kontakty. Nejprve si do třídy KontaktDBUtil přidáme metodu pro získání všech kontaktů z databáze. V následující ukázce si ji můžete prohlédnout. Vytváříme statement objekt, na kterém spouštíme SQL dotaz a získáváme ResultSet. Pomocí něj poté procházíme všechny získané položky a ukládáme je do listu. Poté na Statement a ResultSet objektu voláme metodu close a vytvořený list vracíme.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

public class KontaktDBUtil {
    private Connection conn;
    
    public KontaktDBUtil(DataSource dataSource) {
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public List<Kontakt> getAll() {
        ArrayList<Kontakt> kontakty = new ArrayList<Kontakt>();
        try {
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("SELECT * FROM kontakty");
            
            while (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                kontakty.add(kontakt);
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return kontakty;
    }
    
    public void add(Kontakt kontakt) {
        try {
            PreparedStatement statement = conn.prepareStatement("INSERT INTO kontakty (jmeno, prijmeni, telefon) VALUES (?, ?, ?)");
            
            statement.setString(1, kontakt.getJmeno());
            statement.setString(2, kontakt.getPrijmeni());
            statement.setString(3, kontakt.getTelefon());
            
            statement.execute();
            
            statement.close();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public void close() {
        try {
            conn.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
    }
}

Teď si vytvoříme servlet, který nazveme "ContactServlet" a k němu JSP stránku, kterou pojmenujeme jako "Contacts.jsp". Servlet v metodě doGet pomocí metody add třídy KontaktDBUtil získá list kontaktů a předá je JSP stránce k zobrazení. Ta vytvoří tabulku a pro každý kontakt do ní vloží řádek. Následující ukázky ukazují kód tohoto servletu a JSP stránky. V servletu vlastnost dataSource definujeme úplně stejně jako dříve v servletu CreateContactServlet. Tomcat nám ji tedy automaticky nastaví.

import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class ContactsServlet extends HttpServlet {
    @Resource(name="jdbc/kontakty")
    private DataSource dataSource;
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        List<Kontakt> kontakty = dbUtil.getAll();
        dbUtil.close();
        
        req.setAttribute("kontakty", kontakty);
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Contacts.jsp");
        dispatcher.forward(req, res);
    }
}
  • 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" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Práce s databází</title>
    
    <style>
        table, tr, th, td {
            border: 1px solid black;
            border-collapse: collapse;
        }
    </style>
</head>
<body>
    <a href="./">Zpět</a>
    <br><br>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Jméno</th>
                <th>Příjmení</th>
                <th>Telefon</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <c:choose>
                <c:when test="${fn:length(kontakty) > 0}">
                    <c:forEach var="kontakt" items="${kontakty}">
                        <tr>
                            <td><c:out value="${kontakt.id}" /></td>
                            <td><c:out value="${kontakt.jmeno}" /></td>
                            <td><c:out value="${kontakt.prijmeni}" /></td>
                            <td><c:out value="${kontakt.telefon}" /></td>
                            <td><a href="#">Upravit</a></td>
                        </tr>
                    </c:forEach>
                </c:when>
                <c:otherwise>
                    <tr>
                        <td colspan="5">Momentálně nemáš vytvořené žádné kontakty.</td>
                    </tr>
                </c:otherwise>
            </c:choose>
        </tbody>
    </table>
</body>
</html>

Ve web.xml vytvořený servlet namapujeme na "/kontakty".

  • 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>HomeServlet</servlet-name>
        <servlet-class>HomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeServlet</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>CreateContactServlet</servlet-name>
        <servlet-class>CreateContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CreateContactServlet</servlet-name>
        <url-pattern>/vytvorit-kontakt</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>ContactsServlet</servlet-name>
        <servlet-class>ContactsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ContactsServlet</servlet-name>
        <url-pattern>/kontakty</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Nyní máme v aplikaci možnost si naše vytvořené kontakty zobrazit. Pokud na hlavní stránce kliknete na "Zobrazit kontakty", tak se vám vypíší do tabulky, jak ukazuje následující obrázek.

stránka s kontakty

Odkaz "Upravit", který se u jednotlivých kontaktů v tabulce zobrazuje, zatím ještě nefunguje. Nyní jej zprovozníme. Bude odkazovat na stránku "/upravit-kontakt" a jako query parametr se bude předávat ID kontaktu, který se má editovat. Následující ukázka ukazuje upravený řádek kódu JSP stránky s kontakty.

  • 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" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Práce s databází</title>
    
    <style>
        table, tr, th, td {
            border: 1px solid black;
            border-collapse: collapse;
        }
    </style>
</head>
<body>
    <a href="./">Zpět</a>
    <br><br>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Jméno</th>
                <th>Příjmení</th>
                <th>Telefon</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            <c:choose>
                <c:when test="${fn:length(kontakty) > 0}">
                    <c:forEach var="kontakt" items="${kontakty}">
                        <tr>
                            <td><c:out value="${kontakt.id}" /></td>
                            <td><c:out value="${kontakt.jmeno}" /></td>
                            <td><c:out value="${kontakt.prijmeni}" /></td>
                            <td><c:out value="${kontakt.telefon}" /></td>
                            <td><a href="./upravit-kontakt?id=${kontakt.id}">Upravit</a></td>
                        </tr>
                    </c:forEach>
                </c:when>
                <c:otherwise>
                    <tr>
                        <td colspan="5">Momentálně nemáš vytvořené žádné kontakty.</td>
                    </tr>
                </c:otherwise>
            </c:choose>
        </tbody>
    </table>
</body>
</html>

Jelikož budeme chtít podle ID získávat kontakt k editaci z databáze, tak si na to ve třídě KontaktDBUtil vytvoříme metodu. Následující ukázka ji ukazuje.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

public class KontaktDBUtil {
    private Connection conn;
    
    public KontaktDBUtil(DataSource dataSource) {
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public List<Kontakt> getAll() {
        ArrayList<Kontakt> kontakty = new ArrayList<Kontakt>();
        try {
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("SELECT * FROM kontakty");
            
            while (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                kontakty.add(kontakt);
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return kontakty;
    }
    
    public Kontakt get(int id) {
        try {
            PreparedStatement statement = conn.prepareStatement("SELECT * FROM kontakty WHERE id = ?");
            
            statement.setInt(1, id);
            
            ResultSet rs = statement.executeQuery();
            
            if (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                return kontakt;
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return null;
    }
    
    public void add(Kontakt kontakt) {
        try {
            PreparedStatement statement = conn.prepareStatement("INSERT INTO kontakty (jmeno, prijmeni, telefon) VALUES (?, ?, ?)");
            
            statement.setString(1, kontakt.getJmeno());
            statement.setString(2, kontakt.getPrijmeni());
            statement.setString(3, kontakt.getTelefon());
            
            statement.execute();
            
            statement.close();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public void close() {
        try {
            conn.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
    }
}

Můžeme se pustit do tvorby servletu a JSP stránky. Servlet načte z databáze kontakt a předá jej JSP stránce k zobrazení ve formuláři. V tomto formuláři uživatel bude moci kontakt upravit. Pokud se kontakt nenajde, tak se zobrazí stránka se zprávou, že se nenašel. Následující ukázky ukazují kód tohoto servletu a JSP stránky.

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class EditContactServlet extends HttpServlet {
    @Resource(name="jdbc/kontakty")
    private DataSource dataSource;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        int id = Integer.parseInt(req.getParameter("id"));
        
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        Kontakt kontakt = dbUtil.get(id);
        dbUtil.close();
        
        if (kontakt != null) {
            req.setAttribute("kontakt", kontakt);
            RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/EditContact.jsp");
            dispatcher.forward(req, res);			
        } else {
            req.setAttribute("zprava", "Kontakt nebyl nalezen.");
            req.setAttribute("odkaz", "./");
            RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Message.jsp");
            dispatcher.forward(req, res);
        }
    }
}
  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Práce s databází</title>
</head>
<body>
    <a href="./">Zpět</a>
    <br><br>
    <form action="./upravit-kontakt" method="POST">
        <input type="hidden" name="id" value="${kontakt.id}" />
        <label for="jmeno">Jméno:</label> <input type="text" id="jmeno" name="jmeno" value="<c:out value="${kontakt.jmeno}"/>" />
        <br><br>
        <label for="prijmeni">Příjmení:</label> <input type="text" id="prijmeni" name="prijmeni" value="<c:out value="${kontakt.prijmeni}"/>" />
        <br><br>
        <label for="telefon">Telefon:</label> <input type="text" id="telefon" name="telefon" value="<c:out value="${kontakt.telefon}"/>" />
        <br><br>
        <button>Upravit</button>
    </form>
</body>
</html>

Vytvořený servlet namapujeme ve web.xml na "/upravit-kontakt".

  • 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>HomeServlet</servlet-name>
        <servlet-class>HomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeServlet</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>CreateContactServlet</servlet-name>
        <servlet-class>CreateContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CreateContactServlet</servlet-name>
        <url-pattern>/vytvorit-kontakt</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>ContactsServlet</servlet-name>
        <servlet-class>ContactsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ContactsServlet</servlet-name>
        <url-pattern>/kontakty</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>EditContactServlet</servlet-name>
        <servlet-class>EditContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EditContactServlet</servlet-name>
        <url-pattern>/upravit-kontakt</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Pokud nyní na stránce s kontakty u některého vytvořeného kontaktu klikneme na "Upravit", tak se nám zobrazí stránka, na které můžeme kontakt upravit.

stránka pro editaci kontaktu

Abychom mohli kontakt upravit, tak v servletu EditContact servlet implementujeme metodu doPost. Ta bude sloužit pro zpracování formuláře a editaci kontaktu v databázi. Formulář obsahuje skrytý input, který obsahuje ID kontaktu. Podle toho zjistíme, který kontakt se má upravit. Nejdříve si ale ve třídě KontaktDBUtil potřebujeme vytvořit metodu pro editaci kontaktu. Ukazuje ji následující ukázka. Jako parametr bere ID kontaktu, který se má změnit a hodnoty pro jméno, příjmení a telefon. Jako navrátový typ má boolean hodnotu, která signalizuje, zda byl kontakt nalezen nebo ne.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

public class KontaktDBUtil {
    private Connection conn;
    
    public KontaktDBUtil(DataSource dataSource) {
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public List<Kontakt> getAll() {
        ArrayList<Kontakt> kontakty = new ArrayList<Kontakt>();
        try {
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("SELECT * FROM kontakty");
            
            while (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                kontakty.add(kontakt);
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return kontakty;
    }
    
    public Kontakt get(int id) {
        try {
            PreparedStatement statement = conn.prepareStatement("SELECT * FROM kontakty WHERE id = ?");
            
            statement.setInt(1, id);
            
            ResultSet rs = statement.executeQuery();
            
            if (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                return kontakt;
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return null;
    }
    
    public void add(Kontakt kontakt) {
        try {
            PreparedStatement statement = conn.prepareStatement("INSERT INTO kontakty (jmeno, prijmeni, telefon) VALUES (?, ?, ?)");
            
            statement.setString(1, kontakt.getJmeno());
            statement.setString(2, kontakt.getPrijmeni());
            statement.setString(3, kontakt.getTelefon());
            
            statement.execute();
            
            statement.close();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public boolean update(int id, String jmeno, String prijmeni, String telefon) {
        int updatedCount = 0;
        try {
            PreparedStatement statement = conn.prepareStatement("UPDATE kontakty SET jmeno = ?, prijmeni = ?, telefon = ? WHERE id = ?");
            
            statement.setString(1, jmeno);
            statement.setString(2, prijmeni);
            statement.setString(3, telefon);
            statement.setInt(4, id);
            
            updatedCount = statement.executeUpdate();
            
            statement.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return updatedCount > 0;
    }
    
    public void close() {
        try {
            conn.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
    }
}

Teď můžeme tuto nově vytvořenou metodu použít v metodě doPost, kterou vytvoříme v servletu EditContact. V následující ukázka si ji můžete prohlédnout.

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class EditContactServlet extends HttpServlet {
    @Resource(name="jdbc/kontakty")
    private DataSource dataSource;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        int id = Integer.parseInt(req.getParameter("id"));
        
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        Kontakt kontakt = dbUtil.get(id);
        dbUtil.close();
        
        if (kontakt != null) {
            req.setAttribute("kontakt", kontakt);
            RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/EditContact.jsp");
            dispatcher.forward(req, res);			
        } else {
            req.setAttribute("zprava", "Kontakt nebyl nalezen.");
            req.setAttribute("odkaz", "./");
            RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Message.jsp");
            dispatcher.forward(req, res);
        }
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        int id = Integer.parseInt(req.getParameter("id"));
        String jmeno = req.getParameter("jmeno");
        String prijmeni = req.getParameter("prijmeni");
        String telefon = req.getParameter("telefon");
        
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        boolean success = dbUtil.update(id, jmeno, prijmeni, telefon);
        dbUtil.close();
        
        req.setAttribute("zprava", success ? "Kontakt byl upraven." : "Kontakt nebyl nalezen.");
        req.setAttribute("odkaz", "./");
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Message.jsp");
        dispatcher.forward(req, res);
    }
}

Můžete si nějaký kontakt zkusit upravit. Mělo by to fungovat a zobrazit se zpráva, že kontakt byl úspěšně upraven.

stránka, oznamující že byl kontakt upraven

Poslední věc, která nám zbývá udělat, je přidání možnosti smazat kontakt. U toho jsem se rozhodl, že na to uděláme samostatnou stránku, kde uživatel zadá ID kontaktu, který chce smazat. Začneme s přidáním metody pro odstranění kontaktu z databáze do třídy KontaktDBUtil. Ukazuje ji následující ukázka.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

public class KontaktDBUtil {
    private Connection conn;
    
    public KontaktDBUtil(DataSource dataSource) {
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public List<Kontakt> getAll() {
        ArrayList<Kontakt> kontakty = new ArrayList<Kontakt>();
        try {
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("SELECT * FROM kontakty");
            
            while (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                kontakty.add(kontakt);
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return kontakty;
    }
    
    public Kontakt get(int id) {
        try {
            PreparedStatement statement = conn.prepareStatement("SELECT * FROM kontakty WHERE id = ?");
            
            statement.setInt(1, id);
            
            ResultSet rs = statement.executeQuery();
            
            if (rs.next()) {
                Kontakt kontakt = new Kontakt();
                kontakt.setId(rs.getInt("id"));
                kontakt.setJmeno(rs.getString("jmeno"));
                kontakt.setPrijmeni(rs.getString("prijmeni"));
                kontakt.setTelefon(rs.getString("telefon"));
                return kontakt;
            }
            
            statement.close();
            rs.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return null;
    }
    
    public void add(Kontakt kontakt) {
        try {
            PreparedStatement statement = conn.prepareStatement("INSERT INTO kontakty (jmeno, prijmeni, telefon) VALUES (?, ?, ?)");
            
            statement.setString(1, kontakt.getJmeno());
            statement.setString(2, kontakt.getPrijmeni());
            statement.setString(3, kontakt.getTelefon());
            
            statement.execute();
            
            statement.close();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
    
    public boolean update(int id, String jmeno, String prijmeni, String telefon) {
        int updatedCount = 0;
        try {
            PreparedStatement statement = conn.prepareStatement("UPDATE kontakty SET jmeno = ?, prijmeni = ?, telefon = ? WHERE id = ?");
            
            statement.setString(1, jmeno);
            statement.setString(2, prijmeni);
            statement.setString(3, telefon);
            statement.setInt(4, id);
            
            updatedCount = statement.executeUpdate();
            
            statement.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return updatedCount > 0;
    }
    
    public boolean delete(int id) {
        int deletedCount = 0;
        try {
            PreparedStatement statement = conn.prepareStatement("DELETE FROM kontakty WHERE id = ?");
            
            statement.setInt(1, id);
            
            deletedCount = statement.executeUpdate();
            
            statement.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
        return deletedCount > 0;
    }
    
    public void close() {
        try {
            conn.close();
        } catch(SQLException e) {
            System.out.println(e);
        }
    }
}

Teď vytvoříme servlet a JSP stránku. Ukazují je následující ukázky.

import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class DeleteContactServlet extends HttpServlet {
    @Resource(name="jdbc/kontakty")
    private DataSource dataSource;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        int id = Integer.parseInt(req.getParameter("id"));
        
        KontaktDBUtil dbUtil = new KontaktDBUtil(dataSource);
        boolean success = dbUtil.delete(id);
        dbUtil.close();
        
        req.setAttribute("zprava", success ? "Kontakt byl smazán." : "Kontakt nebyl nalezen.");
        req.setAttribute("odkaz", "./");
        RequestDispatcher dispatcher = req.getRequestDispatcher("WEB-INF/jsp/Message.jsp");
        dispatcher.forward(req, res);
    }
}
  • src/main/webapp/WEB-INF/jsp
<%@ page contentType="text/html" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Práce s databází</title>
</head>
<body>
    <a href="./">Zpět</a>
    <br><br>
    <form action="./odstranit-kontakt" method="POST">
        <label for="id">ID:</label> <input type="number" id="id" name="id" />
        <br><br>
        <button>Odstranit</button>
    </form>
</body>
</html>

Servlet v souboru web.xml namapujeme na "/odstranit-kontakt".

  • 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>HomeServlet</servlet-name>
        <servlet-class>HomeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HomeServlet</servlet-name>
        <url-pattern>/home</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>CreateContactServlet</servlet-name>
        <servlet-class>CreateContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CreateContactServlet</servlet-name>
        <url-pattern>/vytvorit-kontakt</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>ContactsServlet</servlet-name>
        <servlet-class>ContactsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ContactsServlet</servlet-name>
        <url-pattern>/kontakty</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>EditContactServlet</servlet-name>
        <servlet-class>EditContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EditContactServlet</servlet-name>
        <url-pattern>/upravit-kontakt</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>DeleteContactServlet</servlet-name>
        <servlet-class>DeleteContactServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DeleteContactServlet</servlet-name>
        <url-pattern>/odstranit-kontakt</url-pattern>
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>home</welcome-file>
    </welcome-file-list>
</web-app>

Po otevření odkazu "Odstranit kontakt" na hlavní stránce se nám nyní zobrazí formulář, do kterého můžeme zadat ID kontaktu a smazat jej.

stránka pro odstranění kontaktu

Naše aplikace je hotová. Není to samozřejmě úplně reálná aplikace, protože v ní například chybí validace a tak podobně. Její tvorbou jsme si hlavně chtěli jen vyzkoušet práci s databází, což bylo cílem této části.

Touto částí celý tutoriál o servletech a JSP končí. Po jeho absolvování máte základ, na kterém teď můžete stavět. Pokud si někdy budete chtít něco připomenout, tak se sem můžete vrátit a třeba si najít nějakou specifickou část tutoriálu v obsahu. Také se můžete podívat i na tutoriály/články v sekci další tutoriály.