Opas tietokantasovellusten tekemisen aloittamiseen Java-kielellä, osa 5

Edellisessä osassa tallennettiin Uimari-olio tietokantaan.

Tässä osassa luodaan Uimaseura johon kukin uimari kuuluu. Jokainen uimari tietää uimaseuransa.

Uimaseura

Kuten aiemminkin, pohditaan ensiksi miltä luokka Uimaseura voisi näyttää. Yksinkertaisella uimaseura-oliolla on ainakin nimi.

package harjoitus;

import java.util.List;

public class Uimaseura {
    private String nimi;
}

Jos olet unohtanut, NetBeansin avulla saa getterit ja setterit luotua kätevästi valitsemalla koodinäkymässä oikealla hiirennäppäimellä "Insert code" ja "Getters and Setters". Samasta valikosta löytyy myös konstruktorin luonti.

ORM-sovelluskehyksiä käyttäessä käytetään (lähes) aina myös id-kenttää taulun sarakkeiden ilmaisemiseen. Luodaan Uimaseura-luokalle siis myös id-attribuutti.

public class Uimaseura {
    private long id;
    private String nimi;

    // getterit ja setterit
}

Lisätään seuraavaksi annotaatio @Entity, jolla kerromme luokan olevan tietokantaan tallennettava. Entity-tyyppisten luokkien täytyy toteuttaa rajapinta Serializable, sekä sisältää annotaation @Id, joka kertoo mitä attribuuttia käytetään luokan ensisijaisena avaimena. Id on yleensä numero, ja hyvin monet ORM-kehykset eivät hyväksy muita vaihtoehtoja. Käytetään jo aiemmin luotua id-attribuuttia, ja asetetaan se automaattisesti generoitavaksi.

package harjoitus;

import java.io.Serializable;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Uimaseura implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    
    private String nimi;

    // getterit ja setterit
}

Luodaan seuraavaksi linkki uimarista uimaseuraan.

JoinColumn

Jotta uimari tietäisi seuransa, täytyy sillä olla viite siihen. Lisätään luokalle Uimari attribuutti uimaseura. Annotaatiolla @JoinColumn kerrotaan että attribuutti uimaseura viittaa toiseen tauluun.

package harjoitus;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;

@Entity
public class Uimari implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column
    private String nimi;
    @Column
    private int syntymaVuosi;

    @JoinColumn
    private Uimaseura uimaseura;

    // getterit ja setterit ym, mukaanlukien getUimaseura()
}

Uutta toiminnallisuutta listaan

Muutetaan lista.jsp:n toiminnallisuutta siten, että se tarjoaa mahdollisuuden luoda uimaseuroja. Jos uimaseuroja ei ole olemassa, uimareitakaan ei voida lisätä. Tägillä <c:if voidaan luoda vertailuja.

Jotta vertaus toimii, sinun tulee lisätä ListaServlet-luokan eteenpäin välitettäviin attribuutteihin lista käytössä olevista uimaseuroista. Alla olevassa pätkässä attribuutin nimeksi on asetettu seurat. Uimaseurojen hakemiseen kannattaa katsoa mallia Rekisteri-luokan getUimarit-metodista.

        <!-- testataan onko attribuutti "seurat" tyhjä //-->
        <c:if test="${not empty seurat}">

            <!-- jos seurat ei ole tyhjä, annetaan mahdollisuus luoda uusia uimareita //-->
            <form name="uusiUimari"
                  action="${pageContext.request.contextPath}/LisaaUimari"
                  method="post">
                Nimi: <input type="text" name="nimi"/> <br/>
                Syntymävuosi: <input type="text" name="syntymaVuosi"/> <br/>
                Uimaseura: <!-- uimarille pitää valita myös uimaseura //-->
                <select name="seuraId">
                    <c:forEach var="seura" items="${seurat}">
                        <option value="${seura.id}">${seura.nimi}</option>
                    </c:forEach>
                </select><br/>

                <input type="submit" value="Lähetä"/>
            </form>
                  
        </c:if>

