You are on page 1of 35

1/4/2023

Prekvalifikacije za IT 1

Napredne tehnike i principi razvoja softvera


Razvoj web servisa i serverske strane web aplikacija

TEMA 4:

SLOJ SERVISA
Vladimir Dimitrieski, PhD, dimitrieski@uns.ac.rs
Nebojša Horvat, MSc, horva.n@uns.ac.rs
Aleksandar Ignjatijević, B.Sc., aleksandar.ignjatijevic@uns.ac.rs

Prekvalifikacije za IT 2

Pregled
• Servisni sloj u Springu
• Servisi za rad sa bazom podataka
• HQL
• Servisi za rad sa fajlovima
• Logovanje
• log4j
• Zadaci

1
1/4/2023

Prekvalifikacije za IT 3

SERVISNI SLOJ U
SPRINGU

Prekvalifikacije za IT 4

Servisni sloj
• Servisni sloj u Springu nalazi se ispod Web sloja
• na kojem su smešteni kontroleri koji komuniciraju sa klijentskom
stranom
• Istovremeno komunicira i sa slojem na kojem su smešteni
repozitorijumi
• Na ovom nivou nalaze se metode
• koje implementiraju poslovnu logiku aplikacije
• koje implementiraju komunikaciju sa spoljnim resursima (fajl
sistem)
• koje implementiraju komunikaciju sa email serverima

2
1/4/2023

Prekvalifikacije za IT 5

Servisni sloj

Prekvalifikacije za IT 6

SERVISI ZA RAD SA
BAZOM PODATAKA
HQL

3
1/4/2023

Prekvalifikacije za IT 7

Primer
• Kreirati REST endpoint
• Koji vraća listu adresa na osnovu prosleđenog imena korisnika
• putanja /api/v1/addresses/user/{name}

• kreirati novi paket


• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.dataaccess.services

Prekvalifikacije za IT 8

Primer
• Kreirati nov interfejs u paketu
• desni klik na paket -> new -> interface
• nazvati ga AddressDao
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je AddressDaoImpl
• klasa AddressDaoImpl implementira interfejs AddressDao

4
1/4/2023

Prekvalifikacije za IT 9

Primer

