HowTo: BlazeDS/FDS-Tomcat + Flex + Hibernate + MySQL

7. Juni 2008 – 14:41

Einleitung

In diesem HowTo möchte ich euch zeigen wie man mit den beiden Servern eine persistente Datenhaltung realisiert. Dabei werden wir mit MySQL/JDBC und die LiveCycle Data Services (kurz LCDS) arbeiten. Die LCDS sind in beiden Servern bereits integriert. Wir werden alle Datenkommunikationen per RemoteObject betreiben. Ich werde nicht auf Basics eingehen, deshalb ist es empfehlenswert die Testdrive Tutorials schon einmal angeschaut und nachvollzogen zu haben. Ich werde auch nicht auf die Installation der beiden Server eingehen. Wie man

com.mysql.jdbc.Driverbeide auf einem Linux-System installiert habe ich in diesem HowTo bereits gezeigt.

Am Ende des Tutorials haben wir als Frontend eine minimale Flexanwendung(mxml-Anwendung) geschrieben, die über Data Access Objects (DAO) Daten in die Datenbank schreibt und auch ausliest. Für das HowTo verwende ich Teile aus unserem Projekt radioSiTY.

Gleich vorweg der Source. Da ich nicht alle Klassen und Config’s zeige könnt ihr so besser mitarbeiten. Dort findet ihr auch den SQL-Dump für unsere kleine Datenbank und müsste diese so nicht selbst erstellen ;-)

Source (.rar, 271KB)

Vorbereitungen Datenhaltung

In radioSiTY haben wir verschiedene Funktionen mit Hibernate und RPC umgesetzt. Für dieses HowTo modellieren wir die Kommentar- und Streamfunktionen. Das heißt konkret das wir folgende Funktionen implementieren:

  • addStream()
  • addComment()
  • showComments()
  • showStreams()

Da zu jedem Kommentar auch ein Benutzer gehört dürfen wir natürlich eine User-Tabelle nicht vergessen. Unsere Datenbank sieht also wie folgt aus:

howto_datamodel

Damit ihr das Tutorial möglichst schnell nachvollziehen könnt habe ich hier mal den SQL-Dump. Denn braucht ihr nur mit folgenden Befehl in die Datenbank einschleusen:

mysql.exe -u username -p radiositiy_db1 < db.sql

Die Datenbank muss vorher natürlich angelegt sein. Auch der username muss entsprechend angepasst werden.

Die Entity-Klassen in Java haben schließlich folgende Struktur:

howto_classmodel

Wir haben zum einen einen Hibernatehandler der Hibernate ansich initialisiert und alle Funktionen hält. Zum Anderen haben wir die Klassen User, Comments und Stream. Diese Klassen stellen das DAO dar und haben lediglich Getter- und SetterMethoden. Aus Gründen der Übersichtlichkeit habe ich aber nicht alle Methoden aufgeführt.

Vorbereitung zu Hibernate

Hibernate braucht um Arbeiten zu können die Verbindungsangaben zur Datenbank. Desweiteren muss Hibernate auch die einzelnen Tabellen und deren Felder kennen. Diese Angaben macht man in sogenannten Mappingfiles(DAO<->Tabelle) im XML-Format. Zunächst legen wir aber erstmal die Konfigurationsdatei, mit dem Namen hibernate.cfg.xml, für Hibernate an:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>

<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/radiositiy_db1</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<property name="transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>

<!-- Disable the second-level cache  -->
<property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>        <!-- Echo all executed SQL to stdout -->

<property name="show_sql">true</property>

<!-- Load the database table mapping file -->
<mapping resource="Product.hbm.xml"/>
<mapping resource="Stream.hbm.xml"/>
<mapping resource="User.hbm.xml"/>
<mapping resource="comments.hbm.xml"/>
</session-factory>

</hibernate-configuration>

