4. TP 1: Podstawowe zarządzanie kartą płacową
4.1. Introduction
Aby zastosować zdobytą wcześniej wiedzę, proponujemy teraz zadanie polegające na napisaniu aplikacji klienckiej na tablet z systemem Android, umożliwiającej symulację obliczeń listy płac pracowników stowarzyszenia.
Aplikacja będzie miała architekturę klient-serwer:

- serwer [1] jest już udostępniony;
- należy stworzyć klienta na Androida [2].
4.2. Baza danych
4.2.1. Definicja
Dane statyczne potrzebne do sporządzenia listy płac zostaną umieszczone w bazie danych, którą w dalszej części nazwiemy dbpam. Baza ta zawiera następujące tabele:
Struktura:
klucz główny | |
numer wersji – zwiększa się przy każdej zmianie w wierszu | |
numer ubezpieczenia społecznego pracownika – unikalny | |
imię i nazwisko pracownika | |
jego imię | |
jego adres | |
jego miasto | |
jego kod pocztowy | |
klucz obcy w polu [ID] tabeli [INDEMNITES] |
Jego zawartość mogłaby wyglądać następująco:

Struktura:
klucz główny | |
numer wersji – zwiększa się przy każdej zmianie wiersza | |
procent: ogólna składka społeczna + składka na spłatę długu społecznego | |
procent: ogólna składka na ubezpieczenie społeczne podlegająca odliczeniu | |
procent: ubezpieczenie społeczne, renta wdowia, emerytura | |
procent: dodatkowa emerytura + ubezpieczenie od bezrobocia |
Jego treść mogłaby wyglądać następująco:
![]()
Stawki składek na ubezpieczenie społeczne są niezależne od pracownika. Powyższa tabela zawiera tylko jeden wiersz.
klucz główny | |
numer wersji – zwiększa się przy każdej zmianie wiersza | |
indeks przetwarzania – unikalny | |
Cena netto w euro za godzinę dyżuru | |
dodatek na utrzymanie w euro za dzień opieki | |
dodatek na posiłki w euro za dzień opieki | |
dodatek urlopowy. Jest to procent, który należy zastosować do wynagrodzenia podstawowego. |
Jego treść mogłaby wyglądać następująco:

