edellinen
seuraava
 

5.     Osa 3 - Java Server Pages. 1

5.1        Yleistä. 1

5.2        JSP sivu. 2

Huomautus tiedostojen nimeämisestä. 3

Huomautus pavuista. 3

5.2.1     Esimerkki toimintaan. 3

5.2.2     Esimerkin koodit 3

5.3        Implisiittiset objektit 4

5.4        jspInit ja jspDestroy. 4

5.5        Pavuista eli JavaBeaneista. 5

5.5.1     Esimerkin toimintaan laittaminen: 5

Huomautus 1. 6

Huomautus 2. 6

Huomautus 3. 6

5.5.2     Pavun elinaika ja näkyvyys eli scope. 6

5.6        Kuinka käsitellä ongelmatilanteet JSP-sivuilla. 6

5.7        Pieniä esimerkkejä. 9

ViewAllSource.jsp. 13

ViewSource.jsp. 15

 

5.      Osa 3 - Java Server Pages

Tässä osassa tutoriaalia paneudutaan JSP sivujen toimintaan.

5.1         Yleistä

Ennen JSP-tekniikkaa pelkästään servlettejä käytettiin palvelinsovellusten ohjelmointiin. Dynaamisen käyttöliittymien muodostaminen osoittautui erittäin hankalaksi, sillä kaikki tulostettava HTML-koodi piti upottaa servlettiin. Käyttöliittymän ylläpito osoittautui hankalaksi. JSP oli tähän ongelmaan pelastava enkeli. JSP on tekniikkana verrattavissa ASP:hen[1] ja PHP:hen[2]

JSP sivut ovat puhtaita tekstidokumentteja. Selaimen pyytäessä JSP sivua JSP moottori muuttaa JSP koodit servletiksi, kääntää servletin ja upottaa servletin tulostuksen vastaukseen. JSP sivujen avulla on mahdollista prosessoida asiakkaan pyyntö (request) ja vastata siihen (response) aivan kuten servleteilläkin.

JSP sivujen avulla on helpompaa erotella staattinen ja dynaaminen sisältö sovelluksessasi kuin servleteillä. Syy tähän on selvä; servletit tulostavat HTML-sivun, kun taas JSP koodi upotetaan HTML:n joukkoon. Okei, tästä saattaa tulla sellainen kuva, että JSP sivut ovat yhtä sekamelskaa. Välillä HTML:ää ja välillä Java koodia. Oikein koodattuna lopputulos on kaukana tästä. Itse asiassa JSP ohjaa kirjoittajan mielestä paremmin olio-pohjaiseen ohjelmointiin kuin servletit (tästä esimerkkinä myöhemmin osassa käytetyt pavut eli JavaBeanit)! Servlettejä kehittäessä tulee helposti tehtyä lähes proseduraalista ohjelmointia sovelluslogiikan nojatessa doGet ja doPost metodeihin sekä muihin aliohjelmiin.

JSP sivuilla usein käytetty tekniikka on käyttää papuja[3] (JavaBeans). Näin toimiessa ohjelmoija luo luokan, jonka ilmentymää (siis oliota) JSP sivuilla käytetään. Tästä lisää kappaleessa JSP ja JavaBeans.

5.2         JSP sivu

 JSP sivu on tekstipohjainen, ja sisältää kahdenlaisia osia:

Esimerkissä (muokattu  lähteestä [9]) luodaan JSP sivu ja kaksi papua.  Sovelluksessa käyttäjä valitsee kielen (lokaalin) jonka mukaan nykyinen päivä näytetään.

 

Kuva 1.   locales.jsp sivu

Kun olet klikannut get date - painiketta, sivu ladataan uudestaan ja siihen sisällytetään date.jsp sivu.

Kuva 2.   locales.jsp sivun suoritus

Huomautus tiedostojen nimeämisestä

Ole varovainen, kun vaihdat kapitaaleja JSP tiedostojesi nimissä (myös Windowsin käyttäjät)!

Jos sinulla on esimerkiksi ollut tiedosto nimellä testisivu.jsp ja olet ajanut sen,  ja myöhemmin nimeät sen uudelleen testiSivu.jsp, niin saatat joutua käymään poistamassa TOMCAT_HOME\work\standalone\localhost\tutor\testisivu_jsp.java[4] tiedoston ennen kuin saat uudelleen nimeämäsi JSP sivun toimintaan.

Edellä mainittu hakemisto sisältää JSP sivuista tuotettujen servlettien lähdekoodit! Kyseisiä koodeja voit käyttää hyväksesi esimerkiksi debugatessasi[5] JSP sivujasi.