Die erste property ist die Treiberangabe. In unserem Fall wäre das MySQL. Hier könnte man dann auch andere Treiber, wie etwa für HSQL, angeben. Die nächsten drei property Angaben sind selbsterklärend und benötigen lediglich eine Anpassung an eure Datenbank. Wichtig ist weiterhin das man bei der dialect property den MySQLDialect wählt. Analog zum Treiber sind auch hier andere Angaben möglich. Auf die property show_sql komme ich bei der Implementierung des HibernateHandlers noch einmal zu sprechen. Sehr wichtig sind ganz unten die mapping resource’s. Das sind unsere oben angesprochenen Mappingfiles. Sie enthalten im Namen immer *.hbm.

Wobei wir auch schon beim Thema wären: Die Implementierung dieser Files. Aus Gründen der Übersichtlichkeit poste ich nur die Stream.hbm.xml.:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="flex.radioSiTY.Stream" table="tbl_streams">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="url"  column="fld_url"  type="string"/>
<property name="homepage"   column="fld_homepage"   type="string"/>
<property name="name"   column="fld_name"   type="string" />
<property name="genreId" column="genre_id" type="integer"/>
<property name="image" column="fld_image" type="string"/>
<set name="user" table="tbl_stream_comments" lazy="true" inverse="true" >
<key column="stream_id"/>
<many-to-many class="flex.radioSiTY.User" column="id"/>
</set>
</class>
</hibernate-mapping>

Wie man sieht steht in jeder Mappingfile die Klasse/Tabelle die gemappt werden soll. Danach folgen die Angaben zu den einzelnen Spalten. Der type ist immer auf die Javadatentypen bezogen und nicht auf die MySQL-Typen. Ihr solltet auch immer zweimal schauen ob der Spaltenname mit dem in der Datenbank übereinstimmt. Zu guter letzt muss dann noch in einem set die Beziehung zu der anderen Tabelle hergestellt werden. Wichtig zu erwähnen wären noch die many-to-one Relationen in der comments.hbm.xml. Diese Angaben sind essentiel da eine Kommentar schließlich die Angaben beinhalten, von welchen Benutzer, zu welchen Stream ein Kommentar geschrieben wurde.

Alle *.hbm’s und die hibernate.cfg.xml kommen direkt unter das \WEB-INF\classes Verzeichniss.

Ich möchte an dieser Stelle noch die Beispielanwendung zu Hibernate von Thorsten Horn erwähnen. Das ist ebenfalls ein schönes Tutorial und geht genauer auf die Sachen rund um Hibernate ein. Jedoch ohne Flex-Frontend und mit HSQL ;-)

Wenn ihr den FDS-Tomcat verwendet könnt ihr getrost zum nächsten Kapitel springen. Falls ihr den BlazeDS verwendet müssen wir noch ein paar Hibernate *.jar’s kopieren. Dazu müsst ihr aber zuerst den sogenannten Hibernate Core herunterladen. Das Archiv entpacken und folgenden *.jar’s nach BlazeDS\tomcat\webapps\samples\WEB-INF\lib kopieren: asm.jar, cglib-2.1.3.jar, checkstyle-all.jar, commos-collections-2.1.1.jar, dom4j-1.6.1.jar, hibernate3.jar, jta.jar und die log4j-1.2.11.jar.

Das wars dann auch schon :D

Implementierung Backend (Hibernatehandler und DAO’s)

So jetzt gehts ans Eingemacht. Zunächst die Entity-Klassen. Auch hier poste ich nur die Stream.java, da die Anderen zu 90% gleich sind.

package flex.radioSiTY;

import java.util.*;

public class Stream 
{
  private int    id;
  private String url;
  private String homepage;
  private String name;
  private int genreId;
  private String image;
  private Set    user     = new HashSet();
  private Set    comments = new HashSet();
  
  public Stream() { }
  

  public int    getId()         { return id; }
  public String getUrl()    { return url; }
  public String getHomepage()    { return homepage; }
  public String getName()      { return name; }
  public int getgenreId()    { return genreId; }
  public String getImage()      { return image; }
  public Set    getUser()     { return user; }
  public Set    getComments() { return comments; }

