Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
alx_java2b_20250412
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Patryk Czarnik
alx_java2b_20250412
Commits
cfe8a578
Commit
cfe8a578
authored
Jun 01, 2025
by
Patryk Czarnik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Kontrolery RESTowe
parent
81c5a6a5
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
208 additions
and
0 deletions
+208
-0
CustomerEndpoint.java
...klepSpring/src/main/java/sklep/rest/CustomerEndpoint.java
+33
-0
OrderEndpoint.java
PC37-SklepSpring/src/main/java/sklep/rest/OrderEndpoint.java
+38
-0
ProductEndpoint.java
...SklepSpring/src/main/java/sklep/rest/ProductEndpoint.java
+135
-0
spis_tresci.jsp
...pSpring/src/main/webapp/WEB-INF/templates/spis_tresci.jsp
+2
-0
No files found.
PC37-SklepSpring/src/main/java/sklep/rest/CustomerEndpoint.java
0 → 100644
View file @
cfe8a578
package
sklep
.
rest
;
import
java.util.List
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.ui.Model
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.server.ResponseStatusException
;
import
sklep.model.Customer
;
import
sklep.repository.CustomerRepository
;
@RestController
@RequestMapping
(
"/rest/customers"
)
public
class
CustomerEndpoint
{
@Autowired
private
CustomerRepository
customerRepository
;
@GetMapping
public
List
<
Customer
>
listaKlientow
(
Model
model
)
{
return
customerRepository
.
findAll
();
}
@GetMapping
(
"/{email}"
)
public
Customer
jedenKlient
(
Model
model
,
@PathVariable
(
"email"
)
String
email
)
{
return
customerRepository
.
findById
(
email
).
orElseThrow
(()
->
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
));
}
}
PC37-SklepSpring/src/main/java/sklep/rest/OrderEndpoint.java
0 → 100644
View file @
cfe8a578
package
sklep
.
rest
;
import
java.util.List
;
import
java.util.Optional
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.server.ResponseStatusException
;
import
sklep.model.Order
;
import
sklep.repository.OrderRepository
;
@RestController
@RequestMapping
(
"/rest/orders"
)
public
class
OrderEndpoint
{
@Autowired
private
OrderRepository
orderRepository
;
@GetMapping
public
List
<
Order
>
readAll
()
{
return
orderRepository
.
findAll
();
}
@GetMapping
(
"/{id}"
)
public
Order
readOne
(
@PathVariable
(
"id"
)
int
id
)
{
Optional
<
Order
>
order
=
orderRepository
.
findById
(
id
);
if
(
order
.
isPresent
())
{
return
order
.
get
();
}
else
{
throw
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Nie ma zamówienia o numerze "
+
id
);
}
}
}
PC37-SklepSpring/src/main/java/sklep/rest/ProductEndpoint.java
0 → 100644
View file @
cfe8a578
package
sklep
.
rest
;
import
org.springframework.dao.EmptyResultDataAccessException
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.server.ResponseStatusException
;
import
sklep.model.Product
;
import
sklep.photo.PhotoUtil
;
import
sklep.repository.ProductRepository
;
import
java.math.BigDecimal
;
import
java.util.List
;
// @RestController odpowiada adnotacji @Controller z dodatkową adnotacją @ResponseBody
// Inaczej mówiąc, metody nie zwracają nazw szablonów, lecz dane, które mają być odesłane do klienta.
@RestController
@RequestMapping
(
"/rest/products"
)
public
class
ProductEndpoint
{
private
ProductRepository
productRepository
;
private
PhotoUtil
photoUtil
;
// Tutaj stosujemy wstrzykiwanie przez konstruktor.
public
ProductEndpoint
(
ProductRepository
productRepository
,
PhotoUtil
photoUtil
)
{
this
.
productRepository
=
productRepository
;
this
.
photoUtil
=
photoUtil
;
}
@GetMapping
(
produces
=
"application/json"
)
public
List
<
Product
>
getProducts
()
{
return
productRepository
.
findAll
();
}
@GetMapping
(
path
=
"/{id}"
,
produces
=
"application/json"
)
public
Product
getProduct
(
@PathVariable
int
id
)
{
return
productRepository
.
findById
(
id
).
orElseThrow
(
()
->
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Brak produktu o numerze "
+
id
));
}
// Ta metoda pokazana tylko po to, aby wytłumaczyć, że struktura adresów powinna odpowiadać logicznej strukturze danych.
// W prawdziwej aplikacji raczej nie dochodzi się do poziomu pojedynczych pól. Teoretycznie można.
@GetMapping
(
path
=
"/{id}/price"
,
produces
=
"application/json"
)
public
BigDecimal
getPrice
(
@PathVariable
Integer
id
)
{
return
getProduct
(
id
).
getPrice
();
}
/*
* Operacja PUT służy do zapisania danych POD PODANYM ADRESEM.
* Na przykład PUT products/2/price z wartością 100 powinno ustawić w produkcie nr 2 cenę 100.
* Jeśli PUT zadziała, to następnie GET wysłany pod ten sam adres powinien odczytać te same dane,
* które PUT zapisał (być może w innym formacie - to inny temat)
*
* PUT najczęściej jest używany do aktualizacji istniejących danych
* (pojedynczych wartości albo całych rekordów), ale może być też użyty do
* zapisania nowych danych. To, co najważniejsze, to fakt, że PUT zapisuje dane
* pod konkretnym adresem, do którego jest wysyłany.
*
* Aby odczytać dane, które przysłał klient, metoda ma jeden parametr oznaczony @RequestBody.
* To do tego parametru Spring przekaże dane odczytane z "body" zapytania.
*/
@PutMapping
(
"/{id}/price"
)
public
void
setPrice
(
@PathVariable
Integer
id
,
@RequestBody
BigDecimal
newPrice
)
{
Product
product
=
productRepository
.
findById
(
id
).
orElseThrow
(()
->
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
));
product
.
setPrice
(
newPrice
);
productRepository
.
save
(
product
);
}
/*
* PUT może również służyć do zapisania całego rekordu, ale zwn, że musi być
* skierowany pod ten adres, pod którym rekord zostanie faktycznie zapisany, w
* praktyce PUT jest uzywany do aktualizacji rekordów (UPDATE).
*
* Aby w aplikacji Springowej, w której jest włączone security, działały zapytania POST i PUT,
* trzeba wyłączyć zabezpieczenie "CSRF":
* .and().csrf().disable()
*/
@PutMapping
(
"/{id}"
)
public
void
update
(
@PathVariable
(
"id"
)
Integer
productId
,
@RequestBody
Product
product
)
{
// Aby mieć pewność, że zapisujemu produkt o typ ID, wpisuję productId z URL-a.
// Ewentualnie możnaby jeszcze sprawdzić czy rekord istnieje, czy ID się zgadza
// i jeśli coś jest nie tak, to wyrzucić wyjątek.
product
.
setId
(
productId
);
productRepository
.
save
(
product
);
}
/*
* POST jest najbardziej ogólną metodą HTTP; oznacza, że klient
* "wysyła jakieś dane na serwer", a serwer odsyła jakąś odpowiedź.
* W zasadzie POST może służyć do wszystkiego.
*
* W praktyce POST bardzo często służy do dodawania nowych rekordów, ponieważ
* gdy tworzymy nowy rekord, to nie znamy z góry jego ID i nie wiemy pod jakim
* URL-em zostanie zapisany (nie da się więc użyć PUT). Stąd wzięła REST-owa
* konwencja, że aby dodać nowy rekord do katalogu, wysyła się POST z danymi
* tego rekordu pod ogólny adres całego katalogu.
*/
@PostMapping
public
Product
insert
(
@RequestBody
Product
product
)
{
// Aby mieć pewność, że zapytanie tworzy nowy rekord, ustawiam productId na null.
product
.
setId
(
null
);
productRepository
.
save
(
product
);
/* Operacja save (a wewnętrznie persist z Hibernate) spowoduje ustawienie nowego ID w obiekcie.
* Warto taką informację przekazać klientowi. Można:
* 1) odesłać uzupełniony rekord (i tak zrobimy tutaj),
* 2) odesłać "małego JSON-a" z informacją o tym ID
* (i innymi informacjami, które serwer chce przekazać klientowi)
* 3) tylko nagłówek Location z URL-em nowego rekordu (to zobaczymy w wersji JAX-RS).
*/
return
product
;
}
@DeleteMapping
(
"/{id}"
)
public
void
delete
(
@PathVariable
(
"id"
)
Integer
productId
)
{
try
{
productRepository
.
deleteById
(
productId
);
}
catch
(
EmptyResultDataAccessException
e
)
{
throw
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Brak produktu nr "
+
productId
);
}
}
/* Większość komunikacji w usługach REST odbywa się w formacie JSON,
* ale czasami używany jest też format XML,
* a dla niektórych danych stosujemy bezpośrednio jakiś format specjalny, np. PNG, JPG dla obrazów, PDF dla wydruków itp.
*/
@GetMapping
(
path
=
"/{id}/photo"
,
produces
=
"image/jpeg"
)
public
byte
[]
getPhoto
(
@PathVariable
(
"id"
)
int
productId
)
{
return
photoUtil
.
readBytes
(
productId
);
}
@PutMapping
(
path
=
"/{id}/photo"
,
consumes
=
"image/jpeg"
)
public
void
uploadPhoto
(
@PathVariable
(
"id"
)
int
productId
,
@RequestBody
byte
[]
bytes
)
{
photoUtil
.
writeBytes
(
productId
,
bytes
);
}
}
PC37-SklepSpring/src/main/webapp/WEB-INF/templates/spis_tresci.jsp
View file @
cfe8a578
...
@@ -36,6 +36,8 @@
...
@@ -36,6 +36,8 @@
<li><a
href=
"/products/new"
>
nowy produkt
</a></li>
<li><a
href=
"/products/new"
>
nowy produkt
</a></li>
<li><a
href=
"/products/1/edit"
>
edycja produktu
</a></li>
<li><a
href=
"/products/1/edit"
>
edycja produktu
</a></li>
<li><a
href=
"/products/2/photo"
>
przykładowe zdjęcie
</a></li>
<li><a
href=
"/products/2/photo"
>
przykładowe zdjęcie
</a></li>
<li><a
href=
"/products/max"
>
najdroższy produkt
</a></li>
<li><a
href=
"/products/2/ile_drozszych"
>
ile droższych
</a>
niż odkurzacz
</li>
</ul>
</ul>
<h2>
Klienci
</h2>
<h2>
Klienci
</h2>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment