Tworzenie tabel w MySQL

Aby rozpocząć tworzenie tabel, najpierw należy utworzyć bazę danych. Opis jak wykonać takie zadanie w MySQL jest w artykule Tworzenie bazy danych MySQL. Gdy mamy już utworzoną naszą bazę danych możemy przystąpić to tworzenia tabel. Samo tworzenie tabel nie powinno sprawić problemu pod warunkiem, że rozumiemy jak prawidłowo stworzyć tabele w naszym projekcie. W tej kwestii często potrzebne jest doświadczenie. Jednak jak zdobyć takie doświadczenie najlepiej zacznijmy od podstaw. W artykule Jak zrozumieć bazę danych tłumaczę jak przełożyć plik Excel na bazę danych na przykładzie MySQL. Dzięki temu można łatwiej zrozumieć różnicę między arkuszem a bazą danych.

Jeżeli już udało się nam stworzyć projekt na papierze naszej bazy danych, możemy przystąpić do budowy w naszej bazie. Oczywiście nie zniechęcaj się jeżeli za pierwszym razem się nie uda i sam dojdziesz do wniosku, że baza jest pokraczna. Każdy z nas tak właśnie zaczynał i każdy popełniał te same błędy, dopóki nie nabrał trochę doświadczenia.

W tym artykule stworzymy bardzo prostą bazę danych z dwiema tabelami z jedną relacją jeden do wielu. W tej chwili nie będę się skupiał na relacjach, ale jest to ta najtrudniejsza rzecz do zrobienia przy projektowaniu bazy danych.

Pierwsza tabela będzie się nazywała Word i będzie zawierać wszystkie słowa angielskie oraz tłumaczenia polskie do tego słowa, których się uczymy. Drugą tabelą będzie tabela Learn i będzie zawierać wszystkie wpisy, kiedy powtarzaliśmy dane słowo. Wiadomo, że słowo w całej bazie powinno występować tylko raz. Natomiast powtarzanie występuje wiele razy. To właśnie jest relacja jeden to wielu. Jednak taka relacja nie oznacza, że wpisów do tabeli Learn jest wiele. Może tak się zdarzyć, że nie będzie go wcale. Może być taka sytuacja, że możemy chcieć wpisać słowo, którego jeszcze nie powtarzaliśmy, ale chcemy to zrobić za parę dni. Jest to jak najbardziej poprawne.