  public void setId(         int id         ) { this.id = id; }
  public void setUrl( String url    ) { this.url = url; }
  public void setHomepage( String homepage    ) { this.homepage = homepage; }
  public void setName( String name    ) { this.name = name; }
  public void setgenreId ( int genre    ) { this.genreId = genre; }
  public void setImage(   String image      ) { this.image = image; }
  public void setUser(     Set user     ) { this.user = user; }
  public void setComments( Set comments ) { this.comments = comments; }
}


[/Sourcecode]

Jetzt unser <em>HibernateHandler</em>:

1/*!
 * @brief Hibernate Handler
 * 
 * Der HibernateHandler stellt die Schicht zwischen der Flexanwendung und der Datenbank dar. Hibernate ist ein 
 * objektorientiertes Persistence Framework. Das heißt alle Daten liegen als Objekte vor und werden auch so in die Datenbank geschrieben und gelesen.
 * Aufgabe des Handlers ist es die Verbindung zur Datenbank herzustellen, eine Session und Transaction aufzubauen.
 *  
 * Wichtig: Hibernate jar's müssen dem BuildPath hinzugefügt werden!
 */

package flex.radioSiTY;

import java.util.*;

import org.hibernate.*;
import org.hibernate.cfg.Configuration;

import java.security.MessageDigest;
import java.sql.SQLException;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HibernateHandler {
	public SessionFactory sessionFactory = null;

	// public Session sess = null;
	// public Transaction trx = null;

	// ! @brief Hibernate wird im Konstruktor initialisiert
	public HibernateHandler() {
		/*
		 * Die Konfiguration für die Datenbankverbindung und das Mapping der
		 * einzelnen Tabellen liegt in der 'hibernate.conf'
		 */
		if (sessionFactory == null) {
			try {
				System.out
						.println("------------------------------------------------------");
				System.out.println("Initializing Hibernate");
				sessionFactory = new Configuration().configure()
						.buildSessionFactory();
				System.out.println("Finished Initializing Hibernate");
				System.out
						.println("------------------------------------------------------");
			} catch (HibernateException ex) {
				ex.printStackTrace();
				System.exit(5);
			}
		}
	}

	public static void main(String[] args) {

		/*
		 * ! Dies sind lediglich Tests die man lokal durchführen kann. Der
		 * Output erfolgt hier über die Console. Die eigentlichen Aufrufe der
		 * Mehtoden erfolgt durch Flex über RPC. Somit ist die main() eigentlich
		 * hinfällig und dient lediglich weiteren lokalen Tests.
		 */

		 HibernateHandler handler = new HibernateHandler();
		// String test = new String();
		// handler.showCommentsFromStream(78, false);
		// Date date = new Date(1922,110,23);
		// handler.updateUser(25, "Hans Test", "nickname" , "egal",
		// "test@test.de", date);
		// handler.addStream("http://test.de", "http://test.de", "testStream",
		// 5, "C:/test2.image");
		// egal = handler.showUsers();
		// egal =handler.showStreams();
		// handler.showComments();
		// System.out.println(test);
		// User user = new User();
		// Stream stream = new Stream();
		// user = handler.getUser(25);
		// stream = handler.getStream(88);
		// handler.addComments(6, 9, "test4mitch", date, 0);
		// System.out.println(user.getName() );
		// System.out.println(stream.getName());
		
		 //LCDS
		 /*List testListe = new ArrayList(handler.getStreams());
		 for(int i = 0; i< testListe.size(); i++) System.out.println((Stream)testListe.get(i));*/
		 
		 /*Stream testStream = new Stream(handler.getStream(16));		
		 testStream.setName("test me");		
		 handler.update(testStream);*/
		 
	}

	
	/*
	 * ! @brief Diese Methode fügt eine Stream in die DB ein. Verwendet wird sie
	 * wenn ein Benutzer einen Stream hinzufügt.
	 */
	public void addStream(String url, String homepage, String name,
			int genreId, String image) {
		Session sess = null;
		Transaction trx = null;
		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			Stream stream = new Stream();
			// stream.setId(id); wird automatisch inkrementiert
			stream.setUrl(url);
			stream.setHomepage(homepage);
			stream.setName(name);
			stream.setgenreId(genreId);
			stream.setImage(image);

			sess.save(stream);
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
	}

	/*
	 * ! @brief Diese Methode fügt ein Kommentar in die DB ein. Verwendet wird
	 * sie wenn ein Benutzer ein Kommentar hinzufügt.
	 */
	public void addComment(int userId, int streamId, String text, int blocked) {
		System.out.println("\n\nInit add!\n");

		Date date = new Date();

		System.out.println("Comment in DB speichern!!!!!\n");
		Session sess = null;
		Transaction trx = null;

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			Comments comment = new Comments();
			// comment.setId(id); wird automatisch inkrementiert
			comment.setText(text);
			System.out.println(text + "\n");
			comment.setBlocked(blocked);
			System.out.println(blocked + "\n");
			comment.setDate(date);
			System.out.println(date + "\n");
			comment.setUser(getUser(userId));
			comment.setStream(getStream(streamId));

			sess.save(comment);
			System.out.println("Now added!\n\n");
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
	}

	/*
	 * ! @brief Die Methode gibt ein Userobjekt nach ID zurück.
	 * 
	 * Wird von addComment() verwendet @param userId ID des Benutzers @return
	 * User-Objekt
	 */
	public User getUser(int userId) {
		Session sess = null;
		Transaction trx = null;

		User user = new User();

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			System.out.println("\nUser zu Id:" + userId);

			String hql = new String(
					"select user from User as user where user.id = :userId");
			Query query = sess.createQuery(hql);
			query.setInteger("userId", userId);
			Iterator itr = query.iterate();
			while (itr.hasNext()) {
				user = (User) itr.next();
			}
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
		return user;
	}

	/*
	 * ! @brief Die Methode gibt ein Streamobjekt nach ID zurück. Wird von
	 * addComment() verwendet @param streamId ID des Streams @return
	 * Stream-Objekt
	 */
	public Stream getStream(int streamId) {
		Session sess = null;
		Transaction trx = null;
		Stream stream = new Stream();

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			System.out.println("\nStream zu Id:" + streamId);

			String hql = new String(
					"select stream from Stream as stream where stream.id = :streamId");
			Query query = sess.createQuery(hql);
			query.setInteger("streamId", streamId);
			Iterator itr = query.iterate();
			while (itr.hasNext()) {
				stream = (Stream) itr.next();
			}
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
		return stream;
	}

	/*
	 * ! @brief Diese Methode gibt die verfügbaren Kommentare aus.
	 * 
	 * Wahlweise nach User oder Stream @param id Angabe des Streams oder des
	 * Users @param searchUser Angabe ob nach Kommentaren eines Users(true) oder
	 * nach Kommentaren zu einem Stream gesucht wird @return Gibt das Ergebniss
	 * als XML-String zurück
	 */
	public String showComments(int id, boolean searchUser) {
		Session sess = null;
		Transaction trx = null;
		StringBuffer output = new StringBuffer();

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			String hql = new String();
			if (!searchUser) {
				hql = "select comment from Comments as comment where comment.stream = :id order by date asc";
			} else {
				hql = "select comment from Comments as comment where comment.user = :id";
			}

			Query query = sess.createQuery(hql);
			query.setInteger("id", id);
			Iterator itr = query.iterate();

			System.out.println("\n\nComments als XML ausgeben!!!!!\n\n");

			output.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			output.append("<comments>");

			while (itr.hasNext()) {
				Comments comment = (Comments) itr.next();
				output.append("<comment>");
				output.append("\t<text>" + comment.getText() + "</text>");
				output.append("\t<user>" + comment.getUser().getUsername()
						+ "</user>");
				output.append("\t<date>" + comment.getDate().toString()
						+ "</date>");
				output.append("</comment>");
			}

			output.append("</comments>");
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
		String string = new String(output);

		// HttpServletResponse response;
		// response.setContentType("text/html");

		return string;
	}

	// ! @brief Diese Methode gibt alle Kommentare als String zurück
	public String showComments() {
		Session sess = null;
		Transaction trx = null;

		StringBuffer output = new StringBuffer();

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			System.out.println("\nAlle Kommentare:");
			List comments = sess.createQuery("from Comments").list();
			for (int i = 0; i < comments.size(); i++) {
				Comments comment = (Comments) comments.get(i);

				output.append("Commment: " + comment.getText());
				System.out.println("Commment: " + comment.getText()
						+ "\nvon User: " + comment.getUser().getUsername()
						+ "\nStreamname:" + comment.getStream().getName());

			}
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
		String string = new String(output);
		return string;
	}

	// ! @brief Diese Methode gibt alle Streams als String zurück
	public String showStreams() {
		Session sess = null;
		Transaction trx = null;

		StringBuffer output = new StringBuffer();

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			System.out.println("\nStreams:");
			List streams = sess.createQuery("from Stream").list();
			for (int i = 0; i < streams.size(); i++) {
				Stream stream = (Stream) streams.get(i);

				output.append("Streams: " + stream.getName());
				System.out.println("GenreId:  " + stream.getgenreId()
						+ "\nName: " + stream.getName() + "\nHomepage: "
						+ stream.getHomepage() + "\nUrl: " + stream.getUrl()
						+ "\nImage: " + stream.getImage());
			}

			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
		String string = new String(output);
		return string;
	}

	// ! @brief Diese Methode gibt alle User als String zurück
	public String showUsers() {
		Session sess = null;
		Transaction trx = null;

		StringBuffer output = new StringBuffer();

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			List users = sess.createQuery("from User").list();
			for (int i = 0; i < users.size(); i++) {
				User user = (User) users.get(i);

				output.append("User : " + user.getName());
				System.out.println("Name:  " + user.getName() + " Username: "
						+ user.getUsername() + " Alter: " + user.getBirthday());

			}
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}
		String string = new String(output);
		return string;
	}
	
	
}

