4. Tarefa 1: Gestão básica de recibos de vencimento
4.1. Introdução
Para aplicar o que abordámos anteriormente, propomos agora um trabalho que envolve o desenvolvimento de um cliente Android para tablets, concebido para simular cálculos de folhas de pagamento para os funcionários de uma associação.
A aplicação terá uma arquitetura cliente/servidor:

- o servidor [1] é fornecido;
- deve criar o cliente Android [2].
4.2. A base de dados
4.2.1. Definição
Os dados estáticos necessários para criar o recibo de vencimento serão armazenados numa base de dados a que nos referiremos doravante como « » (dbpam). Esta base de dados contém as seguintes tabelas:
Estrutura:
chave primária | |
número de versão – aumenta a cada modificação da linha | |
Número de Segurança Social do funcionário – único | |
Apelido do funcionário | |
Nome | |
a morada | |
a cidade dele/dela | |
o seu código postal | |
Chave estrangeira no campo [ID] da tabela [INDEMNITES] |
O seu conteúdo pode ser o seguinte:

Estrutura:
chave primária | |
número de versão – aumenta a cada modificação da linha | |
Percentagem: Contribuição Social Geral + Contribuição para o Reembolso da Dívida Social | |
percentagem: contribuição social geral dedutível | |
percentagem: segurança social, viuvez, velhice | |
percentagem: pensão complementar + seguro de desemprego |
O seu conteúdo poderia ser o seguinte:
![]()
As taxas de contribuição para a segurança social são independentes do trabalhador. A tabela anterior tem apenas uma linha.
chave primária | |
número de versão – aumenta a cada modificação da linha | |
Índice de processamento – único | |
Preço líquido em euros por uma hora de serviço de plantão | |
Subsídio diário em euros por dia de cuidados | |
Subsídio de refeição em euros por dia de assistência | |
Subsídio de férias pagas. Trata-se de uma percentagem aplicada ao salário base. |
O seu conteúdo pode ser o seguinte:

Note-se que os subsídios podem variar de um prestador de cuidados infantis para outro. Estão associados a um prestador de cuidados infantis específico através da sua categoria salarial. Por exemplo, a Sra. Marie Jouveinal, que tem a categoria salarial 2 (tabela EMPLOYEES), tem um salário por hora de 2,1 euros (tabela INDEMNITES).
4.2.2. Geração
É fornecido o script de geração da base de dados [dbpam_hibernate.sql]:
![]() |
Crie a base de dados [dbpam_hibernate] (este é o nome da base de dados utilizada pelo servidor web/jSON) e certifique-se de que o utilizador root (sem palavra-passe) consegue aceder à mesma. Pode fazê-lo da seguinte forma:
Inicie o MySQL e, em seguida, o [PhpMyAdmin]:
![]() | ![]() |
- [1-2]: Importe o script [dbpam_hibernate.sql] e, em seguida, execute-o;
4.2.3. Modelagem Java da base de dados
Os elementos das tabelas [EMPLOYEES], [ALLOWANCES] e [CONTRIBUTIONS] são modelados pelas seguintes classes:
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) {
...
}
// getters and setters
....
}
- linhas 8–15: estes campos correspondem às colunas da tabela [EMPLOYEES];
- linha 16: o campo [indemniteId] corresponde à coluna [INDEMNITE_ID], que é a chave estrangeira da tabela [EMPLOYEES];
- linha 17: o subsídio do funcionário. Este campo nem sempre é preenchido:
- não é preenchido ao solicitar a URL [/employees],
- mas é preenchido ao solicitar o URL [/salary];
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) {
...
}
// getters and setters
....
}
- linhas 8-14: os campos correspondem às colunas da tabela [INDEMNITES];
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) {
...
}
// getters and setters
...
}
- linhas 8-13: os campos correspondem às colunas da tabela [COTISATIONS];
4.3. Servidor Web / Instalação do JSON
![]() |
4.3.1. Instalação
O binário Java para o servidor web/JSON é fornecido:
![]() |
Para iniciar o servidor web/JSON, proceda da seguinte forma:
- Inicie o SGBD MySQL;
- certifique-se de que a base de dados [dbpam_hibernate] existe;
- Abra uma janela do prompt de comando;
- Navegue até à pasta jar;
- digite o comando:
Isto pressupõe que o executável [java.exe] se encontra no PATH do seu computador. Se não for esse o caso, digite o caminho completo para [java.exe], por exemplo:
Os registos são apresentados:
- linha 16: a URL [/salary/{SS}/{ht}/{jt}] é resolvida;
- linha 17: a URL [/employees] foi descoberta;
4.3.2. URLs de serviço Web/JSON
![]() |
O serviço Web / JSON é implementado pelo Spring MVC e expõe duas URLs:
@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) {
O serviço web aceita as duas URLs seguintes:
- linha 1: /employees: para recuperar a lista de funcionários;
- Linha 4: /salary/SS/ht/jt: para recuperar o recibo de vencimento do funcionário n.º [SS] que trabalhou [ht] horas ao longo de [jt] dias;
Aqui estão algumas capturas de ecrã que ilustram isto.
Consultamos os funcionários:

Fazemos uma cópia de segurança da base de dados, reiniciamos o servidor e consultamos os funcionários:

Consultamos um salário:

Solicitamos o salário de uma pessoa inexistente:

4.3.3. As respostas JSON do serviço web/JSON
![]() |
![]() |
Os URLs do serviço web/jSON devolvem respostas do tipo [Response<T>]:
package client.android.dao.service;
import java.util.List;
public class Response<T> {
// ----------------- properties
// operation status
private int status;
// any status messages
private List<String> messages;
// the body of the reply
private T body;
// manufacturers
public Response() {
}
public Response(int status, List<String> messages, T body) {
this.status = status;
this.messages = messages;
this.body = body;
}
// getters and setters
...
}
- A URL [/employees] devolve uma Response<List<Employee>>;
- A URL [/salary] devolve um tipo Response<PayStub>;
A classe [PayrollSheet] é a seguinte:
package pam.entities;
import java.io.Serializable;
public class FeuilleSalaire implements Serializable {
private static final long serialVersionUID = 1L;
// private fields
private Employe employe;
private Cotisation cotisation;
private ElementsSalaire elementsSalaire;
// manufacturers
public FeuilleSalaire() {
}
public FeuilleSalaire(Employe employe, Cotisation cotisation, ElementsSalaire elementsSalaire) {
...
}
// getters and setters
...
}
- linha 9: a classe [Employee] foi apresentada na secção 4.2.3;
- linha 10: a classe [Contribution] foi apresentada na secção 4.2.3;
A classe [SalaryElements] (linha 11) é a seguinte:
package pam.entities;
import java.io.Serializable;
public class ElementsSalaire implements Serializable {
private static final long serialVersionUID = 1L;
// private fields
private double salaireBase;
private double cotisationsSociales;
private double indemnitesEntretien;
private double indemnitesRepas;
private double salaireNet;
// manufacturers
public ElementsSalaire() {
}
public ElementsSalaire(double salaireBase, double cotisationsSociales, double indemnitesEntretien, double indemnitesRepas, double salaireNet) {
...
}
// getters and setters
...
}
4.4. Testes do cliente Android
![]() |
O ficheiro executável do cliente Android finalizado é fornecido abaixo:
![]() |
Use o rato para arrastar o ficheiro [pam-client.apk] acima para um emulador de tablet [GenyMotion]. Este será então guardado e executado. Inicie também o servidor web/JSON, caso ainda não o tenha feito. O objetivo do cliente Android é recuperar as informações devolvidas pelo servidor web/JSON e formatá-las. As diferentes vistas do cliente Android são as seguintes:
Primeiro, deve ligar-se ao serviço web / JSON:

- em [1], introduza o URL do serviço web/JSON. Com o emulador, introduza um dos endereços IP do PC (mas não 127.0.0.1). Com um tablet, introduza o endereço Wi-Fi da máquina do servidor web/JSON e desative a firewall do servidor, caso exista, pois esta pode bloquear chamadas recebidas;
- Em [2], inicie sessão;
Será então redirecionado para a página de simulação:

- Em [3], selecione um funcionário;
- Em [4], introduza um número de horas;
- Em [5], introduza o número de dias;
- Em [6], execute a simulação;
A página de simulação resultante é a seguinte:

- em [7], os resultados da simulação;
- em [8], guarde-a;

- em [9], a lista de simulações;
- em [10], uma simulação é eliminada;

- em [11], não há mais simulações;
- Em [12], volta ao formulário de simulação;

- em [13], volta ao formulário;
- em [14], volta à página de configuração;

- em [15], volta ao formulário de início de sessão inicial.
4.5. Trabalho a realizar
O esqueleto do cliente Android apresentado anteriormente é fornecido a si. Foi construído a partir do projeto [client-android-skel] descrito na Secção 2.
![]() |
O projeto está pronto a ser executado e já contém as vistas necessárias. Basta adicionar código para que a aplicação faça o que é suposto fazer. O procedimento é o seguinte:
- execute a versão completa para compreender o trabalho a realizar;
- execute a versão simplificada e estude o seu código. Segue os métodos de design utilizados nas páginas anteriores;
- adicione o código que falta;