CREATE TABLE `Word` (
  `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `createDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `word_en` varchar(100) CHARACTER SET utf8 NOT NULL,
  `word_pl` varchar(100) CHARACTER SET utf8 NOT NULL,
  `learned` bit(1) NOT NULL DEFAULT b'0'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_polish_ci

Opisujemy teraz co się tu dzieje. Pierwsza kolumna to kolumna id, jest to automatyczna wartość wiersza nadawana automatycznie po dodaniu wpisu do bazy. Jest to tak zwany klucz główny dla danej tabeli. Powinien występować w każdej tabeli.

Drugą kolumną jest createDate, czyli data utworzenia wpisu. Teoretycznie taka data nie jest potrzebna i bardzo często nigdzie nie jest prezentowana, ale ja ją zawsze dodaje z tego powodu, aby mieć możliwość sprawdzenia kiedy dany wpis do bazy został dodany. Drugą kolumną, która można utworzyć jest updateDate. Jest to również data, ale ostatniej aktualizacji danych. Przydaje się to często gdy ktoś z pracowników upiera się, że dane zostały zmienione, a faktycznie nic takiego nie nastąpiło. Ja tutaj pomijam tę kolumnę.

Word_pl i word_en standardowo przechowują słowa o długości stu znaków. W pierwszym z nich przechowujemy słowo polskie a w drugim słowo w wersji angielskiej.

Ostania kolumna to learned. Kolumna ta przechowuje informację czy dane słowo jest już nauczone, czy nie. Możemy oczywiście zbudować kolejną tabelę, gdzie będziemy przechowywać odpowiednie statusy, ale w tym artykule chce zachować prostotę, aby był lepiej zrozumiały dla początkujących.

Końcowe wpisy konfigurują nam samą tabelę. Te wpisy są z reguły standardowe dla każdej tabeli.

Teraz zobaczmy drugą tabelę Learn.

CREATE TABLE `Learn` (
  `id` bigint NOT NULL AUTO_INCREMENT <meta http-equiv="content-type" content="text/html; charset=utf-8">PRIMARY KEY,
  `idWord` bigint NOT NULL,
  `createDate` datetime DEFAULT CURRENT_TIMESTAMP,
  KEY `Science_idWord_index` (`idWord`),
  CONSTRAINT `Science_Word_id_fk` FOREIGN KEY (`idWord`) REFERENCES `Word` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_polish_ci

Tutaj podobnie jak we wcześniejszej tabeli mamy id, który już wcześniej opisałem więc nie będę tego robił ponownie

Jest również kolumna createDate, która w tym przypadku wskazuje kiedy został dodany dany wpis, ale jednocześnie kiedy słowo zostało powtórzone. Z taką konstrukcją może być problem, jeżeli chcemy dodać wpis z opóźnieniem. Wtedy daty nie będą się pokrywały. W takiej sytuacji trzeba by było stworzyć dodatkową kolumnę, gdzie będziemy przechowywać datę nauki a createDate zostawić tylko jako data wpisu. W naszym przypadku data wpisu i data nauki muszą być zawsze takie same.

Teraz zajmiemy się relacją. Na relacje składa się aż trzy wpisy

`idWord` bigint NOT NULL,
KEY `Science_idWord_index` (`idWord`),
CONSTRAINT `Science_Word_id_fk` FOREIGN KEY (`idWord`) REFERENCES `Word` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

Pierwszy wpis to idWord, który tworzy kolumnę, w którym przechowujemy informacje o relacji. Jest to tak zwany klucz obcy. Czyli numer, który znajdziemy w tej kolumnie, będzie odpowiadał kolumnie id w tabeli Word. Dzięki temu możemy powiązać te dwie tabele.

Aby przyśpieszyć wyszukiwanie, ustawiamy KEY, czyli tworzymy indeks dla klucza obcego.

Ostatni element to poinformowanie bazy danych o relacji. My możemy tego nie robić, ale wtedy jesteśmy narażeni na niespójność danych. Przykładowo tworzymy sobie w tabeli Word jeden wpis. Czyli mamy wiersz z kluczem głównym id o numerze jeden, ale przez pomyłkę w tabeli Learn w idWord dajemy 2. Jeżeli nie dodamy tego wpisu do tabeli, to baza danych pozwoli nam to zapisać, ale ten wpis nie będzie powiązany z tabelą Word. Jeżeli wpis zostanie wprowadzony, to w takiej sytuacji baza danych zwróci błąd. Dzięki temu w tabeli nie będzie pustych wpisów niepowiązanych z tabelą Word. Dodatkowym argumentem za tym, aby stosować takie rozwiązanie, jest to, że taki błąd bardzo łatwo można znaleźć podczas tworzenia projektu i go poprawić, więc koszt jest dużo mniejszy.

Zaszufladkowano do kategorii Baza danych, MySQL, SQL | Otagowano , , | Dodaj komentarz

Tworzenie bazy danych MySQL

Pierwszym etapem tworzenia nowego projektu w jakimkolwiek języku jest stworzenie bazy danych. Możemy korzystać z baz SQL i NoSQL. My w tym artykule zajmiemy się SQL a dokładniej MySQL. Po utworzeniu bazy danych dopiero kolejnym krokiem jest stworzenie odpowiednich tabel, w których będziemy mogli przechowywać nasze dane. Możemy oczywiście stworzyć kilka baz danych w zależności od naszych potrzeb.

Aby przystąpić do tworzenia bazy danych najpierw w naszym systemie należy zainstalować MySQL w wersji jaka będzie nam potrzeba. Ten proces jest bardzo mocno uzależniony od systemu operacyjnego używanego na sprzęcie na którym chcemy wykonać taką operację i właśnie z tego powodu nie będę go tu opisywał. Google służy pomocą w tej kwestii.

Gdy mamy zainstalowaną i uruchomioną bazę danych wykonujemy kolejne kroki:

  1. Logujemy się do naszego MySQL poleceniem:
mysql -u root -p    

Po prawidłowym zalogowaniu otrzymujemy tak zwany znak zachęty który świadczy że operacja została wykonana prawidłowo.

mysql>

Teraz przechodzimy do tworzenia bazy danych oraz użytkownika. W pierwszej kolejności utworzymy bazę danych o nazwie language:

Tworzenie bazy danych

Następnie tworzymy użytkownika wraz z hasłem. Użytkownik będzie się nazywał tak samo ja baza danych i powiadał hasło maSbDmxnBXMLy54

create user language identified by 'maSbDmxnBXMLy54';

Teraz zostało nam powiązanie bazy danych z użytkownikiem

GRANT ALL PRIVILEGES ON language.* TO language WITH GRANT OPTION;

I już możemy opuścić konsole MySQL, nie zapominając o odświeżeniu serwera baz danych poleceniami.

commit;
flush privileges;
exit

Baza danych jest gotowa i można tworzyć tabele. Jak to zrobimy, to zależy od nas. Można skorzystać z gotowych narzędzi DBeaver i tam wy klikać sobie całą tabelę lub samemu stworzyć zapytanie do tworzenia tabel. Takie zapytanie do tworzenia tabel możemy również uruchamiać w DBeaver lub jak powyżej w linii poleceń bazy danych. To który sposób wybierzemy, zależy od nas. Jednak ja polecam DBeaver

Zaszufladkowano do kategorii Baza danych, MySQL, SQL | Otagowano , , | Możliwość komentowania Tworzenie bazy danych MySQL została wyłączona

Rozliczenie pojazdu REST JPA

Rozliczenie pojazdu REST, JPA, MySQL. To ostatni opisany przeze mnie sposób na komunikację z bazą danych. Jest to najczęściej wykorzystywana metodą do komunikacji z bazą danych i jednocześnie najszybsza. Wielu programistów używa jej na co dzień, ponieważ automatyzuje wiele elementów budowy projektu. Jest to metoda najbardziej wydajna, jeżeli wiesz, co robisz. Według mnie na początku nauki nie powinno się zaczynać od JPA, gdyż zbyt wiele rzeczy dzieje się tu automatycznie i dopóki działa, jest ok. Jednak gdy przestaje, brak doświadczenia utrudnia znalezienie rozwiązania. Tak jak w poprzednich dwóch projektach projekt wykorzystuje wzorzec projektowy REST API i stworzona aplikacja pozwalające na komunikację klient – server. Tak samo, jak w artykule Rozliczenie pojazdu REST MyBatis i Rozliczenie pojazdu REST JDBC nie będzie to w pełni działająca aplikacja. Pozwoli to porównać, jakie należy wprowadzić zmiany w zależności od wybranego sposobu komunikacji z bazą danych.

Rozliczenie pojazdu REST JPA – Tworzymy projekt

Zacznijmy od stworzenia nowego projektu. Na początku wejdę na stronę https://start.spring.io/, gdzie utworzę nasz projekt. W moim przypadku będzie on wyglądał następująco.

Rozliczenie pojazdu REST JPA – Budowa projektu

Konfiguracja projektu

W pierwszej kolejności będziemy dodawać odpowiednie biblioteki, dzięki którym w naszym projekcie będzie można korzystać z REST, JPA oraz MySQL. Przechodzimy do pliku pom.xml i dodajemy do sekcji dependences następujące elementy.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

Pierwsze dwie sekcje dependencji informuje Spring, że ta aplikacja ma być aplikacją webową, czyli po jej uruchomieniu ma ciągle nasłuchiwać w oczekiwaniu na żądania. Trzecią to sterownik bazy danych MySQL. Czwarta dodaje bibliotekę JPA. Jak widać porównując plik pom.xml ze wszystkich trzech wersji zmieniamy tylko jeden wpis w dependecji i zmienia się użyty mechanizm komunikacji z bazą danych.

Konfiguracja w pliku property jest jednakowa dla wszystkich trzech wersji, ponieważ korzystamy z tej samej bazy danych.

spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://localhost:3306/transportMyBatis?serverTimezone=UTC
spring.datasource.username=transportMyBatis
spring.datasource.password=transportMyBatis

logging.file.name=log/transportJPA.log
server.address=localhost
server.port=8092
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl

Różnica jest tylko w dwóch ostatnich wpisach, które są specyficzne dla JPA.

Teraz zaczynamy wykorzystywać JPA.

W przypadku JPA tworzymy tylko interfejs TransportRepository i to wszystko. Nie piszmy żadnych pytań, jedynie na podstawie nazw metod i adnotacji system automatycznie tworzy zapytanie i je wykonuje. Dlatego gdy wiemy, co robimy, jest to bardzo szybka i przyjemna metoda. Jednak przy braku doświadczenia jest ciężko zrozumieć, co jest nie tak z nazwą.

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.common.Ride;

import java.util.List;

@Repository
public interface TransportRepository extends JpaRepository<Ride, Long> {
    List<Ride> findByVehicleId(long vehicleId);
    Ride findByVehicleIdAndId(long vehicleId, long rideId);
}

To wystarczy do komunikacji z bazą danych. Teraz musimy podłączyć to do naszego kontrolera. Robimy to w następujący sposób:

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.common.Ride;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.common.Settlement;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.repository.TransportRepository;

import java.util.List;

@RestController
public class TransportController {
    private final static Logger log = LoggerFactory.getLogger(TransportController.class);
    private final TransportRepository transportRepository;

    @Autowired
    public TransportController(TransportRepository transportRepository) {
        this.transportRepository = transportRepository;
    }

    @GetMapping("/")
    public String getTest() {
        return "Działa JPA";
    }

    @GetMapping("/vehicle/{vehicleId}/rides")
    public List<Ride> getRides(@PathVariable("vehicleId") long vehicleId) {
        log.info("Wyświetlamy listę przejazdów");
        List<Ride> rides = transportRepository.findByVehicleId(vehicleId);
        rides.forEach(this::getGenerateRide);
        return rides;
    }
    @GetMapping("vehicle/{vehicleId}/ride/{rideId}")
    public Ride getRide(@PathVariable("vehicleId") long vehicleId, @PathVariable("rideId") long rideId) {
        log.info("Wyświetlamy przejazd");
        Ride ride = transportRepository.findByVehicleIdAndId(vehicleId, rideId);
        getGenerateRide(ride);
        return ride;
    }

    private void getGenerateRide(Ride ride) {
        List<Settlement> settlements = ride.getSettlements();
        double fuel = 0.0;
        double price = 0.0;
        if(!settlements.isEmpty()) {
            for (Settlement settlement : settlements) {
                fuel = fuel + settlement.getFuel();
                if(settlement.getRefuel()!=null)
                price = settlement.getRefuel().getPrice();
            }
        }
        ride.setFuel(fuel);
        ride.setPrice(price);
        ride.setCurrency(fuel * price);
    }
}

I to wystarczy do komunikacji z bazą danych, ponieważ taki krótki zapis pozwala na stworzenie naszej prostej aplikacji. Schody się zaczynają, gdy potrzebujemy je pobrać z wielu tabel i chcemy to zrobić w bardzo specyficzny sposób.

Teraz klasy dodatkowe JPA.

Pokażemy jeszcze, pozostałe pliki, pierwszy z nich to Ride

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.common;

import javax.persistence.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "Ride")
public class Ride {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(name = "idVehicle")
    private long vehicleId;
    private LocalDate rideDate;
    private int counterBefore;
    private int counterAfter;
    private int km;
    private String whence;
    private String where;
    private String rideKind;
    private double fuelCondition;
    private double fuelAdd;
    private double fuelAfter;
    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "idRide")
    private List<Settlement> settlements = new ArrayList<>();
    @Transient
    private Double fuel;
    @Transient
    private Double price;
    @Transient
    private Double currency;
    private double fuelNorm;

    public Ride() {}

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public LocalDate getRideDate() {
        return rideDate;
    }

    public void setRideDate(LocalDate rideDate) {
        this.rideDate = rideDate;
    }

    public int getCounterBefore() {
        return counterBefore;
    }

    public void setCounterBefore(int counterBefore) {
        this.counterBefore = counterBefore;
    }

    public int getCounterAfter() {
        return counterAfter;
    }

    public void setCounterAfter(int counterAfter) {
        this.counterAfter = counterAfter;
    }

    public int getKm() {
        return km;
    }

    public void setKm(int km) {
        this.km = km;
    }

    public String getWhence() {
        return whence;
    }

    public void setWhence(String whence) {
        this.whence = whence;
    }

    public String getWhere() {
        return where;
    }

    public void setWhere(String where) {
        this.where = where;
    }

    public String getRideKind() {
        return rideKind;
    }

    public void setRideKind(String rideKind) {
        this.rideKind = rideKind;
    }

    public double getFuelCondition() {
        return fuelCondition;
    }

    public void setFuelCondition(double fuelCondition) {
        this.fuelCondition = fuelCondition;
    }

    public double getFuelAdd() {
        return fuelAdd;
    }

    public void setFuelAdd(double fuelAdd) {
        this.fuelAdd = fuelAdd;
    }

    public double getFuelAfter() {
        return fuelAfter;
    }

    public void setFuelAfter(double fuelAfter) {
        this.fuelAfter = fuelAfter;
    }

    public Double getFuel() {
        return fuel;
    }

    public void setFuel(Double fuel) {
        this.fuel = fuel;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Double getCurrency() {
        return currency;
    }

    public void setCurrency(Double currency) {
        this.currency = currency;
    }

    public double getFuelNorm() {
        return fuelNorm;
    }

    public void setFuelNorm(double fuelNorm) {
        this.fuelNorm = fuelNorm;
    }

    public List<Settlement> getSettlements() {
        return settlements;
    }

    public void setSettlements(List<Settlement> settlements) {
        this.settlements = settlements;
    }
}

W tym przypadku jak widać w kodzie tej klasy, muszę pokazać jeszcze dwie klasy:

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.common;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@Table(name = "Settlement")
public class Settlement {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(name = "idVehicle")
    private long vehicleId;
    @Column(name = "idRide")
    private long rideId;
    @Column(name = "idRefuel")
    private long refuelId;
    private LocalDate createDate;
    private double fuel;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "idRefuel", referencedColumnName = "id", insertable = false, updatable = false)
    private Refuel refuel;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public long getVehicleId() {
        return vehicleId;
    }

    public void setVehicleId(long vehicleId) {
        this.vehicleId = vehicleId;
    }

    public long getRideId() {
        return rideId;
    }

    public void setRideId(long rideId) {
        this.rideId = rideId;
    }

    public long getRefuelId() {
        return refuelId;
    }

    public void setRefuelId(long refuelId) {
        this.refuelId = refuelId;
    }

    public LocalDate getCreateDate() {
        return createDate;
    }

    public void setCreateDate(LocalDate createDate) {
        this.createDate = createDate;
    }

    public double getFuel() {
        return fuel;
    }

    public void setFuel(double fuel) {
        this.fuel = fuel;
    }

    public Refuel getRefuel() {
        return refuel;
    }

    public void setRefuel(Refuel refuel) {
        this.refuel = refuel;
    }
}
package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa.common;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@Table(name = "Refuel")
public class Refuel {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @Column(name = "idVehicle")
    private long vehicleId;
    @Column(name = "idRide")
    private long rideId;
    private LocalDate createDate;
    private LocalDate refuelDate;
    private String name;
    private int counterBefore;
    private int counterAfter;
    private int km;
    private double refuel;
    private double price;
    private double value;
    private double fuelNorm;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public long getVehicleId() {
        return vehicleId;
    }