Okay ersmal eine Menge Source. Wie versprochen sind alle Methoden die wir brauchen aufgeführt. Es sind aber noch zwei weitere hinzugekommen. Nämlich getUser() und getStream(), die für die Funktion addComment(), die dann den jeweiligen User und Stream zurückgeben. Wie ihr seht geben unsere Funktionen bis auf showStreams() immer XML-Strings zurück. Das hat den Grund das wir in radioSiTY diese Strings in ein DataGrid schreiben werden ;-)

Im Source findet ihr übrigens noch die Funktion updateUser(). Dort seht ihr wie man mit Hibernate eine Tabelle updatet.

Erwähnenswert wäre noch die main(). Dort seht ihr die auskommentierten Funktionsaufrufe. Das waren unsere Testmethoden bevor wir überhaupt an das Frontend gegangen sind. Man kann nämlich diese Anwendung auch als Konsolenanwendung starten. Dazu müsst ich nur wieder in die einzelnen Funktionen die Ausgabe über System.out.println() gestalten ansatt einen String zurückzugeben (siehe showStreams()). Ich errinner mich gerade das ich ja nochmal auf den SQL-Output aus der Hibernate-Konfigurationsdatei zu sprechen kommen wollte. Dadurch das wir den Wert auf true gesetzt hatten, sehen wir jetzt die SQL Ausgabe in der Konsole. Das betrifft dann auch die Ausgaben auf der Konsole von BlazeDS/FDS-Tomcat. Sehr nützlich ;-)