public interface AddressDao {

-----------------------------------------------

@Service
public class AddressDaoImpl implements AddressDao{

Prekvalifikacije za IT 10

Primer
• U interfejs dodati metodu koja vraća listu adresa na
osnovu prosleđenog imena korisnika

public List<AddressEntity> findAddressesByUserName(String name);

• U klasu dodati implementaciju metode findAddressesByUserName

10

5
1/4/2023

Prekvalifikacije za IT 11

Primer
@Service
public class AddressDaoImpl implements AddressDao {

@PersistenceContext
private EntityManager em;

@Override
public List<AddressEntity> findAddressesByUserName(String name) {
String sql = "select a " +
"from AddressEntity a " +
"left join fetch a.users u " +
"where u.name = :name ";

Query query = em.createQuery(sql);


query.setParameter("name", name);

List<AddressEntity> result = new ArrayList<>();


result = query.getResultList();
return result;
}
}

11

Prekvalifikacije za IT 12

Primer

• U kontroler AddressControler dodati metodu koja vraća listu adresa


na osnovu prosleđenog imena korisnika

12

6
1/4/2023

Prekvalifikacije za IT 13

Primer
@RestController
@RequestMapping(path = "/api/v1/addresses")
public class AddressController {

//………..

@Autowired
private AddressDao addressDao;

@RequestMapping(method = RequestMethod.GET, value = "/user/{name}")


public List<AddressEntity> getAddressForAUser(@PathVariable String name) {
return addressDao.findAddressesByUserName(name);
}

//………..
}

13

Prekvalifikacije za IT 14

SERVISI ZA RAD SA
FAJLOVIMA

14

7
1/4/2023

Prekvalifikacije za IT 15

Primer
• Kreirati endpoint
• Koji omogućuje upload fajla
• putanja /api/v1/upload
• Ne koristiti REST već implementirati generisanje
stranica na backend-u
• server-side page generation
• frontend kao deo backend-a
• stranice se nalaze i generišu na backend-u i HTML se šalje frontend-u
samo na prikaz
• skoro identična stuktura kao i REST aplikacija osim web sloja

15

Prekvalifikacije za IT 16

STS projekat
• Kreirati novi spring boot
projekat u STS
• File -> New ->
Spring starter project
• na prvom ekranu popuniti kao
što je dato na slici
• nakon popunjavanja pritisnuti
dugme Next
• na drugom ekranu sve ostaviti
kako jeste
• nisu potrebne dodatne
biblioteke
• pritisnuti dugme Finish

16

8
1/4/2023

Prekvalifikacije za IT 17

STS projekat
• Dodati u pom.xml zavisnost od
• spring-boot-starter-web
• spring-boot-starter-thymeleaf
• spring-boot-devtools

17

Prekvalifikacije za IT 18

Primer
• U resources kreirati folder templates
• Kreirati upload.html
• Za mogućnost odabira i slanja fajla
• Kreirati uploadStatus.html
• Za prikaz statusa poslatog fajla

18

9
1/4/2023

Prekvalifikacije za IT 19

Primer – upload.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>

<h1>Spring Boot file upload example</h1>

<form method="POST" action="/upload"


enctype="multipart/form-data">
<input type="file" name="file" /><br/><br/>
<input type="submit" value="Submit" />
</form>

</body>
</html>

19

Prekvalifikacije za IT 20

Primer – uploadStatus.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>

<h1>Spring Boot - Upload Status</h1>

<div th:if="${message}">
<h2 th:text="${message}"></h2>
</div>

</body>
</html>

20

10
1/4/2023

Prekvalifikacije za IT 21

Primer

• kreirati novi paket


• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.uploadexample.controllers
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je UploadController

21

Prekvalifikacije za IT 22

Primer
@Controller
@RequestMapping(path = "/")
public class UploadController {

@RequestMapping(method = RequestMethod.GET)
public String index() {
return "upload";
}

@RequestMapping(method = RequestMethod.GET, value = "/uploadStatus")


public String uploadStatus() {
return "uploadStatus";
}

22

11
1/4/2023

Prekvalifikacije za IT 23

Primer

• kreirati novi paket


• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.uploadexample.services
• Kreirati nov interfejs u paketu
• desni klik na paket -> new -> interface
• nazvati ga FileHandler
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je FileHandlerImpl
• klasa FileHandlerImpl implementira interfejs FileHandler

23

Prekvalifikacije za IT 24

Primer
public interface FileHandler {
public String singleFileUpload(
MultipartFile file, RedirectAttributes
redirectAttributes) throws IOException;
}

24

12
1/4/2023

Prekvalifikacije za IT 25

Primer
@Service
public class FileHandlerImpl implements FileHandler{

//Save the uploaded file to this folder


private static String UPLOADED_FOLDER = "C:\\temp\\";

//………
}

25

Prekvalifikacije za IT 26

Primer
@Override
public String singleFileUpload(MultipartFile file, RedirectAttributes redirectAttributes)
throws IOException {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
return "redirect:uploadStatus";
}
try {

// Get the file and save it somewhere


byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);

redirectAttributes.addFlashAttribute("message",
"You successfully uploaded '" + file.getOriginalFilename() + "'");

} catch (IOException e) {
throw e;
}
return "redirect:/uploadStatus";
}

26

13
1/4/2023

Prekvalifikacije za IT 27

Primer
@Controller
@RequestMapping(path = "/")
public class UploadController {
@Autowired
private FileHandler fileHandler;

@RequestMapping(method = RequestMethod.POST, value = "/upload")


public String singleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
String result = null;
try {
result = fileHandler.singleFileUpload(file, redirectAttributes);
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
// other methods
}

27

Prekvalifikacije za IT 28

Primer

• kreirati novi paket


• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.uploadexample.exceptions
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je GlobalExceptionHandler

28

14
1/4/2023

Prekvalifikacije za IT 29

Primer
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(MultipartException.class)
public String handleError1(MultipartException e,
RedirectAttributes redirectAttributes) {

redirectAttributes.addFlashAttribute("message",
e.getCause().getMessage());
return "redirect:/uploadStatus";

29

Prekvalifikacije za IT 30

Primer
• U klasi gde se nalazi main metoda (npr.
UploadExampleApplication) dodati tomcatEmbedded
metodu koja treba da spreči reset tomcat-a

30

15
1/4/2023

Prekvalifikacije za IT 31

Primer
@Bean
public TomcatServletWebServerFactory tomcatEmbedded() {

TomcatServletWebServerFactory tomcat = new


TomcatServletWebServerFactory();

tomcat.addConnectorCustomizers((TomcatConnectorCustomizer)
connector -> {if ((connector.getProtocolHandler()
instanceof AbstractHttp11Protocol<?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>)
connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});

return tomcat;

31

Prekvalifikacije za IT 32

Primer
• U application.properties fajl dodati:
• spring.servlet.multipart.max-file-size=1MB
• spring.servlet.multipart.max-request-size=1MB

• Pokrenuti aplikaciju
• Kreirati direktorijum C:/temp
• Otici na localhost:8080/

32

16
1/4/2023

Prekvalifikacije za IT 33

LOGOVANJE
log4j

33

Prekvalifikacije za IT 34

Logovanje
• Logovanje predstavlja prikupljanje statističkih podataka o
radu aplikacije
• Primitivan način putem ispisivanja poruka na izlazni
uređaj
• Napredan način putem ispisavanja poruka i pratećih
podataka u odgovarajuće fajlove

34

17
1/4/2023

Prekvalifikacije za IT 35

Log4j
• Apache biblioteka za logovanje u aplikacijama koje su
pisane u Java programskom jeziku
• Dodati u pom.xml zavisnost od
• spring-boot-starter-logging
• spring-boot-starter-log4j2

35

Prekvalifikacije za IT 36

Log4j
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-
logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

36

18
1/4/2023

Prekvalifikacije za IT 37

Log4j
• U application.properties dodati
• logging.level.org.springframework.web=INFO
• logging.level.com.iktpreobuka.uploadexample.controllers=INFO
• logging.level.org.hibernate=ERROR
• logging.file.name=logs/spring-boot-logging.log
• log4j.logger.org.thymeleaf=DEBUG

37

Prekvalifikacije za IT 38

Log4j
• U klasu UploadController dodati instancu Logger-a

private final Logger logger = (Logger) LoggerFactory.getLogger(this.getClass());

• // (import org.slf4j.Logger; import org.slf4j.LoggerFactory;)

• U metodu singleFileUpload dodati

logger.debug("This is a debug message");


logger.info("This is an info message");
logger.warn("This is a warn message");
logger.error("This is an error message");

38

19
1/4/2023

Prekvalifikacije za IT 39

Log4j

39

Prekvalifikacije za IT 40

Log4j

40

20
1/4/2023

Prekvalifikacije za IT 41

SERVISI ZA RAD SA EMAIL


SERVERIMA
JavaMailSender

41

Prekvalifikacije za IT 42

Tehničko podešavanje google i gmail


naloga
• Slanje mejlova se obavlja putem vašeg gmail naloga
• Korak 1: Ukoliko imate podešenu Verifikaciju u 2 koraka, preskočite
korake 1, 2 i 3, a u suprotnom, idite u podešavanja google naloga, u
sekciju Bezbednost.
• Korak 2: U sekciji Bezbednost, u podsekciji
Prijavljivanje na Google, odaberite polje
Verifikacija u 2 koraka.
• Korak 3: Postavite
preferirani vid Verifikacije
u 2 koraka
• Korak 4: U podsekciji
Prijavljivanje na Google,
odaberite polje Lozinke za
aplikacije.

42

21
1/4/2023

Prekvalifikacije za IT 43

Tehničko podešavanje gmail naloga


⚫ Korak 5: Nakon što se otvori prozor Lozinke za aplikacije, odaberite
aplikaciju Pošta i uređaj koji koristite za kurs (Windows računar) I
klikom na Generiši će biti generisana lozinka koju ćete koristiti u
Spring Boot aplikaciji.
⚫ Korak 6: Kopirajte lozinku iz
prozora:

43

Prekvalifikacije za IT 44

Tehničko podešavanje gmail naloga


⚫ Korak 7: Nakon toga je potrebno iskonfigurisati sam gmail nalog.
Na gmail nalogu, nakon klika na podešavanja, u iskačućem prozor
odaberite opciju Pogledajte sva podesavanja.

⚫ Korak 8: Odaberite sekciju


Prosleđivanje i POP/IMAP

44

22
1/4/2023

Prekvalifikacije za IT 45

Tehničko podešavanje gmail naloga


⚫ Korak 9: Omogućite POP i IMAP i sačuvajte izmene.

45

Prekvalifikacije za IT 46

Tehničko podešavanje gmail naloga


⚫ Više o podešavanju možete videti na linku.

46

23
1/4/2023

Prekvalifikacije za IT 47

Spring mejl podrška


• Slanje mejlova se obavlja povezivanjem na odgovarajući
email server
• Interfejsi i klase za Java mejl podršku u Spring
framework-u:
• MailSender interfejs – poseduje osnove funkcionalnosti za slanje
jednostavnih mejlova
• SimpleMailMessage klasa – služi za kreiranje jednostavnih mejlova
(from, to, cc, subject, text fields)
• JavaMailSender interfejs – poseduje podršku za slanje MIME
poruka

47

Prekvalifikacije za IT 48

Spring mejl podrška


• JavaMailSenderImpl klasa– jedna od implentacija JavaMailSender
interfejsa, podržava slanje SimpleMailMessage i MimeMessage
• MimeMessagePreparator interfejs – priprema MIME poruka
• MimeMessageHelper klasa – pomoćna klasa za kreiranje MIME
poruka, podrška za slanje slika, priloga u mejlu kao i oblikovanje
(formatiranje) tekstualnog sadržaja u vidu HTML-a

48

24
1/4/2023

Prekvalifikacije za IT 49

STS projekat
• Kreirati novi spring boot
projekat u STS
• File -> New ->
Spring starter project
• na prvom ekranu popuniti kao
što je dato na slici
• nakon popunjavanja pritisnuti
dugme Next
• na drugom ekranu sve ostaviti
kako jeste
• nisu potrebne dodatne
biblioteke
• pritisnuti dugme Finish

49

Prekvalifikacije za IT 50

STS projekat
• Dodati u pom.xml zavisnost od
• spring-boot-starter-web
• spring-boot-starter-mail

50

25
1/4/2023

Prekvalifikacije za IT 51

STS projekat
• Nakon dodavanja potrebnih zavisnosti, sledeći korak je
podešavanje svojstva email servera
• u ovom primeru će biti korišćen Gmail SMTP server

51

Prekvalifikacije za IT 52

STS projekat
• U application.properties fajl dodati:
• spring.mail.host=smtp.gmail.com
• spring.mail.port=587
• spring.mail.username=<mejl>
• spring.mail.password=<lozinka>
• spring.mail.properties.mail.smtp.auth=true
• spring.mail.properties.mail.smtp.starttls.enable=true

52

26
1/4/2023

Prekvalifikacije za IT 53

Primer
• kreirati novi paket
• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.email_example.models
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je EmailObject

53

Prekvalifikacije za IT 54

Primer
public class EmailObject {

private String to;


private String subject;
private String text;

public EmailObject() {
super();
}
//TODO add getters and setters
}

54

27
1/4/2023

Prekvalifikacije za IT 55

Primer
• kreirati novi paket
• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.email_example.services
• kreirati novi interfejs u paketu
• desni klik na paket -> new -> interface
• nazvati ga EmailService
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je EmailServiceImpl
• klasa EmailServiceImpl implementira interfejs EmailService

55

Prekvalifikacije za IT 56

Primer
public interface EmailService {

void sendSimpleMessage (EmailObject object);


void sendTemplateMessage (EmailObject object) throws
Exception;
void sendMessageWithAttachment (EmailObject object,
String pathToAttachment) throws Exception;
}

56

28
1/4/2023

Prekvalifikacije za IT 57

Primer
@Service
public class EmailServiceImpl implements EmailService{

@Autowired
public JavaMailSender emailSender;

@Override
public void sendSimpleMessage(EmailObject object) {
// TODO Auto-generated method stub
}
@Override
public void sendTemplateMessage(EmailObject object) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void sendMessageWithAttachment(EmailObject object, String
pathToAttachment) throws Exception {
// TODO Auto-generated method stub
}
}
57

Prekvalifikacije za IT 58

Primer
@Override
public void sendSimpleMessage(EmailObject object) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(object.getTo());
message.setSubject(object.getSubject());
message.setText(object.getText());
emailSender.send(message);
}

58

29
1/4/2023

Prekvalifikacije za IT 59

Primer
@Override
public void sendTemplateMessage(EmailObject object) throws
Exception {
MimeMessage mail = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mail,
true);
helper.setTo(object.getTo());
helper.setSubject(object.getSubject());
String text = "<html><body><table "
+ "style='border:2px solid black'>"
+ "<tr><td>" + object.getText() + "</td></tr>"
+ "</table></body></html>";

helper.setText(text, true);
emailSender.send(mail);

59

Prekvalifikacije za IT 60

Primer
@Override
public void sendMessageWithAttachment(EmailObject object,
String pathToAttachment) throws Exception {
MimeMessage mail = emailSender.createMimeMessage();
MimeMessageHelper helper = new
MimeMessageHelper(mail, true);
helper.setTo(object.getTo());
helper.setSubject(object.getSubject());
helper.setText(object.getText(), false);
FileSystemResource file = new FileSystemResource(
new File(pathToAttachment));
helper.addAttachment(file.getFilename(), file);
emailSender.send(mail);
}

60

30
1/4/2023

Prekvalifikacije za IT 61

Primer
• kreirati novi paket
• desni klik na postojeći paket -> new -> package
• nazvati ga com.iktpreobuka.email_example.controllers
• kreirati novu klasu u paketu
• desni klik na paket -> new -> class
• nazvati je EmailController
• u okviru EmailController klase kreirati REST endpoint koji
omogućuje slanje jednostavnog email-a
• putanja /simpleEmail

61

Prekvalifikacije za IT 62

Primer
@RestController
@RequestMapping(path = "/")
public class EmailController {

@Autowired
private EmailService emailService;
private static String PATH_TO_ATTACHMENT = "E://proba//slika.jpg";

@RequestMapping(method = RequestMethod.POST, value = "/simpleEmail")


public String sendSimpleMessage(@RequestBody EmailObject object) {
if(object==null || object.getTo()==null ||
object.getText()==null) {
return null;
}

emailService.sendSimpleMessage(object);
return "Your mail has been sent!";
}
}

62

31
1/4/2023

Prekvalifikacije za IT 63

Primer
• kreirati REST endpoint koji omogućuje slanje email-a,
tako da je tekst mejla oblikovan vidu html-a
• putanja /templateEmail
• kreirati REST endpoint koji omogućuje slanje email-a sa
prilogom
• putanja /emailWithAttachment

63

Prekvalifikacije za IT 64

Primer
@RequestMapping(method = RequestMethod.POST, value =
"/templateEmail")
public String sendTemplateMessage(@RequestBody EmailObject
object) throws Exception {
if(object==null || object.getTo()==null ||
object.getText()==null) {
return null;
}
emailService.sendTemplateMessage(object);
return "Your mail has been sent!";
}

64

32
1/4/2023

Prekvalifikacije za IT 65

Primer
@RequestMapping(method = RequestMethod.POST, value =
"/emailWithAttachment")
public String sendMessageWithAttachment(@RequestBody EmailObject
object) throws Exception {
if(object==null || object.getTo()==null ||
object.getText()==null) {
return null;
}
emailService.sendMessageWithAttachment(object,
PATH_TO_ATTACHMENT);
return "Your mail has been sent!";
}

65

Prekvalifikacije za IT 66

Primer
• Pokrenuti aplikaciju
• Ukoliko postoje problemi sa slanjem mejla,
• proveriti svoj gmail nalog
• Možda je Google poslao poruku da potvrdite da ste vi slali email aplikativno

• prođite još jednom kroz tehnička podešavanja napisana na


početku teme.

• Problem može biti i antivirus


• npr. Avast ne dozvoljava TLS konekcije
• isključiti antivirus na 10 min ili u toku testiranja servisa

66

33
1/4/2023

Prekvalifikacije za IT 67

ZADACI

67

Prekvalifikacije za IT 68

Zadatak 1
• Uraditi sledeće stavke:
• 1.1 omogućiti upload fajla sa listom korisnika gde svaki red u fajlu
sadrži podatke za jednog korisnika (ime i email), gde su podaci
delimitirani zarezom
• 1.2 nakon što je fajl sa korisnicima upload-ovan omogućiti čuvanje
svih korisnika koji se nalaze u fajlu
• 1.3 Prilikom dodavanja novog korisnika ili izmene postojećeg
korisnika omogućiti proveru da li je prosleđena mail adresa
korisnika već uneta u bazu podataka. Ukoliko jeste zabraniti unos
ili izmenu
• 1.4 u klasu UserEntity dodati polje troškovi. Prilikom unosa novog ili
izmene postojećeg korisnika polje troškovi postaviti na vrednost
5000 ukoliko korisnik živi u Novom Sadu, ili 10000 ukoliko korisnik
živi u Beogradu. U svim ostalim situacijama upisati vrednost 0 u
polje troškovi

68

34
1/4/2023

Prekvalifikacije za IT 69

Zadatak 2
• Uraditi sledeće stavke:
• 2.1 Kreirati REST endpoint koji omogućuje download fajla

• 2.2 Kreirati REST endpoint koji omogućuje downolad fajla u kome se nalaze
podaci o svim korisnicima koji se nalaze u bazi podataka. Fajl je potrebno prvo
napraviti na serverskoj strani tako da su podaci o korisnicima razdvojeni
zarezom (csv fajl)

• 2.3 Proširiti zadatak 2.2 tako da REST endpoint prima listu svih atributa klase
UserEntity koje korisnik želi da se nalaze u csv fajlu. Ukoliko se u listi nalazi
atribut koji nije deo UserEntity kase, vratiti odgovarajuću grešku korisniku.
Ukoliko je prosleđena prazna lista, u fajl upisati sve atribute klase UserEntity

• 2.4 Napraviti endpoint za slanje MIME email-a sa attachment-om, gde ce


parametri email-a (to, subject, text) fajl koji je attachment biti prosledjeni
endpoint-u.

69

35

You might also like