Pentru dezvoltarea aplicației am utilizat tehnologiile prezentate în capitolul 2 al curentei lucrări. Astfel, am folosit ca și mediu de lucru… [622962]
28
4. Prezentarea aplicației
4.1. Implementarea aplicației
Pentru dezvoltarea aplicației am utilizat tehnologiile prezentate în capitolul 2 al
curentei lucrări. Astfel, am folosit ca și mediu de lucru IntelliJ IDEA. Serverul web utilizat
este Apache care conține modulele de MySQL și Java, iar pentru crearea structurii bazei de
date am folosit utilitarul HeidiSQL si MySQL Workbench. În timp ce partea care s-a ocupat
cu funcționalitatea aplicației a fost realizată în Java și MySQL, pentru partea vizuală a
programului au fost utilizate HTML, CSS, jQuery si Javascript. Nu în ultimul rând, a fost
folosit cadrul de lucru ( framework ) Stripes care a facilitat implementarea arhitecturii Model-
View-Controller.
Folosit în mod tradițional pentru interfețe grafice desktop (GUI), această arhitectură a
devenit populară pentru proiectarea aplicațiilor web.[18]18
Trebuie precizat că am utilizat Java 11 cu facilitățile sale de programare orientate pe
obiecte ceea ce a presupus implementarea de clase pentru entitățile cu care lucrează aplicația
și implicit abstractizarea aplicației. Faptul că Java 11 lucrează cu obiecte face mult mai
ușoară implementarea aplicației utilizănd arhitectura MVC.
Model – View – Controller ( model – viziune – unitate de control ) este un șablon
software care separă reprezentarea informației de interacțiunea utilizatorului cu
aceasta.Modelul constă în datele aplicației, logică și funcții necesare lucrului cu datele
(regăsire sau actualizare). Modelul implementează practic lucrul cu baza de date . Viziunea
(pagina de vizualizare ) constă în prezentarea datelor și a informațiilor către utilizator.
Viziunea implementează practic partea de interfață grafică. Unitatea de control preia acțiunile
utilizatorului și le transformă în comenzi către model sau view. Unitatea de control
implementează funcționalitatea aplicației.
In figura 4.1 putem observa arhitectura model – view – controller.
Figura 4.1. Arhitectura Model – View – Controller
18 [18] Davis, Ian (2016) „What Are The Benefits of MVC?”
29
Din punctul meu de vedere, utilizarea unei arhitecturi de tipul MVC, este foarte utilă
deoarece impune o anumită rigurozitate în elaborarea codului sursă, care în acest mod este
mai organizat și mai ușor de urmărit și depanat. În plus, foarte multe funcții și metode pot fi
utilizate în mai multe module ceea ce duce la o programare eficientă.
Aplicația cuprinde 2 funcționalități oarecum diferite. Prima se referă la manipularea
datelor desemnate de entitățile bazei de date, în timp ce a doua parte se referă la posibilitatea
obținerii de grafice și rapoarte.
4.1.1. Implementarea bazei de date si a functionalitatii acesteia
Implementarea bazei de date este realizată prin intermediul limbajului de descriere a
datelor (LDD) pentru crearea tabelelor, iar apoi prin limbajul de manipulare a datelor (LMD)
pentru popularea, regăsirea și actualizarea datelor.
Crearea bazei de date a fost realizată utilizând aplicația HeidiSQL care se conectează
la serverul MySQL și accesează baza de date. Crearea tabelelor poate fi făcută atât în mod
vizual folosind asistentul aplicației, cât și prin scrierea de cod SQL. Spre exemplu, crearea
tabelelor role si user se realizează executând următoarele comenzi SQL:
Figura 4.1.1.1 Cod SQL pentru crearea tabelei role
Figura 4.1.1.2 Cod SQL pentru crearea tabelei user
Se observă faptul că tabela “user” are atributele: id, first_name, last_name, username,
password, job_title si role_id, dintre care id este cheie primară si role_id este cheie secundară
straină.
30
Legăturile dintre tabele sunt realizate prin intermediul cheilor secundare straine, însă
în cazul mysql nu este neapărat nevoie ca acestea să fie declarate, ci este suficient ca
atributele considerate chei străine secundare să aibă aceeași denumire și tip de date ca și
atributul din tabela părinte. Putem vorbi despre o legătură logică între tabele.
În ceea ce privește funcționalitatea bazei de date, acesta este realizată prin limbajul de
manipulare a datelor, apelat prin intermediul modelelor. După cum a fost prezentat anterior,
modelul reprezintă o clasă a aplicației care se ocupă cu conectarea la baza de date și asigură
interfața dintre aplicație și baza de date.
Pentru inițializarea bazei de date am folosit clasa ApplicationServlet care extinde
HttpServlet cum se poate vedea în figura de mai jos:
package com.example.restaurant.web ;
import com.example.restaurant.dao.BaseDao ;
import javax.servlet.ServletConfig ;
import javax.servlet.ServletException ;
import javax.servlet.http.HttpServlet ;
public class ApplicationServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
super.init(config) ;
BaseDao. init("com.mysql.jdbc.Driver" , "jdbc:mysql://localhost/restaurant" ,
"root", "root");
System. out.println( "Application initialized successfully" );
}
}
Pentru implementarea modelelor am structurat clasele în modele și Data Access
Objects (DAO) în Java care împreună cu funcția executeQuery ne permit scrierea directă a
codului SQL în aplicația noastră.
Modelul Object Access Data (DAO) este un model structural care ne permite să
izolam stratul aplicație / întreprindere de stratul de persistență (de obicei o bază de date
relațională, dar ar putea fi orice alt mecanism de persistență) folosind un API abstract.
Funcționalitatea acestui API este de a ascunde de aplicație toate complexitățile
implicate în efectuarea operațiunilor CRUD în mecanismul de stocare de bază. Acest lucru
permite ambelor straturi să evolueze separat fără să știe nimic despre ele.
În urmatoarea bucată de cod observăm clasa BaseDao pe care o vor extinde toate
celelalte clase de tip dao din aplicația noastră.
package com.example.restaurant.dao ;
import java.sql.* ;
public class BaseDao {
private static String driver;
private static String url;
private static String username ;
31
private static String password ;
public static void init(String driver , String url , String username , String
password) {
BaseDao. driver = driver ;
BaseDao. url = url;
BaseDao. username = username ;
BaseDao. password = password ;
}
protected ResultSet executeQuery (String query) throws SQLException {
try {
Class. forName (driver).newInstance() ;
} catch (InstantiationException | IllegalAccessException |
ClassNotFoundException e) {
System. err.println( "Can't load driver. Verify CLASSPATH" );
System. err.println(e.getMessage()) ;
}
Connection connection = DriverManager. getConnection (url, username ,
password );
Statement statement = connection.createStatement() ;
return statement.executeQuery(query) ;
}
}
În urmatoarea figură prezentăm clasa EmployeeDao care extinde BaseDao în care
construim obiectul Employee făcând un query către baza de date având deja o conexiune gata
facută datorită extinderii.
package com.example.restaurant.dao ;
import com.example.restaurant.model.Employee ;
import java.sql.ResultSet ;
import java.sql.SQLException ;
import java.util.ArrayList ;
import java.util.Date ;
import java.util.List ;
public class EmployeeDao extends BaseDao {
public Employee get(Integer id) {
try {
ResultSet rs = this.executeQuery( "select * from employee where id = " +
id);
if (rs.next()) {
return this .buildObject(rs) ;
}
} catch (SQLException exception) {
exception.printStackTrace() ;
}
return null;
}
public List<Employee> getList () {
List<Employee> employees = new ArrayList<>() ;
try {
ResultSet rs = this.executeQuery( "select * from employee" );
while (rs.next()) {
Employee employee = this.buildObject(rs) ;
employees.add(employee) ;
}
32
} catch (SQLException exception) {
exception.printStackTrace() ;
return null;
}
return employees ;
}
private Employee buildObject (ResultSet rs) throws SQLException {
Integer id = rs.getInt( "id");
String firstName = rs.getString( "first_name" );
String lastName = rs.getString( "last_name" );
Date employmentDate = rs.getDate( "employment_date" );
Integer baseSalary = rs.getInt( "base_salary" );
return new Employee(id , firstName , lastName , employmentDate , baseSalary) ;
}
}
În continuare putem vedea un exemplu de clasă model pentru obiectul Employee.
package com.example.restaurant.model ;
import java.util.Date ;
public class Employee {
private Integer id;
private String firstName ;
private String lastName ;
private Date employmentDate ;
private Integer baseSalary ;
public Employee () {}
public Employee (Integer id , String firstName , String lastName , Date
employmentDate , Integer baseSalary) {
this.id = id;
this .firstName = firstName ;
this .lastName = lastName ;
this .employmentDate = employmentDate ;
this .baseSalary = baseSalary ;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstName () {
return firstName ;
}
public String getLastName () {
return lastName ;
}
public Date getEmploymentDate () {
return employmentDate ;
}
public Integer getBaseSalary () {
return baseSalary ;
}
public void setFirstName (String firstName) {
33
this.firstName = firstName ;
}
public void setLastName (String lastName) {
this.lastName = lastName ;
}
public void setEmploymentDate (Date employmentDate) {
this.employmentDate = employmentDate ;
}
public void setBaseSalary (Integer baseSalary) {
this.baseSalary = baseSalary ;
}
}
4.1.2. Implementarea interfeței și a functionalitătii acesteia
Interfața este implementată utilizând viziunile și unitățile de control. Din prezentarea
arhitecturii Model – View – Controller, știm că viziunile se ocupă cu prezentarea informațiilor
către utilizator, deci cu partea vizuală a interfeței, în timp ce unitatea de control se ocupă cu
funcționalitatea acesteia, întrucât preia cererile generate de acțiunile utilizatorului și le
procesează, oferind un răspuns ce indică o nouă direcție de navigare în cadrul aplicației sau
filtrează o parte din informațiile ce trebuie redate. Vom oferi ca exemplu clasa “Employee”,
clasă ce implementează logica unei unități de control a șablonului Model-View-Controller.
În multe aplicații web, este obligatoriu să avem un bun sistem de autentificare. Într-
adevăr, cel puțin partea administrativă a unui site Web trebuie să fie foarte sigur. Un sistem de
autentificare web asigură în general un nume de conectare unic și o parolă pentru utilizator,
înainte ca el sa acceseaze paginile. În ciuda acestui mod comun, există multe posibilități de
implementare a acestora, fiecare cu avantaje și dezavantaje diferite.[19]19
Funcționalitatea pentru login este creată folosind clasa AuthenticateInterceptor care
extinde clasa Interceptor existentă in java, pagina jsp și o clasă de tip Action Bean. Acestea
verifică dacă utilizatorul este autentificat și previne accesul neautorizat pe orice altă pagină
din aplicație. Aici am folosit jquery și call-uri ajax pentru a redirecționa utilizatorul către
pagina de login în caz că acesta încearcă să acceseze altă pagină fară a se fi logat în prealabil.
Această funcționalitate a fost implementată cu următorul cod:
@Intercepts (LifecycleStage. BindingAndValidation )
public class AuthenticateInterceptor implements Interceptor {
@Override
public Resolution intercept (ExecutionContext executionContext) throws Exception
{
ActionBean actionBean = executionContext.getActionBean() ;
if (actionBean instanceof LoginAction) {
return executionContext.proceed() ;
}
HttpServletRequest request = actionBean.getContext().getRequest() ;
if (request.getSession().getAttribute( "user_id" ) != null) {
return executionContext.proceed() ;
}
return new RedirectResolution(LoginAction. class);
}
19 [19] Pescaru, Dan; Holotescu, Carmen „ Authentication in an Online Learning Environment. A Case Study”
34
<%@ page contentType=" text/html;charset=UTF-8 " language=" java" %>
<jsp:useBean id="actionBean" scope="request"
type="com.example.restaurant.web.action.LoginAction" />
<%@ include file="/pages/layout/taglibs.jsp " %>
<s:layout-render name="/pages/layout/layout.jsp" >
<s:layout-component name="mainContent" >
<div class="panel panel-default col-md-6 col-md-offset-3" >
<div class="panel-body" >
<form action="" id="form" onsubmit ="return false ">
<div class="form-group" >
<label class="control-label" >Username: </label>
<input name="username" class="form-control" type="text"
value=""/>
</div>
<div class="form-group" >
<label class="control-label" >Password: </label>
<input name="password" class="form-control" type="password"
value=""/>
</div>
<div class="form-group pull-right" >
<button type="submit" class="btn btn-primary"
onClick ="login()">Login</button>
</div>
<div class="col-md-12" id="errorDiv" ></div>
</form>
</div>
</div>
<style>
#errorDiv {
display : none;
text-align : center;
color: #c70707 ;
font-weight : bold;
}
</style>
<script type="text/javascript" >
function login() {
var args = $("#form" ).serialize ();
$.ajax({
url: "Login.action?authenticate" ,
type: "post",
data: args,
success : function (response) {
$("#errorDiv" ).css("display" , "none");
var result = eval('(' + response + ')');
if (result. success ) {
window. location .href = result.page ;
} else {
$("#errorDiv" ).html(result.errorMsg) ;
$("#errorDiv" ).fadeIn();
}
} ,
error: function (xhr) {
alert("An error occurred: " + xhr.statusText + " " +
xhr.responseText );
}
}) ;
}
</script>
</s:layout-component >
</s:layout-render >
35
@UrlBinding ("/Login.action" )
public class LoginAction extends BaseAction {
@DefaultHandler
public Resolution view() {
if(this.getLoggedIn()) {
return new RedirectResolution(EmployeeAction. class);
}
return new ForwardResolution( "/pages/login.jsp" );
}
@HandlesEvent ("authenticate" )
public Resolution authenticate () {
String username = this.request .getParameter( "username" );
String password = this.request .getParameter( "password" );
UserDao userDao = new UserDao() ;
User user = userDao.get(username) ;
JSONObject jsonObject = new JSONObject() ;
if (user != null && user.getPassword().equals(password)) {
jsonObject.put( "success" , true);
jsonObject.put( "page", Section. EMPLOYEE .getUrl()) ;
this .session .setAttribute( "user_id" , user.getId()) ;
} else {
jsonObject.put( "success" , false );
jsonObject.put( "errorMsg" , "Invalid Credentials" );
}
return new StreamingResolution( "text/plain" , jsonObject.toString()) ;
}
@HandlesEvent ("logout" )
public Resolution logout(){
this.session .removeAttribute( "user_id" );
return new RedirectResolution(LoginAction. class);
}
Următoarea funcționalitate despre care putem vorbi este pagina în care vizualizăm un
tabel cu toti angajații și datele relevante pentru acestia și, dupa cum observăm, a fost realizată
folosind elemente de html într-un fisier jsp și chemând clasa EmployeeAction care la rândul
ei face un query către baza de date și returnează o listă cu angajații.
<%@ page contentType=" text/html;charset=UTF-8 " language=" java" %>
<jsp:useBean id="actionBean" scope="request"
type="com.example.restaurant.web.action.EmployeeAction" />
<%@ include file="/pages/layout/taglibs.jsp " %>
<s:layout-render name="/pages/layout/layout.jsp" >
<s:layout-component name="mainContent" >
<h3>Employees </h3>
<table class="table table-striped table-hover" >
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">First name </th>
<th scope="col">Last name </th>
<th scope="col">Base Salary </th>
<th scope="col">Employment Date </th>
</tr>
</thead>
36
<tbody id="employeeTable" >
<c:forEach var="employee" items="${actionBean.employees }">
<tr>
<td> ${employee.id }</td>
<td> ${employee.firstName }</td>
<td> ${employee.lastName }</td>
<td> ${employee.baseSalary }</td>
<td> ${employee.employmentDate }</td>
</tr>
</c:forEach >
</tbody>
</table>
</s:layout-component >
</s:layout-render >
@UrlBinding ("/Employee.action" )
public class EmployeeAction extends BaseAction {
private List<Employee> employees ;
@DefaultHandler
public Resolution view() {
this.section = Section. EMPLOYEE ;
EmployeeDao dao = new EmployeeDao() ;
this .employees = dao.getList() ;
return new ForwardResolution( "/pages/employee.jsp" );
}
public List<Employee> getEmployees () {
return employees ;
}
Pentru a putea adauga un venit zilnic pentru un anumit angajat utilizăm clasa
DailyIncomeAction care, în funcție id-ul angajatului selectat din dropdown, scrie un rând nou
în baza de date cu veniturile angajatului din ziua selectată.
@UrlBinding ("/DailyIncome.action" )
public class DailyIncomeAction extends BaseAction {
private DailyIncome dailyIncome ;
@DefaultHandler
public Resolution view() {
this.section = Section. DAILY_INCOME ;
Integer employeeId = null;
try {
employeeId =
Integer. parseInt (this.request .getParameter( "employee_id" ));
} catch (Exception exception) {
System. err.println( "Exception parsing employee_id: " +
exception.getMessage()) ;
}
if (employeeId != null) {
DailyIncomeDao dao = new DailyIncomeDao() ;
this .dailyIncome = dao.get(employeeId) ;
}
return new ForwardResolution( "/pages/dailyIncome.jsp" );
}
public DailyIncome getDailyIncome () {
return dailyIncome ;
}
37
O altă funcționalitate implementată și poate cea mai importantă este aceea de generare
a rapoartelor pentru veniturile unui angajat dintr-o anumită perioadă. Acest lucru se
realizează selectând un angajat din dropwdown și introducând data start și data sfârșit pentru
raportul dorit iar rezultatul va fi returnat într-un obiect de tip json.
@UrlBinding ("/Report.action" )
public class ReportAction extends BaseAction {
@DefaultHandler
public Resolution view() {
this.section = Section. REPORT;
return new ForwardResolution( "/pages/report.jsp" );
}
@HandlesEvent ("generate" )
public Resolution generate () {
Integer id = null;
try {
id = Integer. parseInt (this.request .getParameter( "id"));
} catch (Exception exception) {
System. err.println( "Exception parsing id: " + exception.getMessage()) ;
}
String startDate = this.request .getParameter( "startDate" );
String endDate = this.request .getParameter( "endDate" );
String json = "report" ;
return new StreamingResolution( "text/plain" , json);
}
}
În urmatoarea figură prezint modul în care am structurat această aplicație.
Figura 4.1.2. Strucutura aplicatiei
Implementarea completă a aplicatiei o puteti gasi in Anexa.
38
4.2. Utilizarea aplicației
Aplicația este intuitivă și ușor de utilizat de orice persoană, chiar și neinițiată în lucrul
cu calculatorul sau în domeniul restaurantelor.
Primul pas care trebuie făcut pentru a putea folosi aplicația este autentificarea, prin
introducerea numelui de utilizator și a parolei setate, ca în figura 4.2.1.
Figura 4.2.1 Pagina de login
După autentificarea în aplicație, utilizatorul are acces la pagina cu lista de angajați,
pagina cu adăugarea venitului zilnic, pagina de generare a rapoartelor și pagina de utilizatori.
În figura 4.2.2 vedem tabelul cu toți angajații firmei, data angajării și salariul de bază
și butonul pe care în versiuni viitoare îl vom folosi pentru a adăuga un angajat nou (momentan
acest lucru se poate face doar din baza de date).
Figura 4.2.2 Lista angajati
Administrarea utilizatorilor se face în pagina Admin unde putem vizualiza utilizatorii
și în versiuni viitoare vom putea adăuga și șterge.
39
Figura 4.2.3 Pagina Admin
Pagina Daily Income ne permite să selectăm un angajat dintr-un dropdown și să
adăugam salariul și ciubucul realizat într-o dată selectată.
Figura 4.2.4 Daily Income
Ultima pagină folosită este cea de Reports unde generăm rapoarte pentru un angajat
selectând angajatul, data start și dată sfârșit. Un modal va apărea pe ecran cu informațiile cerute.
Figura 4.2.5 Rapoarte angajati
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Pentru dezvoltarea aplicației am utilizat tehnologiile prezentate în capitolul 2 al curentei lucrări. Astfel, am folosit ca și mediu de lucru… [622962] (ID: 622962)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