Huomautus pavuista

Jos sinulla on käytössä Java versio 1.4 tai uudempi , niin kaikki pavut pitää olla paketissa (package paketin_nimi;)! Aiemmissa Java-versioissa papuja ei tarvitse paketoida (lisäinformaatiota http://www.thejspbook.com/faq/details.jsp?id=1007) .

 

 

5.2.1    Esimerkki toimintaan

Esimerkin toimintaan laittamisen vaiheet:

  1. Kopioi locales.jsp ja date.jsp webapps\turor hakemistoon
  2. Kopioi pavut hakemisto (myös hakemisto, ei pelkät tiedostot webapps\turor\WEB-INF\classes hakemistoon)

5.2.2    Esimerkin koodit

Oletan, että olet tottunut HTML:n rakenteeseen ja syntaksiin, joten sitä en selitä. Seuraavassa lyhyet selitykset eri JSP elementeistä joita esimerkissä on käytetty. Tarkemmat selitykset löydät ensi kappaleesta. Katso tiedostojen

lähdekoodeja. Papujen koodit kannattaa ehkäpä tutkia vasta kappaleen ”pavuista” lukemisen jälkeen. Seuraavassa taulukossa on lyhyesti selitetty käytettyä JSP syntaksia.

Taulukko 1.                  JSP syntaksista


KOODI

KUVAUS

<%@ page import="java.util.*" %> 

JSP:n page direktiivi, attribuuttina import. Otetaan tarvittavat kirjastot käyttöön.

<jsp:useBean id="locales" scope="application" class="pavut.MyLocales"/>

Jsp_useBean  elementillä luodaan olio määritetystä luokasta.

<% … %>

Skripletti, eli java koodia, jossa on varsinainen sivun toiminta.

<%= … %>

Tämän elementillä (expression-elementti) sisällä olevien muuttujien arvot tulkitaan ja muunnetaan tarvittaessa merkkijonoiksi sekä näytetään sivulla.

<jsp:include … />

kutsutaan toista sivua ja sivun vastaus (response) liitetään tämän sivun vastaukseen.

 

5.3         Implisiittiset objektit

Jokaisella JSP sivulla on muutama implisiittinen objekti valmiina käytettäväksi. Objektit näet katsomalla JSP sivusta tuotetun servletin lähdekoodia (käännettyjen servlettien koodit löytyvät hakemistosta TOMCAT_HOME\work\Standalone\localhost\tutor).

    javax.servlet.jsp.PageContext pageContext = null;

    HttpSession session = null;

    ServletContext application = null;

    ServletConfig config = null;

    JspWriter out = null;

    Object page = this;

Lisäksi implisiittisiä objekteja ovat

5.4         jspInit ja jspDestroy

Aivan kuten servleteissäkin, on JSP sivulle mahdollista määritellä init ja destroy metodit (ks. sendEmailGroup.jsp). Tämä tapahtuu määrittelemällä metodit

·         jspInit (vastaa servletin itit metodia)

·         jspDestroy (vastaa servletin destroy metodia)

Metodien toiminta on aivan vastaavaa kuin servleteillä. JspInit() metodi tapahtuu, kun JSP sivua pyydetään ensi kertaa. JspDestroy metodi puolestaan tapahtuu, kun sivua vastaava servletti vapautetaan muistista. Tähän voi olla syynä joko JSP moottorin sulkeminen tai että sivua ei ole tarvittu vähään aikaan jolloin JSP moottori saattaa vapauttaa muistit tehokkuussyistä.

5.5         Pavuista eli JavaBeaneista

Pavut ovat aivan tavallisia Javalla kirjoitettuja luokkia, mutta papujen anatomian tulisi toteuttaa seuraavat kolme sääntöä[6]:

Seuraavassa esimerkissä on toteutettu muutama papu. 

5.5.1    Esimerkin toimintaan laittaminen:

Esimerkin toimintaan laittamiseksi pitää suorittaa seuraavat vaiheet:

Kun menet sivulle papuTesti.jsp ensimmäistä kertaa, näet tekstin: papu luotu. Nyt kun käyt jossakin toisella sivulla tai suljet selaimen niin huomaat, että papu luodaan uudestaan. Tämä johtuu pavun scope-ominaisuudesta.

Muuta paputesti.jsp tiedostosta teksti

<jsp:useBean id="papu" class="pavut.LukuPapu" scope="page"/>

seuraavanlaiseksi

<jsp:useBean id="papu" class="pavut.LukuPapu" scope="session"/>

Muuta pavun arvoa ja sulje selain (pavun alkuarvona on 1, ks Papu.java). Palaa sivulle takaisin. Huomaat, kuinka papu on säilyttänyt antamasi arvon. Kun muutat pavun arvoa uudestaan, uusi arvo lisätään vanhaan ja tulos näytetään.

Huomautus 1

Älä ikinä käytä skripleteissä luomiasi olioita <jsp:useBean .. /> tagissa. Skripleteissä luodut oliot eivät välttämättä (lue:todennäköisesti) ole saatavilla pageContextista useimmissa JSP moottoreissa.

Huomautus 2

Pyri aina käyttämään <jsp:setProperty … /> ja <jsp:getProperty … /> tageja vaikka voitkin kutsua olion get ja set-metodeja suoraan.

Huomautus 3 

JSP sivusta käännetyt käännetyt servletit löydät lähdekoodeineen  TOMCAT_HOME\work\Standalone\localhost\tutor hakemistosta.

5.5.2    Pavun elinaika ja näkyvyys eli scope

 Voit asettaa pavun scope ominaisuuteen yhden seuraavista arvoista

  1. page (oletus, jos muuta ei määrätä niin tätä käytetään)
  2. request
  3. session (papu pidetään ”hengissä” niin kauan kuin istunto kestää (riippuu session asetuksista, sessio on hengissä tietyn ennaltamäärätyn ajan)
  4. application (papu poistetaan muistista kun serveri (Tomcat) ajetaan alas)

Jossain tapauksissa voit haluta poistaa pavun ennen sen ”luonnollista kuolemaa”. Tämä parantaa palvelimesi suorituskykyä sekä lisää turvallisuutta. Esimerkiksi voisit haluta poistaa käyttäjän loggautumistiedot käyttäjän loggautuessa ulos. Tämän teet seuraavasti pavun nimeä käyttäen. Pavun poistaminen on riippuvainen pavun scopen asetuksesta kuten seuraavasta taulukosta ilmenee:

Taulukko 2.                  Papujen käyttö

Pavun scope

Poisto skripletissä

Poisto servletissä

session

session.removeAttribute(name)

HttpSession. removeAttribute(name)

request/page

pageContext.removeAttribute(name)

ServletRequest. removeAttribute(name)

Application

application.removeAttribute(name)

ServletContext. removeAttribute(name)

 

5.6         Kuinka käsitellä ongelmatilanteet JSP-sivuilla

Palataanpa äskeiseen papuesimerkkiin. Syötä pavulle uudeksi arvoksi ”iso”. Tomcat palvelin generoi virheilmoituksen. Mistä tämä johtuu? Katsotaan pavun koodia (LukuPapu.jsp), jota JSP sivu kutsuu.

   public int muutaLukua( String Luku )

   {

     if( Luku != null && Luku != "" )

       return muutaLukua( Integer.parseInt(Luku) ); //Integer.parseInt aiheuttaa poikkeuksen

     return luku; //jos ehto epätosi

   }

Mitä sitten voimme tehdä tämän estämiseksi? Seuraavassa on esitelty kolme vaihtoehtoa.

  1. Lisätään poikkeuksen käsittely papuun (katso ErrorPapu.java, testaa  errorPapuTesti.jsp)

  

   public int muutaLukua( String Luku )

   {

      int muutos = 0;

      try

      {

        muutos = Integer.parseInt(Luku);

        this.muutaLukua(muutos);

      }catch ( NumberFormatException e ) //poikkeuksen käsittely (error handling)

      { //merkkijonoa ei voitu muuntaa kokonaisluvuksi

        virheLippu = true;

      }

      finally {

        return luku;

      }

   }

  1. Tarkastetaan ennen kutsua ettei käyttäjä ole antanut vääränlaista informaatiota (papuTestiTarkastus.jsp) esimerkiksi seuraavasti (huonoin vaihtoehto, samat koodit joutuu lisäämään jokaiseen papua käyttäjään sivuun)

<%

   String arvo = "";

   int muutos = 0;

   try {

     arvo = request.getParameter("arvo");

 

     if( arvo == null )

       out.print("papu luotu");

     else

     {

       muutos = Integer.parseInt( arvo );

       out.print("<h3>Pavun arvo nyt " + papu.muutaLukua( muutos ) );

     }

   }

   catch (NumberFormatException e ) //käsittellään NumberFormatException

   {

     out.print("Anna kokonaislukuarvo.<BR>");

     out.print( "(" + e.toString() + ")"); //tulostetaan virheilmoitus suluissa

   }

   catch (Exception ee ) //muut poikkeukset

   {

     out.print("Tapahtui odottamaton poikkeus" + ee.toString());

   }

%>

  1. Luodaan poikkeuksia varten oma JSP sivunsa (errorPage). Katso esimerkki aiheutaPoikkeus.jsp. Esimerkissä jsp sivu suorittaa nollalla jakamisen, jolloinka kontrolli siirtyy sivun alussa määriteltyyn virhesivuun (poikkeusSivu.jsp).

Kolmannessa tekniikassa (eli errorPages) käytössä on huomattava, että minkäänlaista tulostusta ei saisi olla syntynyt (eli puskurointi on pois päältä tai tulostuspuskuri on täyttynyt) ennen virheen syntymistä. Jos näin on, tämä tulostus näkyy virhesivulla. Katso esimerkki (aiheutaPoikkeusEiToimi.jsp). Esimerkissä tulostuspuskuri täyttyy mikä puolestaan johtaa puskurin  tyhjenemiseen, jolloin tulostuksemme ehtii tapahtua ennen kontrollin siirtymistä (forward) virhesivulle. Huomaa, ettei koko silmukan tulostus ehdi tapahtua. Mieti miksi!

JSP sivusta tehdään poikkeussivu seuraavalla määrittelyllä (ks. poikkeusSivu.jsp)

<%@ page isErrorPage="true" %>

5.7         Pieniä esimerkkejä

Seuraavaan olen koonnut muutamia pieniä esimerkkejä, jotka saattavat olla sinulle hyödyksi.

  1. Milloin JSP sivua on muokattu viimeksi  (ks. pavut.MyDate.java ja lastModified.jsp)

koodeissa lisäksi päivämäärä ja aika formatoitu Suomen mallisiksi

<%

  File f = new File(application.getRealPath( request.getServletPath() ));

  Date modified = new Date( f.lastModified() );

%>

<jsp:useBean id="date" class="pavut.MyDate" type="MyDate" />

 

<HTML>

<BODY>

Sivua on viimeksi muokattu

<%

  out.print( date.toFinnishDateTime(modified) );

%>

 

  1. JSP moottorin käyttämä JSP versio (JSPversio.jsp)

<%@ page import="javax.servlet.jsp.JspFactory" %>

<% JspFactory factory = JspFactory.getDefaultFactory(); %>

 

<body>

<p>

Käytössä on JSP versio

<%= factory.getEngineInfo().getSpecificationVersion() %>

</body>

  1. Järjestelmäkomentojen suorittaminen. Esimerkissä ajetaan C:\temp\winver.bat tiedosto, jonka tulostus näkyy JSP sivulla (sysCommand.jsp). Kommenteista näet, miten saat selville Unix palvelimen uptimen. Erittäin näppärä tapa lisätä toiminnallisuutta sovelluksiin. JNI:n (Java Native Interface) avulla saat suoritettua myös natiivikoodia esim. DLL:stä

<%@ page import="java.io.*" %>

 

<%!

public String run(String cmd) {

  try {

    Runtime rt = Runtime.getRuntime();

    Process p = rt.exec(cmd);

    InputStreamReader in = new InputStreamReader(p.getInputStream());

    BufferedReader reader = new BufferedReader(in);

    StringBuffer buf = new StringBuffer();

    String line;

    String newline = "\n";

    while ((line = reader.readLine()) != null) {

      buf.append(line);

      buf.append(newline);

    }

    reader.close();

    p.getInputStream().close();

    p.getOutputStream().close();

    p.getErrorStream().close();

    p.waitFor();

    return buf.toString();

  }

  catch (Exception e) {

    return (e.getMessage());

  }

}

%>

<html>

<head>

 <title>Webapplication tutoriaali - järjestelmäkomentojen suorittaminen</title>

</head>

<body>

<%-- Unix ollut pystyssä <%= run("/usr/bin/uptime") %> --%>

Ajetaan c:\temp\winver.bat tiedosto, joka sisältää ainoastaan komennon: <BR>

ver <BR>

Tulos näkyy alla <BR>

<%= run("c:\\temp\\aja.bat") %>

</body>

</html>

  1. Bean, jolla saat selville käytettävissä olevan selaimen (ks. Selain.java, selain.jsp)
  2. JSP sivun lähdekoodin näyttäminen

(eihän tässä muuten mitään ongelmaa ole, mutta kun Tomcat suorittaa kaikki JSP tiedostot niiden koodisisällön näyttämisen sijaan)

http://localhost/tutor/viewSource.jsp?url=JSPversio.jsp)

<jsp:include page=”vsbutton.jsp” flush=”true” />

 

saat sivullesi painikkeen, jonka avulla sivun koodi näytetään uudessa ikkunassa (apuna käytetty JavaScriptiä)

 

·        viewAllSource.jsp. ViewAllSource tulostaa linkkilistan hakemistossa olevista jsp sivuista. Linkkiä klikkaamalla kutsutaan viewSource.jsp tiedostoa, jonka tulostus näytetään. (Antamalla parametrin all listataan kaikkien JSP tiedostojen koodit allekkain. Tätä käyttämällä listasin itse tutoriaalin loppuun kaikki JSP koodit. Lisäksi antamalla parametrille hake arvon, listataan kyseisessä hakemistossa olevat tiedostot, myös muut kuin JSP tiedostot)

Listaa kaikki JSP koodit:

http://localhost/tutor/viewAllSource.jsp?all=ihan_sama_mita_arvoksi

 Listaa kaikki tiedostot tutor/src hakemistosta

http://localhost/tutor/viewAllSource.jsp?all=1&hake=src

 

Kuva 3.   aiheutaPoikkeus.jsp lähdekoodit viewSource.jsp sivulla katsottuna

Listan tulostus

 http://localhost/tutor/viewAllSource.jsp

 

Kuva 4.   viewAllSource.jsp sivun suoritus

 

Seuraavassa koodien kiinnostavat osat kommentoituna:

 

ViewAllSource.jsp

 

<%@ page import="java.io.*" %>

<%

File path = new File(application.getRealPath("viewAllsource.jsp")).getParentFile();

%> //Haetaan viewAllsource.jsp tiedoston absoluuttisen polun hakemisto

     //eli esim c:\programs\…\tomcat\webapps\tutor

<%

  File [] files = path.listFiles(); //Tiedostolistaus tästä hakemistosta

  if( files != null )

  for( int i = 0; i < files.length; i++ ) { 

    // tiedostot käydään läpi silmukalla, jos ,ei jsp tiedosto niin continue

    if(   tarkennin( files[i].getName() ).compareToIgnoreCase(".jsp") != 0)

      continue;

%>

<%

  if( request.getParameter("all") == null )

  {  // jos all parametria ei ole annettu, niin listataan tiedostojen nimet

    out.print("<a href=/tutor/viewSource.jsp?url=");

    out.print(files[i].getName() + ">");

    out.print("<h3>"+files[i].getName()+"</h3></a>");

  }

  else

  { //muutoin tulostetaan tiedoston nimi

    out.println("<h3>" + files[i].getName() + "</h3>");

    //out.print("TEsti");

 

%> //ja incluudataan viewSource.jsp:n tulostus eli tiedoston sisältö

  <jsp:include page="/viewSource.jsp">

   <jsp:param name="url" value="<%=files[i].getName()%>"/>

  </jsp:include>

<%

  }

}

%>

<%! //declaration tagi, aliohjelma palauttaa tarkentimen

  public String tarkennin(String file)

  {

    int i = file.lastIndexOf(".");

    if( i == -1)

      return "";

    return file.substring(i, file.length() );

  }

%>

 

ViewSource.jsp

 

String url = request.getParameter("url");//url==tiedoston nimi

if (url.indexOf("..") > -1)

  throw new java.io.IOException("Relative paths are not allowed");

File realPath = new File(application.getRealPath(url));

%>

<%

FileInputStream fis = null;

try {

  BufferedReader reader;

  reader = new BufferedReader(new InputStreamReader(fis));

  String line; //luetaan tiedostoa rivi kerrallaan

  while ((line = reader.readLine()) != null) {

    line = replace(line, "&", "&amp;"); //html muotoon

    line = replace(line, "<", "&lt;");

    line = replace(line, ">", "&gt;");

    out.println(line);

  }

}

catch (IOException e) {

  out.println("IOException: " + e.getMessage());

}

finally { if (fis != null) fis.close(); }

%>

</pre></body></html>

<%!//aliohjelmalla korvataan old osat replacement osalla

public String replace(String s, String old, String replacement) {

   int i = s.indexOf(old);

   StringBuffer r = new StringBuffer();

   if (i == -1) return s;

   r.append(s.substring(0,i) + replacement);

   if (i + old.length() < s.length())

     r.append(replace(s.substring(i + old.length(), s.length()),

      old, replacement));

   return r.toString();

} %>

 



[1] Active Server Pages

[2] Ks. http://www.php.net/

[3] Ks. Kappale ”Pavuista eli JavaBeaneistä”

[4] Tänne hakemistoon Tomcat kääntää JSP sivut servleteiksi.

[5] Debuggaaminen eli virheiden korjaaminen.

[6] Tarkemmin http://java.sun.com/products/javabeans/docs/spec.html

 
edellinen
seuraava