Html-tägillä <select> näytetään lista käyttäjälle. Lista sisältää option-kenttiä, joiden attribuutti value kertoo arvon joka palvelimelle lähetetään. Nyt esimerkiksi LisaaUimari-osoitteeseen linkatulle servletille seura-olion attribuutin id. Lisätään lista.jsp:hen myös lomake, jolla voidaan luoda uusia uimaseuroja.

        <h2>Lisää seura</h2>
        
        <form name="uusiSeura"
              action="${pageContext.request.contextPath}/LisaaUimaseura"
              method="post">
            Nimi: <input type="text" name="nimi"/> <br/>
            <input type="submit" value="Lähetä"/>
        </form>

Jotta uimaseurojen lisäys toimisi, joudut luomaan myös servletin joka ottaa vastaan pyynnöt osoitteeseen LisaaUimaseura. Lisää servlettiin myös toiminnallisuus, jolla lähetetty uimaseura tallennetaan tietokantaan, ja ohjaa pyyntö lopuksi takaisin listaan. Servletistä LisaaUimariServlet kannattanee ottaa mallia tässä vaiheessa.

Seuran hakeminen id:n perusteella

Jotta lista.jsp:ssä oleva uimarin lisääminen toimisi, tarvitsemme tiedon uimaseurasta id:n perusteella. Muuta ensiksi LisaaUimariServlet-luokan processRequest-metodia siten, että se tulostaa parametrina lähetetyn seuraId-attribuutin.

        String nimi = request.getParameter("nimi");
        int syntymaVuosi = Integer.parseInt(request.getParameter("syntymaVuosi"));
        System.out.println(request.getParameter("seuraId"));

Kun olet testannut, että näet parametrin seuraId, lisätään lisää toiminnallisuutta. Uimaseuran id on tyyppiä long, joten muutetaan pyyntönä saatu parametri long-tyyppiseksi, ja haetaan rekisteristä uimaseuraa seuraId:llä.

        long seuraId = Long.parseLong(request.getParameter("seuraId"));
	Uimaseura seura = rekisteri.haeUimaseura(seuraId);

Ylläoleva uimaseuran hakeminen ei vielä toimi, sillä rekisterillä ei ole metodia haeUimaseura. Luodaan se seuraavaksi. Luokalla EntityManager on vastuu isosta osasta tietokantaolioiden tallennustoiminnallisuudesta, joten sen toiminnallisuuden tarkastelusta on hyvä aloittaa. EntityManager tarjoaa metodin find, jolle annetaan attribuutiksi haettavan luokan tyyppi, sekä avain. Luokan Rekisteri metodi haeUimaseura käyttää siis EntityManager-luokan metodia find oikean uimaseuran löytämiseksi.

    public Uimaseura haeUimaseura(long uimaseuraId) {
        EntityManager em = getEntityManager();
        return em.find(Uimaseura.class, uimaseuraId);
    }

LisaaUimariServlet

Luokan lisaaUimariServlet oleellinen toiminnallisuus on nyt seuraavanlainen.

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        // otetaan pyynnön parametrit
        String nimi = request.getParameter("nimi");
        int syntymaVuosi = Integer.parseInt(request.getParameter("syntymaVuosi"));
        long seuraId = Long.parseLong(request.getParameter("seuraId"));

        // haetaan uimaseura, joka vastaa parametrina saatua seuran id:tä
        Uimaseura seura = rekisteri.haeUimaseura(seuraId);

        // luodaan uusi uimari, ja asetetaan sille sen uimaseura
        Uimari uusi = new Uimari(nimi, syntymaVuosi);
        uusi.setUimaseura(seura);
        rekisteri.lisaaUimari(uusi);

        // siirrytään näyttämään listaa
        request.getRequestDispatcher("/Lista").forward(request, response);       
    } 

Seuraavaksi lisätään mahdollisuus listata uimarit uimaseuran kautta.