====== Ogólnopolska baza połączeń minibusowych ====== Autorzy: **Jakub Gorzała, Łukasz Kowalski** ---- ===== 1. Sformułowanie zadania projektowego ===== Projekt bazy danych, która będzie wykorzystywana w projekcie z przedmiotu Technologie i programowanie WWW. Projekt ten ma na celu stworzenie portalu zawierającego rozkłady jazdy minibusów z całej polski. ===== 2. Analiza stanu wyjściowego ===== W sieci istnieje strona o podobnej tematyce, lecz posiada ona sporo wad. Po pierwsze jest wykonana w bardzo prostej technologii (zwykły html + css), jest nieczytelna przez co prezentuje się bardzo nie atrakcyjnie i nie wzbudza zainteresowania. Nie jest aktualizowana, więc informacje na niej zawarte mogą być mylące dla użytkowników. Strona w głównej mierze jest zbiorem linków do poszczególnych przewoźników, a nie centralnym zbiorem rozkładów, przez co wyszukiwanie interesującego połączenia jest trudne. Storna nie posiada możliwości wystawiania opinii ani komentarzy przewoźnikom, a takie informacje mogły by być przydatne. ===== 3. Analiza wymagań użytkownika (wstępna) ===== Główne funkcjonalności portalu: * zarejestrowanie nowej firmy przewozowej + podstawowych informacji adresowych * dodanie kursów oferowanych przez tą firmę * możliwość wyszukiwania kursów filtrując po przystankach z miejscowości A do B * możliwość dodania komentarzy dla poszczególnych firm przez użytkowników * moduł rejestracji użytkowników * dodawanie cen biletów na poszczególnych trasach * powiadomienia mailowe odnośnie nowych przewoźników w regionie bądź zmian w rozkładach jazdy ===== 4. Określenie scenariuszy użycia ===== - **Scenariusze dla Użytkownika** - Wyszukanie połączenia: * Wejście na stronę * Przejście na zakładkę 'Szukaj busa' * Wprowadzenie danych przystanku początkowego i końcowego * Podanie godziny odjazdu lub przyjazdu * Uruchomienie wyszukiwania i przeglądnięcie wyników - Założenie konta: * Wejście na stronę * Kliknięci w panel 'Rejestracja!' * Wprowadzenie danych użytkownika * Potwierdzenie założenia konta - **Scenariusze dla Użytkownika posiadającego firmę** - Założenie firmy * Wejście na stronę * Zalogowanie się * Kliknięcie w panel 'Dodaj firmę' * Wprowadzenie nazwy firmy oraz maila firmowego * Potwierdzenie dodania firmy - Wprowadzenie trasy * Wejście na stronę * Zalogowanie się * Wybranie zakładki 'Dodaj linię' * Wprowadzenie kolejnych przystanków, czasów odjazdu oraz cen biletów * Potwierdzenie dodania linii - Zarządzanie trasami * Wejście na stronę * Zalogowanie się * Wybranie zakładki 'Połączenia' * Edycja/usuwanie zdefiniowanych połączeń ===== 5. Identyfikacja funkcji ===== Baza danych będzie przechowywać informacje o: * kontach użytkowników * zarejestrowanych firmach * przystankach * zdefiniowanych połączeniach * opiniach o firmie ===== 6. Analiza hierarchii funkcji projektowanej aplikacji (FHD – Functional Hierarchy Diagram) ===== {{:pl:dydaktyka:ztb:2010:projekty:minibus:fhd.png|}} ===== 7. Budowa i analiza diagramu przepływu danych (DFD – Data Flow Diagram) ===== * Level 0 {{:pl:dydaktyka:ztb:2010:projekty:minibus:dfd_1.png|}} * Level 1 {{:pl:dydaktyka:ztb:2010:projekty:minibus:dfd_2.png|}} * Level 2 - Wyszukiwanie busa {{:pl:dydaktyka:ztb:2010:projekty:minibus:dfd_3_1.png|}} * Level 2 - Zarządzanie połączeniami {{:pl:dydaktyka:ztb:2010:projekty:minibus:dfd_3_2.png|}} * Level 2 - Dodawanie komentarza {{:pl:dydaktyka:ztb:2010:projekty:minibus:dfd_3_3.png|}} ===== 8. Wybór encji (obiektów) i ich atrybutów ===== @Entity @Table(name="COMPANIES") @NamedQueries({ @NamedQuery(name="findCompanyByName", query="SELECT c FROM Company c WHERE c.name = :name"), @NamedQuery(name="findCompanyByOwnerName", query="SELECT c FROM Company c WHERE c.owner.name = :name") }) public class Company implements Serializable { private static final long serialVersionUID = 5074588959885714521L; @GeneratedValue(strategy=GenerationType.AUTO) private long companyid; @Column(nullable=false) private String name; @Column(nullable=false) private String mail; @ManyToOne private User owner; @OneToMany(mappedBy="company", targetEntity=Opinion.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private Set opinions; @OneToMany(mappedBy="owner", targetEntity=Course.class, cascade=CascadeType.ALL, fetch=FetchType.LAZY) private Set courses; } @Entity @Table(name="COURSES") @NamedQuery(name="findCourseByCompany", query="SELECT c FROM Course c WHERE c.owner.name = :name") public class Course implements Serializable { private static final long serialVersionUID = 3008699718560976506L; @GeneratedValue(strategy=GenerationType.AUTO) private long courseid @OneToOne private Company owner; @Column(nullable=true) private String description; @OneToMany(mappedBy="course", targetEntity=Stop.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private List stops; } @Entity @Table(name="OPINIONS") @NamedQuery(name="findOpinionByCompany", query="SELECT o FROM Opinion o WHERE o.company.name = :name") public class Opinion implements Serializable { private static final long serialVersionUID = 2475121744579807544L; @GeneratedValue(strategy=GenerationType.AUTO) private long opinionid; @ManyToOne private Company company; @Column(nullable=true) private boolean positive; @Column(nullable=true) private String description; } @Entity @Table(name="PLACES") @NamedQueries({ @NamedQuery(name="findPlaceByName", query="SELECT p FROM Place p WHERE p.city = :city AND p.name = :name"), @NamedQuery(name="autocompletePlace", query="SELECT p FROM Place p WHERE p.city LIKE :city AND p.name LIKE :name"), @NamedQuery(name="autocompletePlaceByCity", query="SELECT p FROM Place p WHERE p.city LIKE :city"), @NamedQuery(name="autocompletePlaceByName", query="SELECT p FROM Place p WHERE p.name LIKE :name") }) public class Place implements Serializable { private static final long serialVersionUID = 7561920390812143011L; @GeneratedValue(strategy=GenerationType.AUTO) private long placeid; @Column(nullable=false) private String city; @Column(nullable=false) private String name; @Column(nullable=true) private BigDecimal lon; @Column(nullable=true) private BigDecimal lat; } @Entity @Table(name="STOPS") @NamedQuery(name="findStopByPlace", query="SELECT s FROM Stop s WHERE s.place.city = :city and s.place.name = :name") public class Stop implements Serializable { private static final long serialVersionUID = 2015220800633676479L; @GeneratedValue(strategy=GenerationType.AUTO) private long stopid; @ManyToOne private Course course; @OneToOne private Place place; @Column(nullable=false) private int orderNumber; @Column(nullable=true) private BigDecimal cost; @Column(nullable=true) private String hours; } @Entity @Table(name="USERS") public class User implements Serializable { private static final long serialVersionUID = 8651753619995718647L; @GeneratedValue(strategy=GenerationType.AUTO) private long userid; @Column(nullable=false) private String name; @Column(nullable=false) private String password; @Column(nullable=false) private String mail; @Column(nullable=false) private int role = 1; @OneToMany(mappedBy="owner", targetEntity=Company.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private Set companies; } ===== 9. Projektowanie powiązań (relacji) pomiędzy encjami (ERD) ===== {{:pl:dydaktyka:ztb:2010:projekty:minibus:erd2.png|}} ===== 10. Projekt diagramów STD (State Transition Diagram) ===== * Wyszukiwanie busa {{:pl:dydaktyka:ztb:2010:projekty:minibus:std1.png|}} * Dodawanie połączenia {{:pl:dydaktyka:ztb:2010:projekty:minibus:std2.png|}} ===== 11. Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów ===== CREATE TABLE companies ( id bigint NOT NULL, "name" character varying(255) NOT NULL, mail character varying(255) NOT NULL, owner_id bigint, CONSTRAINT companies_pkey PRIMARY KEY (id), CONSTRAINT fk51e1f1bbedbce178 FOREIGN KEY (owner_id) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE courses ( id bigint NOT NULL, description character varying(255), hours character varying(255), owner_id bigint, CONSTRAINT courses_pkey PRIMARY KEY (id), CONSTRAINT fk63e4af986eae0d5e FOREIGN KEY (owner_id) REFERENCES companies (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE opinions ( id bigint NOT NULL, positive boolean, description character varying(255), company_id bigint, CONSTRAINT opinions_pkey PRIMARY KEY (id), CONSTRAINT fk176ead31d905f754 FOREIGN KEY (company_id) REFERENCES companies (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE places ( id bigint NOT NULL, city character varying(255) NOT NULL, "name" character varying(255) NOT NULL, lon numeric(19,2), lat numeric(19,2), CONSTRAINT places_pkey PRIMARY KEY (id) ) CREATE TABLE stops ( id bigint NOT NULL, ordernumber integer NOT NULL, "cost" numeric(19,2), lag numeric(19,2), place_id bigint, course_id bigint, CONSTRAINT stops_pkey PRIMARY KEY (id), CONSTRAINT fk4b9009137509994 FOREIGN KEY (place_id) REFERENCES places (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT fk4b90091894e45e0 FOREIGN KEY (course_id) REFERENCES courses (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE users ( id bigint NOT NULL, "name" character varying(255) NOT NULL, "password" character varying(255) NOT NULL, mail character varying(255) NOT NULL, "role" integer NOT NULL, CONSTRAINT users_pkey PRIMARY KEY (id) ) CREATE SEQUENCE hibernate_sequence INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1; ===== 12. Analiza zależności funkcyjnych i normalizacja tabel ===== Wydaje się, że baza danych spełnia założenia 3NF. Wynika to z faktu, że przechowywane w niej dane są istnotnie atomiczne - z punktu widzenia implementacji projektu. W każdej tabeli atrybuty są w pełni bezpośrednio zależne od klucza głównego. Generalnie baza była projektowana tak by przy możlie maksymalnej funkcjonalności tabel, zapewnić trzecią postać normalną. ===== 13. Projektowanie operacji na danych ===== Kwerendy i zapytania wynikają z mechanizmu mapowania obiektowo relacyjnego w j2ee i są poniekąd dostarczone przez klasę EntityManager standardu JPA Hibernate. Pozostałe zapytania w celu optymalizacji wydajności pracy aplikacji zrealizowane zostały jako NamedQuery - zapytania prekompilowane i stworzone przy użyciu składni HQL - Hibernate Query Language. Można je zobaczyć nad kodem encji do których przynależą. ===== RAPORT KOŃCOWY ===== ===== 14. Stos technologiczny ===== Aplikacja zrealizowana jest na bazie wzorca projektowego MVC (model widok kotroller). Sklada sie z 3 wyraznie wyrożnionych warstw: * baza danych - Postrgres 8.3, Mapowanie relacyjno obiektowe standard Java JPA Persistence * logika biznesowa - Zrealizowana za pomocą technologii EJB 3.0 * widok - Zrealizowany za pomocą JSF (java server faces 1.2) z nakładką jQery oraz jQueryUI ===== 15. Implementacja bazy danych ===== Patrz punkt 11. Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów. ===== 16. Zdefiniowanie interfejsów do prezentacji, edycji i obsługi danych ===== -formularz rejestracji użytkownika {{:pl:dydaktyka:ztb:2010:projekty:minibus:rejestracja1.png|}} -formularz logowania użytkownika {{:pl:dydaktyka:ztb:2010:projekty:minibus:logowanie1.png|}} -formularz zakładania firmy przez użytkownika {{:pl:dydaktyka:ztb:2010:projekty:minibus:dodawanie_firmy1.png|}} -formularz edycji danych użytkownika {{:pl:dydaktyka:ztb:2010:projekty:minibus:moje_dane.png|}} -formularz dodawania komentarzy {{:pl:dydaktyka:ztb:2010:projekty:minibus:komentarze1.png|}} -formularz dodawania połączenia {{:pl:dydaktyka:ztb:2010:projekty:minibus:dodawanie_polaczenia1.png|}} -formularz wyszukiwania połączeń {{:pl:dydaktyka:ztb:2010:projekty:minibus:wyszukiwanie1.png|}} ===== 17. Zdefiniowanie dokumentów do przetwarzania i prezentacji danych ===== -prezentacja wyników wyszukiwania {{:pl:dydaktyka:ztb:2010:projekty:minibus:wyszukiwanie1.png|}} -prezentacja dodanej trasy {{:pl:dydaktyka:ztb:2010:projekty:minibus:dodawanie_polaczenia2.png|}} -prezentacja aktualnosci {{:pl:dydaktyka:ztb:2010:projekty:minibus:aktualnosci1.png|}} -prezentacja komentarzy {{:pl:dydaktyka:ztb:2010:projekty:minibus:komentarze1.png|}}