Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
java_weekendowa_20221008
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_weekendowa_20221008
Commits
d414a2ad
Commit
d414a2ad
authored
Dec 11, 2022
by
Patryk Czarnik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Wielomodulowy-RestSerwer
parent
e542dea5
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1083 additions
and
0 deletions
+1083
-0
pom.xml
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/pom.xml
+54
-0
AplikacjaRestowa.java
...ulowy-RestSerwer/src/main/java/rest/AplikacjaRestowa.java
+19
-0
Hello.java
...38-Wielomodulowy-RestSerwer/src/main/java/rest/Hello.java
+22
-0
RCustomer.java
...ielomodulowy-RestSerwer/src/main/java/rest/RCustomer.java
+79
-0
ROrder.java
...8-Wielomodulowy-RestSerwer/src/main/java/rest/ROrder.java
+88
-0
RProduct.java
...Wielomodulowy-RestSerwer/src/main/java/rest/RProduct.java
+167
-0
RProductJSON.java
...omodulowy-RestSerwer/src/main/java/rest/RProductJSON.java
+128
-0
RProductPDF.java
...lomodulowy-RestSerwer/src/main/java/rest/RProductPDF.java
+35
-0
RProductXML.java
...lomodulowy-RestSerwer/src/main/java/rest/RProductXML.java
+112
-0
ObslugaXSL.java
...odulowy-RestSerwer/src/main/java/rest/ext/ObslugaXSL.java
+54
-0
PDFWriter.java
...modulowy-RestSerwer/src/main/java/rest/ext/PDFWriter.java
+47
-0
RecordNotFoundMapper.java
...stSerwer/src/main/java/rest/ext/RecordNotFoundMapper.java
+23
-0
SklepExceptionMapper.java
...stSerwer/src/main/java/rest/ext/SklepExceptionMapper.java
+32
-0
fop-conf.xml
...omodulowy-RestSerwer/src/main/webapp/WEB-INF/fop-conf.xml
+162
-0
sklep-fo.xsl
...omodulowy-RestSerwer/src/main/webapp/WEB-INF/sklep-fo.xsl
+60
-0
pom.xml
PC38-Wielomodulowy/pom.xml
+1
-0
No files found.
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/pom.xml
0 → 100644
View file @
d414a2ad
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<parent>
<groupId>
pl.alx.kjava.wielomodulowy
</groupId>
<artifactId>
PC38-Wielomodulowy
</artifactId>
<version>
1.0
</version>
</parent>
<artifactId>
PC38-Wielomodulowy-RestSerwer
</artifactId>
<packaging>
war
</packaging>
<build>
<plugins>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-war-plugin
</artifactId>
<version>
3.3.2
</version>
<configuration>
<failOnMissingWebXml>
false
</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>
${project.groupId}
</groupId>
<artifactId>
PC38-Wielomodulowy-Model
</artifactId>
<version>
${project.version}
</version>
</dependency>
<dependency>
<groupId>
${project.groupId}
</groupId>
<artifactId>
PC38-Wielomodulowy-BazaDanych
</artifactId>
<version>
${project.version}
</version>
</dependency>
<dependency>
<groupId>
javax
</groupId>
<artifactId>
javaee-web-api
</artifactId>
<version>
8.0.1
</version>
<scope>
provided
</scope>
</dependency>
<dependency>
<groupId>
org.apache.xmlgraphics
</groupId>
<artifactId>
fop
</artifactId>
<version>
2.8
</version>
<exclusions>
<exclusion>
<groupId>
xml-apis
</groupId>
<artifactId>
xml-apis
</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
\ No newline at end of file
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/AplikacjaRestowa.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
javax.ws.rs.ApplicationPath
;
import
javax.ws.rs.core.Application
;
@ApplicationPath
(
"/"
)
public
class
AplikacjaRestowa
extends
Application
{
/* Ta klasa pełni rolę "aktywatora" usługi restowej w ramach projektu.
* Gdy serwer zauważy taką klase w projekcie, to skonfiguruje mechanizmy JAX-RS.
* Ta klasa może też zawierać konfigurację:
* - @ApplicationPath - wspólny prefiks przed wszystkimi zapytaniami REST-owymi
*
* - metoda getClasses - zwraca zbiór klas, z których składa się aplikacja
*
* - metoda getSingletons - zwraca obiekty, z których składa się aplikacja
*
* Gdy tych metod nie ma, to serwer skanuje projekt i znajduje wszystkie klasy z adnotacjami @Path lub @Provider
*/
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/Hello.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
java.time.LocalDateTime
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.Path
;
@Path
(
"/hello"
)
public
class
Hello
{
@GET
public
String
helloWorld
()
{
return
"Hello world"
;
}
@GET
@Path
(
"/time"
)
public
String
ktoraGodzina
()
{
return
LocalDateTime
.
now
().
toString
();
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/RCustomer.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
java.util.List
;
import
javax.enterprise.context.RequestScoped
;
import
javax.ws.rs.Consumes
;
import
javax.ws.rs.DELETE
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.POST
;
import
javax.ws.rs.PUT
;
import
javax.ws.rs.Path
;
import
javax.ws.rs.PathParam
;
import
javax.ws.rs.Produces
;
import
javax.ws.rs.core.Response
;
import
javax.ws.rs.core.UriBuilder
;
import
sklep.db.CustomerDAO
;
import
sklep.db.DBConnection
;
import
sklep.db.DBException
;
import
sklep.db.RecordNotFound
;
import
sklep.model.Customer
;
@RequestScoped
@Path
(
"/customers"
)
@Produces
({
"application/xml"
,
"application/json"
})
@Consumes
({
"application/xml"
,
"application/json"
})
public
class
RCustomer
{
@POST
public
Response
save
(
final
Customer
customer
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
CustomerDAO
customerDAO
=
db
.
customerDAO
();
customerDAO
.
save
(
customer
);
db
.
commit
();
return
Response
.
created
(
UriBuilder
.
fromResource
(
RCustomer
.
class
).
path
(
String
.
valueOf
(
customer
.
getEmail
())).
build
()).
build
();
}
}
@GET
@Path
(
"/{id}"
)
public
Customer
findById
(
@PathParam
(
"id"
)
final
String
email
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
CustomerDAO
customerDAO
=
db
.
customerDAO
();
return
customerDAO
.
findByEmail
(
email
);
}
}
@GET
public
List
<
Customer
>
listAll
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
CustomerDAO
customerDAO
=
db
.
customerDAO
();
return
customerDAO
.
readAll
();
}
}
@PUT
@Path
(
"/{id}"
)
public
Response
update
(
@PathParam
(
"id"
)
String
email
,
final
Customer
customer
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
CustomerDAO
customerDAO
=
db
.
customerDAO
();
customer
.
setEmail
(
email
);
customerDAO
.
save
(
customer
);
db
.
commit
();
}
return
Response
.
noContent
().
build
();
}
@DELETE
@Path
(
"/{id}"
)
public
Response
deleteById
(
@PathParam
(
"id"
)
String
email
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
CustomerDAO
customerDAO
=
db
.
customerDAO
();
customerDAO
.
delete
(
email
);
db
.
commit
();
}
return
Response
.
noContent
().
build
();
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/ROrder.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
java.net.URI
;
import
java.util.List
;
import
javax.enterprise.context.RequestScoped
;
import
javax.ws.rs.Consumes
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.Path
;
import
javax.ws.rs.PathParam
;
import
javax.ws.rs.Produces
;
import
javax.ws.rs.core.Response
;
import
javax.ws.rs.core.Response.Status
;
import
javax.ws.rs.core.UriBuilder
;
import
sklep.db.DBConnection
;
import
sklep.db.DBException
;
import
sklep.db.OrderDAO
;
import
sklep.db.RecordNotFound
;
import
sklep.model.Order
;
@RequestScoped
@Path
(
"/orders"
)
@Produces
({
"application/xml"
,
"application/json"
})
@Consumes
({
"application/xml"
,
"application/json"
})
public
class
ROrder
{
@GET
public
List
<
Order
>
listAll
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
OrderDAO
orderDAO
=
db
.
orderDAO
();
return
orderDAO
.
readAll
();
}
}
@GET
@Path
(
"/{id:[0-9][0-9]*}"
)
public
Response
findById
(
@PathParam
(
"id"
)
final
Integer
id
)
{
// Klasa Response pozwala nam z pełną precyzją przygotować odpowiedź, która ma zostać odesłana klientowi.
// W przypadku pozytywnym (ok) zostanie odesłany obiekt przetłumaczony na XML lub JSON, a kod wynikowy to będzie 200.
// Ale w przypadku błędów możemy sami zdecydować co odsyłami (tutaj odpowiednie kody HTTP).
try
(
DBConnection
db
=
DBConnection
.
open
())
{
OrderDAO
orderDAO
=
db
.
orderDAO
();
Order
order
=
orderDAO
.
findById
(
id
);
return
Response
.
ok
(
order
).
build
();
}
catch
(
DBException
e
)
{
e
.
printStackTrace
();
return
Response
.
status
(
Status
.
INTERNAL_SERVER_ERROR
).
build
();
}
catch
(
RecordNotFound
e
)
{
return
Response
.
status
(
Status
.
NOT_FOUND
).
build
();
}
}
/*
// Metoda, która ma obsłużyć pobranie info o właścicielu zamówienia:
// /orders/1/customer
// W tej wersji metoda zwraca bezpośrednio dane klienta.
// Wada tego podejścia: ten sam rekord (konkretny klient) jest widoczny pod różnymi adresami URL.
@GET
@Path("/{id:[0-9][0-9]*}/customer")
public Customer getCustomer(@PathParam("id") Integer orderId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
OrderDAO orderDAO = db.orderDAO();
CustomerDAO customerDAO = db.customerDAO();
Order order = orderDAO.findById(orderId);
Customer customer = customerDAO.findByEmail(order.getCustomerEmail());
return customer;
}
}
*/
// W tej wersji w odpowiedzi na zapytanie o dane klienta, który złożył zamówienie,
// wyślemy przekierowanie pod adres tego klienta.
// To jest lepsze z punktu widzenia "dobrych praktyk REST".
@GET
@Path
(
"/{id:[0-9][0-9]*}/customer"
)
public
Response
getCustomer
(
@PathParam
(
"id"
)
Integer
orderId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
OrderDAO
orderDAO
=
db
.
orderDAO
();
Order
order
=
orderDAO
.
findById
(
orderId
);
URI
customerURI
=
UriBuilder
.
fromResource
(
RCustomer
.
class
)
.
path
(
"/{email}"
)
.
build
(
order
.
getCustomerEmail
());
return
Response
.
seeOther
(
customerURI
).
build
();
}
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/RProduct.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
java.math.BigDecimal
;
import
java.net.URI
;
import
java.util.List
;
import
javax.ws.rs.Consumes
;
import
javax.ws.rs.DELETE
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.POST
;
import
javax.ws.rs.PUT
;
import
javax.ws.rs.Path
;
import
javax.ws.rs.PathParam
;
import
javax.ws.rs.Produces
;
import
javax.ws.rs.core.Context
;
import
javax.ws.rs.core.Response
;
import
javax.ws.rs.core.UriInfo
;
import
sklep.db.DBConnection
;
import
sklep.db.DBException
;
import
sklep.db.ProductDAO
;
import
sklep.db.RecordNotFound
;
import
sklep.model.Product
;
import
sklep.model.ProductList
;
import
sklep.photo.PhotoUtil
;
// JAX-RS - część Javy EE
// Aplikacja (projekt) składa się z wielu "resource classes", z których każda obsługuje pewien rodzaj encji
// np. pod adresem /products działa ta klasa RProduct, która zajmuje się obsługą produktów
// a pod adresem /orders działa ROrder, która zajmuje się zamówieniami.
// Przykładowa dobra (szczegółowa) dokumentacja: https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest3x/index.html
@Path
(
"/products"
)
public
class
RProduct
{
// Gdy w Produces jest wiele formatów, to klient może wybrać za pomocą nagłówka Accept
// Gdy w Consumes jest wiele formatów, to klient może przysłać dane w dowolnym z nich (nagłówek Content-Type)
@GET
@Produces
({
"application/json"
,
"application/xml"
,
"application/pdf"
,
"text/plain;charset=UTF-8"
})
public
ProductList
readAllProducts
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
new
ProductList
(
productDAO
.
readAll
());
}
}
// Może też być tak, że kilka metod działa pod tym samym adresem, ale służą one do tworzenia odpowiedzi w różnych formatach.
// Przykład: tworzenie HTML w oddzielnej metodzie
@GET
@Produces
(
"text/html;charset=UTF-8"
)
public
String
readAllProductsHTML
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
List
<
Product
>
products
=
productDAO
.
readAll
();
StringBuilder
txt
=
new
StringBuilder
(
"<!DOCTYPE html>\n<html><body>\n"
);
txt
.
append
(
"<h1>Lista produktów</h1>\n"
);
for
(
Product
product
:
products
)
{
txt
.
append
(
product
.
toHtml
()).
append
(
'\n'
);
}
txt
.
append
(
"</body></html>"
);
return
txt
.
toString
();
}
}
@Path
(
"/{id}"
)
@GET
@Produces
({
"application/json"
,
"application/xml"
,
"application/pdf"
,
"text/plain"
})
public
Product
readOneProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
productDAO
.
findById
(
productId
);
}
}
@Path
(
"/{id}"
)
@GET
@Produces
(
"text/html;charset=UTF-8"
)
public
String
readOneProductsHTML
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
Product
product
=
readOneProduct
(
productId
);
return
"<!DOCTYPE html>\n<html><body>"
+
product
.
toHtml
()
+
"</body></html>"
;
}
@Path
(
"/{id}/foto"
)
@GET
@Produces
(
"image/jpeg"
)
public
byte
[]
foto
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
return
PhotoUtil
.
readBytes
(
productId
);
}
@Path
(
"/{id}/price"
)
@GET
@Produces
({
"application/json"
,
"text/plain"
})
public
BigDecimal
getPrice
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
Product
product
=
productDAO
.
findById
(
productId
);
return
product
.
getPrice
();
}
}
// W metodach HTTP POST i PUT klient przysyła dane na serwer (tzw. body / entity / content).
// Adnotacja @Consumes mówi w jakim formacie powinny być te dane.
// Metoda w JAX-RS może posiadać co najwyżej jeden parametr nieoznaczony żadną adnotacją.
// Właśnie poprzez ten parametr przekazywane są dane przysłane w treści zapytania (w praktyce: POST i PUT).
@Path
(
"/{id}/price"
)
@PUT
@Consumes
({
"application/json"
,
"text/plain"
})
public
void
setPrice
(
@PathParam
(
"id"
)
int
productId
,
BigDecimal
newPrice
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
Product
product
=
productDAO
.
findById
(
productId
);
product
.
setPrice
(
newPrice
);
productDAO
.
save
(
product
);
db
.
commit
();
}
}
@Path
(
"/{id}"
)
@PUT
@Consumes
({
"application/json"
,
"application/xml"
})
public
void
updateProduct
(
@PathParam
(
"id"
)
int
productId
,
Product
product
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
product
.
getProductId
()
==
null
)
{
// jeśli przysłany rekord nie posiada ID, to utawiam ID z adresu
// w szczególności pozwalam na zapisanie nowego produktu, ale pod określonym adresem
product
.
setProductId
(
productId
);
}
else
if
(
product
.
getProductId
()
!=
productId
)
{
// ale jeśli ID było ustawione, ale było inne niż w adresie, to jest to podejrzana sytuacja i takie zapytania nie wykonamy
throw
new
IllegalArgumentException
(
"ID produktu nie zgodne z adresem URL"
);
}
productDAO
.
save
(
product
);
db
.
commit
();
}
}
// za pomocą POST będzie można przysłać wyłącznie nowe produkty be określonego ID,
// a aplikacja sama wybierze nowe ID z sekwencjii
// w wyniku zostanie odesłany uzupełniony produkt
@POST
@Consumes
({
"application/json"
,
"application/xml"
})
public
Response
addProduct
(
Product
product
,
@Context
UriInfo
uriInfo
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
product
.
getProductId
()
!=
null
)
{
throw
new
IllegalArgumentException
(
"Nowy produkt nie może mieć ustawionego ID"
);
}
productDAO
.
insertNew
(
product
);
db
.
commit
();
URI
uri
=
uriInfo
.
getAbsolutePathBuilder
().
path
(
"/{id}"
).
build
(
product
.
getProductId
());
return
Response
.
created
(
uri
).
build
();
}
}
@DELETE
@Path
(
"/{id}"
)
public
void
removeProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
productDAO
.
delete
(
productId
))
{
db
.
commit
();
}
else
{
throw
new
RecordNotFound
(
"Nie ma produktu nr "
+
productId
);
}
}
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/RProductJSON.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
java.math.BigDecimal
;
import
java.util.List
;
import
javax.ws.rs.Consumes
;
import
javax.ws.rs.DELETE
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.POST
;
import
javax.ws.rs.PUT
;
import
javax.ws.rs.Path
;
import
javax.ws.rs.PathParam
;
import
javax.ws.rs.Produces
;
import
sklep.db.DBConnection
;
import
sklep.db.DBException
;
import
sklep.db.ProductDAO
;
import
sklep.db.RecordNotFound
;
import
sklep.model.Product
;
import
sklep.photo.PhotoUtil
;
@Path
(
"/products.json"
)
@Consumes
(
"application/json"
)
@Produces
(
"application/json"
)
public
class
RProductJSON
{
// @Produces i @Consumes na poziomie klasy są domyślnymi ustawieniami dla wszystkich metod.
// Metoda może to ustawienie zmienić - tak jest w foto.
// Inaczej niż w Springu, ustawienie Produces/Consumes na poziomie klasy dotyczy tylko tych metod,
// które coś produkują lub konsumują. Metody typu GET nie zwracają uwagi na Consumes,
// a metody typu void są poprawne mimo tego, że nie produkują JSONa.
@GET
public
List
<
Product
>
readAllProducts
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
productDAO
.
readAll
();
}
}
@Path
(
"/{id}"
)
@GET
public
Product
readOneProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
productDAO
.
findById
(
productId
);
}
}
@Path
(
"/{id}/foto"
)
@GET
@Produces
(
"image/jpeg"
)
public
byte
[]
foto
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
return
PhotoUtil
.
readBytes
(
productId
);
}
@Path
(
"/{id}/price"
)
@GET
public
BigDecimal
getPrice
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
Product
product
=
productDAO
.
findById
(
productId
);
return
product
.
getPrice
();
}
}
// W metodach HTTP POST i PUT klient przysyła dane na serwer (tzw. body / entity / content).
// Adnotacja @Consumes mówi w jakim formacie powinny być te dane.
// Metoda w JAX-RS może posiadać co najwyżej jeden parametr nieoznaczony żadną adnotacją.
// Właśnie poprzez ten parametr przekazywane są dane przysłane w treści zapytania (w praktyce: POST i PUT).
@Path
(
"/{id}/price"
)
@PUT
public
void
setPrice
(
@PathParam
(
"id"
)
int
productId
,
BigDecimal
newPrice
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
Product
product
=
productDAO
.
findById
(
productId
);
product
.
setPrice
(
newPrice
);
productDAO
.
save
(
product
);
db
.
commit
();
}
}
@Path
(
"/{id}"
)
@PUT
public
void
updateProduct
(
@PathParam
(
"id"
)
int
productId
,
Product
product
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
product
.
getProductId
()
==
null
)
{
// jeśli przysłany rekord nie posiada ID, to utawiam ID z adresu
// w szczególności pozwalam na zapisanie nowego produktu, ale pod określonym adresem
product
.
setProductId
(
productId
);
}
else
if
(
product
.
getProductId
()
!=
productId
)
{
// ale jeśli ID było ustawione, ale było inne niż w adresie, to jest to podejrzana sytuacja i takie zapytania nie wykonamy
throw
new
IllegalArgumentException
(
"ID produktu nie zgodne z adresem URL"
);
}
productDAO
.
save
(
product
);
db
.
commit
();
}
}
// za pomocą POST będzie można przysłać wyłącznie nowe produkty be określonego ID,
// a aplikacja sama wybierze nowe ID z sekwencjii
// w wyniku zostanie odesłany uzupełniony produkt
@POST
public
Product
addProduct
(
Product
product
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
product
.
getProductId
()
!=
null
)
{
throw
new
IllegalArgumentException
(
"Nowy produkt nie może mieć ustawionego ID"
);
}
productDAO
.
insertNew
(
product
);
db
.
commit
();
return
product
;
}
}
@DELETE
@Path
(
"/{id}"
)
public
void
removeProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
productDAO
.
delete
(
productId
))
{
db
.
commit
();
}
else
{
throw
new
RecordNotFound
(
"Nie ma produktu nr "
+
productId
);
}
}
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/RProductPDF.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.Path
;
import
javax.ws.rs.PathParam
;
import
javax.ws.rs.Produces
;
import
sklep.db.DBConnection
;
import
sklep.db.DBException
;
import
sklep.db.ProductDAO
;
import
sklep.db.RecordNotFound
;
import
sklep.model.Product
;
import
sklep.model.ProductList
;
@Path
(
"/products.pdf"
)
@Produces
(
"application/pdf"
)
public
class
RProductPDF
{
@GET
public
ProductList
readAllProducts
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
new
ProductList
(
productDAO
.
readAll
());
}
}
@Path
(
"/{id}"
)
@GET
public
Product
readOneProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
productDAO
.
findById
(
productId
);
}
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/RProductXML.java
0 → 100644
View file @
d414a2ad
package
rest
;
import
javax.ws.rs.Consumes
;
import
javax.ws.rs.DELETE
;
import
javax.ws.rs.GET
;
import
javax.ws.rs.POST
;
import
javax.ws.rs.PUT
;
import
javax.ws.rs.Path
;
import
javax.ws.rs.PathParam
;
import
javax.ws.rs.Produces
;
import
sklep.db.DBConnection
;
import
sklep.db.DBException
;
import
sklep.db.ProductDAO
;
import
sklep.db.RecordNotFound
;
import
sklep.model.Price
;
import
sklep.model.Product
;
import
sklep.model.ProductList
;
import
sklep.photo.PhotoUtil
;
@Path
(
"/products.xml"
)
@Consumes
(
"application/xml"
)
@Produces
(
"application/xml"
)
public
class
RProductXML
{
@GET
public
ProductList
readAllProducts
()
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
new
ProductList
(
productDAO
.
readAll
());
}
}
@Path
(
"/{id}"
)
@GET
public
Product
readOneProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
return
productDAO
.
findById
(
productId
);
}
}
@Path
(
"/{id}/foto"
)
@GET
@Produces
(
"image/jpeg"
)
public
byte
[]
foto
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
return
PhotoUtil
.
readBytes
(
productId
);
}
@Path
(
"/{id}/price"
)
@GET
public
Price
getPrice
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
Product
product
=
productDAO
.
findById
(
productId
);
return
new
Price
(
product
.
getPrice
());
}
}
@Path
(
"/{id}/price"
)
@PUT
public
void
setPrice
(
@PathParam
(
"id"
)
int
productId
,
Price
newPrice
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
Product
product
=
productDAO
.
findById
(
productId
);
product
.
setPrice
(
newPrice
.
getValue
());
productDAO
.
save
(
product
);
db
.
commit
();
}
}
@Path
(
"/{id}"
)
@PUT
public
void
updateProduct
(
@PathParam
(
"id"
)
int
productId
,
Product
product
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
product
.
getProductId
()
==
null
)
{
product
.
setProductId
(
productId
);
}
else
if
(
product
.
getProductId
()
!=
productId
)
{
throw
new
IllegalArgumentException
(
"ID produktu nie zgodne z adresem URL"
);
}
productDAO
.
save
(
product
);
db
.
commit
();
}
}
@POST
public
Product
addProduct
(
Product
product
)
throws
DBException
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
product
.
getProductId
()
!=
null
)
{
throw
new
IllegalArgumentException
(
"Nowy produkt nie może mieć ustawionego ID"
);
}
productDAO
.
insertNew
(
product
);
db
.
commit
();
return
product
;
}
}
@DELETE
@Path
(
"/{id}"
)
public
void
removeProduct
(
@PathParam
(
"id"
)
int
productId
)
throws
DBException
,
RecordNotFound
{
try
(
DBConnection
db
=
DBConnection
.
open
())
{
ProductDAO
productDAO
=
db
.
productDAO
();
if
(
productDAO
.
delete
(
productId
))
{
db
.
commit
();
}
else
{
throw
new
RecordNotFound
(
"Nie ma produktu nr "
+
productId
);
}
}
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/ext/ObslugaXSL.java
0 → 100644
View file @
d414a2ad
package
rest
.
ext
;
import
java.io.BufferedOutputStream
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.net.URI
;
import
javax.servlet.ServletContext
;
import
javax.ws.rs.WebApplicationException
;
import
javax.xml.bind.JAXBContext
;
import
javax.xml.bind.util.JAXBSource
;
import
javax.xml.transform.Result
;
import
javax.xml.transform.Transformer
;
import
javax.xml.transform.TransformerFactory
;
import
javax.xml.transform.sax.SAXResult
;
import
javax.xml.transform.stream.StreamSource
;
import
org.apache.fop.apps.Fop
;
import
org.apache.fop.apps.FopFactory
;
import
org.apache.xmlgraphics.util.MimeConstants
;
public
class
ObslugaXSL
{
private
ServletContext
servletContext
;
public
ObslugaXSL
(
ServletContext
servletContext
)
{
this
.
servletContext
=
servletContext
;
}
// obiekt -(za pomocą JAXB)-> XML -(za pomocą transformera)-> XML(XSL-FO)
// --(za pomocą Apache FOP)-> PDF -> output
public
void
wypiszPDF
(
Object
obj
,
OutputStream
output
)
{
try
(
InputStream
configStream
=
servletContext
.
getResourceAsStream
(
"WEB-INF/fop-conf.xml"
))
{
JAXBContext
ctx
=
JAXBContext
.
newInstance
(
obj
.
getClass
());
JAXBSource
src
=
new
JAXBSource
(
ctx
,
obj
);
FopFactory
fopFactory
=
FopFactory
.
newInstance
(
new
URI
(
""
),
configStream
);
try
(
BufferedOutputStream
pdfOut
=
new
BufferedOutputStream
(
output
))
{
Fop
fop
=
fopFactory
.
newFop
(
MimeConstants
.
MIME_PDF
,
pdfOut
);
TransformerFactory
tf
=
TransformerFactory
.
newInstance
();
StreamSource
xsl
=
new
StreamSource
(
servletContext
.
getResourceAsStream
(
"WEB-INF/sklep-fo.xsl"
));
Transformer
tr
=
tf
.
newTransformer
(
xsl
);
Result
res
=
new
SAXResult
(
fop
.
getDefaultHandler
());
tr
.
transform
(
src
,
res
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
throw
new
WebApplicationException
(
"Problem FOP "
+
e
.
getMessage
(),
e
,
500
);
}
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/ext/PDFWriter.java
0 → 100644
View file @
d414a2ad
package
rest
.
ext
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.lang.annotation.Annotation
;
import
java.lang.reflect.Type
;
import
javax.servlet.ServletContext
;
import
javax.ws.rs.WebApplicationException
;
import
javax.ws.rs.core.Context
;
import
javax.ws.rs.core.MediaType
;
import
javax.ws.rs.core.MultivaluedMap
;
import
javax.ws.rs.ext.MessageBodyWriter
;
import
javax.ws.rs.ext.Provider
;
import
sklep.model.Product
;
import
sklep.model.ProductList
;
@Provider
public
class
PDFWriter
implements
MessageBodyWriter
<
Object
>
{
private
static
final
MediaType
PDF_TYPE
=
new
MediaType
(
"application"
,
"pdf"
);
@Context
private
ServletContext
servletContext
;
@Override
public
boolean
isWriteable
(
Class
<?>
type
,
Type
genericType
,
Annotation
[]
annotations
,
MediaType
mediaType
)
{
return
(
type
==
ProductList
.
class
||
type
==
Product
.
class
)
&&
PDF_TYPE
.
isCompatible
(
mediaType
);
}
@Override
public
void
writeTo
(
Object
obj
,
Class
<?>
type
,
Type
genericType
,
Annotation
[]
annotations
,
MediaType
mediaType
,
MultivaluedMap
<
String
,
Object
>
httpHeaders
,
OutputStream
output
)
throws
IOException
,
WebApplicationException
{
String
fileName
=
"products.pdf"
;
if
(
obj
instanceof
Product
)
{
Product
product
=
(
Product
)
obj
;
fileName
=
product
.
getProductName
().
replace
(
' '
,
'_'
)
+
".pdf"
;
}
// httpHeaders.add("Content-Disposition", "attachment;filename=" + fileName);
httpHeaders
.
add
(
"Content-Disposition"
,
"inline;filename="
+
fileName
);
ObslugaXSL
obslugaXSL
=
new
ObslugaXSL
(
servletContext
);
obslugaXSL
.
wypiszPDF
(
obj
,
output
);
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/ext/RecordNotFoundMapper.java
0 → 100644
View file @
d414a2ad
package
rest
.
ext
;
import
javax.ws.rs.core.Response
;
import
javax.ws.rs.ext.ExceptionMapper
;
import
javax.ws.rs.ext.Provider
;
import
sklep.db.RecordNotFound
;
@Provider
public
class
RecordNotFoundMapper
implements
ExceptionMapper
<
RecordNotFound
>
{
@Override
public
Response
toResponse
(
RecordNotFound
exception
)
{
String
html
=
"<html><body><h1>Nie znaleziono</h1><p style='color:red'>"
+
exception
.
getMessage
()
+
"</p></body></html>"
;
return
Response
.
status
(
404
)
.
type
(
"text/html;charset=utf-8"
)
.
entity
(
html
)
.
build
();
}
}
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/java/rest/ext/SklepExceptionMapper.java
0 → 100644
View file @
d414a2ad
package
rest
.
ext
;
import
javax.ws.rs.core.Response
;
import
javax.ws.rs.core.Response.Status
;
import
javax.ws.rs.ext.ExceptionMapper
;
import
javax.ws.rs.ext.Provider
;
import
sklep.db.SklepException
;
@Provider
public
class
SklepExceptionMapper
implements
ExceptionMapper
<
SklepException
>
{
@Override
public
Response
toResponse
(
SklepException
e
)
{
String
tresc
=
String
.
format
(
"<html><body>"
+
"<h1>Błąd</h1>"
+
"<div>Błąd typu <code>%s</code></div>"
+
"<div style='color:red'>%s</div>"
+
"</body></html>"
,
e
.
getClass
().
getName
(),
e
.
getMessage
());
return
Response
.
status
(
Status
.
INTERNAL_SERVER_ERROR
)
.
type
(
"text/html;charset=utf-8"
)
.
entity
(
tresc
)
.
build
();
}
}
// a gdybyśmy chcieli mapować wszystkie wyjątki
// public class DefaultExceptionMapper implements ExceptionMapper<Exception> { ... }
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/webapp/WEB-INF/fop-conf.xml
0 → 100644
View file @
d414a2ad
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id: fop.xconf 447325 2006-09-18 08:55:33Z jeremias $ -->
<!--
This is an example configuration file for FOP.
This file contains the same settings as the default values
and will have no effect if used unchanged.
Relative config url's will be resolved relative to
the location of this file.
-->
<!-- NOTE: This is the version of the configuration -->
<fop
version=
"1.0"
>
<!-- Base URL for resolving relative URLs -->
<base>
.
</base>
<!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
<source-resolution>
72
</source-resolution>
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
<target-resolution>
72
</target-resolution>
<!-- Default page-height and page-width, in case
value is specified as auto -->
<default-page-settings
height=
"11in"
width=
"8.26in"
/>
<!-- Information for specific renderers -->
<!-- Uses renderer mime type for renderers -->
<renderers>
<renderer
mime=
"application/pdf"
>
<filterList>
<!-- provides compression using zlib flate (default is on) -->
<value>
flate
</value>
<!-- encodes binary data into printable ascii characters (default off)
This provides about a 4:5 expansion of data size -->
<!-- <value>ascii-85</value> -->
<!-- encodes binary data with hex representation (default off)
This filter is not recommended as it doubles the data size -->
<!-- <value>ascii-hex</value> -->
</filterList>
<fonts>
<!-- embedded fonts -->
<!--
This information must exactly match the font specified
in the fo file. Otherwise it will use a default font.
For example,
<fo:inline font-family="Arial" font-weight="bold" font-style="normal">
Arial-normal-normal font
</fo:inline>
for the font triplet specified by:
<font-triplet name="Arial" style="normal" weight="bold"/>
If you do not want to embed the font in the pdf document
then do not include the "embed-url" attribute.
The font will be needed where the document is viewed
for it to be displayed properly.
possible styles: normal | italic | oblique | backslant
possible weights: normal | bold | 100 | 200 | 300 | 400
| 500 | 600 | 700 | 800 | 900
(normal = 400, bold = 700)
-->
<!--
<font kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/arial.ttf">
<font-triplet name="Arial" style="normal" weight="normal"/>
<font-triplet name="ArialMT" style="normal" weight="normal"/>
</font>
<font kerning="yes" embed-url="/usr/share/fonts/truetype/msttcorefonts/arial.ttf">
<font-triplet name="Arial" style="normal" weight="normal"/>
<font-triplet name="ArialMT" style="normal" weight="normal"/>
</font>
-->
<!-- PC -->
<directory
recursive=
"true"
>
/usr/share/fonts/truetype/
</directory>
<directory
recursive=
"true"
>
C:\Windows\Fonts
</directory>
</fonts>
<!-- This option lets you specify additional options on an XML handler -->
<!--xml-handler namespace="http://www.w3.org/2000/svg">
<stroke-text>false</stroke-text>
</xml-handler-->
</renderer>
<renderer
mime=
"application/postscript"
>
<!-- This option forces the PS renderer to rotate landscape pages -->
<!--auto-rotate-landscape>true</auto-rotate-landscape-->
<!-- This option lets you specify additional options on an XML handler -->
<!--xml-handler namespace="http://www.w3.org/2000/svg">
<stroke-text>false</stroke-text>
</xml-handler-->
</renderer>
<renderer
mime=
"application/vnd.hp-PCL"
>
</renderer>
<!-- MIF does not have a renderer
<renderer mime="application/vnd.mif">
</renderer>
-->
<renderer
mime=
"image/svg+xml"
>
<format
type=
"paginated"
/>
<link
value=
"true"
/>
<strokeText
value=
"false"
/>
</renderer>
<renderer
mime=
"application/awt"
>
</renderer>
<renderer
mime=
"image/png"
>
<!--transparent-page-background>true</transparent-page-background-->
</renderer>
<renderer
mime=
"image/tiff"
>
<!--transparent-page-background>true</transparent-page-background-->
<!--compression>CCITT T.6</compression-->
</renderer>
<renderer
mime=
"text/xml"
>
</renderer>
<!-- RTF does not have a renderer
<renderer mime="text/rtf">
</renderer>
-->
<renderer
mime=
"text/plain"
>
<pageSize
columns=
"80"
/>
</renderer>
</renderers>
</fop>
PC38-Wielomodulowy/PC38-Wielomodulowy-RestSerwer/src/main/webapp/WEB-INF/sklep-fo.xsl
0 → 100644
View file @
d414a2ad
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version=
"1.0"
xmlns:xsl=
"http://www.w3.org/1999/XSL/Transform"
xmlns:fo=
"http://www.w3.org/1999/XSL/Format"
>
<xsl:output
method=
"xml"
encoding=
"utf-8"
/>
<xsl:template
match=
"/"
>
<fo:root
font-family=
"Arial"
>
<fo:layout-master-set>
<fo:simple-page-master
master-name=
"A4"
page-width=
"210mm"
page-height=
"297mm"
margin-top=
"1cm"
margin-bottom=
"1cm"
margin-left=
"1.5cm"
margin-right=
"1.5cm"
>
<fo:region-body
margin=
"2cm"
/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence
master-reference=
"A4"
>
<fo:flow
flow-name=
"xsl-region-body"
>
<xsl:apply-templates
/>
<fo:block/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template
match=
"product"
>
<fo:block-container
space-before.minimum=
"0.5em"
page-break-inside=
"avoid"
>
<fo:block>
<xsl:text>
Produkt nr
</xsl:text>
<xsl:value-of
select=
"@id"
/>
<xsl:text>
.
</xsl:text>
</fo:block>
<fo:block-container
margin=
"1em"
border-style=
"solid"
border-width=
"2.5pt"
padding=
"3pt"
border-color=
"#2233AA"
>
<fo:block
font-weight=
"bold"
font-size=
"14pt"
margin-bottom=
"1em"
color=
"#FF2244"
>
<xsl:apply-templates
select=
"product-name"
/>
</fo:block>
<fo:block
font-weight=
"bold"
color=
"green"
>
<xsl:text>
Cena:
</xsl:text>
<xsl:value-of
select=
"price"
/>
</fo:block>
<fo:block
color=
"green"
>
<xsl:text>
VAT:
</xsl:text>
<fo:inline
font-style=
"italic"
>
<xsl:value-of
select=
"vat * 100"
/>
<xsl:text>
%
</xsl:text>
</fo:inline>
</fo:block>
<fo:block
font-size=
"12pt"
margin-bottom=
"1em"
>
<xsl:apply-templates
select=
"description"
/>
</fo:block>
</fo:block-container>
</fo:block-container>
</xsl:template>
</xsl:stylesheet>
PC38-Wielomodulowy/pom.xml
View file @
d414a2ad
...
...
@@ -13,5 +13,6 @@
<modules>
<module>
PC38-Wielomodulowy-Model
</module>
<module>
PC38-Wielomodulowy-BazaDanych
</module>
<module>
PC38-Wielomodulowy-RestSerwer
</module>
</modules>
</project>
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