Aplikacje Internetowe Dostęp do danych w aplikacji bazy danych i XML
Data Access Objects (DAO) Główna idea: uniezależnić aplikację od źródła danych Interfejs DAO zapewnia wszystkie operacje na danych (tzw. CRUD Create Retrieve Update Delete) Składniki: interfejs DAO źródło danych (DataSource) obiekt transferowy (JavaBean)
Przykładowe DAO Typowe metody interfejsu DAO Klasa (lub interfejs) PracownicyDAO void add(pracownik pracownik) Collection findbynazwisko(string nazwisko) Pracownik get(integer nr_prac) // nr_prac jest kluczem! void save(pracownik pracownik) void delete(pracownik pracownik) Klasa Pracownik (JavaBean obiekt transferowy): pola nr_prac, nazwisko,... gettery i settery dla każdego z nich
Bean Pracownik class Pracownik { int nrp; String nazw; Date dataur; public String getnrp() {return nrp;} public void setnrp(int nrp) {this.nrp = nrp;} public String getnazw() {return nazw;} public void setnazw(string nazw) {this.nazw=nazw;} } public Date getdataur() {return dataur;} public void setdataur(date dataur) {this.dataur=dataur;}
Warstwa DAO Implementacja metod wykonujących operacje na bazie Często operacje te różnią się dla różnych serwerów Dlatego najczęściej przygotowuje się: interface PracownicyDAO implementacje: class MySQLPracownicyDAO implements PracownicyDAO class OraclePracownicyDAO implements PracownicyDAO... Uwaga: większość operacji jest w SQL i jest taka sama dla każdej implementacji
Bean Car public class Car { int idc; String make; String model; String regnum; Double price; public int getidc() { return idc; } //dalsze gettery i settery }
Interfejs DAO Interfejs CarDAO Metody: void add(car car) void delete(int numer) Car get(int numer) List<Car> find(string make) Implementacja: CarDAOImpl
Statyczne połączenie z bazą public class CarDAOImpl implements CarDAO { static Connection con; static { } com.mysql.jdbc.jdbc2.optional.mysqldatasource ds = new com.mysql.jdbc.jdbc2.optional.mysqldatasource(); ds.setuser("root"); ds.setpassword(""); ds.setdatabasename("nowa"); try{ con = ds.getconnection(); }catch(sqlexception ex) {ex.printstacktrace();}
Metoda add public void add(car car) { try{ con.createstatement().executeupdate( "insert into car values("+ } car.getidc()+","+ "'"+car.getmake()+"',"+ "'"+car.getmodel()+"',"+ "'"+car.getregnum()+"',"+ car.getprice()+")" ); }catch(sqlexception ex) {ex.printstacktrace();}
Metoda find public List<Car> find(string make) { List<Car> carlist = new ArrayList<Car>(); try{ ResultSet rs = con.createstatement().executequery( "select * from car where make like '"+make+"'"); while(rs.next()) { Car car = new Car(); car.setidc(rs.getint("idc")); car.setmake(rs.getstring("make")); car.setmodel(rs.getstring("model")); car.setregnum(rs.getstring("regnum")); car.setprice(rs.getdouble("price")); carlist.add(car); } }catch(sqlexception ex) {ex.printstacktrace();} return carlist; }
Problemy Konieczność implementacji każdej metody Gdy dużo kolumn w tabeli długie implementacje Łatwo zapomnieć o szczegółach przecinki, nawiasy w zapytaniach SQL Problemy z dodawaniem, usuwaniem pól zmianą schematu bazy Główny problem: konieczność ręcznego mapowania obiektów na wiersze w tabeli!
Mapowanie obiektowe ORM: Object-to-Relational Mapping Idea: jednolitość interfejsu obiektowego Użycie obiektów zamiast ResultSet'ów Jak najmniej SQLa jak najwięcej programowania obiektowego Istnieją biblioteki/frameworki upraszczające tworzenie ORM: Hibernate Różne implementacje standardu JDO ibatis Java Persistence (EJB 3.0)
Biblioteka Hibernate Biblioteka dla Javy zapewniająca ORM Dostęp do danych tylko przez specjalne klasy Nie wymaga znajomości SQL w ogóle go nie używamy! Konfiguracja w pliku XML hibernate.cfg.xml Każde mapowanie opisane w osobnym pliku: <nazwa_tablicy/obiektu>.hbm.xml
Konfiguracja projektu Dodanie bibliotek (katalog lib) antlr-2.7.6.jar asm-attrs.jar asm.jar c3p0-0.9.1.jar cglib-2.1.3.jar commons-collections-2.1.1.jar commons-logging-1.0.4.jar dom4j-1.6.1.jar hibernate3.jar jta.jar
Plik konfiguracyjny hibernate.cfg.xml definicja źródła danych pliki mapowań Konfiguracja Hibernate: Configuration cfg = new Configuration().configure([PLIK]); SessionFactory factory = cfg.buildsessionfactory(); Obiekt factory posłuży do otwierania połączeń z bazą
Pliki mapowań i obiekty transferowe Domyślnie: NazwaTablicy.hbm.xml Zawartość: Definicje pól i ich odwzorowań na klasy JavaBeans Definicje relacji Klasa transferowa: do tworzenia obiektów zwykły JavaBean z getterami i setterami
Plik mapowania dla Car <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="pl.kurs.car" table="car"> <id name="idc" column="idc"> <generator class="increment"/> </id> <property name="make" column="make"/> <property name="model" column="model"/> <property name="regnum" column="regnum"/> <property name="price" column="price"/> </class> </hibernate-mapping>
Konfiguracja hibernate.cfg.xml <!DOCTYPE hibernate-configuration SYSTEM "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class"> org.gjt.mm.mysql.driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost/nowa </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.dialect"> org.hibernate.dialect.mysqlinnodbdialect </property> <!-- List of XML mapping files --> <mapping resource="pl/kurs/car.hbm.xml"/> </session-factory> </hibernate-configuration>
Modyfikacje w programie Zmiany tylko w CarDAOImpl Zamiast obiektu Connection przechowujemy teraz obiekt SessionFactory public class CarDAOHib implements CarDAO {... private final static SessionFactory factory; static { } Configuration cfg = new Configuration().configure(); factory = cfg.buildsessionfactory();
Zmiany w metodzie add Nowa metoda add: public void add(car car) { } Session session = factory.opensession(); Transaction tx = session.begintransaction(); session.saveorupdate(car); tx.commit(); session.close(); Za mapowania odpowiada już Hibernate!
Nowa metoda find() Zamiast instrukcji select - zapytanie HQL zwracające gotowe obiekty public List<Car> find(string make) { Session session = factory.opensession(); Transaction tx = session.begintransaction(); List<Car> carlist = session.createquery( "from Car").list(); tx.commit(); session.close(); return carlist; }
Najważniejsze metody sesji save(obj), persist(obj) saveorupdate(obj) delete(obj) get("nazwaklasy",id) createquery("from NazwaKlasy") query.list() createcriteria("nazwakasy") criteria.add(example.create(obj)) criteria.list()
Użycie adnotacji Adnotacje Pakiet hibernate-annotations Dodanie trzech bibliotek: ejb3-persistence.jar hibernate-annotations.jar hibernate-commons-annotations.jar Można już usunąć plik Car.hbm.xml a definicję mapowań przenieść do klasy Car.java
Modyfikacje w programie Zmiany tylko w CarDAOImpl Zamiast Configuration używamy AnnotationConfiguration public class CarDAOHibAnno implements CarDAO {... private final static SessionFactory factory; static { } Configuration cfg = new AnnotationConfiguration().configure(); factory = cfg.buildsessionfactory();
Encja Car Dodanie adnotacji @Entity przed class Dodanie adnotacji @Id przed getidc() Dodanie implements Serializable @Entity public class Car implements Serializable{ int idc;... @Id public int getidc() { return idc; }
Nie zawsze baza danych Dane nie zawsze wygodnie jest przechowywać w relacyjnej bazie danych Bardzo popularnym formatem jest XML
XML Skrót od: extensible Markup Language Uniwersalny język opisu Duża konfigurowalność i rozszerzalność Otwarty format łatwo stworzyć parser Składnia ścisła i struktura możliwa do ograniczania Idealny do wymiany informacji pomiędzy różnymi aplikacjami/systemami Pojawia się już właściwie w każdym miejscu
Budowa dokumentu XML root obejmuje cały dokument element składa się z nazwy, listy atrybutów, listy dzieci tekst tekst pomiędzy dwoma znacznikami komentarz pomiędzy <!-- a --> instrukcja sterująca ma cel (target) i wartość, wewnątrz znaków <??> Tekst niesformatowany: <![CDATA[ <to mój tekst>bez<parsowania> ]]>
Element Składniki: nazwa, atrybuty, namespaces, zawartość Budowa: <nazwa atr1="w1" atr2="w2">zawartość</nazwa> Atrybuty kolejność nie ma znaczenia Zawartość elementu pusta (<nazwa/>) inne elementy tekst mieszana (tekst i elementy np. w XHTML)
Aplikacja XML Słownik elementów i ich atrybutów pozwalający na opisanie obiektów pewnej dziedziny Opis języka w specjalnym formacie (schemat) DTD XML Schema Najczęściej z aplikacją powiązana jest przestrzeń nazw (namespace - xmlns) <xmlns:xi="http://www.w3.org/2001/xinclude"> Dzięki namespace można w jednym dokumencie stosować kilka aplikacji
Namespaces Definicja grupy elementów poprzez związanie ich z pewnym URI Idea podobna do pakietów Javy: ten sam element <Book> może znaleźć się w różnych namespace'ach URI to najczęściej URL (wraz z protokołem http) dokumentu opisującego namespace Dla URI definiuje się zwykle prefix (w zasadzie dowolny) <xmlns:xi="http://www.w3.org/2001/xinclude"> Użycie w dokumencie: <xi:include href="order_details.xml"/>
Document Type Definition (DTD) Opis może być w dokumencie lub osobnym pliku: <!DOCTYPE note [... ]> <!DOCTYPE note SYSTEM "test.dtd"> Definicje elementów <!ELEMENT imie (#PCDATA)> <!ELEMENT adres(ulica, miasto, kraj)> Definicje atrybutów <!ATTLIST klient id ID #REQUIRED>
Typy atrybutów CDATA dowolny tekst NMTOKEN nazwa XML NMTOKENS lista nazw XML ID wartość unikalna IDREF wartość ID innego elementu IDREFS lista wartości ID innych elementów ENTITY, ENTITIES nazwa encji NOTATION lista dozwolonych wartości przedzielonych " "
Element content model <!ELEMENT element-name (child-name)> jedno wystąpienie potomka <!ELEMENT element-name (child-name+)> przynajmniej jedno wystąpienie potomka <!ELEMENT element-name (child-name*)> zero lub więcej wystąpień potomka <!ELEMENT element-name (child-name?)> zero lub jedno wystąpienie potomka
Domyślne wartości atrybutów #REQUIRED wymagany #IMPLIED opcjonalny #FIXED "wartość" stały "wartość" wartość domyślna
Problemy z DTD Sprawdza tylko strukturę dokumentu a nie typy danych Nie można ograniczyć zakresu wartości Własny niestrukturalny format przy dużych Własny niestrukturalny format przy dużych schematach trudny do analizy
XMLSchema Opis schematu w pliku XML <xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema"> Pozwala na znacznie więcej niż DTD Można grupować definicje Można nakładać rozbudowane ograniczenia
Przykład xsd <xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema"> <xsd:element name="purchaseorder" type="purchaseordertype"/> <xsd:element name="comment" type="xsd:string"/> <xsd:complextype name="purchaseordertype"> <xsd:sequence> <xsd:element name="shipto" type="usaddress"/> <xsd:element name="billto" type="usaddress"/> <xsd:element ref="comment" minoccurs="0"/> <xsd:element name="items" type="items"/> </xsd:sequence> <xsd:attribute name="orderdate" type="xsd:date"/> </xsd:complextype>
Przykład ograniczenia <xsd:element name="quantity"> <xsd:simpletype> <xsd:restriction base="xsd:positiveinteger"> <xsd:maxexclusive value="100"/> </xsd:restriction> </xsd:simpletype> </xsd:element>
Edycja XML w Eclipse Wbudowany edytor XML Walidacja DTD i XMLSchema Edytor DTD Specjalny graficzny edytor XMLSchema
Tworzenie dokumentu XML Lista samochodów <carlist> <title>oto lista samochodów</title> <car idc="1"> <make>fiat</make> <model>brava</model> <regnum>kr45321</regnum> <price>4000</price> </car> </carlist>
Plik DTD <!ELEMENT carlist (title,car+)> <!ATTLIST carlist xmlns:car CDATA #IMPLIED> <!ELEMENT car (make,model,regnum,price)> <!ATTLIST car idc CDATA #REQUIRED> <!ELEMENT title (#PCDATA)> <!ELEMENT make (#PCDATA)> <!ELEMENT model (#PCDATA)> <!ELEMENT regnum (#PCDATA)> <!ELEMENT price (#PCDATA)>
Dołączanie DTD Wpis w nagłówku dokumentu: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE carlist SYSTEM "car.dtd"> <carlist xmlns="http://www.example.org/car" Teraz działać już powinna walidacja!
Tworzenie XML Schema Plik car.xsd Nagłowek: <?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/xmlschema targetnamespace="http://www.example.org/car" xmlns:tns="http://www.example.org/car elementformdefault="qualified">
Element <carlist> <xs:element name="carlist"> <xs:complextype> <xs:sequence> <xs:element name="title" type="xs:string" /> <xs:element ref=" tns:car" maxoccurs="unbounded" /> </xs:sequence> </xs:complextype> </xs:element>
Element <car> <xs:element name="car"> <xs:complextype> <xs:sequence> <xs:element name="make" type="xs:string" /> <xs:element name="model" type="xs:string" /> <xs:element name="regnum" type="xs:string" /> <xs:element name="price" type="xs:double" /> </xs:sequence> <xs:attribute name="idc" type="xs:positiveinteger" use="required"> </xs:attribute> </xs:complextype> </xs:element>
Dodawanie ograniczeń Typ danej Lista dozwolonych wartości Wartości minimalne i maksymalne Określenie długości i minimalnej długości Własne wzorce
Dodawanie ograniczeń Wybór z listy Odwołanie do nowego typu: <xs:element name= make" type="tns:maketype" /> Definicja <xs:simpletype name="maketype"> <xs:restriction base="xs:string"> <xs:enumeration value= Ford"></xs:enumeration> <xs:enumeration value= Opel"></xs:enumeration> </xs:restriction> </xs:simpletype>
Ograniczenie wartości Odwołanie do typu <xs:element name="price" type="tns:pricetype" /> Definicja <xs:simpletype name="pricetype"> <xs:restriction base="xs:double"> <xs:mininclusive value="1000"></xs:mininclusive> <xs:maxinclusive value="2000"></xs:maxinclusive> </xs:restriction> </xs:simpletype>
Określenie długości Odwołanie do typu <xs:element name="price" type="tns:pricetype" /> Definicja <xs:simpletype name="regnumtype"> <xs:restriction base="xs:string"> <xs:length value="7"></xs:length> </xs:restriction> </xs:simpletype>
Przykłady wzorców <xs:pattern value= [abc] /> 1 litera, a lub b lub c <xs:pattern value= [a-za-z] /> dowolna litera <xs:pattern value= [A-Z][A-Z] /> dwie duże litery <xs:pattern value= X([0-9])* /> X i dowolna liczba cyfr <xs:pattern value= ([0-9])? /> opcjonalna cyfra <xs:pattern value= ([0-9]){8} /> dokładnie 8 cyfr
XML a HTML Zamiast przesyłać dane HTML można użyć XML Przeglądarka internetowa to klient znający aplikację Protokoły są zawsze znane
Idea Web Services Połączenie aplikacji internetowej z aplikacją desktopową Język komunikacji XML Określone standardy SOAP, WSDL Zalety: Możliwość komunikacji pomiędzy różnymi aplikacjami (.NET, Java, PHP ) Język XML może być używany wszędzie
Zastosowanie WS Popularny przykład: pakiet Axis Najprościej jako aplikacja internetowa (WAR) dołączana do Tomcata Zgodna ze standardami WS Możliwość instalowania usług Użytkownicy usług łączą się przez serwer
Instalacja Axis Katalog webapps/axis do katalogu webapps Dostępny przez: http://localhost:8080/axis Opis usługi: axis/usluga?wsdl Uruchomienie usługi przez protokół SOAP Klient wysyła zgłoszenie i odbiera dokument XML z odpowiedzią
Możliwości użycia Klasy *.jws automatycznie przekształcane w Web Serwisy Tworzenie serwisu i deskryptora pliku WSDD opisującego co udostępnić
Calculator.jws public class Calculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } }
Użycie w programie // odczyt parametrów String endpoint = "http://localhost:8080/axis/calculator.jws"; String method = args[0]; if (!(method.equals("add") method.equals("subtract"))) { System.err.println("Usage: CalcClient <add subtract> arg1 arg2"); return; } Integer i1 = new Integer(args[1]); Integer i2 = new Integer(args[2]);
Użycie w programie //ustawienie zapytania call.settargetendpointaddress( new java.net.url(endpoint) ); call.setoperationname( method ); call.addparameter( "op1", XMLType.XSD_INT, ParameterMode.IN ); call.addparameter( "op2", XMLType.XSD_INT, ParameterMode.IN ); call.setreturntype( XMLType.XSD_INT ); // wysłanie zapytania i odbiór wyniku Integer ret = (Integer) call.invoke( new Object [] { i1, i2 }); System.out.println("Got result : " + ret);
Podsumowanie Web Services pozwalają na wymianę danych pomiędzy zupełnie różnymi aplikacjami Standard XML jest bardzo uniwersalny a przy tym prosty w obsłudze Dane zapisane w XML są jednak dłuższe ( przegadane )