Należy zauważyć, że dodatki mogą się różnić w zależności od opiekunki. Są one bowiem powiązane z konkretną opiekunką poprzez jej wskaźnik wynagrodzenia. Tak więc pani Marie Jouveinal, której wskaźnik wynagrodzenia wynosi 2 (tabela EMPLOYES), otrzymuje wynagrodzenie godzinowe w wysokości 2,1 euro (tabela INDEMNITES).
4.2.2. Generowanie
Dostarczono skrypt [dbpam_hibernate.sql] służący do generowania bazy danych:
![]() |
Utwórz bazę danych [dbpam_hibernate] (jest to nazwa bazy danych BD, z której korzysta serwer WWW / jSON) i upewnij się, że login root bez hasła ma do niej dostęp. Można to zrobić w następujący sposób:
Uruchom MySQL, a następnie [PhpMyAdmin]:
![]() | ![]() |
- [1-2]: zaimportuj skrypt [dbpam_hibernate.sql], a następnie go uruchom;
4.2.3. Modelowanie bazy danych w języku Java
Elementy tabel [EMPLOYES], [INDEMNITES] i [COTISATIONS] są modelowane przez następujące klasy:
[Employe]
package pam.entities;
import java.io.Serializable;
public class Employe implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private int version;
private String SS;
private String nom;
private String prenom;
private String adresse;
private String ville;
private String codePostal;
private int idIndemnite;
private Indemnite indemnite;
public Employe() {
}
public Employe(String SS, String nom, String prenom, String adresse, String ville, String codePostal, Indemnite indemnite) {
...
}
// metody pobierające i ustawiające
....
}
- wiersze 8–15: pola te odpowiadają kolumnom tabeli [EMPLOYES];
- wiersz 16: pole [indemniteId] odpowiada kolumnie [INDEMNITE_ID], która jest kluczem obcym tabeli [EMPLOYES];
- wiersz 17: dodatek pracownika. Pole to nie zawsze jest wypełnione:
- nie jest wypełnione, gdy żąda się URL [/employes],
- jest wypełnione, gdy żądane są raporty URL i [/salaire];
[Indemnite]
package pam.entities;
import java.io.Serializable;
public class Indemnite implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private int version;
private int indice;
private double baseHeure;
private double entretienJour;
private double repasJour;
private double indemnitesCp;
public Indemnite() {
}
public Indemnite(int indice, double baseHeure, double entretienJour, double repasJour, double indemnitesCP) {
...
}
// metody pobierające i ustawiające
....
}
- wiersze 8–14: pola odpowiadają kolumnom tabeli [INDEMNITES];
[Cotisation]
package pam.entities;
import java.io.Serializable;
public class Cotisation implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private int version;
private double csgrds;
private double csgd;
private double secu;
private double retraite;
public Cotisation() {
}
public Cotisation(double csgrds, double csgd, double secu, double retraite) {
...
}
// metody pobierające i ustawiające
...
}
- wiersze 8–13: pola odpowiadają kolumnom tabeli [COTISATIONS];
4.3. Instalacja serwera WWW / jSON
![]() |
4.3.1. Instalacja
Otrzymali Państwo plik binarny serwera WWW w języku Java / jSON:
![]() |
Aby uruchomić serwer WWW / jSON, należy postępować w następujący sposób:
- uruchom plik SGBD MySQL;
- upewnij się, że istnieją pliki BD i [dbpam_hibernate];
- otwórz okno DOS;
- przejdź do folderu pliku jar;
- wpisz polecenie:
Zakłada się, że plik binarny [java.exe] znajduje się w katalogu PATH na Twoim komputerze. Jeśli tak nie jest, wpisz pełną ścieżkę do pliku [java.exe], na przykład:
Wyświetlą się logi:
- wiersz 16: wykryto plik URL [/salaire/{SS}/{ht}/{jt}];
- wiersz 17: wykryto URL [/employes];
4.3.2. URL serwisu internetowego/jSON
![]() |
Usługa internetowa / jSON jest zaimplementowana przez Spring MVC i udostępnia dwa elementy URL:
@RequestMapping(value = "/employes", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
public EmployesResponse getEmployes() {
...
@RequestMapping(value = "/salaire/{SS}/{ht}/{jt}", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
public FeuilleSalaireResponse getFeuilleSalaire(@PathVariable("SS") String SS, @PathVariable("ht") double ht, @PathVariable("jt") int jt) {
Usługa internetowa akceptuje następujące dwa URL:
- wiersz 1: /employes: w celu uzyskania listy pracowników;
- wiersz 4: /salaire/SS/ht/jt: aby uzyskać listę płac pracownika o numerze [SS], który przepracował [ht] godzin w ciągu [jt] dni;
Oto zrzuty ekranu ilustrujące to.
Wymagane są dane pracowników:

Wyłączamy bazę danych, ponownie uruchamiamy serwer i sprawdzamy pracowników:

Wprowadzamy wynagrodzenie:

Żądamy wynagrodzenia dla osoby, która nie istnieje:

4.3.3. Odpowiedzi serwisu internetowego: jSON / jSON
![]() |
![]() |
Odpowiedzi URL z serwisu internetowego / jSON wysyłają odpowiedzi typu [Response<T>]:
package client.android.dao.service;
import java.util.List;
public class Response<T> {
// ----------------- właściwości
// status operacji
private int status;
// ewentualne komunikaty o statusie
private List<String> messages;
// treść odpowiedzi
private T body;
// konstruktory
public Response() {
}
public Response(int status, List<String> messages, T body) {
this.status = status;
this.messages = messages;
this.body = body;
}
// metody pobierające i ustawiające
...
}
- URL [/employes] zwraca typ Response<List<Employe>>;
- URL i [/salaire] zwracają typ Response<FeuilleSalaire>;
Klasa [FeuilleSalaire] ma następującą postać:
package pam.entities;
import java.io.Serializable;
public class FeuilleSalaire implements Serializable {
private static final long serialVersionUID = 1L;
// pola prywatne
private Employe employe;
private Cotisation cotisation;
private ElementsSalaire elementsSalaire;
// konstruktory
public FeuilleSalaire() {
}
public FeuilleSalaire(Employe employe, Cotisation cotisation, ElementsSalaire elementsSalaire) {
...
}
// metody pobierające i ustawiające
...
}
- wiersz 9: klasa [Employe] została przedstawiona w paragrafie 4.2.3;
- wiersz 10: klasa [Cotisation] została przedstawiona w paragrafie 4.2.3;
Klasa [ElementsSalaire] (wiersz 11) ma następujący wygląd:
package pam.entities;
import java.io.Serializable;
public class ElementsSalaire implements Serializable {
private static final long serialVersionUID = 1L;
// pola prywatne
private double salaireBase;
private double cotisationsSociales;
private double indemnitesEntretien;
private double indemnitesRepas;
private double salaireNet;
// konstruktory
public ElementsSalaire() {
}
public ElementsSalaire(double salaireBase, double cotisationsSociales, double indemnitesEntretien, double indemnitesRepas, double salaireNet) {
...
}
// metody pobierające i ustawiające
...
}
4.4. Testy klienta na systemie Android
![]() |
Oto gotowy plik wykonywalny klienta dla systemu Android:
![]() |
Za pomocą myszki przeciągnij powyższy plik wykonywalny [pam-client.apk] na emulator tabletu [GenyMotion]. Zostanie on wówczas zapisany, a następnie uruchomiony. Uruchom również serwer WWW / jSON, jeśli jeszcze tego nie zrobiłeś. Zadaniem klienta na Androida jest pobieranie informacji zwracanych przez serwer WWW / jSON oraz ich formatowanie. Poszczególne widoki klienta na Androida są następujące:
Najpierw należy połączyć się z usługą internetową / jSON:

- w [1] podajemy adres URL usługi internetowej / jSON. W emulatorze należy wprowadzić jeden z adresów IP lub PC (ale nie 127.0.0.1). Na tablecie wprowadź adres Wi-Fi urządzenia serwera WWW / jSON i wyłącz zaporę sieciową serwera, jeśli taka istnieje, ponieważ może ona blokować połączenia przychodzące;
- w [2] nawiązujemy połączenie;
Następnie pojawia się strona symulacji:

- w [3] wybieramy pracownika;
- w [4] należy podać liczbę godzin;
- w [5] należy podać liczbę dni;
- w [6] uruchamia się symulację;
Wyświetla się następująca strona symulacji:

- w [7] – uzyskana symulacja;
- w [8] zapisuje się ją;

- w [9] – lista symulacji;
- w [10] usuwa się symulację;

- w [11] nie ma już żadnych symulacji;
- w [12], powrót do formularza symulacji;

- w [13] ponownie wyświetla się formularz;
- w [14] następuje powrót do strony konfiguracji;

- po wprowadzeniu kodu [15] ponownie wyświetla się początkowy formularz logowania.
4.5. Zadanie do wykonania
Podano wam szkielet klienta dla systemu Android przedstawiony powyżej. Został on stworzony na podstawie projektu [client-android-skel] opisanego w akapicie 2.
![]() |
Projekt jest gotowy do uruchomienia i zawiera już niezbędne widoki. Wystarczy dodać kod, aby aplikacja działała zgodnie z przeznaczeniem. Należy postępować w następujący sposób:
- uruchomcie pełną wersję, aby zapoznać się z zadaniem;
- uruchom wersję uproszczoną i zapoznaj się z jej kodem. Jest on zgodny z metodami projektowania opisanymi na poprzednich stronach;
- dodaj brakujący kod;










