320 likes | 397 Views
MySQL, Java und einiges mehr. Wir bauen uns eine Webapplikation!. Unsere Webapplikation kann nach Schauspieler/innen suchen… . Unsere Webapplikation kann nach Schauspieler/inne suchen…. … und alle Filme mit einer Schauspielerin anzeigen. Wie funktioniert das? Client-Server Applikationen.
E N D
MySQL, Java und einiges mehr Wir bauen uns eine Webapplikation!
Wie funktioniert das?Client-Server Applikationen Client Der Browser Firefox Chrome Safari Internet Explorer… Server Apache Tomcat Jetty Microsoft IIS … URLhttp://localhost:8080/html/index.html Internet Die darzustellende Webseite HTML
Wie funktioniert das?Jetty und seine Handler Jetty-Server addContext("/html", "html/"); ResourceHandler Liest angefragte Datei index.html in Verzeichnis html/ URLhttp://localhost:8080/html/index.html Dateipfad index.html angefragte DateiRessource angefragte DateiRessource Der ResourceHandler ist eine Klasse von Jetty. Er liefert einfach Dateien zurück.
Wie funktioniert das?Jetty und seine Handler Klasse ImdbServer, Hauptprogramm main: ContextHandlerhtmlHandler = handlers.addContext("/html", "html/"); htmlHandler.setHandler(newResourceHandler()); ContextHandlercssHandler = handlers.addContext("/css", "css/"); cssHandler.setHandler(newResourceHandler()); ContextHandlerimgHandler = handlers.addContext("/images", "images/"); imgHandler.setHandler(newResourceHandler());
Wie funktioniert das?Jetty und unser eigener Handler URLhttp://localhost:8080/query/actors/?name=watson%2C+emma Jetty-Server addContext("/query/actors", ""); ActorsQueryHandler Macht Datenbank-Abfrage und Darstellung der Webseite Parameter name=watson%2C+emma Fixfertiges HTMLRessource Fixfertiges HTMLRessource Der ActorsQueryHandler ist eine unserer eigenen Klassen. Er sucht in der Datenbank nach Schauspieler/innen und stellt die Treffer in einer Webseite dar.
Wie funktioniert das?Unser Handler: Datenbank-Abfrage SQL Abfrage SELECT * FROM actors WHERE name like ? ORDER BY name Abfrage-Parameter: "%watson, emma%" ActorsQueryHandler 1. Datenbank-Abfrage MySQL Datenbank Server Enthält die Tabellen mit den IMDB-Daten Parameter name=watson%2C+emma Gefundene Datensätze Der ActorsQueryHandler sucht als erstes in unserer MySQL-Datenbank nach Schauspieler/innen, deren Namen ähnlich ist wie der URL-Parameter name.
Wie funktioniert das?Unser Handler: Datenbank-Abfrage 1. Die Datenbankabfrage aufbereiten in ActorsQueryHandler: 1.1. Prüfen, ob ein Parameter name vorhanden ist if(request.getParameter("name") != null) { PreparedStatementstatement = connection.prepareStatement( "SELECT * FROM actors "+ "WHERE name like ? ORDER BY name" ); statement.setString(1, "%"+request.getParameter("name")+"%« ); returnstatement; }
Wie funktioniert das?Unser Handler: Datenbank-Abfrage 1. Die Datenbankabfrage aufbereiten in ActorsQueryHandler: 1.2. SQL-Abfrage vorbereiten, ohne Input-Daten if(request.getParameter("name") != null) { PreparedStatementstatement = connection.prepareStatement( "SELECT * FROM actors "+ "WHERE name like ? ORDER BY name" ); statement.setString(1, "%"+request.getParameter("name")+"%« ); returnstatement; }
Wie funktioniert das?Unser Handler: Datenbank-Abfrage 1. Die Datenbankabfrage aufbereiten in ActorsQueryHandler: 1.3. Input-Daten auf vorbereiteter Abfrage setzen if(request.getParameter("name") != null) { PreparedStatementstatement = connection.prepareStatement( "SELECT * FROM actors "+ "WHERE name like ? ORDER BY name" ); statement.setString(1, "%"+request.getParameter("name")+"%« ); returnstatement; }
Warum vorbereitete Abfragen?Achtung Gefahr: SQL Injection! Der naïve Ansatzeiner SQL-Abfrage: Die Benutzereingabe (in rot dargestellt) direkt in der SQL-Abfrageverwenden: executeQuery("SELECT * FROM actors WHERE name like '%watson, emma%' ORDER BY name"); Aber was passiert, wenn der BenutzerböswilligeEingabenmacht? executeQuery("SELECT * FROM actors WHERE name like '%';DROP TABLE actors;%' ORDER BY name"); Nach SELECT wird DROP TABLE ausgeführt. Uups. de.wikipedia.org/wiki/SQL-Injection
Wie funktioniert das?Unser Handler: HTML-Erstellung Daten result_list={ { name=Watson, Emma (I), id=1935796 }, { name=Watson, Emma (II), id=1935797 } } ActorsQueryHandler 2. Erstellung von HTML mit Treffern der DB-Abfrage Velocity HTML-Template plus Daten ergibt HTML für Browser Fixfertiges HTMLRessource Fixfertiges HTMLRessource Der ActorsQueryHandler erstellt anschliessend das HTML. Dazu verwendet er das Framework Velocity. So können wir unsere Daten in HTML «mischen».
Wie funktioniert das?Unser Handler: HTML-Erstellung 2. Die Daten der Abfrage für Velocity aufbereiten in ActorsQueryHandler: Map<String, Object> hm = newHashMap<String, Object>(); hm.put("name", resultSet.getString("name")); hm.put("id", resultSet.getInt("actorid")); returnhm; Maps sind Paare von (Name, Wert). Auf die Werte kann zugegriffen werden, indem ein Name abgefragt wird. Die obige Map wird mit zwei Paaren befüllt, die zum Beispiel die Werte haben könnten («name», «Streep, Meryl») und («id», «1235454»).
Wie funktioniert das?Velocity: HTML mit Befehlen Daten result_list={ { name=Watson, Emma (I), id=1935796 }, { name=Watson, Emma (II), id=1935797 } } Auszug aus unserem Velocity-Template <h1>Gefundene Schauspieler</h1> <ul> #foreach ($actor in $result_list) <li><a href="/query/movies?actor_id=$actor.id">$actor.name</a></li> #end </ul> Fixfertiges HTMLRessource Ein Velocity-Template erhält vom Java-Programm Daten. Diese können mit einfach Befehlen ausgelesen und in das HTML eingebaut werden.
Wie funktioniert das?Jetty und unser eigener Handler War das alles? Es braucht noch mehr Code, um Jetty mit MySQL via JDBC und mit Velocity zu integrieren. Wenn eine einzelne SQL-Abfrage ausreicht, können wir die Klasse AbstractSingleQueryHandler erweitern (ca. 200 Zeilen). Diese Klasse stellt die ganze Infrastruktur zur Verfügung. So können sich unsere eigenen Handler die wenigen Teile ergänzen, die spezifisch für unsere SQL-Abfrage sind.
Wie funktioniert das?Jetty und unser eigener Handler Die Klasse AbstractSingleQuery-Handler und ihre Unterklassen sind ein Beispiel des Design Patterns «Schablonenmethode». Die Methode handle verwendet Methoden wie prepareQuery. Diese Methoden sind nicht in der abstrakten Klasse, sondern erst in den Unterklassen definiert. Siehe auch de.wikipedia.org/wiki/Template_Method
Wie funktioniert das?Bausteine unserer Webapplikation Client Jetty-Server ActorsQueryHandler MySQL Internet Velocity
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> …
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … ImdbServer: Handler für /html konfigurierenContextHandlerhtmlHandler = handlers.addContext("/html", "html/"); htmlHandler.setHandler(newResourceHandler());
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … query/actors localhost:8080/query/actors/?name=watson
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … index.html: Das Formulardefiniert Input Parameter<form action="/query/actors" method="get"> <input name="name" type="text" size="30" /> <input type="submit" value=" Absenden " /> </form> query/actors localhost:8080/query/actors/?name=watson ImdbServer: Handler für /query/actors konfigurieren ContextHandleractorsQueryHandler = handlers.addContext("/query/actors", ""); actorsQueryHandler.setHandler(new ActorsQueryHandler());
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … SELECT * FROM actorswhere … prepareQuery(…) query/actors localhost:8080/query/actors/?name=watson
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … SELECT * FROM actorswhere … prepareQuery(…) query/actors localhost:8080/query/actors/?name=watson ActorsQueryHandler: Abfragevorbereiten public PreparedStatementprepareQuery(HttpServletRequestrequest, Connection connection) /*…*/ { if (request.getParameter("name") != null) { PreparedStatementstatement = connection.prepareStatement("SELECT * FROM actors WHERE name like ? ORDER BY name"); statement.setString(1, "%" + request.getParameter("name") + "%"); return statement; } /*…*/ }
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … SELECT * FROM actorswhere … prepareQuery(…) query/actors localhost:8080/query/actors/?name=watson mapResult(…)
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … SELECT * FROM actorswhere … prepareQuery(…) query/actors localhost:8080/query/actors/?name=watson ActorsQueryHandler: Resultateaufbereiten public Map<String, Object> mapResult(ResultSetresultSet) { Map<String, Object> hm = new HashMap<String, Object>(); hm.put("name", resultSet.getString("name")); hm.put("id", resultSet.getInt("actorid")); return hm; } mapResult(…)
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … SELECT * FROM actorswhere … prepareQuery(…) query/actors localhost:8080/query/actors/?name=watson mapResult(…) … <h1>Gefundene Schauspieler</h1> <ul><li><a href="/query/movies?actor_id=007">Bond, James</li></ul> … getVelocityTemplate() actors.vm
Die «Schnitzeljagd» durch die Webapplikation (vereinfacht!) Client Imdb-Server Resource-Handler ActorsQuery-Handler Velocity MySQL localhost:8080/ html/index.html /html/index.html html\index.html … <form action="/query/actors"> <inputname="name" …/> </form> … SELECT * FROM actorswhere … prepareQuery(…) query/actors localhost:8080/query/actors/?name=watson ActorsQueryHandler: Resultateaufbereiten public Map<String, Object> mapResult(ResultSetresultSet) { Map<String, Object> hm = new HashMap<String, Object>(); hm.put("name", resultSet.getString("name")); hm.put("id", resultSet.getInt("actorid")); return hm; } actors.vm: HTML erstellen <ul> #foreach($actor in $result_list) <li><a href="/query/movies?actor_id=$actor.id"> $actor.name</a></li> #end </ul> mapResult(…) … <h1>Gefundene Schauspieler</h1> <ul><li><a href="/query/movies?actor_id=007">Bond, James</li></ul> … getVelocityTemplate() actors.vm
Die «Schnitzeljagd»: Der Kern Imdb-Server AbstractQuery-Handler ActorsQuery-Handler Velocity MySQL handle(…) query/actors answerQuery(…) prepareQuery(…) SELECT * FROM actorswhere … mapResultSet(…) mapResult(…) …