Im Übrigen seht ihr, dass alle Querys in HQL geschrieben sind. Das ist die Hibernate Query Language und muss benutzt werden. Es ist also kein normales SQL möglich. Es ist übrigens sehr wichtig das ihr alle Hibernate *.jar’s zu dem Java Build Path hinzufügt, da sich ansonsten das Projekt nicht kompilieren lässt.

Jetzt legt ihr unter dem Ordner \WEB-INF\classes\flex das Verzeichniss radioSiTY an. Dort hinein kopiert ihr die kompilierten DAO-Klassen und den HibernateHandler.

Implementierung Frontend (mxml-Applikation)

So wir kommen langsam aber sicher zum Ende. Nun ist es nicht mehr viel. Wir schreiben eine ganz kleine Anwendung du die unsere Funktionen nutzt. Nur die addStream() nicht, da diese analog zu addComment() läuft. Aber das seht ihr dann eh selbst im Source.

hibernate_mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[

private function checkComments():void {

remoteObject.showComments(78,false);
}

private function addComments() :void {

remoteObject.addComment(userId.text,streamId.text,text.text,blocked.text);
remoteObject.showComments(streamId.text,false);

}

]]>
</mx:Script>
<mx:RemoteObject id="remoteObject" destination="product"/>

<mx:Button x="115" y="58" label="Get Comments" id="getComments" click="checkComments()"/>
<mx:Button x="587" y="58" label="Get Streams" id="getStreams" click="remoteObject.showStreams()"/>
<mx:TextInput x="70" y="345" width="37" id="streamId"/>
<mx:TextInput x="169" y="345" width="31" id="userId"/>
<mx:TextInput x="282" y="345" width="246" id="text"/>
<mx:TextInput x="599" y="345" width="59" id="blocked"/>
<mx:Button x="684" y="345" label="add Comment" id="addComment" click="addComments()"/>
<mx:TextArea x="483" y="109" width="330" height="196" id="txt_getStreams" text="{remoteObject.showStreams.lastResult}" />
<mx:TextArea x="52" y="109" id="txt_getComments" text="{remoteObject.showComments.lastResult}" width="311" height="196"/>
<mx:Label x="10" y="347" text="streamId:"/>
<mx:Label x="115" y="347" text="userId:"/>
<mx:Label x="239" y="347" text="text:"/>
<mx:Label x="537" y="347" text="blocked?"/>

