Általános jellemzők JavaServer Pages (JSP) Java utasításokat helyezetünk el a HTML lapon Ezket a Java utasításokat a kiszolgáló végrehajtja Az ügyfél felé generált tartalom: statikus HTML kód + Java utasítások eredménye A JSP utasításokat a <%... %> karakterekkel zárjuk közre Példa: <html>... Kedves <%=request.getparameter("nev")%> Köszönjük, hogy JSP tanfolyamunkra jelentkezett.... </html> A request a szervletekhttpservletrequest objektumának, a getparameter() pedig a szervletekgetparameter() metódusának felel meg Kiterjesztésük:.jsp Telepítési hely: bárhová (pl. ahová a statikus weboldalakat) De: a kiszolgáló a JSP oldalt első híváskor szervletté alakítja, s a statikus tartalmat is ez a szerver generálja. Helyük: %tomcat%/work/catalina/localhost/eloadasjsp/org/apache/jsp JSP oldalak elemei: Statikus HTML tartalom Szkript elemek Java programrészek, a szervlet service metódusának részei lesznek Direktívák A szervlet globális jellemzőit specifikálják Akcióelemek Meglévő komponensek használatát specifikálják, ill. a JSP motor viselkedését szabályozzák. JSP specifikáció állandó fejlődése 0.92, 1.0, 1.1, 1.2, 2.0 változatok Tomcat 5.xx kompatibilis a Servlet API 2.4 és JSP 2.0 változattal Statikus tartalom Azonos a közönséges HTML oldalakon használttal egyetlen kivétellel A <% karakterkombinációt a <\% karakterekkel kell megadni (<% ugyanis mindig valamilyen JSP elemet vezet be) 1
Szkript elemek Java kód beillesztésére szolgálnak Három fajtájuk JSP kifejezések <%=kifejezes %> kiértékelésük után beszúródnak a kimenetbe Szkriptek <% kod %> a szervlet service() metódusába szúródnak be Deklarációk <%! kod %> a szervlet osztály törzsébe szúródnak be, minden metóduson kívül JSP kifejezések http://localhost:8080/eloadasjsp/1.jsp A pontos idő: <%= new java.util.date() %> Figyelem: <% = kezdés hibás! De a kifejezes%> és a kifejezes %> befejezés egyaránt megengedett Implicit változók egyszerűsíthetik a kifejezéseket request a kérelemhez kapcsolódó HttpServletRequest objektum response a válaszhoz kapcsolódóhttpservletresponse objektum session a kérelemhez kapcsolódó HttpSession objektum out a PrintWriter osztály pufferelt típusa (JspWriter) XML szintaxis <jsp:expression> Java kifejezés </jsp:expression> http://localhost:8080/eloadasjsp/2.html: <html> <form action="2.jsp"> Adja meg a nevét: <input type=text name=azonneve><br> <input type=submit value=elküldés> <input type=reset value=törlés> </form> </html> // A 2.jsp oldal <html> Üdvözlöm kedves <%=request.getparameter("azonneve")%> </html> JSP szkriptek Összetettebb feladatok elvégzésére Tetszőleges, de osztály és metódusdefiníciót nem tartalmazó Java programrészek beszúrása a service() metódusba Alakjuk: <% kod %> Ezek is hozzáférhetnek az explicit változókhoz Kiirás belőlük a HTML az out változóval történhet Az XML szintaxis <jsp:scriptlet> java kod </jsp:scriptlet> Az előbbi példa megoldása JSP szkripttel // Az egyik megoldás Üdvözlöm kedves <% String nev = request.getparameter("azonneve"); out.println(nev); %> // A másik megoldás <% String nev = request.getparameter("azonneve"); out.println("üdvözlom kedves " + nev); %> 2
Mivel a statikus tartalom is print utasításként szúródik be a Java utasítások közé, ezért a szkripteknek nem kell komplett Java utasításoknak lenni! Példa <% if (Math.random() < 0.5) { %> Nagyon <B>boldog</B> születésnapot kívánok! <% else { %> Sok <B>Boldogságot</B> kívánok születésnapodon! <% %> A fentiek az alábbiakba fordítódnak le if (Math.random() < 0.5) { out.println( "Nagyon <B>boldog</B> születésnapot kívánok!" ); else { out.println( "Sok <B>Boldogságot</B> kívánok születésnapodon!" ); JSP deklarációk Metódusok és példányváltozók definiálását teszik lehetővé A szervlet osztály törzsébe szúródnak be Maguk nem generálnak kimenetet Alakjuk: <%! kod %> Az XML szintaxis <jsp:declaration> java kod </jsp:declaration> Példa: a szervlet betöltése óta fellépet kérelmek előállítása <%! private int accesscount = 0; %> Az oldal lekéréseinek száma a szervlet betöltése óta: <%= ++accesscount %> http://localhost:8080/eloadasjsp/3.jsp Felhasználó definiált osztályok Mint láttuk, magán a JSP oldalon nem deklarálhatók, de az alkalkazás WEB-INF/classes könyvtárában igen! Bár kerülendők, mivel portábilisabb megoldásokkal helyettesíthetők (lásd később: JavaBeans és felhasználó definiált akciós elemek). Figyelem: az adott osztályt csomagban kell elhelyezni, s a csomagnak megfelelően a classes könyvtár megfelelő alkönyvtárába tenni! http://localhost:8080/eloadasjsp/sajatosztaly.jsp Példa: A JSP oldal <%@ page import="auxclasses.readtextfile, java.util.regex.*" %> <% ReadTextFile rtf = new readtextfile(application.getrealpath("data/testdata.txt")); String s = rtf.read(); s = Pattern.compile("\n").matcher(s).replaceAll("<br>"); out.println(s); %> Az osztály package auxclasses; import java.io.*; public class ReadTextFile { String filepath = null; boolean hiba = false; public ReadTextFile(String filepath) { this.filepath = filepath; public String read(){ String ss = "", s; try { FileReader fr = new FileReader(filePath); BufferedReader br = new BufferedReader(fr); while((s=br.readline())!=null) ss += s + "\n"; fr.close(); catch (IOException e) { hiba = true; return null; return ss; 3
JSP direktívák A szervlet globális struktúráját módosítják Három fajtájuk page direktíva: osztályok importálása, szevlet testreszabása, stb. include direktíva: fájlok beszúrása a JSP oldalnak szervletté transzformálásakor taglib direktíva: saját jelölőelemek használatára Alakja <%@ direktivanev jellemzo="ertek" %> vagy akár <%@ direktivanev jellemzo1="ertek1" jellemzo2="ertek2"... jellemzon="ertekn" %> XML szintaxis <jsp:directive.direktivatipus jellemzo="ertek" /> konkrétan pl. a page direktívára <jsp:directive.page import="java.util.*" /> A page direktíva Lehetséges jellemzői import, contenttype, isthreadsafe, session, buffer, autoflush, extends, infoo, errorpage, iserrorpage, language Az import jellemző - Java csomagok importálása - A többi jellemzővel ellentétben többször is előfordulhat - Példák <%@ page import="java.util.*" %> <%@ page import="java.math.*,java.sql.*" %> A contenttype jellemző - a kimenet MIME típusát állítja be - kiindulási értéke text/html - Példák <%@ page contenttype="text/plain" %> <%@ page contenttype="text/html; charset=iso-8859-2" %> - alternatív megoldás <% response.setcontenttype("text/plain"); %> A page direktíva (folytatás) Az isthreadsafe jellemző - Igaz értéke esetén a létrehozandó szervlet implementálja a SingleTheradModel interfészt (ez a kiindulási érték) - Példák <%@ page isthreadsafe="true" %> <%@ page isthreadsafe="false" %> A session jellemző - Azt szabályozza, hogy az adott oldal részt vesz-e a munkafolyamatban - Kiindulási értéke true, amikor is részt vesz - Példák http://localhost:8080/eloadasjsp/jatek12.jsp <%@ page session="true" %> <%@ page session="false" %> A buffer jellemző - A JspWriter osztály out változóhához a puffer mértét specifikálja - A kiszolgáló addig nem generál kimenetet, amíg a puffer be nem telik - Példa <%@ page buffer="32kb" %> A page direktíva (folytatás) Az autoflush jellemző - Igaz értéke (default) esetén a puffer kiürítendő, ha megtelt - Hamis értéke esetén kivételt generál a rendszer, ha a puffer túlcsordul - Példák <%@ page autoflush="true" %> <%@ page autoflush="false" %> Az errorpage jellemző - Azt az oldalt specifikálja, amelynek át kell adni a vezérlést, ha egy Throwable kivételt az adott oldal nem kezel le - Példa <%@ page errorpage="relativurl" %> Az iserrorpage jellemző - Igaz értéke arra utal, hogy ez az oldal egy másik oldal hibakezelő oldalaként szolgál. Kiindulási értéke hamis. - Példa <%@ page iserrorpage="true" %> 4
Az include direktíva jsp\includedirective\jsp1.2syntaxreference\index.html Fájlok beszúrására használható az oldalnak szervletbe való transzformálásának időpontjában A beszúrt fájl maga is html vagy jsp típusú is lehet Alakja <%@ include file="relativurl" %> A relatív URL a JSP oldalhoz képest értendő, de / jellel kezdve azt, az alkalmazás gyökeréhez relatív 1.... Példa: egy navigációs elem beszúrása az oldal elejére <BODY> <%@ include file="/navbar.html" %>... </BODY> Speciáls szerkezetek JSP megjegyzés: a fordító figyelmen kívül hagyja, s nem adódik át a HTML oldalnak <%-- megjegyzés --%> HTML megjegyzés: ez átadódik a HTML oldalnak, és a benne lévő JSP kód végrehatódik! <!-- megjegyzés --> Statikus szövegben a <% és %> helyett <\% és %\> Jellemzőben a ' és " és %> és <% helyett \' és \" és <\% és %\> Előre definiált változók Implicit objektumoknak is nevezik őket. Fajtáik: request, response, out, session, application, config, pagecontext. request, response, out, session: lásd korábban Az application változó -ServletContext típusú objektum - /getservletcontext() metódussal kapható meg a szervletekben/ - perzisztens adatok tárolhatók benne, s ezek mindegyik szervlet és JSP számára hozzáférhetők - olvasás/írás a getattribute() és setattribute() metódussal Csak Object típus írható bele!!! Object típust ad vissza az olvasás - kasztolás!!! //írás String s = request.getparameter("userneve"); application.setattribute("nev",s); //olvasás String txt = (String)application.getAttribute("nev"); Az application változó (folytatás) - Az alkalmazás telepítési leírójában (deployment descriptor) megadott konfigurációs paramétert is hozzáférhetővé teszi az alkalmazás minden szervlete és jsp oldala számára http://localhost:8080/eloadasjsp/applicationtest.jsp http://localhost:8080/eloadasjsp/mester.jsp szurlolo.jsp manuálisan megnyitandó <context-param> <param-name>jelszo</param-name> <param-value>nagytigris</param-value> </context-param> String psw = application.getinitparameter("jelszo"); - Az alkalmazás ServletContext objektumán metódusok használata http://localhost:8080/eloadasjsp/applicationtest1.jsp <%= application.getrealpath("/"); 5
A config változó Lehetővé teszi az adott JSP oldal számára specifikus init paraméterekhez a hozzáférést. Ezek a paraméterek a telepítési leíróban adhatók meg a servlet elemekben (az ok: a JSP oldalakat a kiszolgáló szervletekbe fordítja). http://localhost:8080/eloadasjsp/configtest.jsp <servlet> <servlet-name>configtest</servlet-name> <jsp-file>/configtest.jsp</jsp-file> <init-param> <param-name>jelszo</param-name> <param-value>kistigris</param-value> </init-param> </servlet> A pagecontext változó Lehetővé teszi az összes objektumhoz a hozzáférést az oldal hatáskörében, s rajtuk a javax.servlet.jsp.pagecontex osztály metódusainak használatát. Különösen hasznos az EL objektumok és a közönséges JSP objektumok közötti együttműködéskör, mivel ez az egyetlen közös objektum a két rendszerben (lásd később). Mivel a JSP oldal tartalmazza a jelenlegi kérelmet, munkafolyamatot és alklmazást, a pagecontext lehetővé teszi a hozzáférést a JSP oldallal társított összes hatáskörhöz. Ez a default hatáskör mindenobjektum számára, beleértve a JavaBeans komponenseket is. A page hatáskörű objektumok tipikusan lokális változókhoz kötöttek, melyekhez szkriptletekben, kifejezésekben, JavaBeans elemekben és felhasználódefiniált elemekben férünk hozzá. <servlet-mapping> <servlet-name>configtest</servlet-name> <url-pattern>/configtest.jsp</url-pattern> </servlet-mapping> String psw = config.getinitparameter("jelszo"); Akcióelemek XML szintaxist használnak A szervlet motor viselkedését szabályozzák A rendelkezésre álló elemek (JSP 2.0) jsp:usebean, jsp:setproperty, jsp:getproperty jsp:include jsp:forward jsp:plugin jsp:attribute jsp:body jsp:invoke jsp:output jsp:root jsp:text A jsp:usebean,jsp:setproperty és a jsp:getproperty akcióelemek JavaBeans API Szabványos forma - Vizuális fejlesztő eszközök feltárhassák az osztályok tulajdonságait - Programkód írása nélkül létrehozhatók és manipulálhatók legyenek ilyen osztályok, stb. Legalapvetőbb jellemzők a JSP oldalak vonatkozásában Az osztálynak nem lehet konstruktora, vagy ha van, akkor egy nulla argumentumúnak is kell lenni Az osztály nem tartalmazhat nyilvános példányváltozókat A példányváltozókhoz a getxxx() és setxxx() alakú metódusokkal, ill. a logikai típusok esetén az isxxx() és setxxx() alakú metódusokkal kell hozzáférni a példányváltozó első betűje kisbetűből nagybetűvé változik a metódusban! Míg a JSP szkriptek és kifejezések egy osztály tetszőleges metódusához hozzáférhetnek, a JSP akcióelemek csak az előbbi metódusokat használva férhetnek hozzá. Előnyök a közönséges osztályokkal szemben XML szintax Hatáskör rendelhető hozzájuk Portábilisak 6
Alapvető szintaxis Specifikálás a megadott osztályból egy objektum példányosítása, s társítása az id-vel specifikált névhez <jsp:usebean id="test" class="package.class" /> A példányosított bean egy tulajdonságának módosítása <jsp:setproperty name="test" property="message" value="hello Világ" /> A példányosított bean egy tulajdonságának olvasása <jsp:getproperty name="test" property="message" /> Járulékos lehetőségek Olvasás és írás szkriptlettel <%=test.getmessage() %> <% test.setmessage("hello Világ"); %> Írás futásidejű értékkel pl. az űrlapról beolvasott értékkel <% test.setmessage(request.getparameter("txt1")) %> // vagy <jsp:setproperty name="test" property="message" value='<%=request.getparameter("txt1")%>' /> // vagy <jsp:setproperty name="test" property="message" param="txt1" />!! Osztott használat a scope jellemző <jsp:usebean id="test" class="package.class" scope="session" /> Négy különböző érték rendelhető hozzá page Default érték. A bean csak a jelenlegi oldal számára férhető hozzá (jelenlegi PageContext objektum tárolja). application Az osztott használatúservletcontext tárolja a beant, így az application objektumon keresztül az alkalmazás összes JSP oldala számára hozzáférhető. Alternatív hozzáférés a getservletcontext()-tel megkapott ServletContext objektum getattribute(), setattribute() metódusaival. session A HttpSession tárolja a beant, így a munkafolyamat oldalai számára hozzáférhető. request A ServletRequest tárolja a beant a jelenlegi JSP oldal fennállása alatt, s ezen objektum getattribute() metódusával is hozzáférhető Feltételes létrehozás Csak akkor hoz létre egy beant a rendszer, ha azonos id és scope jellemzővel még nincs létrehozott bean. Ellenkező esetben a meglévőre ad vissza egy referenciát. Konténeres alak használata <jsp:usebean...> Body </jsp:usebean> A törzs csak akkor hajtódik vége, ha új beant hoz létre a rendszer. Példa: Számlálandó a hozzáférések száma az alkalmazás oldalainak egy csoportjához, s tárolandó az első hozzáfért oldal neve. Nem tudjuk azonban, melyik oldalhoz történik először a hozzáférés, melyikben tároljuk az oldal nevét? A feltételes végrehajtás segít. A csoport minden oldalán elhelyezendő jsp utasítások: <jsp:usebean id="counter" class="/awp.mybeans.accesscountbean" scope="application"> <jsp:setproperty name="counter" property="firstpage" value="current Page Name" /> </jsp:usebean> A csoportba tartozó oldalakhoz a hozzáférések száma: <jsp:getproperty name="counter" property="accesscount" /> Az AccessCountBean.java package mybeans; public class AccessCountBean { private String firstpage; private int accesscount = 1; public String getfirstpage(){return(firstpage); public void setfirstpage(string fp){firstpage = fp; public int getaccesscount(){return(accesscount++); 7
1. példa: táblázat generálás http://localhost:8080/eloadasjsp/tablebean.jsp A jsp oldal <html> <jsp:usebean id="table" class="beans.tablebean" /> <jsp:setproperty name="table" property="source" value="11::22::33;; aa::bb::cc;; xx::yy::zz" /> <jsp:getproperty name="table" property="result" /> </html> A tablebean osztály package beans; public class tablebean { private String source = null; private String result = null; public void setsource(string source) {this.source = source; public String getresult(){ String ttt = "<table border=1>"; String[] sorok = source.split(";;"); for(int i=0; i<sorok.length; i++){ ttt += "<tr>"; String[] oszlopok = sorok[i].split("::"); for(int j=0; j<oszlopok.length; j++) ttt += "<td>" + oszlopok[j] + "</td>"; ttt += "</tr>"; return (ttt+"</table>"); 2. példa: adatbázis tábla letöltés http://localhost:8080/eloadasjsp/dbselectbean.jsp A jsp oldal <html> <jsp:usebean id="bbb" class="beans.dbselectbean" /> <jsp:setproperty name="bbb" property="driver" value="sun.jdbc.odbc.jdbcodbcdriver" /> <jsp:setproperty name="bbb" property="url" value="jdbc:odbc:tanszek" /> <jsp:setproperty name="bbb" property="query" value="select * from munkatarsak" /> <jsp:setproperty name="bbb" property="cim" value="munkatársak" /> <jsp:getproperty name="bbb" property="result" /> <jsp:setproperty name="bbb" property="query" value="select Név,Életkor from munkatarsak where Életkor<60" /> <jsp:getproperty name="bbb" property="result" /> A JavaBeans osztály package beans; import java.sql.*; public class DBSelectBean { private String driver = null; private String url = null; private String query = null; private String cim = null; private String result = null; Az AccessCountBean.java // A beállító metódusok public void setdriver(string driver) {this.driver = driver; public void seturl(string url) {this.url = url; public void setquery(string query) {this.query = query; public void setcim(string cim) {this.cim = cim; <!-- ${bbb.result --> </html> 8
A JavaBeans osztály (1. folytatás) // Az egyetlen kiolvasó metódus public String getresult(){ String ss = null; try { Class.forName(driver); Connection con = DriverManager.getConnection(url,"",""); Statement stmt = con.createstatement(); ResultSet rs = stmt.executequery(query); ss = printresultset(rs); rs.close(); stmt.close(); con.close(); Az AccessCountBean.java return ss; catch (Exception ex) { return "Az adatbázis nem érheto el"; A JavaBeans osztály (2. folytatás) // Belső, privát segédmetódus private String printresultset(resultset rs) throws SQLException{ String s = ""; ResultSetMetaData rsmd = rs.getmetadata(); int numcols = rsmd.getcolumncount (); s = "<html>"; s += "<head><title>dbservlet</title>"; s += "<style type=text/css>"; s += "td {width:200;font-size:14pt;font-family:helvetica"; s += "</style></head>"; s += "<body>"; s += Az "<table AccessCountBean.java border=1 style='width:" + (200*numCols) + ";background-color:black'>"; s += "<caption><h2>" + cim +"</h2></caption>"; s += "<tr style='color:white; font-weight:bold;'>"; for(int i=1; i<=numcols; i++) s += "<td>" + rsmd.getcolumnname(i) + "</td>"; s += "</tr>"; s += "</table>"; A JavaBeans osztály (3. folytatás) s += "<div style='overflow:auto; width:" + (200*numCols+16)+";height: 160px;'>"; s += "<table border=1 style='background-color:#c0c0c0'>"; while ( rs.next() ) { s += "<tr>"; for (int i=1; i<=numcols; i++) { s += "<td>" + rs.getstring(i) + "</td>"; s += "</tr>"; s Az += AccessCountBean.java "</table>"; s += "</div>"; s += "</body>"; s += "</html>"; return s; Az include akcióelem Lehetővé teszi egy statikus fájl vagy egy másik web komponens eredményének a beszúrását, azaz statikus és dinamikus erőforrások egyaránt beszúrhatók vele Statikus esetben a megcímzett tartalom egyszerűen beszúródik Dinamikus esetben a forrásoldal kérelmet küld a célerőforrásnak, s a visszaküldött válasz szúródik be a forrásoldalba A beszúrás után folytatódik a forrásoldal végrehajtása Dinamikus célerőforrásnak paraméter is átadható a jsp:param gyermekelemmel Példák <jsp:include page="/utils/processtable.jsp" /> <jsp:include page="script/login.jsp"> <jsp:param name="username" value="akovacs" /> </jsp:include> 9
A forward akcióelem Lehetővé teszi a kérelem átirányítását egy másik lapra azonos alkalmazási környezetben Az átirányítás után a forrásoldal feldolgozása már nem folytatódik Figyelem: Ha a forrásoldal nem pufferolt (buffer="none"), s ha a JSP oldal out objektumában van adat, akkor a jsp:forward IllegalStateExceprion kivételt vált ki! A page jellemzőjével kell megadni a céloldal relatív URL-jét, amely protokollt, portot és doménnevet nem tartalmazhat A page értéke akár statikus, akár futásidőben kiszámolt lehet A céloldalnak az include akcióelemhez hasonlóan paraméterek is átadhatók a jsp:param gyermekelemmel Példák <jsp:forward page="/utils/errorreporte.jsp" /> <jsp:forward page="<%= valamilyen Java kifejezes %>" /> 10