    public void setVehicleId(long vehicleId) {
        this.vehicleId = vehicleId;
    }

    public long getRideId() {
        return rideId;
    }

    public void setRideId(long rideId) {
        this.rideId = rideId;
    }

    public LocalDate getCreateDate() {
        return createDate;
    }

    public void setCreateDate(LocalDate createDate) {
        this.createDate = createDate;
    }

    public LocalDate getRefuelDate() {
        return refuelDate;
    }

    public void setRefuelDate(LocalDate refuelDate) {
        this.refuelDate = refuelDate;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getCounterBefore() {
        return counterBefore;
    }

    public void setCounterBefore(int counterBefore) {
        this.counterBefore = counterBefore;
    }

    public int getCounterAfter() {
        return counterAfter;
    }

    public void setCounterAfter(int counterAfter) {
        this.counterAfter = counterAfter;
    }

    public int getKm() {
        return km;
    }

    public void setKm(int km) {
        this.km = km;
    }

    public double getRefuel() {
        return refuel;
    }

    public void setRefuel(double refuel) {
        this.refuel = refuel;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public double getValue() {
        return value;
    }

    public void setValue(double value) {
        this.value = value;
    }

    public double getFuelNorm() {
        return fuelNorm;
    }

    public void setFuelNorm(double fuelNorm) {
        this.fuelNorm = fuelNorm;
    }
}

W porównaniu do wcześniejszych artykułów tym razem bardziej opieramy nasze klasy o adnotację, ponieważ to właśnie adnotacje informują system, w jaki sposób ma pobrać dane z tabeli i jak je połączyć.

@IDAdnotacja informująca system ze ta kolumna to klucz główny
@EntityAdnotacja informuje system że ta klasa jest powiązana z tabelą w bazie danych.
@Table(name = „Refuel”)Tu ustawiamy nazwę powiązanej tabeli.
@GeneratedValue(strategy = GenerationType.AUTO)Ustawiamy jak będzie generowany klucz główny
@Column(name = „idVehicle”)Ustawiamy nazwę kolumny w tabeli. W niektórych przypadkach nie musimy tego ustawiać jeżeli nazwy są takie same.
@OneToMany(fetch = FetchType.LAZY)Informujemy, że ta zmienna jest relacją jeden do wielu. Czyli do klasy w której znajdziemy taki zapis może być powiązane więcej niż jedna klasa lub wcale.
@OneToOne(cascade = CascadeType.ALL)Informujemy o tym że dla klasy w której jest przypisany ten wpis jest ona powiązana tylko jedna klasa lub wcale.
@JoinColumn(name = „idRide”)Informujemy o konfiguracji naszej relacji. Ustawiamy nazwę kolumny powiązanej i wiele innych rzeczy.
Tabela adnotacji

Zapraszam do zgłębienia tematu adnotacji, ponieważ ja w tym artykule opisałem je bardzo pobieżnie. Jednak to właśnie adnotacje odpowiadają za prawidłowe działanie JPA, dlatego bez tej wiedzy nie ma co rozpoczynać przygody z JPA.

Jeszcze jeden element od pokazania mianowicie główny plik projektu, który jest bardzo prosty.

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@SpringBootApplication
public class RozliczeniePojazduRestJpaApplication {

    public static void main(String[] args) {
        SpringApplication.run(RozliczeniePojazduRestJpaApplication.class, args);
    }
}

Tak wygląda cała aplikacja z wykorzystaniem JPA. Pozostało nam wszystko przetestować i powinno działać. Jeżeli jednak nie działa, warto podejrzeć, jak ja to zrobiłem. Zapraszam na mojego GitHub pod adresem:

https://github.com/grzegorzkossa/rozliczenie_pojazdu_rest_jpa

Zaszufladkowano do kategorii Rozliczenie pojazdu | Otagowano , , | Dodaj komentarz

Rozliczenie pojazdu REST JDBC

Rozliczenie pojazdu REST, JDBC, MySQL. Zaczynamy drugi projekt z wykorzystaniem wcześniej zbudowanej bazy danych. Jest to prostsza wersja komunikacji z bazą danych wbudowana w Spring Boot. Zaletą jest prostota budowy zapytań, jednak wadą jest fakt, że nie da się jej zastosować do bardziej wymagających zapytań. Jednak w naszym prostym projekcie zupełnie wystarczy. Tak jak w przypadku pierwszego projektu wykorzystamy wzorzec projektowy REST API i stworzymy aplikację pozwalające na komunikację klient – server. Tak samo, jak w artykule Rozliczenie pojazdu REST MyBatis nie będzie to w pełni działająca aplikacja. Pozwoli to porównać, jakie należy wprowadzić zmiany w zależności od zastosowanego sposobu komunikacji z bazą danych. Część front end powstanie w innym artykule.

Rozliczenie pojazdu REST JDBC – Tworzymy projekt

Zacznijmy od stworzenia nowego projektu. Na początku wejdę na stronę https://start.spring.io/, gdzie utworzę nasz projekt. W moim przypadku będzie on wyglądał następująco.

Rozliczenie pojazdu REST JDBC – Budowa projektu

Konfiguracja projektu

W pierwszej kolejności będziemy dodawać odpowiednie biblioteki, dzięki którym w naszym projekcie będzie można korzystać z REST, JDBC oraz MySQL. Przechodzimy do pliku pom.xml i dodajemy do sekcji dependences następujące elementy.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

Pierwsze dwie sekcje dependencji informuje Spring, że ta aplikacja ma być aplikacją webową, czyli po jej uruchomieniu ma ciągle nasłuchiwać w oczekiwaniu na żądania. Trzecią to sterownik bazy danych MySQL. Czwarta dodaje bibliotekę JDBC. Jak porównamy wcześniejszy artykuł, zmiana jest tylko w ostatnim zapisie.

Kolejnym krokiem jest skonfigurowanie bazy danych. W tym celu edytujemy plik application.property i dodajemy odpowiednie linijki.

spring.datasource.url=jdbc:mysql://localhost:3306/transportMyBatis?serverTimezone=UTC
spring.datasource.username=transportMyBatis
spring.datasource.password=transportMyBatis

logging.file=log/transportMyBatis.log
server.port=8091

Jak widać, korzystamy z bazy danych stworzonych przy okazji wcześniejszego artykułu, jednak w tym przypadku nie ma to znaczenia.

Teraz zaczynamy wykorzystywać JDBC.

W przypadku JDBC tworzymy tylko klasę TransportDB w schemacie db. W klasie będziemy przechowywać wszystkie metody wraz z zapytaniami.

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc.db;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc.common.Ride;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TransportDB {
    private final static Logger log= LoggerFactory.getLogger(TransportDB.class);
    private final NamedParameterJdbcTemplate template;
    private final BeanPropertyRowMapper<Ride> rideMapper = BeanPropertyRowMapper.newInstance(Ride.class);

    public TransportDB(NamedParameterJdbcTemplate template) {
        this.template = template;
    }


    public List<Ride> getRides(long vehicleId) {
        log.info("List rides");
        return template.query(
                "SELECT r.id, r.rideDate, r.counterBefore, r.counterAfter, r.km, " +
                        "r.whence, r.`where`, r.rideKind, r.fuelCondition, r.fuelAdd, r.fuelAfter, " +
                        "SUM(s.fuel) as fuel, f.price, SUM(s.fuel*f.price) as currency, r.fuelNorm " +
                        "FROM transportMyBatis.Ride r " +
                        "LEFT JOIN transportMyBatis.Settlement  s on r.id = s.idRide " +
                        "LEFT JOIN transportMyBatis.Refuel f on f.id = s.idRefuel " +
                        "WHERE r.idVehicle = :vehicleId "+
                        "GROUP BY r.id, r.whence, r.`where`, r.rideKind, f.price " +
                        "ORDER BY r.id ",
                new MapSqlParameterSource("vehicleId", vehicleId), rideMapper);
    }

    public Ride getRide(long vehicleId,  long rideId) {
        log.info("Object ride");
        Map<String, String> map = new HashMap<>();
        map.put("vehicleId", Long.toString(vehicleId));
        map.put("rideId", Long.toString(rideId));
        return template.queryForObject(
                "SELECT r.id, r.rideDate, r.counterBefore, r.counterAfter, r.km, " +
                        "r.whence, r.`where`, r.rideKind, r.fuelCondition, r.fuelAdd, r.fuelAfter, " +
                        "SUM(s.fuel) as fuel, f.price, SUM(s.fuel*f.price) as currency, r.fuelNorm " +
                        "FROM transportMyBatis.Ride r " +
                        "LEFT JOIN transportMyBatis.Settlement  s on r.id = s.idRide " +
                        "LEFT JOIN transportMyBatis.Refuel f on f.id = s.idRefuel " +
                        "WHERE r.idVehicle = :vehicleId and r.id = :rideId " +
                        "GROUP BY r.id, r.whence, r.`where`, r.rideKind, f.price " +
                        "ORDER BY r.id",
                map, rideMapper);
    }
}

Uwaga: W razie problemów z bazą danych należy sprawdzić w każdym zapytaniu, czy na końcu linii jest pusty znak. Jeżeli go zabraknie, zapytanie się nie wykona.

To wystarczy do komunikacji z bazą danych. Teraz musimy podłączyć to do naszego kontrolera. Robimy to w następujący sposób:

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc.common.Ride;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc.db.TransportDB;

import java.util.List;

@RestController
public class TransportController {
    private final static Logger log = LoggerFactory.getLogger(TransportController.class);
    private final TransportDB transportDB;

    public TransportController(TransportDB transportDB) {
        this.transportDB = transportDB;
    }

    @GetMapping("/vehicle/{vehicleId}/rides")
    public List<Ride> getRides(@PathVariable("vehicleId") long vehicleId) {
        log.info("Wyświetlamy listę przejazdów");
        return transportDB.getRides(vehicleId);
    }
    @GetMapping("vehicle/{vehicleId}/ride/{rideId}")
    public Ride getRide(@PathVariable("vehicleId") long vehicleId, @PathVariable("rideId") long rideId) {
        log.info("Wyświetlamy przejazd");
        return transportDB.getRide(vehicleId, rideId);
    }
}

Jednak jest tu w porównaniu do artykułu z Rozliczenie pojazdu REST MyBatis mała zmiana. Wcześniej przy czytywaniu interfejsu TransportDAO używaliśmy @Autowired. Tym razem jednak robimy to przez konstruktor. Obie metody są dobre, ale ogólnie preferowana jest metoda przez konstruktor. Jest to związane przede wszystkim z testowaniem aplikacji. Dlatego teraz właśnie takie podejście zaprezentowałem.

Pokażemy jeszcze, jak wygląda klasa Ride:

public class Ride {
    private long id;
    private LocalDate rideDate;
    private int counterBefore;
    private int counterAfter;
    private int km;
    private String whence;
    private String where;
    private String rideKind;
    private double fuelCondition;
    private double fuelAdd;
    private double fuelAfter;
    private Double fuel;
    private Double price;
    private Double currency;
    private double fuelNorm;

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public LocalDate getRideDate() {
        return rideDate;
    }
    public void setRideDate(LocalDate rideDate) {
        this.rideDate = rideDate;
    }
    public int getCounterBefore() {
        return counterBefore;
    }
    public void setCounterBefore(int counterBefore) {
        this.counterBefore = counterBefore;
    }
    public int getCounterAfter() {
        return counterAfter;
    }
    public void setCounterAfter(int counterAfter) {
        this.counterAfter = counterAfter;
    }
    public int getKm() {
        return km;
    }
    public void setKm(int km) {
        this.km = km;
    }
    public String getWhence() {
        return whence;
    }
    public void setWhence(String whence) {
        this.whence = whence;
    }
    public String getWhere() {
        return where;
    }
    public void setWhere(String where) {
        this.where = where;
    }
    public String getRideKind() {
        return rideKind;
    }
    public void setRideKind(String rideKind) {
        this.rideKind = rideKind;
    }
    public double getFuelCondition() {
        return fuelCondition;
    }
    public void setFuelCondition(double fuelCondition) {
        this.fuelCondition = fuelCondition;
    }
    public double getFuelAdd() {
        return fuelAdd;
    }
    public void setFuelAdd(double fuelAdd) {
        this.fuelAdd = fuelAdd;
    }
    public double getFuelAfter() {
        return fuelAfter;
    }
    public void setFuelAfter(double fuelAfter) {
        this.fuelAfter = fuelAfter;
    }
    public Double getFuel() {
        return fuel;
    }
    public void setFuel(Double fuel) {
        this.fuel = fuel;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    public Double getCurrency() {
        return currency;
    }
    public void setCurrency(Double currency) {
        this.currency = currency;
    }
    public double getFuelNorm() {
        return fuelNorm;
    }
    public void setFuelNorm(double fuelNorm) {
        this.fuelNorm = fuelNorm;
    }
}

Jeszcze jeden element od pokazania mianowicie główny plik projektu trochę się zmienił, więc go prezentujemy.

package pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import pl.lomza.programowanie.rozliczenie_pojazdu_rest_jdbc.db.TransportDB;
import javax.sql.DataSource;

@SpringBootApplication
public class RozliczeniePojazduRestJdbcApplication {
	public static void main(String[] args) {
		SpringApplication.run(RozliczeniePojazduRestJdbcApplication.class, args);
	}
	@Bean
	public TransportDB transportDB(NamedParameterJdbcTemplate template){
		return new TransportDB(template);
	}
	@Bean
	public PlatformTransactionManager transactionManager(DataSource dataSource)
	{
		return new DataSourceTransactionManager(dataSource);
	}
}

Tak wygląda cała aplikacja z wykorzystaniem JDBC. Pozostało nam wszystko przetestować i powinno działać. Jeżeli jednak nie działa, warto podejrzeć, jak ja to zrobiłem. Zapraszam na mojego GitHub pod adresem:

https://github.com/grzegorzkossa/rozliczenie_pojazdu_rest_jdbc

To jednak nie koniec. W następnym artykule pokaże jak te samo zadanie wykonać przy wykorzystaniu JPA. Zapraszam do kolejnego artykułu.

Zaszufladkowano do kategorii Rozliczenie pojazdu | Możliwość komentowania Rozliczenie pojazdu REST JDBC została wyłączona

Jak zacząć przygodę z programowaniem

Jak zacząć przygodę z programowaniem. Takie pytanie stawia sobie wiele osób. Jednak samo programowanie nie jest czymś trudnym. Trudnością jest ilość wiedzy, jaką trzeba przyswoić, aby swobodnie poruszać się w świecie programowania.

Na przykład, aby rozpocząć pracę jako programista, trzeba wiedzieć, co to są zapytania SQL. Aplikacja z reguły zapisuje dane do jakiejś bazy danych. Gdy już to opanujemy, wybieramy język programowania. Wybór jest stosunkowo duży, ale wszystkie te języki są w pewnym stopniu podobne do siebie. Gdy opanujemy podstawy języka, na przykład Java przychodzi czas na Spring, dzięki któremu jesteśmy w stanie stworzyć działającą aplikację webową. Jednak gdy spojrzymy na samego spring i uświadomimy sobie, ile jest tam modułów, to bardzo szybko przychodzi pytanie „Po co mi to”, na które w tym momencie ciężko znaleźć odpowiedź

Więc jak zacząć przygodę z programowaniem

Dlatego naukę programowania trzeba zacząć od końca, a najlepiej od przykładów, które ściągamy z artykułów z gotowym kodem. Takie rozwiązanie daje dwie rzeczy. Po pierwsze możemy uruchomić aplikację, która zacznie działać, więc już zaczynamy, się bawić. Po drugie do takich projektów są również opisy, więc można czytać opis i szukać tego w kodzie. Daje to dużo lepsze możliwości nisz uczenie się na pamięć formułek, których nie rozumiemy.

Dopiero po analizie kilku gotowych projektów możemy spróbować stworzyć własny projekt. Ja w tej sytuacji polecam, aby to była aplikacja potrzebna w codziennym życiu lub pracy. Tak, aby po zbudowaniu jej mieć energie na ciągłą zmianę w projekcie i ulepszanie działania projektu.

Kiedy uczyć się teorii

Teoria według mnie może poczekać. Zaczynając od analizy gotowego kodu, warto również utrwalać nazewnictwo. Jeżeli nie możemy zapamiętać danego sformułowania od razy, zapiszmy go sobie i dzięki temu możemy za jakiś czas do niego wrócić, aby uzupełnić wiedzę. Jest to bardzo ważne zwłaszcza przy rozmowie kwalifikacyjnej, gdzie znajomość nazewnictwa branżowego jest podstawą do sukcesu.

Zaszufladkowano do kategorii Jak zacząć | Możliwość komentowania Jak zacząć przygodę z programowaniem została wyłączona

Rozliczenie pojazdu REST MyBatis

Rozliczenie pojazdu REST, MyBatis, MySQL. Zaczynamy pierwszy projekt z wykorzystaniem wcześniej zbudowanej bazy danych. Wykorzystamy do tego wzorzec projektowy REST API i stworzymy aplikację pozwalające na komunikację klient – server. Nie będzie to oczywiście w pełni działająca aplikacja, ponieważ zajmiemy się tylko back endem naszej aplikacji. Część front end powstanie w innym artykule. Takie podejście pozwoli nam na porównanie różnych sposobów tworzenia aplikacji, gdyż to będzie cykl artykułów tworzących tę samą funkcjonalność w zupełnie różny sposób.

Rozliczenie pojazdu REST MyBatis – Tworzymy projekt

Zacznijmy od stworzenia nowego projektu. Ja na co dzień pracuje z IntelliJ IDEA i mógłbym pokazać jak to zrobić przy wykorzystaniu tego narzędzia. Jednak mam świadomość, że część osób może wykorzystywać inne IDE, dlatego wykonam to w taki sposób, aby każdy mógł z tego skorzystać.

Na początku wejdę na stronę https://start.spring.io/, gdzie utworzę nasz projekt. W moim przypadku będzie on wyglądał następująco.

Rozliczenie pojazdu generowanie projektu REST MyBatis

Projekt możesz pobrać z mojego repozytorium, które jest pod adresem.

Rozliczenie pojazdu REST MyBatis – Budowa projektu

Konfiguracja projektu

Więc w pierwszej kolejności będzie dodanie odpowiednich bibliotek, dzięki którym w naszym projekcie będzie można korzystać z REST, MyBatis oraz MySQL. Przechodzimy do pliku pom.xml i dodajemy do sekcji dependences następujące elementy.

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

Pierwsza dependencja informuje Spring, że ta aplikacja ma być aplikacją webową, czy po jej uruchomieniu ma ciągle nasłuchiwać w oczekiwaniu na żądania. Drugą i trzecią uruchamia komunikację z bazą danych. Czwarta dodaje bibliotekę MyBatis, a ostatnia jest to system do testowania czy nasza aplikacja działa.

Jednak w obecnie chwili nasza aplikacja jeszcze nie zadziała. Należy najpierw skonfigurować bazę danych. W tym celu edytujemy plik application.property i dodajemy odpowiednie linijki.

spring.datasource.url=jdbc:mysql://localhost:3306/transportMyBatis?serverTimezone=UTC
spring.datasource.username=transportMyBatis
spring.datasource.password=transportMyBatis

logging.file=log/transportMyBatis.log
server.port=8090

Teraz po uruchomieniu serwer zacznie działać bez problemu, ale nic tak naprawdę nie będzie się działo. Nie mamy jeszcze gotowej żadnej usługi, czym się teraz zajmiemy.

Controller

Pierwszym elementem, jaki się zajmiemy to kontroler. Przy okazji jego utworzenie przetestujemy czy nasz web serwis na pewno działa. Więc po utworzeniu pakietu controller utworzymy plik Javy TransportController.

@RestController
public class TransportController {

    @GetMapping("/")
    public String getTest() {
        return "Działa";
    }
}

Gdy uruchomimy nasz serwer i wpiszemy w przeglądarkę http://localhost:8090/, naszym oczom ukarze się napis Działa. Jeżeli masz taki sam efekt, czyli do tej pory wszystko jest ok i możemy przejść dalej. W innym przypadku musisz jeszcze raz wszystko sprawdzić.

Teraz zaczynamy wykorzystywać MyBatis.

W pierwszej kolejności należy poprawić plik pom, aby można było użyć MyBatis. Dlatego teraz ten plik będzie wyglądał następująco:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.7.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>pl.lomza.programowanie</groupId>
	<artifactId>rozliczenie_projektu_rest_mybatis</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>rozliczenie_projektu_rest_mybatis</name>
	<description>Rozliczenie projektu - web serwis REST MyBatis</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.ibatis</groupId>
			<artifactId>ibatis-core</artifactId>
			<version>3.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

Kolejnym elementem jest utworzenie interfejs TransportDAO, w którym będziemy przechowywać wszystkie metody. Jednak teraz stworzymy tylko dwie do pobierania przejazdów. Pozostałe powstaną w kolejnym artykule.

package pl.lomza.programowanie.rozliczenie_projektu_rest_mybatis.mappers;
...
@Component
public interface TransportDAO {
    List<Ride> getRides(@Param("vehicleId") long vehicleId, @Param("personId") long personId);
    Ride getRide(@Param("vehicleId") long vehicleId, @Param("rideId") long rideId);
}

W przypadku MyBatis jest również możliwość użycia adnotacji na tym etapie i zapisu zapytań w tych adnotacjach. Jednak ja uważam, że jest to nie wygodne, dlatego użyje do zapisu zapytań pliku XML.

Zwróć uwagę, gdzie umieszczamy nasz pakiet. Gdy stworzymy nasz XML, musimy go umieścić dokładnie na tej samej ścieżce.

Jeżeli korzystasz z IDE, to pakiety XML są umieszczane w taki sposób: pl.lomza.programowanie.rozliczenie_pojazdu_rest_mybatis.mappers. Jednak tak to jest wyświetlane. W rzeczywistości powinno to wyglądać tak, sprawdź to poza IDE: pl/lomza/programowanie/rozliczenie_pojazdu_rest_mybatis/mappers. Więc, gdy po uruchomieniu system mówi, że nie widzi TransportDAO. W pierwszej kolejności sprawdź, czy ścieżka pliku XML jest prawidłowa. Może to oszczędzić wiele czasu i nerwów. Więc czas na utworzenie XML.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pl.lomza.programowanie.rozliczenie_projektu_rest_mybatis.mappers.TransportDAO">
    <select id="getRides" resultType="pl.lomza.programowanie.rozliczenie_projektu_rest_mybatis.common.Ride">
        <![CDATA[
        SELECT r.id, r.rideDate, r.counterBefore, r.counterAfter, r.km,
        r.whence, r.`where`, r.rideKind, r.fuelCondition, r.fuelAdd, r.fuelAfter,
        SUM(s.fuel) as fuel, f.price, SUM(s.fuel*f.price) as currency, r.fuelNorm
        FROM transportMyBatis.Ride r
        LEFT JOIN transportMyBatis.Settlement  s on r.id = s.idRide
        LEFT JOIN transportMyBatis.Refuel f on f.id = s.idRefuel
        WHERE r.idVehicle = #{vehicleId}
        GROUP BY r.id, r.whence, r.`where`, r.rideKind, f.price
        ORDER BY r.id
        ]]>
    </select>
    <select id="getRide" resultType="pl.lomza.programowanie.rozliczenie_projektu_rest_mybatis.common.Ride">
        <![CDATA[
        SELECT r.id, r.rideDate, r.counterBefore, r.counterAfter, r.km,
        r.whence, r.`where`, r.rideKind, r.fuelCondition, r.fuelAdd, r.fuelAfter,
        SUM(s.fuel) as fuel, f.price, SUM(s.fuel*f.price) as currency, r.fuelNorm
        FROM transportMyBatis.Ride r
        LEFT JOIN transportMyBatis.Settlement  s on r.id = s.idRide
        LEFT JOIN transportMyBatis.Refuel f on f.id = s.idRefuel
        WHERE r.idVehicle = #{vehicleId} and r.id = #{rideId}
        GROUP BY r.id, r.whence, r.`where`, r.rideKind, f.price
        ORDER BY r.id
        ]]>
    </select>
</mapper>

To wystarczy do komunikacji z bazą danych. Teraz musimy podłączyć to do naszego kontrolera. Robimy to w następujący sposób:

@RestController
public class TransportController {
    private final static Logger log = LoggerFactory.getLogger(TransportController.class);

    @Autowired
    private TransportDAO transportDAO;

    @GetMapping("/")
    public String getTest() {
        return "Działa";
    }

    @GetMapping("vehicle/{vehicleId}/rides")
    public List<Ride> getRides(@PathVariable("vehicleId") long vehicleId) {
        log.info("Wyświetlamy listę przejazdów");
        return transportDAO.getRides(vehicleId);
    }
    @GetMapping("vehicle/{vehicleId}/ride/{rideId}")
    public Ride getRide(@PathVariable("vehicleId") long vehicleId, @PathVariable("rideId") long rideId) {
        log.info("Wyświetlamy przejazd");
        return transportDAO.getRide(vehicleId, rideId);
    }
}

Jak pewnie zauważyłeś za każdym razem zwracamy klasę Ride. W jednej metodzie jako listę obiektów a w drugim jako obiekt. Klasa ta wygląda następująco:

public class Ride {
    private long id;
    private LocalDate rideDate;
    private int counterBefore;
    private int counterAfter;
    private int km;
    private String whence;
    private String where;
    private String rideKind;
    private double fuelCondition;
    private double fuelAdd;
    private double fuelAfter;
    private double fuel;
    private double price;
    private double currency;
    private double fuelNorm;

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public LocalDate getRideDate() {
        return rideDate;
    }
    public void setRideDate(LocalDate rideDate) {
        this.rideDate = rideDate;
    }
    public int getCounterBefore() {
        return counterBefore;
    }
    public void setCounterBefore(int counterBefore) {
        this.counterBefore = counterBefore;
    }
    public int getCounterAfter() {
        return counterAfter;
    }
    public void setCounterAfter(int counterAfter) {
        this.counterAfter = counterAfter;
    }
    public int getKm() {
        return km;
    }
    public void setKm(int km) {
        this.km = km;
    }
    public String getWhence() {
        return whence;
    }
    public void setWhence(String whence) {
        this.whence = whence;
    }
    public String getWhere() {
        return where;
    }
    public void setWhere(String where) {
        this.where = where;
    }
    public String getRideKind() {
        return rideKind;
    }
    public void setRideKind(String rideKind) {
        this.rideKind = rideKind;
    }
    public double getFuelCondition() {
        return fuelCondition;
    }
    public void setFuelCondition(double fuelCondition) {
        this.fuelCondition = fuelCondition;
    }
    public double getFuelAdd() {
        return fuelAdd;
    }
    public void setFuelAdd(double fuelAdd) {
        this.fuelAdd = fuelAdd;
    }
    public double getFuelAfter() {
        return fuelAfter;
    }
    public void setFuelAfter(double fuelAfter) {
        this.fuelAfter = fuelAfter;
    }
    public double getFuel() {
        return fuel;
    }
    public void setFuel(double fuel) {
        this.fuel = fuel;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public double getCurrency() {
        return currency;
    }
    public void setCurrency(double currency) {
        this.currency = currency;
    }
    public double getFuelNorm() {
        return fuelNorm;
    }
    public void setFuelNorm(double fuelNorm) {
        this.fuelNorm = fuelNorm;
    }
}

Jeszcze jeden element od pokazania mianowićie główny plik projektu trochę się zmienił więc go prezentujemy.

@SpringBootApplication
@EnableCaching
@EnableTransactionManagement
@MapperScan(value = "pl.lomza.programowanie.rozliczenie_projektu_rest_mybatis.mappers")
public class RozliczenieProjektuRestMybatisApplication {

	public static void main(String[] args) {
		SpringApplication.run(RozliczenieProjektuRestMybatisApplication.class, args);
	}
}

Taka konfiguracja jest nie zbędna, aby wszystko działało prawidłowo. Pozostało nam wszystko przetestować i powinno działać. Jeżeli jednak nie działa, warto podejrzeć, jak ja to zrobiłem. Zapraszam na mojego GitHub pod adresem: https://github.com/grzegorzkossa/rozliczenie_projektu_rest_mybatis.

To jednak nie koniec. Zrobiliśmy tylko odczyt, a nie zajęliśmy się w ogóle zapisu. Pozostało nam jeszcze zabezpieczyć nasze rozwiązanie, ale to już w kolejnym artykule.

Zaszufladkowano do kategorii Rozliczenie pojazdu | Otagowano , , , | Możliwość komentowania Rozliczenie pojazdu REST MyBatis została wyłączona

Rozliczenie pojazdu pobranie

Czas na rozliczenie pojazdu pobranie danych z naszych tabel i wyświetlenie ich. Ten artykuł będzie trochę inny niż wcześniejszy z tej serii. Do tej pory robiliśmy zapytania do wszystkich tabel po kolei. Teraz stworzymy zapytania, które użyjemy w odpowiednich miejscach naszego projektu.

Rozliczenie pojazdu pobranie – wprowadzenie

Na samym początku trzeba podkreślić, że zapytanie SELECT jest bardzo rozbudowanym zapytaniem i daje bardzo duże możliwości. Dlatego pokaże przykłady podstawowej struktury i zajmiemy się tym jakie dane możemy wyciągnąć z naszej bazy danych.

Select * FROM [nazwa bazy].[nazwa tabeli]

Tyle wystarczy, aby pobrać dane z tabeli. Jednak my chcemy otrzymać bardziej przystosowane dane do naszych potrzeb dlatego możemy zastosować ograniczanie ilości wyświetlanych danych na przykład prze klauzule WHERE tak jak z zapytaniach UPDATE.

SELECT * FROM [nazwa bazy].[nazwa tabeli] WHERE id = [identyfikator]

Rozliczenie pojazdu pobranie – zapytania

Teraz zajmiemy się tworzeniem zapytań na wielu tabelach tak, aby uzyskać pewną ilość określonych danych, które później możemy zaprezentować użytkownikowi naszej aplikacji.

Lista pojazdów

Zastanówmy się, co tak naprawdę będziemy chcieli prezentować naszemu użytkownikowi. Na pewno będzie to lista pojazdów, które należą do niego.

SELECT registrationNumber, mark FROM transportMyBatis.Vehicle WHERE idPerson = 1

I ten sposób pobieramy wszystkie pojazdy dla użytkownika o identyfikatorze 1. Jednak jest pewien problem, co w przypadku gdy użytkownik będzie miał tylko jeden pojazd. Bez sensu jest mu pokazywanie listy z jednym pojazdem. Lepiej od razu przejść dalej. Tylko skąd będziemy wiedzieli, że w tym przypadku mamy właśnie taką sytuację. Musimy najpierw wykonać odpowiednie zapytanie, aby to sprawdzić.

SELECT COUNT(id) FROM transportMyBatis.Vehicle WHERE idPerson = 1

To zapytanie zwróci nam jedną wartość, czyli ilość pojazdów. Wtedy będziemy wiedzieli, który mamy przypadek i co należy wyświetlić. Przypadku są następujące:

  • Zwracana wartość to zero – czyli informujemy, że nie masz jeszcze pojazdów.
  • Otrzymana wartość to jeden – czyli przechodzimy do strony z przejazdami.
  • Wartość większa od jedynki – czyli pokazujemy listę przejazdów.

Lista przejazdów

SELECT r.id, r.whence, r.`where`, r.rideKind, r.rideDate, SUM(s.fuel), f.price, SUM(s.fuel*f.price)
FROM transportMyBatis.Ride r 
LEFT JOIN transportMyBatis.Settlement  s on r.id = s.idRide
LEFT JOIN transportMyBatis.Refuel f on f.id = s.idRefuel
GROUP BY r.id, r.whence, r.`where`, r.rideKind, f.price
ORDER BY r.id

Tak wygląda zapytanie, dzięki któremu pobierzemy potrzebne nam dane. Omówmy, co dokładnie ono robi. Zacznijmy od końca. Ostatni zapis każe wykonać sortowanie po identyfikatorach i wyświetlić w tej kolejności. Kolejny zapis to grupowanie kolumn. Jeżeli usuniemy ten zapis, to zapytanie się nie wykona. Dlatego że w pierwszej linii są dwa zapisy SUM. Te dwa zapisy mówią bazie, że wartości tych kolumn chcemy sumować w naszym zapytaniu. Jednak baza nie wiem, co chcemy zrobić z pozostałymi. Dlatego jest właśnie klauzula GROUP BY która informuje bazę, że wartości w tych kolumnach mają zostać bez zmian. Pozwala to na wyświetlenie każdego przejazdu z osobna.

Kolejnym zapisem jest LEFT JOIN. Jest to zapis informujący bazę, że chcemy połączyć nasze tabele, aby uzyskać dostęp do większej ilości kolumn. Dodatkową informacją jest to, w jaki sposób będziemy łączyć te tabele. Tabele są w relacji jeden do wielu, czyli jeden wiersz pierwszej tabeli i wszystkie pasujące drugiej, pasujące do wzorca. Wytłumaczmy to na naszym przykładzie. Jeden wpis do tabeli przejazd (Ride) i wszystkie pasujące z tabeli rozliczenie (Settlement). Drugą relacją jest relacją jeden do jednego, czyli jeden wpis w tabeli rozliczenie (Settlement) odpowiada jednemu wpisowi w tabeli Refuel. Dzięki takiemu powiązaniu można wyświetlić wszystkie potrzebne mam kolumny.

Łączenie tabel odbywa się na podstawie identyfikatorów. Są one zawsze zapisane po wartości on. W naszym przypadku łączymy kolumnę id z tabeli przejazd z kolumną idRide z tabeli rozliczenie. W drugiej relacji łączymy kolumnę id z tabeli tankowanie z kolumną idRefuel z tabeli rozliczenie.

Tak wyglądają główne zapytania, które później użyjemy w naszym projekcie. Pozostałymi zajmiemy się, gdy będziemy mieli potrzebę ich wykorzystania. Zapraszam do kolejnych artykułów rozliczenie pojazdu aplikacja.

Zaszufladkowano do kategorii Rozliczenie pojazdu | Otagowano , , | Możliwość komentowania Rozliczenie pojazdu pobranie została wyłączona

Rozliczenie pojazdu aktualizacja

Rozliczenie pojazdu aktualizacja do bazy. Zajmiemy się aktualizacją danych w tabeli. Jest to drugi element budowy projektu, a zarazem będzie nam potrzebny, w dalszych artykułach.

Rozliczenie pojazdu aktualizacja – wprowadzenie

Za aktualizację w bazie odpowiada instrukcja update. Przykład zastosowania instrukcji update to:

UPDATE [nazwa bazy].[nazwa tabeli]
SET [kolumna 1]=[wartość 1], [kolumna 2]=[wartość 2]
WHERE id=[wartość ID];

Nasza tabela może zawierać wiele kolumn. Jednak aktualizacja ma dotyczyć tylko dwóch z nich. Nie ma potrzeby wpisywania danych do kolumn, które nie wymagają aktualizacji. Możliwe jest również aktualizowanie jednej kolumny, pozostawiamy wtedy wartość kolumna 1 i wartość 1 a przecinek i kolumna 2 i wartość 2 usuwamy. Jeżeli jest potrzeba dodania kolejnych kolumn, rozdzielamy je przecinkiem. W większości przypadków są również kolumny, których nie powinno się zmieniać nigdy. Do takich kolumn należy na przykład createDate. Przechowujemy w niej datę utworzenia wpisu, więc jeżeli jest nam potrzebna informacja o ostatniej aktualizacji, lepszym rozwiązaniem jest dodanie kolejnej kolumny.

Rozliczenie pojazdu aktualizacja – zapytania

Tabela Person (osoba)

Aktualizujemy dane o osobie:

UPDATE transportMyBatis.Person
SET firstName='Janek', lastName='Kowalski'
WHERE id=1;

W przypadku tabeli Person zmieniamy wartości obydwu kolumn, czyli zarówno imie, jak i nazwisko. Jednak w rzeczywistości może istnieje potrzeba zmiany tylko jednej z nich, wtedy należy skorygować odpowiednio zapytanie, tak jak opisałem to we wstępie. Istnieje również możliwość podania w zmiennej wartości null i w samym zapytania sprawdzenie, czy dane są null, a jeżeli tak to pominięcie tej kolumny aktualizacji. To rozwiązanie zależy od bazy danych.

Tabela Vehicle (pojazd)

UPDATE transportMyBatis.Vehicle
SET registrationNumber='LMA4521', mark='Opel'
WHERE id=1;

W tabeli pojazd również aktualizujemy jedynie dwie wartości, czyli markę samochodu oraz numer rejestracyjny. Pozostałe dane powinny zostać bez zmian.

Tabela Ride (przejazd)

UPDATE transportMyBatis.Ride
SET rideDate=' 2020-04-12', counterBefore=12200, counterAfter=12346, km=146, whence='Łomża', `where`='Warszawa', rideKind='Dojazd do pracy', fuelCondition=60, fuelAdd=0, fuelAfter=51.9, fuelConsumed=8.1, fuelNorm=5.7
WHERE id=1;

W przejazdach jest już więcej kolumn do aktualizacji. Jednak w przykładach w dalszych artykułach będziemy przygotowywać takie dane, które będą nam potrzebne w danej sytuacji. Możemy chcieć pozostawić normę spalania ustawioną na null i dopiero po jakimś czasie synchronizator uzupełnia tę wartość.

Tabela Refuel (tankowanie)

UPDATE transportMyBatis.Refuel
SET name='', counterBefore=11950, counterAfter=12675, km=725, refuel=44.7, price=4.40, value=196.7, fuelNorm=6.2
WHERE id=1;

W naszym przykładzie aktualizujemy tylko wybrane kolumny. Przy tworzeniu już konkretnego rozwiązania pozmieniamy ilość aktualizowanych kolumn w zależności do potrzeb. Jednak na razie wybraliśmy tylko te, których aktualizacja ma sens.

Tabela Settlement ()

UPDATE transportMyBatis.Settlement
SET fuel=6.4
WHERE id=1;

Teraz aktualizujemy zużycie paliwa na 100 kilometrów. Pozostałe identyfikatory pozostawiamy bez zmian.

Zapraszam do kolejnych artykułów rozliczenie pojazdu aplikacja.

Zaszufladkowano do kategorii Rozliczenie pojazdu | Możliwość komentowania Rozliczenie pojazdu aktualizacja została wyłączona

Rozliczenie pojazdu zapis

Rozliczenie pojazdu zapis do bazy. Zajmiemy się dodawaniem danych do tabel. Jest to nam potrzebne, do dalszych artykułów.

Rozliczenie pojazdu zapis – zapytania

Za zapis do bazy odpowiada instrukcja insert. Przykład zastosowania instrukcji insert to:

INSERT INTO [nazwa bazy].[nazwa tabeli]
([kolumna 1], [kolumna 2], ...)
VALUES([wartość 1, [wartość 2], ...);

W przykładnie zastosowałem dwie kolumny i żyłem trzech kropek, które świadczą, że kolumn może być więcej. Jednak faktycznie najmniej może być jedna kolumna.

Tabela Person (osoba)

Dodajemy dane o osobie:

INSERT INTO transportMyBatis.Person
(firstName, lastName)
VALUES('Jan', 'Kowalski');

Jak pamiętamy ze wcześniejszego artykułu, tabela zawiera trzy kolumny a w naszym zapisie mamy tylko dwie. Wiemy jednak, że brakująca kolumna to Id. Kolumna Id jest kolumną tworzoną automatycznie, przy tworzeniu rekordu. Dlatego uzupełnianie jej nie jest potrzebne.

Tabela Vehicle (pojazd)

INSERT INTO transportMyBatis.Vehicle
(idPerson, createDate, registrationNumber, mark)
VALUES(1, '2020-04-12 17:34:51.0', 'LOM4521', 'Opel');

Tym razem również brakuje kolumny id, która utworzy się automatycznie. Mamy dodatkowo relacje do tabeli Person. Jak pamiętasz, IdPerson jest powiązany z tabelą Person. Wskazuje na pierwszego użytkownika aplikacji, czyli w naszym przypadku samochód należy do Jana Kowalskiego, jak wynika z utworzonego pierwszego wpisu do tabeli Person.

Tabela Ride (przejazd)

INSERT INTO transportMyBatis.Ride
(idVehicle, createDate, rideDate, counterBefore, counterAfter, km, whence, `where`, rideKind, fuelCondition, fuelAdd, fuelAfter, fuelConsumed, fuelNorm)
VALUES(1, '2020-04-12 17:34:51.0', '2020-04-12 00:00:00.0', 12200, 12346, 146, 'Łomża', 'Warszawa', 'Dojazd do pracy', 60, 0, 51.9, 8.1, 5,7);

Jak widzimy w tym zapisie, przejazd jest połączony z pojazdem (kolumna 1). W drugiej kolumnie mamy datę utworzenia wpisu. Trzecia kolumna to data przejazdu.

Kolejne trzy kolumny to stan początkowy licznika, stan końcowy i ilość przejechanych kilometrów. Następnie mamy dane dotyczące skąd jedziemy, gdzie i w jakim celu. Ostanie pięć kolumn dotyczy rozliczenia tankowania. Dziesiąta to stan początkowy paliwa, jedenasta ilość zatankowanych litrów a dwunasta to stan po zakończeniu przejazdu. Kolejna kolumna mówi, ile zużyliśmy paliwa, Ostania jest to zużycie na sto kilometrów.

Tabela Refuel (tankowanie)

INSERT INTO transportMyBatis.Refuel
(idVehicle, idRide, createDate, refuelDate, name, counterBefore, counterAfter, km, refuel, price, value, fuelNorm)
VALUES(0, 0, '', '', '', 0, 0, 0, 0, 0, 0, 0);

W kolumnie tankowanie przechowujemy wszystkie informacje związane z zakupem paliwa. Tabela jest powiązana z tabelami projazd i przejazd, w relacji jeden do wielu. Dodajemy również dany zakupu i datę utworzenia wpisu.

Teraz zaczyna się coś bardziej interesującego. Mianowicie stan licznika od ostatniego tankowania oraz stan licznika przy tankowaniu. Dzięki tym kolumnom możemy wyliczyć, ile przejechaliśmy kilometrów. Te dane będą nam potrzebne do wyliczenia zużycia paliwa w ostatniej kolumnie. Pozostałe kolumny to ilość zatankowanego paliwa, cena oraz wartość. Dzięki tym informacjom możemy określić, ponoszone koszty. Takie zestawienia przygotujemy w artykule pobieranie danych.

Tabela Settlement ()

INSERT INTO transportMyBatis.Settlement
(idVehicle, idRide, idRefuel, createDate, fuel)
VALUES(1,1, 1, '2020-04-12 17:34:51.0', 6.3);

Została już nam ostatnia tabela. Ta tabela przyda się nam przy rozliczeniach. Dzięki niej będziemy w stanie określić, ile kosztował nas każdy kurs.

Zapraszam do kolejnych artykułów rozliczenie pojazdu aplikacja.

Zaszufladkowano do kategorii Rozliczenie pojazdu | Możliwość komentowania Rozliczenie pojazdu zapis została wyłączona

Java witaj świecie

Przyjęło się, że na początku każdego kursu programowania prezentuje się jako bonus fragment kodu. Jednak aby nie przestraszyć czytelnika, jest to bardzo prosty fragment. Ja zmienię trochę tę tradycję i zamieszczę dwie aplikację, Java Witaj świecie. Pierwsza bardzo prosta i druga trochę trudniejsza. Zrobię to w ten sposób, ponieważ chcę już w pierwszym artykule, tej serii zaprezentować jak wygląda programowanie. Nie chodzi o przestraszenie nikogo, ale raczej pokazanie, w czym tkwi sedno programowania.

Przykład „Java witaj świecie” – najprostsza wersja

Java jest językiem obiektowym, dzięki czemu każdy kod jest tworzony wewnątrz klasy. Klasa jest tak naprawdę przepisem na obiekt, który jest uruchomiony w systemie.

public class Start {
    public static void main(String[] args) {
        System.out.println("Java witaj świecie");
    }
}

W tym przykładzie mamy klasę, która praktycznie nic nie robi. Posiada ona tylko jedną metodę main, której zadaniem jest wyświetlenia w konsoli tekstu „Java witaj świecie”.

Przykład „Java witaj świecie” – trudniejsza wersja

Jednak zanim przejdę dalej, stworzę coś bardziej ambitnego i wytłumaczę, jak to działa.

import java.util.ArrayList;
import java.util.List;

public class Dog {
    private String name;
    private String race;
    private String color;

    public Dog(String name, String race, String color) {
        this.name = name;
        this.race = race;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRace() {
        return race;
    }

    public void setRace(String race) {
        this.race = race;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public static void main(String[] args) {
        List<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog("Pikuś","Jamnik","Szary"));
        dogs.add(new Dog("Ares","Owczarek niemiecki","czarny"));
        for (Dog dog:dogs) {
            System.out.println("Pies: imię: "+dog.name+", rasa: "+dog.race+", kolor: "+dog.color);
        }
    }
}

Straszne co. Taki jest efekt na początku, ale po wytłumaczeniu wszystko powinno się wyjaśnić.

Budowa klasy

Dlatego podzielmy nasz kod na fragmenty i zacznijmy pracę.

import java.util.ArrayList;
import java.util.List;

Pierwsze dwie linijki to deklaracje użytych obiektów, którymi na tym etapie nie musisz się zajmować. Jednak muszą być dodane na początku, aby aplikacja działała i dała się skompilować.

public class Dog {
    private String name;
    private String race;
    private String color;

Następna jest deklaracja klasy Dog (pies) oraz pola. Interpretujemy to tak nazwa klasy to pies, ale każdy pies ma pewne cechy (pola). Pierwszą cechą psa jest, name (imię). Drugą cechą jest race (rasa) a trzecią color (kolor). Te cechy w klasach to pola, w których przechowujemy odpowiednie wartości. W naszym przypadku wszystkie pola przed nazwą mają String, czyli są polami tekstowymi. Jest również zapis private (prywatny), czyli nie mamy bezpośredniego dostępu do pól. Musimy do tego celu użyć odpowiedniej metody.

Kolej na metody. W metodach wykonujemy operacje. Najciekawsza jest metoda main, która jest metodą startową dla aplikacji. Metoda main musi być jedną metodą dla całej aplikacji, więc gdy mamy pięć klas, to zawsze jest tylko jedna metoda main. Metodą main zajmiemy się w dalszej części artykułu.

Pozostałe metody, mają takie same nazwy jak pola. Różnią się przedrostkami get i set na początku. Jest to spowodowane tym, że nasze pola były zadeklarowane jako private (prywatne) i teraz musimy mieć możliwość ich ustawiania i odczytu. Do tego służą właśnie te metody. Metody get służą do odczytu danych z pól, a metody set służą do ustawiania danych pól.

Pewnie się zastanawiasz, dlaczego nie omówiliśmy tego fragmentu kodu, już go wyjaśniam. Jest to konstruktor klasy.

public Dog(String name, String race, String color) {
        this.name = name;
        this.race = race;
        this.color = color;
    }

Są dwa sposoby na ustawienie wartości pól. Poznaliśmy już metody set, dzięki którym możemy ustawiać wartości. Można to zrobić również przy tworzeniu obiektu w konstruktorze, na starcie obiektu. Dlatego w niektórych przypadkach możemy w ogóle nie używać metod set a wartości ustawiać jedynie w konstruktorze. Jest to dobre rozwiązanie, gdy nie chcemy zmieniać wartości pól w utworzonym obiekcie.

Tworzenie obiektu, metoda Main

Wróćmy do metody main. Jej zadaniem jest uruchamianie naszej aplikacji napisanej w Javie. W każdej aplikacji musimy mieć jedną taką metodę. W naszym przypadku mamy tylko jedną klasę więc metoda main jest umieszczona właśnie w niej. Jak widzimy, jest ona dużo trudniejsza od wcześniejszych metod.

List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog("Pikuś","Jamnik","Szary"));
dogs.add(new Dog("Ares","Owczarek niemiecki","czarny"));
for (Dog dog:dogs) {
  System.out.println("Pies: imię: "+dog.name+", rasa: "+dog.race+", kolor: "+dog.color);
}

Aby wyjaśnić, co się dzieje, muszę wykonać pewne założenie. Zakładam, że moja aplikacja utworzy dwa obiekty Dog, a następnie wyświetli ich zawartość.

W pierwszej linii tworzymy listę obiektów Dog. Lista pozwala na przechowywanie więcej niż jeden obiekt danego typu.

Kolejne dwie linie to dodanie do naszej listy dwóch obiektów Dog. Realizujemy to przez metodę „add” i wykorzystujemy konstruktor do utworzenia obiektu i ustawienia danych początkowych jednocześnie. Jednak możemy nie używać konstruktora i zapisać to w taki sposób:

Dog dog = new Dog();
dog.setName("Pikuś");
dog.setRace("Jamnik");
dog.setColor("czarny");
dogs.add(dog);

Jak widać, zapis jest dużo dłuższy. Osiągamy dokładnie ten sam efekt. Dlatego w takich przypadkach lepiej korzystać z konstruktora.

Pętle

Zostało nam jeszcze wyświetlenie tych danych w konsoli.

for (Dog dog:dogs) {
      System.out.println("Pies: imię: "+dog.name+", rasa: "+dog.race+", kolor: "+dog.color);
}

Pętle pozwalają na przeglądanie elementów listy jeden po drugim. W naszym przypadku wykonujemy dwie operacje. Pierwsza odczytuje dany obiekt z listy. Drugi wyświetla zawartość dla każdego pola w konsoli.

Kompilacja i uruchamianie

Mamy już gotową aplikację czas sprawdzić, czy działa. Jednak w przypadku Java nie jest to pełna kompilacja to kodu wykonywalnego, czyli do exe dla Windows. Tworzony jest element pośredni, który później można uruchamiać na wielu systemach operacyjnych. Do kompilacji i uruchomienia jest niezbędna zainstalowana Java w odpowiedniej wersji w naszym systemie.

Java jest dostępna dla wielu systemów operacyjnych. Systemy te różnią się miedzy sobą i właśnie te różnice niwelują wersje instalacyjne dla danego systemu operacyjnego. Dzięki temu my programiści tworzymy jeden kod, który uruchamiamy w różnych systemach.

Proces kompilacji odbywa się przy użyciu polecenia:

javac dog.java

Aby skompilować naszą aplikację, musimy wykonać następujące polecenie. Jednak najpierw musimy mieć zainstalowaną Javę zgodną z naszym systemem operacyjnym.

Jeżeli wcześniejszy krok się powiódł, możemy teraz uruchomić naszą aplikację.

java dog

W tym przypadku wykorzystuje zwykły edytor i uruchomiam wynik mojej pracy w konsoli. Jest to w tym przypadku możliwe, jednak gdy będziemy tworzyć prawdziwe aplikacje warto zaopatrzyć się którychś z IDE obsługujących Javę. W tych aplikacjach cała kompilacja i uruchamianie to naciśniecie jednego przycisku.

Wynik działania

I teraz otrzymujemy taki wynik w konsoli:

Pies: imię: Pikuś, rasa: Jamnik, kolor: Szary
Pies: imię: Ares, rasa: Owczarek niemiecki, kolor: czarny

I to już wszystko w tym artykule. Zapraszam do kolejnych moich artykułów z serii Java.

Zaszufladkowano do kategorii Java | Otagowano , | Możliwość komentowania Java witaj świecie została wyłączona