Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
java_dzienna_15_09
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
java_dzienna_15_09
Commits
dca054b2
Commit
dca054b2
authored
Oct 07, 2022
by
Patryk Czarnik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ProductController - pełna wersja
parent
9f972f10
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
170 additions
and
10 deletions
+170
-10
PhotoUtil.java
PC37-RestSpring/src/main/java/sklep/photo/PhotoUtil.java
+44
-0
ProductController.java
...estSpring/src/main/java/sklep/rest/ProductController.java
+126
-10
No files found.
PC37-RestSpring/src/main/java/sklep/photo/PhotoUtil.java
0 → 100644
View file @
dca054b2
package
sklep
.
photo
;
import
java.io.File
;
import
java.io.IOException
;
import
java.nio.file.Files
;
import
java.nio.file.Path
;
import
java.nio.file.Paths
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.server.ResponseStatusException
;
@Component
public
class
PhotoUtil
{
private
static
final
String
EXT
=
".jpg"
;
@Value
(
"${alx.photo_dir}"
)
private
String
dir
;
private
Path
getPath
(
int
productId
)
{
String
fileName
=
productId
+
EXT
;
return
Paths
.
get
(
dir
,
fileName
);
}
public
File
getFile
(
int
productId
)
{
Path
path
=
getPath
(
productId
);
File
file
=
path
.
toFile
();
if
(
file
.
exists
())
{
return
file
;
}
else
{
throw
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Cannot read photo for product id = "
+
productId
);
}
}
public
byte
[]
readBytes
(
int
productId
)
{
Path
path
=
getPath
(
productId
);
try
{
return
Files
.
readAllBytes
(
path
);
}
catch
(
IOException
e
)
{
throw
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Cannot read photo for product id = "
+
productId
);
}
}
}
PC37-RestSpring/src/main/java/sklep/rest/ProductController.java
View file @
dca054b2
package
sklep
.
rest
;
package
sklep
.
rest
;
import
java.math.BigDecimal
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.Optional
;
import
org.springframework.
beans.factory.annotation.Autowired
;
import
org.springframework.
dao.EmptyResultDataAccessException
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.
stereotype.Controller
;
import
org.springframework.
web.bind.annotation.DeleteMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.PutMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.server.ResponseStatusException
;
import
org.springframework.web.server.ResponseStatusException
;
import
sklep.model.Product
;
import
sklep.model.Product
;
import
sklep.photo.PhotoUtil
;
import
sklep.repository.ProductRepository
;
import
sklep.repository.ProductRepository
;
/* RestController to jest taki Controller, który nie uzywa szablonów, tylko wyniki metod odsyła w treści odpowiedzi do klienta.
* Inaczej mówiąc działa tak, jakby każda metoda miała @ResponseBody.
*
* Najczęściej na poziomie klasy umieszcza się też @RequestMapping z ogólnym adresem, pod którym działa cała ta klasa.
* Metody wewnątrz mogą mieć podany "dalszy ciąg adresu".
*/
@RestController
@RestController
@RequestMapping
(
"/products"
)
@RequestMapping
(
"/products"
)
public
class
ProductController
{
public
class
ProductController
{
@Autowired
private
ProductRepository
productRepository
;
private
ProductRepository
productRepository
;
private
PhotoUtil
photoUtil
;
// W tej klasie stosujemy wstrzykiwanie poprzez konstruktor,
// czyli nie piszemy @Autowired przed polem productRepository,
// tylko tworzymy konstruktor, który wymaga podania tego obiektu.
public
ProductController
(
ProductRepository
productRepository
,
PhotoUtil
photoUtil
)
{
this
.
productRepository
=
productRepository
;
this
.
photoUtil
=
photoUtil
;
}
@GetMapping
@GetMapping
public
List
<
Product
>
readAll
()
{
public
List
<
Product
>
getAllProducts
()
{
return
productRepository
.
findAll
();
return
productRepository
.
findAll
();
}
}
@GetMapping
(
"/{id}"
)
@GetMapping
(
"/{id}"
)
public
Product
readOne
(
@PathVariable
(
"id"
)
int
productId
)
{
public
Product
getOneProduct
(
@PathVariable
Integer
id
)
{
Optional
<
Product
>
product
=
productRepository
.
findById
(
productId
);
Optional
<
Product
>
product
=
productRepository
.
findById
(
id
);
if
(
product
.
isPresent
())
{
return
product
.
orElseThrow
(()
->
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Brak produktu nr "
+
id
));
return
product
.
get
();
}
/*
* Tylko jako przykład możliwości: odczyt wybranego pola z rekordu. To twórca
* usługi decyduje o tym, jakie adresy będą dostępne i co pod nimi będzie. Jeśli
* uważamy, że klientom "przyda się" bezpośredni dostęp do wybranego pola, to
* możemy stworzyć taką metodę, ale nie ma żadnego obowiązku, aby robić to dla
* wszystkich pól.
*/
@GetMapping
(
"/{id}/price"
)
public
BigDecimal
getPrice
(
@PathVariable
(
"id"
)
Integer
productId
)
{
return
getOneProduct
(
productId
).
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.
*/
@PutMapping
(
"/{id}/price"
)
public
void
setPrice
(
@PathVariable
(
"id"
)
Integer
productId
,
@RequestBody
BigDecimal
newPrice
)
{
Optional
<
Product
>
optionalProduct
=
productRepository
.
findById
(
productId
);
if
(
optionalProduct
.
isPresent
())
{
Product
product
=
optionalProduct
.
get
();
product
.
setPrice
(
newPrice
);
productRepository
.
save
(
product
);
}
else
{
}
else
{
throw
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
);
// 404
throw
new
ResponseStatusException
(
HttpStatus
.
NOT_FOUND
,
"Brak produktu nr "
+
productId
);
}
}
}
}
/*
* 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łaczone 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
.
setProductId
(
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łuzyć 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, ustawwiam productId na
// null.
product
.
setProductId
(
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"
)
Integer
productId
)
{
return
photoUtil
.
readBytes
(
productId
);
}
}
}
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