</mx:Application>

Ich denke der Source ist leicht verständlich. Wichtig ist das RemoteObject. Denn das gibt an aus welcher Klasse überhaupt die Methoden aufgerufen werden sollen. Diese Destination muss ähnlich wie bei bei der web.xml in einer Konfigurationsdatei bekannt gegeben werden. Aber dazu komm ich gleich. Weiterhin hätte man die XML-Ausgabe bei den Kommentaren auch in ein DataGrid lesen können.

Da das RemoteObject teil der LCDS ist muss man bei der Projekterstellung noch ein paar Sachen beachten. So müsst ihr unter Server technology die J2EE angeben. Der Haken bei Use remote object access service muss natürlich gesetzt sein. Im nächsten Fenster sind auch noch ein paar Einstellungen zu treffen. Hier muss ein Server ausgewählt werden, auf dem die Applikation kompiliert und ausgeführt werden soll. Wichtig dabei ist das der Server vor dem validieren gestartet ist. Ich zeige euch die Einstellungen für den BlazeDS und für den FDS-Tomcat:

hibernate_fds_conf

hibernate_blaze_conf

Es ist übrigens sehr wichtig auf dem Server zu kompilieren, da es ansonsten zu Fehlern kommt das die RemoteObject-Klasse nicht gefunden wird(in userem Fall der HibernateHandler). Das äussert sich dann in Can’t find Destination Fehlern.

Kommen wir zum letzten Schritt. Wir müssen die Destination noch angeben. Wenn man mit RemoteObject arbeitet findet diese Angabe in der remoting-config.xml unter \WEB-INF\flex statt. Analog zu dem Beispieleintrag fügen also folgendes ein:

<destination id="product">
<properties>
<source>flex.radioSiTY.HibernateHandler</source>
</properties>
</destination>

Jetzt nur noch in Flex das Projekt starten und staunen :D

Conclusion

Dieses HowTo war recht umfangreich aber ich denke es hat sich gelohnt. Habt ihr alles umgesetzt habt ihr eine gute Basis um eigene Projekt mit Flex und Hibernate zu realisieren. Ich werde bei Gelegenheit die eine oder andere Sache vielleicht noch ein wenig ausführlicher beschreiben. Auch hier noch einmal der Link zum Tutorial von Thorsten Horn, da er wie gesagt die Sachen rund um persistente Datenhaltung, Hibernate und Debugging sehr viel genauer beschreibt.

Ich hoffe ich habe nix vergessen oder übersehen. Bei Fragen oder Anregungen könnt ihr mir wie immer mailen oder ein Kommentar hinterlassen. In dem Sinne viel Erfolg :D

Post a Comment