Baza danych
Dla celów testowych i na “środowisku developerskim” (czytaj moim własnym komputerze) używam prostej bazy danych. Mam tu na myśli HyperSQL. Jest to baza danych, której zawartość może być trzymana wyłącznie w pamięci.
Tego typu rozwiązanie idealnie nadaje się do pracy na środowisku programistycznym. Często też bazy danych tego typu używane są w trakcie testów integracyjnych. W trakcie takich testów możliwe jest testowanie właściwej integracji z bazą danych.
Dostęp do tej bazy danych możliwy jest po dodaniu jednej linijki do konfiguracji Gradle
compile group: 'org.hsqldb', name: 'hsqldb', version: '2.4.0'
Jeśli chcesz dowiedzieć się czegoś więcej o samym Gradle zachęcam do przeczytania wprowadzenia do Gradle.
JPA i ORM
I tu wchodzą nam dwie wielkie kobyły ;). JPA czyli Java Persistence API i ORM czyli Object-Relational Mapping. JPA to specyfikacja, która została włączona do specyfikacji EJB (ang. Enterprise Java Beans). Specyfikacja ta określa mechanizmy, które pozwalają na “proste” zarządzanie zawartością bazy danych przez obiekty w Java.
Innymi słowy instancje klas odpowiadają wierszom w bazie danych. Mapowanie zawartości bazy danych na obiekty Javy to “mapowanie obiektowo-relacyjne” – ORM. Najszerzej stosowaną implementacją JPA jest Hibernate. To właśnie tę implementację użyłem w Pogodynce. Aby uzyskać wsparcie Hibernate niezbędne są następujące zależności:
compile group: 'org.hibernate', name: 'hibernate-entitymanager', version: '5.2.10.Final'
compile group: 'org.hibernate', name: 'hibernate-core', version: '5.2.10.Final'
ORM
Nie wchodząc w szczegóły samego JPA i Hibernate opiszę co udało mi się osiągnąć. Przy pomocy odpowiednich adnotacji w kodzie Javy mapuję obiekty klasy TemperatureMeasurement
na wiersze w tabeli temperature_measurements
. Całość wymagała kilku adnotacji w kodzie oraz dodatkowej konfiguracji, która pozwoliła na mapowanie typu DateTime na odpowiedni typ w bazie danych.
Jedyny obiekt modelu, który aktualnie jest dostępny wygląda następująco:
@Entity
@Table(name = "temperature_measurements",
indexes = @Index(name = "idx_temperature_measurements_when_meaasured",
columnList = "when_measured"))
public class TemperatureMeasurement {
@Id
@SequenceGenerator(name = "measurements_sequence", allocationSize = 5, sequenceName = "temperature_measurements_seq")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "measurements_sequence")
private Long id;
private BigDecimal temperature;
@Column(name = "when_measured")
private DateTime whenMeasured;
public TemperatureMeasurement() {
}
public TemperatureMeasurement(BigDecimal temperature, DateTime whenMeasured) {
this.temperature = temperature;
this.whenMeasured = whenMeasured
}
@NotNull
public BigDecimal getTemperature() {
return temperature;
}
@NotNull
public DateTime getWhenMeasured() {
return whenMeasured;
}
}
Warstwa dostępu do danych
Warstwa DAO (ang. Data Access Object) jest automatycznie generowana. Są to obiekty pośredniczące zarządzane przez Spring. Interfejs DAO, którym posługuję się w aplikacji sprowadza się do kilku linijek:
@Repository
public interface TemperatureMeasurementDAO extends CrudRepository<TemperatureMeasurement, Long> {
}
Taka “magia” dostępna jest dzięki użyciu Spring Data:
compile group: 'org.springframework.data', name: 'spring-data-jpa', version: '1.11.3.RELEASE
Magiczna konfiguracja Spring
Całość konfiguracji to jeden nowy plik. Tworzy on odpowiednie obiekty, które wymagane są przez specyfikację JPA
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "pl.samouczekprogramisty.pogodynka.datavault.model")
public class JPAConfigration {
@Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbc.JDBCDriver");
dataSource.setUrl("jdbc:hsqldb:mem:datavault_test");
dataSource.setUsername("datavault_test");
dataSource.setPassword("datavault_test");
return dataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(getDataSource());
entityManager.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManager.setPackagesToScan("pl.samouczekprogramisty.pogodynka.datavault.model");
Properties jpaProperties = new Properties();
jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
jpaProperties.setProperty("hibernate.show_sql", "true");
jpaProperties.setProperty("hibernate.format_sql", "true");
jpaProperties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
jpaProperties.setProperty("jadira.usertype.autoRegisterUserTypes", "true");
entityManager.setJpaProperties(jpaProperties);
return entityManager;
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
Podsumowanie
Dzisiaj mam “gotową” aplikację webową, która wystawia dwa adresy URL. Pozwalają one na utworzenie nowej instancji pomiaru temperatury i pobrania wszystkich istniejących pomiarów. Kolejnym krokiem będzie zaimplementowanie “logowania” użytkowników i wystawienia takiej aplikacji na świat. Następnie będę mógł zintegrować czujnik z tak działającą aplikacją.
Po kilku dniach działania aplikacji będę miał wystarczająco dużo rzeczywistych pomiarów temperatury, które pozwolą mi na pracę nad interfejsem użytkownika.
Jeśli chcesz zobaczyć aktualną wersję aplikacji możesz ją znaleźć na samouczkowym githubie. Trzymaj się i do następnego razu!
Pobierz opracowania zadań z rozmów kwalifikacyjnych
Przygotowałem rozwiązania kilku zadań algorytmicznych z rozmów kwalifikacyjnych. Rozkładam je na czynniki pierwsze i pokazuję różne sposoby ich rozwiązania. Dołącz do grupy ponad 6147 Samouków, którzy jako pierwsi dowiadują się o nowych treściach na blogu, a prześlę je na Twój e-mail.
Zostaw komentarz