Commit 0d1a2f19 by Patryk Czarnik

Dodatkowe projekty, gdbymy nie zdążył pokazać na żywo

parent 5e4e1967
/target/
/.classpath
/.project
/.settings/
/*.iml
/.idea/
<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>
<groupId>pl.alx.kjava</groupId>
<artifactId>PC31-HibernateNaSerwerze</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
package sklep.model;
import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
/**
* The persistent class for the customers database table.
*
*/
@Entity
@Table(name="customers")
@NamedQuery(name="Customer.findAll", query="SELECT c FROM Customer c")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="customer_email")
private String customerEmail;
private String address;
private String city;
private String name;
@Column(name="phone_number")
private String phoneNumber;
@Column(name="postal_code")
private String postalCode;
//bi-directional many-to-one association to Order
@OneToMany(mappedBy="customer")
private List<Order> orders;
public Customer() {
}
public String getCustomerEmail() {
return this.customerEmail;
}
public void setCustomerEmail(String customerEmail) {
this.customerEmail = customerEmail;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return this.city;
}
public void setCity(String city) {
this.city = city;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPostalCode() {
return this.postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public List<Order> getOrders() {
return this.orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
public Order addOrder(Order order) {
getOrders().add(order);
order.setCustomer(this);
return order;
}
public Order removeOrder(Order order) {
getOrders().remove(order);
order.setCustomer(null);
return order;
}
}
\ No newline at end of file
package sklep.model;
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
import java.sql.Timestamp;
import java.util.List;
/**
* The persistent class for the orders database table.
*
*/
@Entity
@Table(name="orders")
@NamedQuery(name="Order.findAll", query="SELECT o FROM Order o")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="order_id", insertable=false, updatable=false)
private Integer orderId;
@Temporal(TemporalType.DATE)
@Column(name="delivery_date")
private Date deliveryDate;
@Column(name="order_date")
private Timestamp orderDate;
@Temporal(TemporalType.DATE)
@Column(name="planned_delivery_date")
private Date plannedDeliveryDate;
private String status;
//bi-directional many-to-one association to OrderProduct
@OneToMany(mappedBy="order")
private List<OrderProduct> orderProducts;
//bi-directional many-to-one association to Customer
@ManyToOne
@JoinColumn(name="customer_email")
private Customer customer;
public Order() {
}
public Integer getOrderId() {
return this.orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Date getDeliveryDate() {
return this.deliveryDate;
}
public void setDeliveryDate(Date deliveryDate) {
this.deliveryDate = deliveryDate;
}
public Timestamp getOrderDate() {
return this.orderDate;
}
public void setOrderDate(Timestamp orderDate) {
this.orderDate = orderDate;
}
public Date getPlannedDeliveryDate() {
return this.plannedDeliveryDate;
}
public void setPlannedDeliveryDate(Date plannedDeliveryDate) {
this.plannedDeliveryDate = plannedDeliveryDate;
}
public String getStatus() {
return this.status;
}
public void setStatus(String status) {
this.status = status;
}
public List<OrderProduct> getOrderProducts() {
return this.orderProducts;
}
public void setOrderProducts(List<OrderProduct> orderProducts) {
this.orderProducts = orderProducts;
}
public OrderProduct addOrderProduct(OrderProduct orderProduct) {
getOrderProducts().add(orderProduct);
orderProduct.setOrder(this);
return orderProduct;
}
public OrderProduct removeOrderProduct(OrderProduct orderProduct) {
getOrderProducts().remove(orderProduct);
orderProduct.setOrder(null);
return orderProduct;
}
public Customer getCustomer() {
return this.customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
\ No newline at end of file
package sklep.model;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
/**
* The persistent class for the order_products database table.
*
*/
@Entity
@Table(name="order_products")
@NamedQuery(name="OrderProduct.findAll", query="SELECT o FROM OrderProduct o")
public class OrderProduct implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private OrderProductPK id;
@Column(name="actual_price")
private BigDecimal actualPrice;
@Column(name="actual_vat")
private BigDecimal actualVat;
private Integer quantity;
//bi-directional many-to-one association to Order
@ManyToOne
@JoinColumn(name="order_id", insertable=false, updatable=false)
private Order order;
//uni-directional many-to-one association to Product
@ManyToOne
@JoinColumn(name="product_id", insertable=false, updatable=false)
private Product product;
public OrderProduct() {
}
public OrderProductPK getId() {
return this.id;
}
public void setId(OrderProductPK id) {
this.id = id;
}
public BigDecimal getActualPrice() {
return this.actualPrice;
}
public void setActualPrice(BigDecimal actualPrice) {
this.actualPrice = actualPrice;
}
public BigDecimal getActualVat() {
return this.actualVat;
}
public void setActualVat(BigDecimal actualVat) {
this.actualVat = actualVat;
}
public Integer getQuantity() {
return this.quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Order getOrder() {
return this.order;
}
public void setOrder(Order order) {
this.order = order;
}
public Product getProduct() {
return this.product;
}
public void setProduct(Product product) {
this.product = product;
}
}
\ No newline at end of file
package sklep.model;
import java.io.Serializable;
import javax.persistence.*;
/**
* The primary key class for the order_products database table.
*
*/
@Embeddable
public class OrderProductPK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
@Column(name="order_id", insertable=false, updatable=false)
private Integer orderId;
@Column(name="product_id", insertable=false, updatable=false)
private Integer productId;
public OrderProductPK() {
}
public Integer getOrderId() {
return this.orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getProductId() {
return this.productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof OrderProductPK)) {
return false;
}
OrderProductPK castOther = (OrderProductPK)other;
return
this.orderId.equals(castOther.orderId)
&& this.productId.equals(castOther.productId);
}
public int hashCode() {
final int prime = 31;
int hash = 17;
hash = hash * prime + this.orderId.hashCode();
hash = hash * prime + this.productId.hashCode();
return hash;
}
}
\ No newline at end of file
package sklep.model;
import java.io.Serializable;
import javax.persistence.*;
import java.math.BigDecimal;
/**
* The persistent class for the products database table.
*
*/
@Entity
@Table(name="products")
@NamedQuery(name="Product.findAll", query="SELECT p FROM Product p")
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="product_id", insertable=false, updatable=false)
private Integer productId;
private String description;
private BigDecimal price;
@Column(name="product_name")
private String productName;
private BigDecimal vat;
public Product() {
}
public Integer getProductId() {
return this.productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public BigDecimal getPrice() {
return this.price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public String getProductName() {
return this.productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public BigDecimal getVat() {
return this.vat;
}
public void setVat(BigDecimal vat) {
this.vat = vat;
}
}
\ No newline at end of file
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sklep.model.Product;
// http://localhost:8080/PC29-HibernateNaSerwerze-1.0/Lista0
@WebServlet("/lista0")
public class Lista0 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
// W tej wersji obiekty JPA (emf i em) otwieram w sposób ogólny, tak jakby to była zwykła aplikacja.
// Nie zakładam, że jestem na serwerze.
EntityManagerFactory emf = null;
EntityManager em = null;
try {
emf = Persistence.createEntityManagerFactory("sklep");
em = emf.createEntityManager();
out.println("Mam połączenie. em = " + em);
TypedQuery<Product> query = em.createNamedQuery("Product.findAll", Product.class);
List<Product> products = query.getResultList();
out.println("Odczytano " + products.size() + " produktów:");
for (Product product : products) {
out.println(" * " + product.getProductName() + " za " + product.getPrice());
}
} catch(Exception e) {
out.println("Katastrofa " + e);
e.printStackTrace(out);
} finally {
if(em != null) em.close();
if(emf != null) emf.close();
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sklep.model.Product;
// Wersja z ręcznym uzyskaniem dostępu do `persistence` - poprzez fabrykę, a nie wstrzykiwanie zależności.
// To jest napisane niemal tak, jak "zwykły program z mainem".
// To serwer zapewnia implementację JPA - my nie dodajemy jej do pom.xml (dodajemy tylko javaee-web-api)
// WildFly użyje Hibernate, a Glassfish użyje Eclipse Link.
// Wersja zadziała także przy konfiguracji połączenia "RESOURCE_LOCAL" z parametrami połączenia podanymi w persistence.xml
@WebServlet("/lista1")
public class Lista1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
EntityManagerFactory emf = null;
EntityManager em = null;
try {
emf = Persistence.createEntityManagerFactory("sklep");
em = emf.createEntityManager();
TypedQuery<Product> query = em.createNamedQuery("Product.findAll", Product.class);
List<Product> products = query.getResultList();
out.println("Odczytano " + products.size() + " rekordów:");
for (Product product : products) {
out.println(product.getProductName() + " " + product.getPrice());
}
} catch(Exception e) {
out.println("Wyjątek: " + e);
} finally {
if(em != null) em.close();
if(emf != null) emf.close();
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.TypedQuery;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sklep.model.Product;
// Wersja ze wstrzykiwaniem EntityManagerFactory za pomocą adnotacji @PersistenceUnit.
// Jeśli w aplikacji jest tylko jeden persistence unit, to nazwy można nie podawać, ale ja wolę zawsze podać.
// Ta wersja jest odpowiednia także dla konfiguracji opartej o RESOURCE_LOCAL
@WebServlet("/lista2")
public class Lista2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@PersistenceUnit(unitName="sklep")
private EntityManagerFactory emf;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
EntityManager em = null;
try {
em = emf.createEntityManager();
TypedQuery<Product> query = em.createNamedQuery("Product.findAll", Product.class);
List<Product> products = query.getResultList();
out.println("Odczytano " + products.size() + " rekordów:");
for (Product product : products) {
out.println(product.getProductName() + " " + product.getPrice());
}
} catch(Exception e) {
out.println("Wyjątek: " + e + "\n");
e.printStackTrace(out);
} finally {
if(em != null) em.close();
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sklep.model.Product;
// Wersja ze wstrzykiwaniem EntityManager (a nie fabryki) za pomocą adnotacji @PersistenceContext.
// Jeśli w aplikacji jest tylko jeden persistence unit, to nazwy można nie podawać, ale ja wolę zawsze podać.
// Ta wersja jest odpowiednia dla konfiguracji opartej o JTA
@WebServlet("/lista3")
public class Lista3 extends HttpServlet {
private static final long serialVersionUID = 1L;
@PersistenceContext(unitName="sklep")
private EntityManager em;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
try {
TypedQuery<Product> query = em.createNamedQuery("Product.findAll", Product.class);
List<Product> products = query.getResultList();
out.println("Odczytano " + products.size() + " rekordów:");
for (Product product : products) {
out.println(product.getProductName() + " " + product.getPrice());
}
} catch(Exception e) {
out.println("Wyjątek: " + e + "\n");
e.printStackTrace(out);
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/sql1")
public class Sql1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
try {
final String sql = "SELECT * FROM products";
try (Connection c = DriverManager.getConnection("jdbc:postgresql://localhost/sklep", "kurs", "abc123")) {
out.println("Connection połączone: " + c);
try (PreparedStatement stmt = c.prepareStatement(sql)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("product_id");
String productName = rs.getString("product_name");
BigDecimal price = rs.getBigDecimal("price");
String description = rs.getString("description");
out.printf("\n * Produkt nr %d: %s w cenie %s (%s)\n", id, productName, price, description);
}
}
}
}
} catch (SQLException e) {
e.printStackTrace(out);
} catch (Exception e) {
e.printStackTrace(out);
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
@WebServlet("/sql2")
public class Sql2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
try {
// Połączenie z bazą (jako DataSource) pobieramy z rejestru serwera (technologia JNDI - zasoby zarządzane przez serwer Java EE)
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:/SklepDS");
out.println("DataSource znaleziony: " + ds);
final String sql = "SELECT * FROM products";
try (Connection c = ds.getConnection()) {
try (PreparedStatement stmt = c.prepareStatement(sql)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("product_id");
String productName = rs.getString("product_name");
BigDecimal price = rs.getBigDecimal("price");
String description = rs.getString("description");
out.printf("\n * Produkt nr %d: %s w cenie %s (%s)\n", id, productName, price, description);
}
}
}
}
} catch (SQLException e) {
e.printStackTrace(out);
} catch (NamingException e) {
e.printStackTrace(out);
} catch (Exception e) {
e.printStackTrace(out);
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
@WebServlet("/sql3")
public class Sql3 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Resource(lookup="java:/SklepDS")
private DataSource ds;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("DataSource wstrzyknięty: " + ds);
final String sql = "SELECT * FROM products";
try (Connection c = ds.getConnection()) {
try (PreparedStatement stmt = c.prepareStatement(sql)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("product_id");
String productName = rs.getString("product_name");
BigDecimal price = rs.getBigDecimal("price");
String description = rs.getString("description");
out.printf("\n * Produkt nr %d: %s w cenie %s (%s)\n", id, productName, price, description);
}
}
}
}
} catch (SQLException e) {
e.printStackTrace(out);
} catch (Exception e) {
e.printStackTrace(out);
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceUnit;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sklep.model.Product;
@WebServlet("/zmiana2")
public class Zmiana2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@PersistenceUnit(unitName="sklep")
private EntityManagerFactory emf;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
if(request.getParameter("id") == null) {
out.println("Trzeba podać id produktu");
return;
}
Integer id = Integer.valueOf(request.getParameter("id"));
BigDecimal podwyzka = null;
if(request.getParameter("podwyzka") != null) {
podwyzka = new BigDecimal(request.getParameter("podwyzka"));
}
EntityManager em = null;
try {
em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Product product = em.find(Product.class, id);
if(product == null) {
out.println("Nie znaleziono produktu o numerze " + id);
return;
}
out.println(product.getProductName() + " " + product.getPrice());
if(podwyzka != null) {
product.setPrice(product.getPrice().add(podwyzka));
}
out.println("Po zmianie:");
out.println(product.getProductName() + " " + product.getPrice());
transaction.commit();
} catch (SecurityException | IllegalStateException e) {
throw new ServletException("wielka bieda", e);
} finally {
if(em != null) {
em.close();
}
}
}
}
package sklep.serwlety;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import sklep.model.Product;
@WebServlet("/zmiana3")
public class Zmiana3 extends HttpServlet {
private static final long serialVersionUID = 1L;
@PersistenceContext(unitName="sklep")
private EntityManager em;
@Resource
private UserTransaction transaction; // konwencja nazw: utx
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
if(request.getParameter("id") == null) {
out.println("Trzeba podać id produktu");
return;
}
Integer id = Integer.valueOf(request.getParameter("id"));
BigDecimal podwyzka = null;
if(request.getParameter("podwyzka") != null) {
podwyzka = new BigDecimal(request.getParameter("podwyzka"));
}
try {
transaction.begin();
Product product = em.find(Product.class, id);
if(product == null) {
out.println("Nie znaleziono produktu o numerze " + id);
return;
}
out.println(product.getProductName() + " " + product.getPrice());
if(podwyzka != null) {
product.setPrice(product.getPrice().add(podwyzka));
}
out.println("Po zmianie:");
out.println(product.getProductName() + " " + product.getPrice());
transaction.commit();
// } catch (SecurityException | IllegalStateException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SystemException | NotSupportedException e) {
} catch (Exception e) {
throw new ServletException("wielka bieda", e);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="sklep" transaction-type="JTA">
<jta-data-source>java:/SklepDS</jta-data-source>
<class>sklep.model.Customer</class>
<class>sklep.model.OrderProduct</class>
<class>sklep.model.OrderProductPK</class>
<class>sklep.model.Order</class>
<class>sklep.model.Product</class>
<properties>
<property name="hibernate.show_sql" value="true"/> <!-- pokazywanie zapytań SQL -->
</properties>
</persistence-unit>
</persistence>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hibernate na serwerze</title>
</head>
<body>
<h1>Hibernate na serwerze</h1>
<h2>Zapytania SQL</h2>
<ul>
<li><a href="sql1">sql1</a> - normalne <code>getConnection</code> - nie zadziała bez sterownika</li>
<li><a href="sql2">sql2</a> - DataSource za pomocą <code>ctx.lookup</code></li>
<li><a href="sql3">sql3</a> - wstrzykiwanie DataSource</li>
</ul>
<h2>Zapytania JPA/Hibernate</h2>
<ul>
<li><a href="lista0">lista0</a> - wersja bez konfiguracji serwera, później zmieniona na użycie data source typu resource/local</li>
<li><a href="lista1">lista1</a> - stara wersja odstawowa</li>
<li><a href="lista2">lista2</a> - wersja ze wstrzykiwaniem EntityManagerFactory, działająca dla datasource typu resource/local</li>
<li><a href="lista3">lista3</a> - wersja ze wstrzykiwaniem EntityManager, działająca dla datasource typu JTA (wymaga zmiany konfiguracji)</li>
</ul>
<h2>Modyfikacja danych JPA/Hibernate</h2>
<p>(podwyżka ceny pralki o 500)</p>
<ul>
<li><a href="zmiana2?id=1&amp;podwyzka=500">zmiana2</a> - wersja dla datasource typu resource/local</li>
<li><a href="zmiana3?id=1&amp;podwyzka=500">zmiana3</a> - wersja dla datasource typu JTA (wymaga zmiany konfiguracji)</li>
</ul>
</body>
</html>
\ No newline at end of file
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.1'
id 'io.spring.dependency-management' version '1.1.5'
}
group = 'pl.alx.kjava'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed 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
#
# https://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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
rootProject.name = 'PC36-SpringTechnicznie'
package com.example.demo;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/")
public String root() {
return "index.html";
}
@GetMapping("/hello")
public String hello(Model model) {
model.addAttribute("txt", "Hello world!");
model.addAttribute("time", LocalTime.now());
return "hello.html";
}
@RequestMapping("/ping")
public String ping(HttpServletRequest request, Model model) {
// Do modelu można też dodać słownik / mapę.
// Odczyt wartości wygląda później np. tak ${clientInfo.userAgent}
String ip = request.getRemoteAddr();
System.out.println("Zapytanie z adresu " + ip);
model.addAttribute("clientInfo", Map.of(
"userAgent", request.getHeader("User-Agent"),
"ip", ip,
"data", LocalDateTime.now()
));
return "ping.html";
}
}
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Pc36SpringTechnicznieApplication {
public static void main(String[] args) {
SpringApplication.run(Pc36SpringTechnicznieApplication.class, args);
}
}
package com.example.demo.data;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.example.demo.model.Employee;
@Controller
public class Controller0 {
@Autowired
private Repository0_Memory repository;
@GetMapping("/emps0")
public String showExampleEmployee(Model model) {
List<Employee> emps = repository.findAll();
model.addAttribute("emps", emps);
return "employees.html";
}
}
package com.example.demo.data;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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 com.example.demo.model.Employee;
@Controller
@RequestMapping("/emps1")
public class Controller1_EM {
/* W tej wersji Controller bezpośrednio korzysta z technologii JPA/Hibernate.
* Ułatwieniem jest to, że Spring automatycznie "wstryknie" nam obiekt EntityManager.
*/
@Autowired
private EntityManager em;
@GetMapping
public String showAll(Model model) {
TypedQuery<Employee> query = em.createNamedQuery("Employee.findAll", Employee.class);
List<Employee> emps = query.getResultList();
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/{id}")
public String showOne(Model model,
@PathVariable("id") Integer employeeId) {
Employee emp = em.find(Employee.class, employeeId);
model.addAttribute("emps", List.of(emp));
return "employees.html";
}
}
package com.example.demo.data;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.RequestParam;
import com.example.demo.model.Employee;
@Controller
@RequestMapping("/emps2")
public class Controller2 {
@Autowired
private Repository2 repository;
@GetMapping
public String showAll(Model model) {
List<Employee> emps = repository.findAll();
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/{id}")
public String showOne(Model model,
@PathVariable("id") Integer employeeId) {
Employee emp = repository.findOne(employeeId);
model.addAttribute("emps", List.of(emp));
return "employees.html";
}
@GetMapping("/by_name")
public String showByName(Model model,
@RequestParam("name") String name) {
List<Employee> emps = repository.findByLastName(name);
model.addAttribute("emps", emps);
return "employees.html";
}
}
package com.example.demo.data;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.RequestParam;
import com.example.demo.model.Employee;
@Controller
@RequestMapping("/emps3")
public class Controller3 {
/* Aby bezpośrednio w Controllerze nie używać kodów dot. Hibernate, SQL itd...
* wydzielam operacje bazodanowe do oddzielnej klasy, opisanej jako Repository
* i wstrzykuję referencję do repozytorium tutaj w controllerze.
* W doatku robię to porzez interfejs (zgodne z najlepszymi praktykami Springa),
* aby ułatwić podmianę implementacji na inną.
*/
@Autowired
private Repository3_Interface repository;
@GetMapping
public String showAll(Model model) {
List<Employee> emps = repository.findAll();
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/{id}")
public String showOne(Model model,
@PathVariable("id") Integer employeeId) {
Employee emp = repository.findOne(employeeId);
model.addAttribute("emps", List.of(emp));
return "employees.html";
}
@GetMapping("/by_name")
public String showByName(Model model,
@RequestParam("name") String name) {
List<Employee> emps = repository.findByLastName(name);
model.addAttribute("emps", emps);
return "employees.html";
}
}
package com.example.demo.data;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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 com.example.demo.model.Employee;
@Controller
@RequestMapping("/emps4")
public class Controller4 {
@Autowired
private Repository4 repository;
@GetMapping
public String showAll(Model model) {
List<Employee> emps = repository.findAll();
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/{id}")
public String showOne(Model model,
@PathVariable("id") Integer employeeId) {
Optional<Employee> emp = repository.findById(employeeId);
List<Employee> emps;
if (emp.isPresent()) {
emps = List.of(emp.get());
} else {
emps = List.of();
}
model.addAttribute("emps", emps);
return "employees.html";
}
}
package com.example.demo.data;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.demo.model.Employee;
@Controller
@RequestMapping("/emps5")
public class Controller5 {
@Autowired
private Repository5 repository;
@GetMapping("/all")
public String showAll(Model model) {
List<Employee> emps = repository.findAll();
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/by_id/{id}")
public String showOne(Model model,
@PathVariable("id") Integer employeeId) {
Optional<Employee> emp = repository.findById(employeeId);
List<Employee> emps;
if (emp.isPresent()) {
emps = List.of(emp.get());
} else {
emps = List.of();
}
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/by_name")
public String showByName(Model model,
@RequestParam("name") String name) {
List<Employee> emps = repository.findByLastName(name);
model.addAttribute("emps", emps);
return "employees.html";
}
// http://localhost:8080/emps5/by_job/IT_PROG
@GetMapping("/by_job/{job}")
public String getEmployeesByJobId(Model model,
@PathVariable("job") String jobId) {
List<Employee> emps = repository.findByJob_JobId(jobId);
model.addAttribute("emps", emps);
return "employees.html";
}
// http://localhost:8080/emps5/by_city/Oxford
@GetMapping("/by_city/{city}")
public String getEmployeesByCity(Model model,
@PathVariable("city") String city) {
List<Employee> emps = repository.findByDepartment_Location_City(city);
model.addAttribute("emps", emps);
return "employees.html";
}
// http://localhost:8080/emps5/by_salary?min=5000&max=10000
@GetMapping("/by_salary")
public String getEmployeesBySalary(Model model,
@RequestParam(name="min", defaultValue="0") BigDecimal min,
@RequestParam(name="max", defaultValue="1000000000") BigDecimal max) {
List<Employee> employees = repository.findBySalary(min, max);
model.addAttribute("emps", employees);
return "employees.html";
}
@GetMapping("/by_year/{year}")
public String getEmployeesByYear(Model model,
@PathVariable("year") int year) {
List<String> names = repository.namesByYear(year);
model.addAttribute("names", names);
return "names.html";
}
@GetMapping("/zara")
public String zarabiajacy(Model model,
@RequestParam("id") int id) {
List<Employee> emps = repository.zarabiajacyWiecejNiz(id);
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/szef/{id}")
@ResponseBody
public String szef(@PathVariable("id") Integer idPracownika) {
return repository.nazwiskoSzefa(idPracownika);
}
@GetMapping("/save/{id}")
public String modify(Model model,
@PathVariable("id") Integer idPracownika,
@RequestParam(value="salary", required=false) BigDecimal newSalary,
@RequestParam(value="first_name", required=false) String newFirstName,
@RequestParam(value="last_name", required=false) String newLastName) {
Optional<Employee> found = repository.findById(idPracownika);
List<Employee> emps;
if(found.isPresent()) {
Employee emp = found.get();
if(newSalary != null)
emp.setSalary(newSalary);
if(newFirstName != null)
emp.setFirstName(newFirstName);
if(newLastName != null)
emp.setLastName(newLastName);
repository.save(emp);
emps = List.of(emp);
} else {
emps = List.of();
}
model.addAttribute("emps", emps);
return "employees.html";
}
@GetMapping("/move/{id}")
@ResponseBody
public String modify(Model model,
@PathVariable("id") Integer idPracownika,
@RequestParam(value="dep", required=false) int newDep,
@RequestParam(value="job", required=false) String newJob) {
repository.moveEmployee(idPracownika, newDep, newJob);
return "Przeniesiono";
}
}
package com.example.demo.data;
import java.math.BigDecimal;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Department;
import com.example.demo.model.Employee;
import com.example.demo.model.Job;
import com.example.demo.model.Location;
/* Klasa pełniąca rolę repozytoium, czyli dostraczanie danych,
* ale zaimplementowana bez bazy danych - po prostu zwraca przykładowe obiekty.
*/
@Repository
public class Repository0_Memory {
public List<Employee> findAll() {
Employee emp = exampleEmployee1();
return List.of(emp);
}
private Employee exampleEmployee1() {
Employee emp = new Employee();
emp.setFirstName("Jan");
emp.setLastName("Kowalski");
emp.setSalary(BigDecimal.valueOf(12345));
emp.setJob(exampleJob());
emp.setDepartment(exampleDepartment());
return emp;
}
private Department exampleDepartment() {
Location loc = new Location();
loc.setCity("Warszawa");
Department dep = new Department();
dep.setDepartmentName("Szkolenia");
dep.setLocation(loc);
return dep;
}
private Job exampleJob() {
Job job = new Job();
job.setJobTitle("Trainer");
return job;
}
}
package com.example.demo.data;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Employee;
@Repository
public class Repository2 {
@Autowired
private EntityManager em;
public List<Employee> findAll() {
TypedQuery<Employee> query = em.createNamedQuery("Employee.findAll", Employee.class);
List<Employee> emps = query.getResultList();
return emps;
}
public Employee findOne(int employeeId) {
return em.find(Employee.class, employeeId);
}
public List<Employee> findByLastName(String lastName) {
TypedQuery<Employee> query = em.createQuery(
"SELECT emp FROM Employee emp WHERE emp.lastName = :name", Employee.class);
query.setParameter("name", lastName);
List<Employee> emps = query.getResultList();
return emps;
}
}
package com.example.demo.data;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Employee;
@Repository
public class Repository3_Impl implements Repository3_Interface {
@Autowired
private EntityManager em;
@Override
public List<Employee> findAll() {
TypedQuery<Employee> query = em.createNamedQuery("Employee.findAll", Employee.class);
List<Employee> emps = query.getResultList();
return emps;
}
@Override
public Employee findOne(int employeeId) {
return em.find(Employee.class, employeeId);
}
@Override
public List<Employee> findByLastName(String lastName) {
TypedQuery<Employee> query = em.createQuery(
"SELECT emp FROM Employee emp WHERE emp.lastName = :name", Employee.class);
query.setParameter("name", lastName);
List<Employee> emps = query.getResultList();
return emps;
}
}
package com.example.demo.data;
import java.util.List;
import com.example.demo.model.Employee;
public interface Repository3_Interface {
List<Employee> findAll();
Employee findOne(int employeeId);
List<Employee> findByLastName(String lastName);
}
\ No newline at end of file
package com.example.demo.data;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.model.Employee;
public interface Repository4 extends JpaRepository<Employee, Integer> {
// Spring sam tworzy instancję tego interfejsu, która zawiera implementację wszystkich standardowych metod
}
package com.example.demo.data;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.example.demo.model.Employee;
public interface Repository5 extends JpaRepository<Employee, Integer> {
List<Employee> findByLastName(String name);
List<Employee> findByLastNameContainingIgnoringCase(String name);
List<Employee> findByJob_JobId(String jobId);
// employee.getDepartment().getLocation().getCity()
// ale w zapytaniu zostanie to zamienione na SQL, który JOIN-em dołącza tabele departments i locations i w WHERE sprawdza city
List<Employee> findByDepartment_Location_City(String city);
// Zapytanie w składni JPQL
@Query("SELECT emp FROM Employee emp WHERE emp.salary BETWEEN :min AND :max ORDER BY emp.salary")
List<Employee> findBySalary(BigDecimal min, BigDecimal max);
@Query(nativeQuery=true,
value="""
SELECT first_name || ' ' || last_name
FROM employees
WHERE extract(year FROM hire_date) = :year
ORDER BY last_name
""")
List<String> namesByYear(int year);
// W ramach takiego interfejsu można też pisać metody z własną implementacją.
// Tu przykład już nie bazodanowy...
default List<Integer> losowe(int limit, int ilosc) {
return ThreadLocalRandom.current().ints(ilosc, 0, limit).boxed().collect(Collectors.toList());
}
// podobno tak wygląda wywołanie procedury składowanej, ale nam nie działa
@Query(nativeQuery=true, value="CALL przenies_pracownika(:idPracownika, :newDep, :newJob)")
void moveEmployee(Integer idPracownika, int newDep, String newJob);
@Query(nativeQuery=true, value="SELECT zarabiajacy_wiecej_niz(:id)")
List<Employee> zarabiajacyWiecejNiz(int id);
@Query(nativeQuery=true, value="SELECT nazwisko_szefa(:idPracownika)")
String nazwiskoSzefa(Integer idPracownika);
}
package com.example.demo.licznik;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
@Controller
public class AController1 {
@GetMapping("/test0")
public String test0() {
return "licznik.html";
}
@GetMapping("/test1")
public String test1(Model model) {
model.addAttribute("licznik", "Ala ma kota, a nie żaden licznik");
return "licznik.html";
}
@GetMapping("/test2")
public String test2(Model model, Licznik licznik) {
// Nawet gdy sami nie dodamy obiektu do modelu, to Spring i tak to zrobi
// model.addAttribute("licznik", licznik);
return "licznik.html";
}
@GetMapping("/test3")
public String test3(@ModelAttribute Licznik licznik) {
// Ta adnotacja mówi jednoznacznie, że ten parametr jest elementem modelu
return "licznik.html";
}
}
package com.example.demo.licznik;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
@Controller
public class AController4 {
@ModelAttribute
public Licznik getLicznik() {
// Gdy w klasie istynieje taka metoda oznaczona @ModelAttribute, to ona zostanie użyta do utworzenia obiektu.
// Jeśli nie ma takiej metody (jak w Controller1), to konstruktor domyślny.
return new Licznik("ModelAttribute z metody", 400);
}
@GetMapping("/test4")
public String test4(@ModelAttribute Licznik licznik) {
return "licznik.html";
}
@GetMapping("/test4a")
public String test4a(Licznik licznik) {
return "licznik.html";
}
}
package com.example.demo.licznik;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
@Controller
@SessionAttributes({"licznik"})
public class AController5 {
// W tej wersji atrybut modelu żyje w zakresie sesji.
@ModelAttribute
public Licznik getLicznik() {
return new Licznik("v5 z metody", 500);
}
@GetMapping("/test5")
public String test5(@ModelAttribute Licznik licznik) {
return "licznik.html";
}
}
package com.example.demo.licznik;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AController6 {
@Autowired
private LicznikComponent6 licznikComponent6;
@GetMapping("/test6")
public String test6(Model model) {
model.addAttribute("licznik", licznikComponent6.getLicznik());
return "licznik.html";
}
}
package com.example.demo.licznik;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AController7 {
@Autowired
private LicznikComponent7 licznikComponent7;
@GetMapping("/test7")
public String test7(Model model) {
model.addAttribute("licznik", licznikComponent7.getLicznik());
return "licznik.html";
}
}
package com.example.demo.licznik;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AController8 {
@Autowired
private LicznikBean8 licznikBean8;
@GetMapping("/test8")
public String test8(Model model) {
model.addAttribute("licznik", licznikBean8.getLicznik());
return "licznik.html";
}
}
package com.example.demo.licznik;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Configuration8 {
// Adnotacja @Bean jest używana na poziomie metody.
// Wynik wywołania tej metody zostanie zapamiętany przez Springa i będzie traktowany jak "bean",
// czyli zostanie wstrzyknięty tam, gdzie będzie go ktoś potrzebował.
// Taka metoda musi być umieszczona w klasie, którą "przeczyta" Spring i wykona takie metody.
// Najczęściej stosuje się klasy oznaczone @Configuration
@Bean
public LicznikBean8 generuj() {
LicznikBean8 wynik = new LicznikBean8();
wynik.setLicznik(new Licznik("bean z konfiguracji", 800));
return wynik;
}
}
package com.example.demo.licznik;
public class Licznik {
private String napis;
private int value;
public Licznik(String napis, int value) {
this.napis = napis;
this.value = value;
}
public Licznik() {
this("default", 0);
}
public synchronized String getNapis() {
return napis;
}
public synchronized void setNapis(String napis) {
this.napis = napis;
}
public synchronized int getValue() {
return ++value;
}
@Override
public String toString() {
return "Licznik [napis: " + getNapis() + ", value: " + getValue() + "]";
}
}
package com.example.demo.licznik;
public class LicznikBean8 {
private Licznik licznik;
public Licznik getLicznik() {
return licznik;
}
public void setLicznik(Licznik licznik) {
this.licznik = licznik;
}
}
package com.example.demo.licznik;
import org.springframework.stereotype.Component;
@Component // albo @Service, @Repository
public class LicznikComponent6 {
private Licznik licznik = new Licznik();
public Licznik getLicznik() {
return licznik;
}
public void setLicznik(Licznik licznik) {
this.licznik = licznik;
}
}
package com.example.demo.licznik;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Component
@Scope(scopeName="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class LicznikComponent7 {
private Licznik licznik = new Licznik();
public Licznik getLicznik() {
return licznik;
}
public void setLicznik(Licznik licznik) {
this.licznik = licznik;
}
}
package com.example.demo.model;
import java.io.Serializable;
import jakarta.persistence.*;
/**
* The persistent class for the countries database table.
*
*/
@Entity
@Table(name="countries")
@NamedQuery(name="Country.findAll", query="SELECT c FROM Country c")
public class Country implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="country_id")
private String countryId;
@Column(name="country_name")
private String countryName;
//bi-directional many-to-one association to Region
@ManyToOne
@JoinColumn(name="region_id")
private Region region;
public Country() {
}
public String getCountryId() {
return this.countryId;
}
public void setCountryId(String countryId) {
this.countryId = countryId;
}
public String getCountryName() {
return this.countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public Region getRegion() {
return this.region;
}
public void setRegion(Region region) {
this.region = region;
}
}
\ No newline at end of file
package com.example.demo.model;
import java.io.Serializable;
import java.util.List;
import jakarta.persistence.*;
/**
* The persistent class for the departments database table.
*
*/
@Entity
@Table(name="departments")
@NamedQuery(name="Department.findAll", query="SELECT d FROM Department d")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="DEPARTMENTS_DEPARTMENTID_GENERATOR", sequenceName="DEPARTMENTS_SEQ", allocationSize=10)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="DEPARTMENTS_DEPARTMENTID_GENERATOR")
@Column(name="department_id")
private Integer departmentId;
@Column(name="department_name")
private String departmentName;
@Column(name="manager_id")
private Integer managerId;
//uni-directional many-to-one association to Location
@ManyToOne
@JoinColumn(name="location_id")
private Location location;
//bi-directional many-to-one association to Employee
@OneToMany(mappedBy="department")
private List<Employee> employees;
public Department() {
}
public Integer getDepartmentId() {
return this.departmentId;
}
public void setDepartmentId(Integer departmentId) {
this.departmentId = departmentId;
}
public String getDepartmentName() {
return this.departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public Integer getManagerId() {
return this.managerId;
}
public void setManagerId(Integer managerId) {
this.managerId = managerId;
}
public Location getLocation() {
return this.location;
}
public void setLocation(Location location) {
this.location = location;
}
public List<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Employee addEmployee(Employee employee) {
getEmployees().add(employee);
employee.setDepartment(this);
return employee;
}
public Employee removeEmployee(Employee employee) {
getEmployees().remove(employee);
employee.setDepartment(null);
return employee;
}
}
\ No newline at end of file
package com.example.demo.model;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import jakarta.persistence.*;
/**
* The persistent class for the employees database table.
*
*/
@Entity
@Table(name="employees")
@NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="EMPLOYEES_EMPLOYEEID_GENERATOR", sequenceName="EMPLOYEES_SEQ", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="EMPLOYEES_EMPLOYEEID_GENERATOR")
@Column(name="employee_id")
private Integer employeeId;
@Column(name="commission_pct")
private BigDecimal commissionPct;
private String email;
@Column(name="first_name")
private String firstName;
@Temporal(TemporalType.DATE)
@Column(name="hire_date")
private Date hireDate;
@Column(name="last_name")
private String lastName;
@Column(name="phone_number")
private String phoneNumber;
private BigDecimal salary;
//bi-directional many-to-one association to Department
@ManyToOne
@JoinColumn(name="department_id")
private Department department;
//uni-directional many-to-one association to Employee
@ManyToOne
@JoinColumn(name="manager_id")
private Employee manager;
//bi-directional many-to-one association to Job
@ManyToOne
@JoinColumn(name="job_id")
private Job job;
public Employee() {
}
public Integer getEmployeeId() {
return this.employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
public BigDecimal getCommissionPct() {
return this.commissionPct;
}
public void setCommissionPct(BigDecimal commissionPct) {
this.commissionPct = commissionPct;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public Date getHireDate() {
return this.hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public BigDecimal getSalary() {
return this.salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public Department getDepartment() {
return this.department;
}
public void setDepartment(Department department) {
this.department = department;
}
public Employee getManager() {
return this.manager;
}
public void setManager(Employee manager) {
this.manager = manager;
}
public Job getJob() {
return this.job;
}
public void setJob(Job job) {
this.job = job;
}
}
\ No newline at end of file
package com.example.demo.model;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import jakarta.persistence.*;
/**
* The persistent class for the jobs database table.
*
*/
@Entity
@Table(name="jobs")
@NamedQuery(name="Job.findAll", query="SELECT j FROM Job j")
public class Job implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="job_id")
private String jobId;
@Column(name="job_title")
private String jobTitle;
@Column(name="max_salary")
private BigDecimal maxSalary;
@Column(name="min_salary")
private BigDecimal minSalary;
//bi-directional many-to-one association to Employee
@OneToMany(mappedBy="job")
private List<Employee> employees;
public Job() {
}
public String getJobId() {
return this.jobId;
}
public void setJobId(String jobId) {
this.jobId = jobId;
}
public String getJobTitle() {
return this.jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public BigDecimal getMaxSalary() {
return this.maxSalary;
}
public void setMaxSalary(BigDecimal maxSalary) {
this.maxSalary = maxSalary;
}
public BigDecimal getMinSalary() {
return this.minSalary;
}
public void setMinSalary(BigDecimal minSalary) {
this.minSalary = minSalary;
}
public List<Employee> getEmployees() {
return this.employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public Employee addEmployee(Employee employee) {
getEmployees().add(employee);
employee.setJob(this);
return employee;
}
public Employee removeEmployee(Employee employee) {
getEmployees().remove(employee);
employee.setJob(null);
return employee;
}
}
\ No newline at end of file
package com.example.demo.model;
import java.io.Serializable;
import jakarta.persistence.*;
/**
* The persistent class for the locations database table.
*
*/
@Entity
@Table(name="locations")
@NamedQuery(name="Location.findAll", query="SELECT l FROM Location l")
public class Location implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name="LOCATIONS_LOCATIONID_GENERATOR", sequenceName="LOCATIONS_SEQ", allocationSize=100)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="LOCATIONS_LOCATIONID_GENERATOR")
@Column(name="location_id")
private Integer locationId;
private String city;
@Column(name="postal_code")
private String postalCode;
@Column(name="state_province")
private String stateProvince;
@Column(name="street_address")
private String streetAddress;
//uni-directional many-to-one association to Country
@ManyToOne
@JoinColumn(name="country_id")
private Country country;
public Location() {
}
public Integer getLocationId() {
return this.locationId;
}
public void setLocationId(Integer locationId) {
this.locationId = locationId;
}
public String getCity() {
return this.city;
}
public void setCity(String city) {
this.city = city;
}
public String getPostalCode() {
return this.postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getStateProvince() {
return this.stateProvince;
}
public void setStateProvince(String stateProvince) {
this.stateProvince = stateProvince;
}
public String getStreetAddress() {
return this.streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public Country getCountry() {
return this.country;
}
public void setCountry(Country country) {
this.country = country;
}
}
\ No newline at end of file
package com.example.demo.model;
import java.io.Serializable;
import java.util.List;
import jakarta.persistence.*;
/**
* The persistent class for the regions database table.
*
*/
@Entity
@Table(name="regions")
@NamedQuery(name="Region.findAll", query="SELECT r FROM Region r")
public class Region implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="region_id")
private Integer regionId;
@Column(name="region_name")
private String regionName;
//bi-directional many-to-one association to Country
@OneToMany(mappedBy="region")
private List<Country> countries;
public Region() {
}
public Integer getRegionId() {
return this.regionId;
}
public void setRegionId(Integer regionId) {
this.regionId = regionId;
}
public String getRegionName() {
return this.regionName;
}
public void setRegionName(String regionName) {
this.regionName = regionName;
}
public List<Country> getCountries() {
return this.countries;
}
public void setCountries(List<Country> countries) {
this.countries = countries;
}
public Country addCountry(Country country) {
getCountries().add(country);
country.setRegion(this);
return country;
}
public Country removeCountry(Country country) {
getCountries().remove(country);
country.setRegion(null);
return country;
}
}
\ No newline at end of file
package com.example.demo.wstrzykiwanie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FabrykaKomponentow {
{ System.out.println("FabrykaKomponentow init"); }
@Bean
Komponent dajKomponent() {
System.out.println("Zaraz utworzę Komponent w klasie FabrykaKomponentow");
return new Komponent();
}
}
package com.example.demo.wstrzykiwanie;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Inject1 {
// 1. sposób wstrzykiwania: pole
@Autowired
private Komponent komponent;
@Autowired
private Repo repo;
{ System.out.println("Inject1 init"); } // initialization block
public Inject1() {
System.out.println("Inject1 constr, komponent = " + komponent); // null
}
@PostConstruct
public void pc() {
System.out.println("inject1 @PostConstruct, komponent = " + komponent);
}
@RequestMapping("/inject1")
@ResponseBody
public String get() {
return repo.getText() + " " + komponent.getValue();
}
}
package com.example.demo.wstrzykiwanie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Inject2 {
{ System.out.println("Inject2 init"); }
// 2. sposób wstrzykiwania: setter
private Komponent komponent;
private Repo repo;
public Komponent getKomponent() {
return komponent;
}
@Autowired
public void setKomponent(Komponent komponent) {
System.out.println("SET KOMPONENT");
this.komponent = komponent;
}
public Repo getRepo() {
return repo;
}
@Autowired
public void setRepo(Repo repo) {
this.repo = repo;
}
@RequestMapping("/inject2")
@ResponseBody
public String get() {
return repo.getText() + " " + komponent.getValue();
}
}
package com.example.demo.wstrzykiwanie;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Inject3 {
{ System.out.println("Inject3 init"); }
// 3. sposób wstrzykiwania: konstruktor
// To podejście zwykle jest podawane jako najlepsze, bo umożliwia łatwą podmianę komponentów na "mocki" podczas testów
// Przy tym podejściu problemem byłaby jednak cykliczna zależność między komponentami.
private Komponent komponent;
private Repo repo;
// Zauważmy, że ta klasa nie jest już poprawnym "JavaBean", bo nie posiada konstruktora domyślnego.
// Adnotacja Autowired tym razem nie jest potrzebna.
public Inject3(Komponent komponent, Repo repo) {
System.out.println("KONSTRUKTOR Inject3(komponent, repo); komponent = " + komponent);
this.komponent = komponent;
this.repo = repo;
}
@RequestMapping("/inject3")
@ResponseBody
public String get() {
return repo.getText() + " " + komponent.getValue();
}
}
package com.example.demo.wstrzykiwanie;
import java.util.concurrent.atomic.AtomicInteger;
public class Komponent {
{ System.out.println("Komponent init"); }
private AtomicInteger licznik = new AtomicInteger();
public int getValue() {
return licznik.incrementAndGet();
}
}
package com.example.demo.wstrzykiwanie;
import org.springframework.stereotype.Repository;
@Repository // na podobnych zasadach: @Component, @Service, @Repository - tworzony jest jeden obiekt "singleton"
public class Repo {
{ System.out.println("Repo init"); }
public String getText() {
return "Ala ma kota";
}
}
spring.application.name=PC36-SpringTechnicznie
spring.datasource.url=jdbc:postgresql://localhost:5432/hr
spring.datasource.username=alx
spring.datasource.password=abc123
spring.jpa.show-sql=true
body {
background-color: #FFFFCC;
font-family: 'Arial', sans-serif;
}
h1 {
color: green;
text-align: center;
}
form {
margin: 30px auto;
padding: 20px;
width: 800px;
border: 4px solid blue;
background-color: #AAEEFF;
}
.wynik {
background-color: #FFFFFF;
border: 3px solid green;
margin: 20px auto;
width: 800px;
padding: 10px;
color: green;
}
.error {
background-color: #FFFFFF;
border: 6px double red;
margin: 20px auto;
padding: 10px;
width: 800px;
color: red;
font-weight: bold;
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Employees</title>
<style type="text/css">
table {
border-collapse: collapse;
}
th, td {
border: 1px solid #444444;
padding: 4px;
}
</style>
</head>
<body>
<table>
<tr>
<th>Imię</th><th>Nazwisko</th><th>Stanowisko</th><th>Pensja</th><th>Departament</th><th>Miasto</th>
</tr>
<tr th:each="emp : ${emps}">
<td th:text="${emp.firstName}">firstName</td>
<td th:text="${emp.lastName}">lastName</td>
<td th:text="${emp.job.jobTitle}">jobTitle</td>
<td th:text="${emp.salary}">salary</td>
<td th:text="${emp.department.departmentName}" th:if="${emp.department != null}">departmentName</td>
<td th:text="${emp.department.location.city}" th:if="${emp.department != null}">city</td>
</tr>
</table>
<p><a th:href="@{/}">wróć do spisu treści</a></p>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello</title>
</head>
<body>
<p>[[${txt}]]</p>
<p>Teraz jest godzina: [[${time}]]</p>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Spis treści</title>
<link rel="stylesheet" type="text/css" th:href="@{/styl.css}" href="../static/styl.css">
</head>
<body>
<h1>Spis treści</h1>
<ul>
<li><a href="/hello">Hello</a></li>
<li><a href="/ping">Ping</a></li>
</ul>
<h2>Spring Data</h2>
<ul>
<li><a href="/emps0">InMemoryRepository</a></li>
<li><a href="/emps1">emps1</a> - wersja z bespośrednio użytym JPA</li>
<li><a href="/emps1/100">emps1/100</a> - odczyt jednego pracownika po id</li>
<li><a href="/emps2">emps2</a> - wersja z użyciem JPA wyciągniętym do osobnej klasy @Repository</li>
<li><a href="/emps2/100">emps2/100</a> - odczyt jednego pracownika po id</li>
<li><a href="/emps2/by_name?name=King">emps2/by_name?last_name=King</a> - odczyt pracowników po nazwisku, przykład <strong>Query</strong></li>
<li><a href="/emps3">emps3</a> - j.w. ale interfejs</li>
<li><a href="/emps3/100">emps3/100</a> - odczyt jednego pracownika po id</li>
<li><a href="/emps3/by_name?name=King">emps3/by_name?last_name=King</a> - odczyt pracowników po nazwisku, przykład <strong>Query</strong></li>
<li><a href="/emps4">emps4</a> - Spring Data JpaRepository – domyślny interfejs</li>
<li><a href="/emps4/100">emps4/100</a> - odczyt jednego pracownika po id</li>
<li><a href="/emps5/all">emps5</a> - Spring Data JpaRepository – rozszerzony interfejs</li>
<li><a href="/emps5/by_id/101">emps5/by_id/101</a> - wg id</li>
<li><a href="/emps5/by_name?name=King">emps5/by_name?last_name=King</a> - odczyt pracowników po nazwisku, przykład <strong>Query</strong></li>
<li><a href="/emps5/by_job/ST_CLERK">/by_job/ST_CLERK</a> - wg stanowiska
<li><a href="/emps5/by_city/Seattle">emps5/by_city/Seattle</a> - wg miasta</li>
<li><a href="/emps5/by_salary?min=5000&amp;max=10000">emps5/by_salary</a> - wg pensji</li>
<li><a href="/emps5/by_year/1999">emps5/by_year</a> - wg roku zatrudneinia - przykład <strong>native query</strong></li>
<li><a href="/emps5/szef/105">szef/105</a> - nazwisko sefa (przykład własnej funkcji)
<li><a href="/emps5/zara?id=103">zara?id=103</a> - zarabiający więcej niż (przykład własnej funkcji)
<li><a href="/emps5/move/110?dep=90&job=AD_PRES">move</a> - przenieś pracownika
</ul>
<h2>Wstrzykiwanie na 3 sposoby</h2>
<ul>
<li><a href="/inject1">Wstrzykiwanie 1</a> - pole</li>
<li><a href="/inject2">Wstrzykiwanie 2</a> - setter</li>
<li><a href="/inject3">Wstrzykiwanie 3</a> - konstruktor</li>
</ul>
<h2>Eksperymenty z beanami</h2>
<ul>
<li><a href="/test0">Test 0</a> &mdash; brak modelu</li>
<li><a href="/test1">Test 1</a> &mdash; <code>Model</code></li>
<li><a href="/test2">Test 2</a> &mdash; parametr metody i <code>Model</code></li>
<li><a href="/test3">Test 3</a> &mdash; parametr <code>@ModelAttribute</code></li>
<li><a href="/test4">Test 4</a> &mdash; <code>@ModelAttribute</code> przy metodzie i w parametrze</li>
<li><a href="/test4a">Test 4a</a> &mdash; <code>@ModelAttribute</code> przy metodzie, ale nie w parametrze</li>
<li><a href="/test5">Test 5</a> &mdash; <code>@ModelAttribute</code> w połączeniu z <code>@SessionAttributes</code></li>
<li><a href="/test6">Test 6</a> &mdash; <code>@Component</code> w połączeniu z <code>@Autowired</code></li>
<li><a href="/test7">Test 7</a> &mdash; <code>@Component @Scope(session)</code></li>
<li><a href="/test8">Test 8</a> &mdash; <code>@Bean</code> w połączeniu z <code>@Autowired</code></li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Test beanów za pomocą licznika</title>
<link rel="stylesheet" type="text/css" th:href="@{/styl.css}"/>
</head>
<body>
<h1>Test beanów za pomocą licznika</h1>
<p>licznik = <strong th:text="${licznik}">X</strong></p>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Names</title>
</head>
<body>
<ul>
<li th:each="name : ${names}" th:text="${name}">ktoś</li>
</ul>
<p><a th:href="@{/}">wróć do spisu treści</a></p>
</body>
</html>
<!DOCTYPE html>
<html lang="pl" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Ping</title>
<link rel="stylesheet" type="text/css" th:href="@{/styl.css}" href="../static/styl.css">
</head>
<body>
<h2>Informacje o kliencie</h2>
<ul>
<li>Adres: <strong th:text="${clientInfo.ip}">1.2.3.4</strong></li>
<li>Przeglądarka: <strong th:text="${clientInfo.userAgent}">IE</strong></li>
<li>Data: <strong th:text="${clientInfo.data}">data</strong></li>
</ul>
</body>
</html>
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Pc36SpringTechnicznieApplicationTests {
@Test
void contextLoads() {
}
}
target/
.settings/
.classpath
.project
*.iml
.idea/
<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>
<groupId>pl.alx.kjava</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>wielomodulowy-model</module>
<module>wielomodulowy-baza</module>
<module>wielomodulowy-rest</module>
<module>wielomodulowy-klient_rest</module>
<module>wielomodulowy-web</module>
<module>wielomodulowy-ear</module>
<module>wielomodulowy-soap_serwer</module>
<module>wielomodulowy-soap_klient</module>
<module>wielomodulowy-soap_api</module>
</modules>
</project>
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-baza</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
package sklep.db;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Customer;
public class CustomerDAO {
private final DBConnection db;
CustomerDAO(DBConnection db) {
this.db = db;
}
public Customer findByEmail(String email) throws DBException, RecordNotFound {
final String sql = "SELECT * FROM customers WHERE customer_email = ?";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setString(1, email);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return customerFromRS(rs);
} else {
throw new RecordNotFound("Cannot find customer with email " + email);
}
}
} catch (SQLException e) {
throw new DBException("SQL error in CustomerDAO.findById: " + e.getMessage(), e);
}
}
public List<Customer> readAll() throws DBException {
final String sql = "SELECT * FROM customers";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
try (ResultSet rs = stmt.executeQuery()) {
return customerListFromRS(rs);
}
} catch (SQLException e) {
throw new DBException("SQL error in CustomerDAO.readAll: " + e.getMessage(), e);
}
}
private List<Customer> customerListFromRS(ResultSet rs) throws SQLException {
List<Customer> records = new ArrayList<>();
while (rs.next()) {
Customer product = customerFromRS(rs);
records.add(product);
}
return records;
}
private Customer customerFromRS(ResultSet rs) throws SQLException {
return new Customer(
rs.getString("customer_email"),
rs.getString("customer_name"),
rs.getString("phone_number"),
rs.getString("address"),
rs.getString("postal_code"),
rs.getString("city"));
}
public void insert(Customer customer) throws DBException {
// używać gdy obiekt ma wpisane ID (tu: email)
final String sql = "INSERT INTO customers("
+ "customer_email, customer_name, phone_number, address, postal_code, city)"
+ " VALUES (?, ?, ?, ?, ?, ?)";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setString(1, customer.getEmail());
stmt.setString(2, customer.getName());
stmt.setString(3, customer.getPhoneNumber());
stmt.setString(4, customer.getAddress());
stmt.setString(5, customer.getPostalCode());
stmt.setString(6, customer.getCity());
stmt.executeUpdate();
} catch (SQLException e) {
throw new DBException("Error during INSERT CUSTOMER", e);
}
}
public boolean update(Customer customer) throws DBException {
final String sql = "UPDATE customers SET "
+ " customer_name=?, phone_number=?, address=?, postal_code=?, city=?"
+ " WHERE customer_email = ?";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setString(1, customer.getName());
stmt.setString(2, customer.getPhoneNumber());
stmt.setString(3, customer.getAddress());
stmt.setString(4, customer.getPostalCode());
stmt.setString(5, customer.getCity());
stmt.setString(6, customer.getEmail());
int count = stmt.executeUpdate();
return count > 0;
} catch (SQLException e) {
throw new DBException("Error during UPDATE CUSTOMER", e);
}
}
public void save(Customer customer) throws DBException {
if(customer.getEmail() == null) {
throw new IllegalArgumentException("Customer email cannot be null");
} else {
if(! update(customer)) {
insert(customer);
}
}
}
public boolean delete(String email) throws DBException {
final String sql = "DELETE FROM customers WHERE customer_email = ?";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setString(1, email);
int count = stmt.executeUpdate();
return count > 0;
} catch (SQLException e) {
throw new DBException("Error during DELETE CUSTOMER", e);
}
}
public boolean delete(Customer customer) throws DBException {
return delete(customer.getEmail());
}
}
package sklep.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import sklep.exn.DBException;
public class DBConnection implements AutoCloseable {
private Connection sqlConnection;
private DBConnection(Connection sqlConnection) {
this.sqlConnection = sqlConnection;
}
public static DBConnection open() throws DBException {
return open(false);
}
public static DBConnection open(boolean autoCommit) throws DBException {
try {
Properties props = DBSettings.load();
if(props.containsKey("driver_class")) {
Class.forName(props.getProperty("driver_class"));
}
Connection c = DriverManager.getConnection(props.getProperty("url") , props);
c.setAutoCommit(autoCommit);
return new DBConnection(c);
} catch (ClassNotFoundException | SQLException e) {
throw new DBException("Cannot connect to postgresql: " + e, e);
}
}
public static DBConnection openLocalhost() throws DBException {
try {
Connection c = DriverManager.getConnection("jdbc:postgresql://localhost/sklep", "kurs", "abc123");
c.setAutoCommit(false);
return new DBConnection(c);
} catch (SQLException e) {
throw new DBException("Cannot connect to postgresql: " + e, e);
}
}
@Override
public void close() {
try {
if (sqlConnection != null) {
sqlConnection.close();
sqlConnection = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public Connection getSqlConnection() {
return sqlConnection;
}
public void commit() throws DBException {
try {
sqlConnection.commit();
} catch (SQLException e) {
throw new DBException("Error during commit: " + e.getMessage(), e);
}
}
public void rollback() throws DBException {
try {
sqlConnection.rollback();
} catch (SQLException e) {
throw new DBException("Error during rollback: " + e.getMessage(), e);
}
}
public ProductDAO productDAO() {
return new ProductDAO(this);
}
public CustomerDAO customerDAO() {
return new CustomerDAO(this);
}
public OrderDAO orderDAO() {
return new OrderDAO(this);
}
}
package sklep.db;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import sklep.exn.DBException;
public class DBSettings {
public static final String DB_SETTINGS_SYSTEM_PROPERTY = "sklep.db_settings_location";
private static final String INTERNAL_DEFAULT_PROPERTIES = "/sklep.properties";
private static DBSettings dbSettings; // singleton
private final Properties props;
private DBSettings() throws DBException {
props = new Properties();
String systemProperty = System.getProperty(DB_SETTINGS_SYSTEM_PROPERTY);
try(InputStream input = systemProperty != null
? new FileInputStream(new File(systemProperty))
: DBSettings.class.getResourceAsStream(INTERNAL_DEFAULT_PROPERTIES) ) {
props.load(input);
} catch (IOException e) {
//e.printStackTrace();
throw new DBException("Cannot read settings. " + e, e);
}
}
public static synchronized DBSettings getInstance() throws DBException {
// Dla klasy typu "singleton" w aplikacji powstaje tylko jedna instancja (obiekt) tej klasy.
// Dostęp do tego obiektu odbywa się poprzez metodę statyczną taką jak ta.
// Tutaj mamy "leniwą inicjalizację", czyli obiekt jest tworzony przy pierwszej próbie dostepu.
if(dbSettings == null) {
dbSettings = new DBSettings();
}
return dbSettings;
}
public Properties getProperties() {
return props;
}
public static Properties load() throws DBException {
return getInstance().getProperties();
}
}
package sklep.db;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Order;
import sklep.model.OrderProduct;
public class OrderDAO {
private static final String[] ID_COLUMNS = {"order_id", "order_date"};
private final DBConnection db;
OrderDAO(DBConnection db) {
this.db = db;
}
public Order findById(int orderId) throws DBException, RecordNotFound {
final String sql = "SELECT * FROM orders WHERE order_id = ?";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setInt(1, orderId);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return orderFromRS(rs);
} else {
throw new RecordNotFound("Cannot find order with id " + orderId);
}
}
} catch (SQLException e) {
throw new DBException("SQL error in OrderDAO.findById: " + e.getMessage(), e);
}
}
public List<Order> readAll() throws DBException {
final String sql = "SELECT * FROM orders ORDER BY order_id";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
try (ResultSet rs = stmt.executeQuery()) {
return orderListFromRS(rs);
}
} catch (SQLException e) {
throw new DBException("SQL error in OrderDAO.readAll: " + e.getMessage(), e);
}
}
public List<Order> customerOrders(String email) throws DBException {
final String sql = "SELECT * FROM orders WHERE customer_email = ? ORDER BY order_id";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setString(1, email);
try (ResultSet rs = stmt.executeQuery()) {
return orderListFromRS(rs);
}
} catch (SQLException e) {
throw new DBException("SQL error in OrderDAO.customerOrders: " + e.getMessage(), e);
}
}
private List<Order> orderListFromRS(ResultSet rs) throws SQLException, DBException {
List<Order> orders = new ArrayList<>();
while (rs.next()) {
Order order = orderFromRS(rs);
orders.add(order);
}
return orders;
}
private Order orderFromRS(ResultSet rs) throws SQLException, DBException {
Order order = Order.ofDbFields(
rs.getInt("order_id"),
rs.getString("customer_email"),
rs.getTimestamp("order_date"),
rs.getString("status"));
order.addProducts(orderProductsForOrder(order.getOrderId()));
return order;
}
List<OrderProduct> orderProductsForOrder(int orderId) throws DBException {
final String sql = "SELECT * FROM order_products WHERE order_id = ? ORDER BY product_id";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setInt(1, orderId);
try (ResultSet rs = stmt.executeQuery()) {
List<OrderProduct> ops = new ArrayList<>();
while(rs.next()) {
ops.add(orderProductFromRS(rs));
}
return ops;
}
} catch (SQLException e) {
throw new DBException("SQL error in OrderDAO.customerOrders: " + e.getMessage(), e);
}
}
private OrderProduct orderProductFromRS(ResultSet rs) throws SQLException {
return new OrderProduct(rs.getInt("order_id"), rs.getInt("product_id"), rs.getInt("quantity"), rs.getBigDecimal("actual_price"));
}
}
package sklep.db;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
/* DAO - Data Access Object(s)
Dostęp do baz danych oparty o takie zasady:
tabelom bazodanowym odpowiadają klasy w naszej aplikacji
np. dla tabeli products mamy klasę Product (w pakiecie model)
dla takie pary tabela products + klasa Product tworzymy klasę narzędziową ProductDAO , której zadaniem jest obsługa tej tabeli: odczyt, zapis, wyszukiwanie, i inne operacje jeśli są potrzebne.
*/
public class ProductDAO {
private static final BigDecimal MAX_PRICE = new BigDecimal(1_000_000_000);
private static final String[] ID_COLUMNS = {"product_id"};
private final DBConnection db;
ProductDAO(DBConnection db) {
this.db = db;
}
public Product findById(int productId) throws DBException, RecordNotFound {
final String sql = "SELECT * FROM products WHERE product_id = ?";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setInt(1, productId);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return productFromRS(rs);
} else {
throw new RecordNotFound("Cannot find product with id " + productId);
}
}
} catch (SQLException e) {
throw new DBException("SQL error in ProductDAO.findById: " + e.getMessage(), e);
}
}
public List<Product> readAll() throws DBException {
final String sql = "SELECT * FROM products ORDER BY product_id";
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
try (ResultSet rs = stmt.executeQuery()) {
return productListFromRS(rs);
}
} catch (SQLException e) {
throw new DBException("SQL error in ProductDAO.readAll: " + e.getMessage(), e);
}
}
public List<Product> findByPrice(BigDecimal minPrice, BigDecimal maxPrice) throws DBException {
final String sql = "SELECT * FROM products WHERE price BETWEEN ? AND ? ORDER BY product_id";
if(minPrice == null)
minPrice = BigDecimal.ZERO;
if(maxPrice == null)
maxPrice = MAX_PRICE;
try (PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setBigDecimal(1, minPrice);
stmt.setBigDecimal(2, maxPrice);
try (ResultSet rs = stmt.executeQuery()) {
return productListFromRS(rs);
}
} catch (SQLException e) {
throw new DBException("SQL error in ProductDAO.findByPrice: " + e.getMessage(), e);
}
}
private List<Product> productListFromRS(ResultSet rs) throws SQLException {
List<Product> products = new ArrayList<>();
while (rs.next()) {
Product product = productFromRS(rs);
products.add(product);
}
return products;
}
private Product productFromRS(ResultSet rs) throws SQLException {
return new Product(
rs.getInt("product_id"),
rs.getString("product_name"),
rs.getBigDecimal("price"),
rs.getBigDecimal("vat"),
rs.getString("description"));
}
public void insert(Product product) throws DBException {
// używać gdy obiekt ma wpisane ID
final String sql = "INSERT INTO products("
+ " product_id, product_name, price, vat, description)"
+ " VALUES (?, ?, ?, ?, ?)";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setInt(1, product.getProductId());
stmt.setString(2, product.getProductName());
stmt.setBigDecimal(3, product.getPrice());
stmt.setBigDecimal(4, product.getVat());
stmt.setString(5, product.getDescription());
stmt.executeUpdate();
} catch (SQLException e) {
throw new DBException("Error during INSERT PRODUCT", e);
}
}
public void insertNew(Product product) throws DBException {
// używać gdy obiekt nie ma wpisanego ID (productID == null)
final String sql = "INSERT INTO products("
+ " product_name, price, vat, description)"
+ " VALUES (?, ?, ?, ?)";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql, ID_COLUMNS)) {
stmt.setString(1, product.getProductName());
stmt.setBigDecimal(2, product.getPrice());
stmt.setBigDecimal(3, product.getVat());
stmt.setString(4, product.getDescription());
stmt.executeUpdate();
try (ResultSet rs = stmt.getGeneratedKeys()) {
if(rs.next()) {
// w obiekcie, który mamy w pamięci, uzupełniamy brakujące ID na podstawie tego, co wygenerowała baza
product.setProductId(rs.getInt(1));
}
};
} catch (SQLException e) {
throw new DBException("Error during INSERT PRODUCT", e);
}
}
public boolean update(Product product) throws DBException {
final String sql = "UPDATE products SET "
+ " product_name = ?, price = ?, vat = ?, description = ?"
+ " WHERE product_id = ?";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setString(1, product.getProductName());
stmt.setBigDecimal(2, product.getPrice());
stmt.setBigDecimal(3, product.getVat());
stmt.setString(4, product.getDescription());
stmt.setInt(5, product.getProductId());
int count = stmt.executeUpdate();
return count > 0;
} catch (SQLException e) {
throw new DBException("Error during UPDATE PRODUCT", e);
}
}
public void save(Product product) throws DBException {
if(product.getProductId() == null) {
// wstawiamy nowy rekord korzystajac z sekwecji
insertNew(product);
} else {
if(! update(product)) {
insert(product);
}
}
}
public boolean delete(int productId) throws DBException {
final String sql = "DELETE FROM products WHERE product_id = ?";
try(PreparedStatement stmt = db.getSqlConnection().prepareStatement(sql)) {
stmt.setInt(1, productId);
int count = stmt.executeUpdate();
return count > 0;
} catch (SQLException e) {
throw new DBException("Error during DELETE PRODUCT", e);
}
}
public boolean delete(Product product) throws DBException {
return delete(product.getProductId());
}
}
package sklep.db;
import java.util.List;
import sklep.exn.DBException;
import sklep.model.Product;
public class ZwyklyOdczyt_DAO {
public static void main(String[] args) {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
List<Product> products = productDAO.readAll();
for (Product product : products) {
System.out.println(product);
}
} catch (DBException e) {
e.printStackTrace();
}
}
}
package sklep.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ZwyklyOdczyt_JDBC {
public static void main(String[] args) {
String url = "jdbc:postgresql://localhost:5432/sklep";
String sql = "SELECT * FROM products";
try(Connection c = DriverManager.getConnection(url, "kurs", "abc123");
PreparedStatement stmt= c.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
while(rs.next()) {
System.out.printf("%d: %s za cenę %s\n",
rs.getInt("product_id"), rs.getString("product_name"), rs.getBigDecimal("price"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
url=jdbc:postgresql://localhost:5432/sklep
driver_class=org.postgresql.Driver
user=kurs
password=abc123
photo_dir=/home/patryk/sklep/foto
# Sciezki na Windows: albo piszemy slashe / , albo podwojne backslashe \\
# photo_dir=C:/Users/Patryk/Desktop/sklep/foto
# photo_dir=C:\\Users\\Patryk\\Desktop\\sklep\\foto
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-ear</artifactId>
<packaging>ear</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-web</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-rest</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-soap_serwer</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
</dependencies>
</project>
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-klient_rest</artifactId>
<properties>
<resteasy.version>6.2.6.Final</resteasy.version>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.parsson</groupId>
<artifactId>parsson</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>${resteasy.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package rest_klient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class Klient01_URL {
public static void main(String[] args) {
// Najprostszy sposób w Javie, aby pobrać dane z adresu URL, to użyć klasy URL.
try {
URL url = new URL("http://localhost:8080/PC35-RestSerwer/products.json");
System.out.println("Odczytuję dane...");
try (InputStream input = url.openStream()) {
// teraz z inputa możemy czytać ciąg bajtów
// ja przerzucę bajty czytane z sieci bezpośrednio do System.out
// (w przypadku obcego serwisu może być to niebezpieczne)
input.transferTo(System.out);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonReader;
import jakarta.json.JsonValue;
public class Klient02_URL_JSON {
public static void main(String[] args) {
try {
URL url = new URL(Ustawienia.ADRES_USLUGI + "/products.json");
try(InputStream inputStream = url.openStream();
JsonReader reader = Json.createReader(inputStream)) {
JsonArray array = reader.readArray();
// System.out.println(array);
for(JsonValue jsonValue : array) {
//System.out.println(jsonValue);
System.out.println(jsonValue.asJsonObject().getString("productName"));
System.out.println(" opis: " + jsonValue.asJsonObject().getString("description", ""));
System.out.println(" cena: " + jsonValue.asJsonObject().getJsonNumber("price").bigDecimalValue());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Klient03_HttpClient {
/* W Java 11 pojawiło się rozwiązanie "HttpClient", które umożliwia komunikację HTTP z dużą kontrolą nad szczegółami.
* Wysyłając zapytanie, od razu trzeba podać odpowiedni "BodyHandler",
* który pozwoli nam odczytać treść odpowiedzi we właściwy dla nas sposób.
*
* W tej wersji wynik jest zapisywany do pliku.
*/
public static void main(String[] args) {
HttpClient httpClient = HttpClient.newHttpClient();
try {
URI uri = new URI(Ustawienia.ADRES_USLUGI + "/products.json");
HttpRequest request = HttpRequest.newBuilder(uri).build();
HttpResponse<Path> response = httpClient.send(request, BodyHandlers.ofFile(Paths.get("wynik03.json")));
System.out.println("response " + response);
System.out.println("status: " + response.statusCode());
System.out.println("Content-Type: " + response.headers().firstValue("Content-Type").orElse("BRAK"));
System.out.println("OK, zapisany plik: " + response.body());
} catch (URISyntaxException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
public class Klient04_HttpClient_String {
public static void main(String[] args) {
HttpClient httpClient = HttpClient.newHttpClient();
try {
URI uri = new URI(Ustawienia.ADRES_USLUGI + "/products.json");
HttpRequest request = HttpRequest.newBuilder(uri).build();
// Body z odpowiedzi pobierzemy jako obiekt String z całą treścią
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
System.out.println("response " + response);
System.out.println("status: " + response.statusCode());
System.out.println("Content-Type: " + response.headers().firstValue("Content-Type").orElse("BRAK"));
System.out.println("Treść odpowiedzi:\n" + response.body()); // tutaj
} catch (URISyntaxException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
public class Klient05_HttpClient_Accept {
public static void main(String[] args) {
HttpClient httpClient = HttpClient.newHttpClient();
try {
URI uri = new URI(Ustawienia.ADRES_USLUGI + "/products");
// W tej wersji do zapytania dodajemy nagłówek Accept
HttpRequest request = HttpRequest.newBuilder(uri)
.header("Accept", "text/plain")
.build();
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
System.out.println("response " + response);
System.out.println("status: " + response.statusCode());
System.out.println("Content-Type: " + response.headers().firstValue("Content-Type").orElse("BRAK"));
System.out.println("Treść odpowiedzi:\n" + response.body());
} catch (URISyntaxException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
public class Klient06_HttpClient_JSON {
/* W tej wersji używamy technologii Jakarta JSON P.
*
* Widzimy drzewo danych jsonowych i jego elementytakie jak JsonObject, JsonArray, ...
* Mamy dostęp do poszczególnych pól.
*/
public static void main(String[] args) {
HttpClient httpClient = HttpClient.newHttpClient();
try {
URI uri = new URI(Ustawienia.ADRES_USLUGI + "/products/1");
HttpRequest request = HttpRequest.newBuilder(uri)
.header("Accept", "application/json")
.build();
HttpResponse<InputStream> response = httpClient.send(request, BodyHandlers.ofInputStream());
System.out.println("response " + response);
System.out.println("status: " + response.statusCode());
System.out.println("Content-Type: " + response.headers().firstValue("Content-Type").orElse("BRAK"));
JsonReader reader = Json.createReader(response.body());
JsonObject product = reader.readObject();
System.out.println("Pobrany obiekt jsonowy: " + product);
String nazwa = product.getString("productName");
String opis = product.getString("description", "BRAK OPISU");
BigDecimal cena = product.getJsonNumber("price").bigDecimalValue();
System.out.println(nazwa + " za cenę " + cena + " , opis: " + opis);
reader.close();
} catch (URISyntaxException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
import jakarta.json.JsonValue;
public class Klient07_HttpClient_JSON_Lista {
public static void main(String[] args) {
try {
JsonArray array = pobierzJsona(Ustawienia.ADRES_USLUGI + "/products.json");
for(JsonValue jsonValue : array) {
JsonObject jsonObject = jsonValue.asJsonObject();
System.out.println(jsonObject.getString("productName"));
if(jsonObject.containsKey("description")) {
System.out.println(" opis: " + jsonObject.getString("description", ""));
}
System.out.println(" cena: " + jsonObject.getJsonNumber("price").bigDecimalValue());
}
} catch (IOException | InterruptedException | URISyntaxException e) {
e.printStackTrace();
}
}
private static JsonArray pobierzJsona(String adres) throws IOException, InterruptedException, URISyntaxException {
HttpClient httpClient = HttpClient.newHttpClient();
URI uri = new URI(adres);
HttpRequest request = HttpRequest.newBuilder(uri).build();
HttpResponse<InputStream> response = httpClient.send(request, BodyHandlers.ofInputStream());
System.out.println("response " + response);
System.out.println("status: " + response.statusCode());
System.out.println("Content-Type: " + response.headers().firstValue("Content-Type").orElse("BRAK"));
return wczytajJsona(response.body());
}
private static JsonArray wczytajJsona(InputStream input) {
try(JsonReader reader = Json.createReader(input)) {
return reader.readArray();
}
}
}
package rest_klient;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response;
// Ten i kolejne przykłady pokazują jak aplikacja kliencka napisana w Javie może wysyłać
// zapytania do usługi REST-owej (głównie GET, jest też gdzieś POST)
// korzystając z technologii JAX-RS "po stronie klienta".
// Aby z tego skorzystać, do projektu trzeba dodać bibliotekę z implementacją JAX-RS.
// Tutaj jest to resteasy-client.
public class Klient11_RestClient {
public static void main(String[] args) {
System.out.println("Startujemy");
Client client = ClientBuilder.newClient();
System.out.println("Przygotowuję zapytanie");
WebTarget target = client.target(Ustawienia.ADRES_USLUGI).path("products.json");
Invocation invocation = target.request().buildGet();
System.out.println("Wysyłam zapytanie");
Response response = invocation.invoke();
// Wynikiem jest obiekt klasy Response - tej samej, co na serwerze (używaliśmy np. do generowania kodów 404).
// W obiekcie można sprawdzić informacji o odpowiedzi: media type, status code.
System.out.println("Mam odpowiedź: " + response);
System.out.println("Status: " + response.getStatus());
System.out.println("C-Type: " + response.getMediaType());
System.out.println("Length: " + response.getLength());
// Aby odczytać zawartość zwróconą przez serwer, używamy metody readEntity.
// (przy domyślnych ustawieniach) tę metodę można wywołać tylko raz.
// Dopiero w tym momencie podajemy typ, na który zostanie skonwertowana treść odpowiedzi
// (w miarę możliwości - po prostu niektóre typy zadziałają, a niektóre nie).
byte[] dane = response.readEntity(byte[].class);
System.out.println("Dane mają " + dane.length + " bajtów.");
try {
Files.write(Paths.get("wynik11.json"), dane);
System.out.println("Zapisałem w pliku");
} catch (IOException e) {
System.err.println(e);
}
System.out.println("Koniec");
}
}
package rest_klient;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;
public class Klient12_RestClient_String {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
// Taki styl programowania to "fluent API"
Response response = client.target(Ustawienia.ADRES_USLUGI)
.path("products.json")
.request()
.buildGet()
.invoke();
System.out.println("Mam odpowiedź: " + response);
System.out.println("Status: " + response.getStatus());
System.out.println("C-Type: " + response.getMediaType());
System.out.println("Length: " + response.getLength());
// readEntity(OKREŚLENIE TYPU) stara się odczytać tresc odpowiedzi jako obiekt podanego typu
// Obsługiwane typy to m.in: byte[], String, InputStream, File
// Dodając odpowiednie "MeassgeBodyReader", możemy obsługiwać dowolne typy.
// W szczególności, gdy dodamy do projektu obsługę XML lub JSON (zob. zależności Mavena),
// będziemy mogli odczytywać dane w postaci obiektów naszego modelu, np. Product.
String dane = response.readEntity(String.class);
System.out.println("Otrzymane dane:");
System.out.println(dane);
}
}
package rest_klient;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import javax.swing.JOptionPane;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;
public class Klient13_RestClient_Multiformat {
public static void main(String[] args) {
try {
Client client = ClientBuilder.newClient();
String[] formaty = {"txt", "json", "xml", "html", "pdf"};
String format = (String) JOptionPane.showInputDialog(null, "Wybierz format danych", "Wybór",
JOptionPane.QUESTION_MESSAGE, null, formaty, "txt");
if(format == null) {
return;
}
String mediaType = switch(format) {
case "txt" -> "text/plain";
case "json" -> "application/json";
case "xml" -> "application/xml";
case "html" -> "text/html";
case "pdf" -> "application/pdf";
default -> throw new IllegalArgumentException();
};
// Klient może wybrać format (mediaType), w jakim oczekuje odpowiedzi - to wpływa na nagłówek Accept
Response response = client.target(Ustawienia.ADRES_USLUGI)
.path("products")
.request(mediaType)
.buildGet()
.invoke();
JOptionPane.showMessageDialog(null, String.format("""
Status: %d
C-Type: %s
Length: %d""", response.getStatus(), response.getMediaType(), response.getLength()));
Path plik = Paths.get("wynik13." + format);
InputStream stream = response.readEntity(InputStream.class);
Files.copy(stream, plik, StandardCopyOption.REPLACE_EXISTING);
JOptionPane.showMessageDialog(null, "Zapisano plik " + plik);
} catch(Exception e) {
e.printStackTrace();
}
}
}
package rest_klient;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
public class Klient14_RestClient_PDF {
private static final MediaType PDF_TYPE = new MediaType("application", "pdf");
public static void main(String[] args) {
int productId = 1;
System.out.println("Startujemy...");
Client client = ClientBuilder.newClient();
WebTarget root = client.target(Ustawienia.ADRES_USLUGI);
Response response = root
.path("products")
.path("{id}")
.resolveTemplate("id", productId)
.request()
.accept(PDF_TYPE)
.buildGet()
.invoke();
System.out.println("Otrzymałem response: " + response);
System.out.println("Status: " + response.getStatus());
System.out.println("Content-Type: " + response.getMediaType());
if(response.getStatus() != 200) {
System.out.println("Chyba coś nie tak, więc przerywam.");
return;
}
String nazwaPliku = "wynik.pdf";
String contentDisposition = response.getHeaderString("Content-Disposition");
if(contentDisposition != null && contentDisposition.contains(";filename=")) {
nazwaPliku = contentDisposition.split(";filename=")[1];
}
try(InputStream strumienDanych = response.readEntity(InputStream.class)) {
long ileBajtow = Files.copy(strumienDanych, Paths.get(nazwaPliku), StandardCopyOption.REPLACE_EXISTING);
System.out.printf("Zapisano %d bajtów do pliku %s\n", ileBajtow, nazwaPliku);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Gotowe");
}
}
package rest_klient;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;
import sklep.model.Product;
import sklep.model.ProductList;
public class Klient21_RestClient_JAXB {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
Response response = client.target(Ustawienia.ADRES_USLUGI)
.path("products.xml")
.request()
.buildGet()
.invoke();
System.out.println("Mam odpowiedź: " + response);
System.out.println("Status: " + response.getStatus());
System.out.println("C-Type: " + response.getMediaType());
System.out.println("Length: " + response.getLength());
ProductList products = response.readEntity(ProductList.class);
System.out.println("Otrzymane dane:");
for (Product product : products.getProducts()) {
System.out.println(product);
}
}
}
package rest_klient;
import java.util.List;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Response;
import sklep.model.Product;
public class Klient22_RestClient_JSON {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
Response response = client.target(Ustawienia.ADRES_USLUGI)
.path("products.json")
.request()
.buildGet()
.invoke();
System.out.println("Mam odpowiedź: " + response);
System.out.println("Status: " + response.getStatus());
System.out.println("C-Type: " + response.getMediaType());
System.out.println("Length: " + response.getLength());
// Ponieważ wersja JSON na serwerze zwraca wynik typu List<Product>, to tutaj musimy podać "typ generyczny",
// a nie wystarczy zwykła klasa.
// Nie zadziała:
// List<Product> products = response.readEntity(List.class);
GenericType<List<Product>> typListy = new GenericType<>() {};
List<Product> products = response.readEntity(typListy);
// albo jednolinijkowo:
// List<Product> products = response.readEntity(new GenericType<List<Product>>() {});
for(Product product : products) {
System.out.println(product);
}
}
}
package rest_klient;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import sklep.model.Product;
public class Klient23_RestClient_JSON_JedenProdukt {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
Response response = client.target(Ustawienia.ADRES_USLUGI)
.path("products")
.path("1")
.request()
.accept(MediaType.APPLICATION_JSON)
.buildGet()
.invoke();
System.out.println("Mam odpowiedź: " + response);
System.out.println("Status: " + response.getStatus());
System.out.println("C-Type: " + response.getMediaType());
System.out.println("Length: " + response.getLength());
Product product = response.readEntity(Product.class);
System.out.println("Odczytany produkt: " + product);
}
}
package rest_klient;
import java.math.BigDecimal;
import java.util.Scanner;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import sklep.model.Product;
public class Klient24_Interaktywna_Edycja {
public static void main(String[] args) {
System.out.println("Startujemy...");
Scanner scanner = new Scanner(System.in);
Client client = ClientBuilder.newClient();
WebTarget path = client.target(Ustawienia.ADRES_USLUGI)
.path("products")
.path("{id}");
System.out.println("Przygotowana ścieżka: " + path);
while (true) {
System.out.print("\nPodaj id: ");
int id = scanner.nextInt();
if(id == 0) break;
Response response = path
.resolveTemplate("id", id)
.request(MediaType.APPLICATION_JSON)
.get();
System.out.println("Status: " + response.getStatus());
System.out.println("Content-Type: " + response.getMediaType());
if (response.getStatus() == 200) {
Product product = response.readEntity(Product.class);
System.out.println("Mam produkt:");
System.out.println(" Nazwa: " + product.getProductName());
System.out.println(" Cena: " + product.getPrice());
System.out.println(" Opis: " + product.getDescription());
System.out.println();
System.out.println("Podaj zmianę ceny (0 aby nie zmieniać):");
BigDecimal zmianaCeny = scanner.nextBigDecimal();
if(zmianaCeny.compareTo(BigDecimal.ZERO) != 0) {
BigDecimal newPrice = product.getPrice().add(zmianaCeny);
System.out.println("PUT nowej ceny...");
Response odpPut = path.path("price").resolveTemplate("id", id).request()
.put(Entity.entity(newPrice, MediaType.TEXT_PLAIN_TYPE));
System.out.println("PUT zakończył się kodem " + odpPut.getStatus());
}
} else {
System.out.println("nie mogę odczytać");
}
}
}
}
package rest_klient;
public class Ustawienia {
public static final String ADRES_USLUGI = "http://localhost:8080/wielomodulowy-rest";
}
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-model</artifactId>
<dependencies>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package sklep.exn;
public class DBException extends SklepException {
public DBException() {
super();
}
public DBException(String message, Throwable cause) {
super(message, cause);
}
public DBException(String message) {
super(message);
}
}
package sklep.exn;
public class RecordNotFound extends SklepException {
public RecordNotFound() {
super();
}
public RecordNotFound(String message) {
super(message);
}
}
package sklep.exn;
public class SklepException extends Exception {
public SklepException() {
super();
}
public SklepException(String message, Throwable cause) {
super(message, cause);
}
public SklepException(String message) {
super(message);
}
public SklepException(Throwable cause) {
super(cause);
}
}
package sklep.model;
import java.util.Objects;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
private String email;
private String name;
private String phoneNumber;
private String address;
private String postalCode;
private String city;
public Customer() {
}
public Customer(String email, String name, String phone, String address, String postalCode, String city) {
this.email = email;
this.name = name;
this.phoneNumber = phone;
this.address = address;
this.postalCode = postalCode;
this.city = city;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phone) {
this.phoneNumber = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Customer [email=" + email + ", name=" + name + ", phone=" + phoneNumber + ", address=" + address
+ ", postalCode=" + postalCode + ", city=" + city + "]";
}
@Override
public int hashCode() {
return Objects.hash(email, name, address, city, phoneNumber, postalCode);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Customer other = (Customer) obj;
return Objects.equals(email, other.email) && Objects.equals(name, other.name)
&& Objects.equals(address, other.address) && Objects.equals(city, other.city)
&& Objects.equals(phoneNumber, other.phoneNumber) && Objects.equals(postalCode, other.postalCode);
}
}
package sklep.model;
import java.time.LocalDateTime;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
public class DateTimeAdapter extends XmlAdapter<String, LocalDateTime> {
@Override
public String marshal(LocalDateTime dt) throws Exception {
return dt.toString();
}
@Override
public LocalDateTime unmarshal(String s) throws Exception {
return LocalDateTime.parse(s);
}
}
package sklep.model;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class Order {
@XmlAttribute(name="id")
private Integer orderId;
@XmlElement(name="customer-email")
private String customerEmail;
@XmlElement(name="order-date")
@XmlJavaTypeAdapter(DateTimeAdapter.class)
private LocalDateTime orderDate;
@XmlAttribute(name="status")
private Status orderStatus;
@XmlElementWrapper(name="products")
@XmlElement(name="product")
public final List<OrderProduct> products = new ArrayList<>();
public Order() {
}
public Order(Integer orderId, String customerEmail, LocalDateTime orderDate, Status orderStatus) {
this.orderId = orderId;
this.customerEmail = customerEmail;
this.orderDate = orderDate;
this.orderStatus = orderStatus;
}
public static Order ofDbFields(int orderId, String customerEmail, java.sql.Timestamp orderDate, String orderStatus) {
return new Order(orderId, customerEmail,
orderDate.toLocalDateTime(),
Status.valueOf(orderStatus.toUpperCase()));
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public String getCustomerEmail() {
return customerEmail;
}
public void setCustomerEmail(String customerEmail) {
this.customerEmail = customerEmail;
}
public LocalDateTime getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDateTime orderDate) {
this.orderDate = orderDate;
}
public Status getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(Status orderStatus) {
this.orderStatus = orderStatus;
}
public List<OrderProduct> getProducts() {
return Collections.unmodifiableList(products);
}
public void addProduct(OrderProduct product) {
this.products.add(product);
}
public void addProducts(Collection<OrderProduct> products) {
this.products.addAll(products);
}
public void setProducts(Collection<OrderProduct> products) {
this.products.clear();
this.products.addAll(products);
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", customerEmail=" + customerEmail + ", orderDate=" + orderDate
+ ", orderStatus=" + orderStatus + "]";
}
@Override
public int hashCode() {
return Objects.hash(customerEmail, orderDate, orderId, orderStatus);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Order other = (Order) obj;
return Objects.equals(customerEmail, other.customerEmail) && Objects.equals(orderDate, other.orderDate)
&& Objects.equals(orderId, other.orderId) && orderStatus == other.orderStatus;
}
public enum Status {
NEW,
CONFIRMED,
PAID,
SHIPPED,
CLOSED,
RETURNED,
;
}
}
package sklep.model;
import java.math.BigDecimal;
import java.util.Objects;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlTransient;
public class OrderProduct {
// Ponieważ te obiekty w XML są zawsze umieszczone wewnątrz konkretnego zamówienia,
// to nie ma sensu umieszczać informacji o id tego zamówienia.
// Uwaga - tak można sobie upraszczać, gdy mówimy o odczycie danych (komunikacja jendokierunkowa).
@XmlTransient
// @XmlAttribute(name="order-id")
private Integer orderId;
@XmlAttribute(name="product-id")
private Integer productId;
private int quantity;
@XmlElement(name="price")
private BigDecimal actualPrice;
public OrderProduct() {
}
public OrderProduct(Integer orderId, Integer productId, int quantity, BigDecimal actualPrice) {
this.orderId = orderId;
this.productId = productId;
this.quantity = quantity;
this.actualPrice = actualPrice;
}
public static OrderProduct of(Integer orderId, Product product, int quantity) {
return new OrderProduct(orderId, product.getProductId(), quantity, product.getPrice());
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public BigDecimal getActualPrice() {
return actualPrice;
}
public void setActualPrice(BigDecimal actualPrice) {
this.actualPrice = actualPrice;
}
@Override
public String toString() {
return "OrderProduct [orderId=" + orderId + ", productId=" + productId + ", quantity=" + quantity
+ ", actualPrice=" + actualPrice+ "]";
}
@Override
public int hashCode() {
return Objects.hash(orderId, productId, quantity, actualPrice);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
OrderProduct other = (OrderProduct) obj;
return Objects.equals(orderId, other.orderId) && Objects.equals(productId, other.productId)
&& quantity == other.quantity
&& Objects.equals(actualPrice, other.actualPrice);
}
}
package sklep.model;
import java.math.BigDecimal;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlValue;
@XmlRootElement
public class Price {
@XmlValue
private BigDecimal value;
public Price() {
this.value = BigDecimal.ZERO;
}
public Price(BigDecimal value) {
this.value = value;
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
@Override
public String toString() {
return value.toString();
}
}
package sklep.model;
import java.math.BigDecimal;
import java.util.Objects;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Product {
@XmlAttribute(name="id")
private Integer productId;
@XmlElement(name="product-name")
private String productName;
private BigDecimal price;
private BigDecimal vat;
private String description;
public Product() {
}
public Product(Integer productId, String productName, BigDecimal price, BigDecimal vat, String description) {
this.productId = productId;
this.productName = productName;
this.price = price;
this.vat = vat;
this.description = description;
}
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public BigDecimal getVat() {
return vat;
}
public void setVat(BigDecimal vat) {
this.vat = vat;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public int hashCode() {
return Objects.hash(description, price, vat, productId, productName);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Product other = (Product) obj;
return Objects.equals(productId, other.productId) && Objects.equals(productName, other.productName)
&& Objects.equals(price, other.price)
&& Objects.equals(vat, other.vat)
&& Objects.equals(description, other.description);
}
@Override
public String toString() {
return "Product [productId=" + productId + ", productName=" + productName + ", price=" + price + ", vat=" + vat
+ ", description=" + description + "]";
}
public String toHtml() {
return String.format("<div class='product'>"
+ "<h2>%s</h2>"
+ "<p>(nr %d)</p>"
+ "<p>Cena: <strong>%,.2f PLN</strong></p>"
+ "<p>%s</p>"
+ "</div>",
getProductName(),
getProductId(),
getPrice(),
getDescription());
}
}
package sklep.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="products")
public class ProductList {
@XmlElement(name="product")
private final List<Product> products = new ArrayList<>();
public ProductList() {
// zostawia pustą listę
}
public ProductList(Collection<Product> products) {
this.products.addAll(products);
}
public List<Product> getProducts() {
return Collections.unmodifiableList(this.products);
}
public void setProducts(Collection<Product> products) {
this.products.clear();
this.products.addAll(products);
}
@Override
public String toString() {
return this.products.toString();
}
}
@XmlAccessorType(XmlAccessType.FIELD)
package sklep.model;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-rest</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-baza</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package rest;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
/* Ten projekt jest zrobiony w technologii JAX-RS - implementacja usług RESTowych w ramach Java EE.
*
* Ta klasa pełni rolę "aktywatora" tej technologii na serwerze. Gdy serwer (WildFly / Glassfish / WebLogic)
* zauważy w projekcie taką klasę, to wie, że ma skonfigurować usługę REST pod podanym adresem.
* Adres / (albo pusty String) oznacza, że cały projekt jest "jedną wielką aplikacją RESTową",
* ale można też podać jakiś podkatalog na serwerze.
*
* Domyślnie w skład aplikacji RESTowej będą wchodzić wszystkie klasy w projekcie, które mają adnotację @Path (+ rozszerzenia @Provider i @Interceptor, ale to inny temat...)
* To zachowanie można zmienić nadpisując metody getClasses i getSingletons - pokażę to w innym projekcie...
*/
@ApplicationPath("/")
public class AplikacjaRestowa extends Application {
}
package rest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import sklep.db.DBSettings;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
public class PhotoUtil {
private static final String EXT = ".jpg";
public static File getFile(int productId) throws DBException, RecordNotFound {
Path path = getPath(productId);
File file = path.toFile();
if(file.exists()) {
return file;
} else {
throw new RecordNotFound("Cannot read photo for product id = " + productId);
}
}
public static byte[] readBytes(int productId) throws DBException, RecordNotFound {
Path path = getPath(productId);
try {
return Files.readAllBytes(path);
} catch (IOException e) {
// System.err.println(e);
throw new RecordNotFound("Cannot read photo for product id = " + productId);
}
}
public static void writeStream(int productId, InputStream inputStream) {
try {
Path path = getPath(productId);
Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
// wypisujemy błąd, ale metoda kończy się normalnie
e.printStackTrace();
}
}
public static void writeBytes(int productId, byte[] bytes) {
try {
Path path = getPath(productId);
Files.write(path, bytes, StandardOpenOption.CREATE);
} catch (Exception e) {
// wypisujemy błąd, ale metoda kończy się normalnie
e.printStackTrace();
}
}
private static Path getPath(int productId) throws DBException {
String dir = DBSettings.load().getProperty("photo_dir");
String fileName = productId + EXT;
return Paths.get(dir, fileName);
}
}
package rest;
import java.net.URI;
import java.util.List;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import sklep.db.CustomerDAO;
import sklep.db.DBConnection;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Customer;
@Path("/customers")
@Produces(MediaType.APPLICATION_JSON)
public class RCustomers {
@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();
}
}
@POST
public Response save(final Customer customer) throws DBException {
try(DBConnection db = DBConnection.open()) {
CustomerDAO customerDAO = db.customerDAO();
customerDAO.save(customer);
db.commit();
URI uri = UriBuilder
.fromResource(RCustomers.class)
.path(String.valueOf(customer.getEmail()))
.build();
return Response.created(uri).build();
}
}
@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();
}
}
package rest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/hello")
public class RHello {
@GET
public String hello() {
return "Hello <b>REST</b>";
}
}
package rest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
@Path("/products.html")
public class RHtmlZaPomocaWritera {
// Ta klasa służy do przetestowania własnego MessageBodyWritera,
// który potrafi zamieniać pojedyncze produkty na HTML.
@GET
@Produces("text/html")
@Path("{id}")
public Product readOne(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId);
}
}
}
package rest;
import java.net.URI;
import java.util.List;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.UriBuilder;
import sklep.db.DBConnection;
import sklep.db.OrderDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Order;
@Path("/orders")
@Produces(MediaType.APPLICATION_JSON)
public class ROrders {
@GET
public List<Order> listAll() throws DBException {
try(DBConnection db = DBConnection.open()) {
OrderDAO orderDAO = db.orderDAO();
return orderDAO.readAll();
}
}
@GET
@Path("/{id:[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]+}/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(RCustomers.class)
.path("/{email}")
.build(order.getCustomerEmail());
return Response.seeOther(customerURI).build();
}
}
}
package rest;
import java.math.BigDecimal;
import java.net.URI;
import java.util.List;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
import sklep.model.ProductList;
@Path("/products")
public class RProducts {
@GET
@Produces({"application/xml", "text/plain"})
public ProductList readAll() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return new ProductList(productDAO.readAll());
}
}
// Żeby w JSON nie było dodatkowego poziomu w strukturze, zwracam bezpośrednio listę rekordów:
@GET
@Produces({"application/json"})
public List<Product> readAllJSON() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return 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 readAllHTML() throws DBException {
List<Product> products = readAll().getProducts();
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();
}
@GET
@Path("/{id}")
@Produces({"application/json", "application/xml", "text/plain"})
public Product readOne(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId);
}
}
@GET
@Produces("text/html;charset=UTF-8")
@Path("/{id}")
public String readOneHTML(@PathParam("id") int productId) throws DBException, RecordNotFound {
Product product = readOne(productId);
return "<!DOCTYPE html>\n<html><body>" + product.toHtml() + "</body></html>";
}
@POST
@Consumes({"application/json", "application/xml"})
// W metodach typu POST i PUT powinien znajdować się dokładnie jeden parametr nieozanczony żadną adnotacją.
// Do tego parametru zostanie przekazana wartość utworzona na podstawie treści zapytania (content / body / entity).
// W adnotacji @Consumes określamy format, w jakim te dane mają być przysłane.
public Response saveProduct(Product product) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.save(product);
db.commit();
// Zwracamy informację, pod jakim adresem został zapisany rekord.
URI uri = UriBuilder
.fromResource(RProducts.class)
.path(String.valueOf(product.getProductId()))
.build();
return Response.created(uri).build();
}
}
// Ta metoda zwraca wartość wybranego pola w rekordzie.
// W praktyce rzadko kiedy twozy się takie metody, ale gdybyśmy wiedzieli, że klient akurat takiej rzeczy może potrzebować,
// to można taką dodatkową meotdę stworzyć.
// Właściwą strukturą adresu będzie wtedy np. products/3/price
@GET
@Path("/{id}/price")
@Produces({"application/json", "text/plain"})
public BigDecimal getPrice(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId).getPrice();
}
}
// Metoda PUT służy w HTTP do zapisywania danych DOKŁADNIE POD PODANYM ADRESEM
@PUT
@Path("/{id}/price")
@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.update(product);
db.commit();
}
}
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") int productId) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.delete(productId);
db.commit();
}
}
@GET
@Path("/{id}/photo")
@Produces("image/jpeg")
public byte[] getPhoto(@PathParam("id") int productId) throws DBException, RecordNotFound {
return PhotoUtil.readBytes(productId);
}
}
package rest;
import java.math.BigDecimal;
import java.util.List;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
@Path("/products.json")
@Produces("application/json")
@Consumes("application/json")
// Adnotacje @Produces / @Consumes na poziomie klasy mówią co domyślnie produkują i konsumują metody.
// - metoda może nadpisać te ustawienia (np. metody dot. zdjęć)
// - adnotacje dotyczą tylko tych metod, które faktycznie coś pobierają lub zwracają
// Np. metoda, która niczego nie konsumuje, nie zwróci uwagi na te adnotacje z poziomu klasy.
// Metoda typu void nie zwraca uwagi na adnotację Produces
public class RProductsJSON {
@GET
public List<Product> readAll() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.readAll();
}
}
@GET
@Path("/{id}")
public Product readOne(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId);
}
}
@POST
// W metodach typu POST i PUT powinien znajdować się dokładnie jeden parametr nieozanczony żadną adnotacją.
// Do tego parametru zostanie przekazana wartość utworzona na podstawie treści zapytania (content / body / entity).
// W adnotacji @Consumes określamy format, w jakim te dane mają być przysłane.
public InformacjaZwrotna saveProduct(Product product) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.save(product);
db.commit();
return new InformacjaZwrotna(product.getProductId());
}
}
// klasa definiująca, co jest zwracane w wyniku POST po zapisaniu produktu
public static class InformacjaZwrotna {
private int noweId;
public InformacjaZwrotna() {
}
public InformacjaZwrotna(int noweId) {
this.noweId = noweId;
}
public int getNoweId() {
return noweId;
}
public void setNoweId(int noweId) {
this.noweId = noweId;
}
}
// Ta metoda zwraca wartość wybranego pola w rekordzie.
// W praktyce rzadko kiedy twozy się takie metody, ale gdybyśmy wiedzieli, że klient akurat takiej rzeczy może potrzebować,
// to można taką dodatkową meotdę stworzyć.
// Właściwą strukturą adresu będzie wtedy np. products/3/price
@GET
@Path("/{id}/price")
public BigDecimal getPrice(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId).getPrice();
}
}
// Metoda PUT służy w HTTP do zapisywania danych DOKŁADNIE POD PODANYM ADRESEM
@PUT
@Path("/{id}/price")
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.update(product);
db.commit();
}
}
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") int productId) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.delete(productId);
db.commit();
}
}
@GET
@Path("/{id}/photo")
@Produces("image/jpeg")
public byte[] getPhoto(@PathParam("id") int productId) throws DBException, RecordNotFound {
return PhotoUtil.readBytes(productId);
}
}
package rest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
import sklep.model.ProductList;
@Path("/products.pdf")
@Produces("application/pdf")
public class RProductsPDF {
@GET
public ProductList readAll() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return new ProductList(productDAO.readAll());
}
}
@GET
@Path("/{id}")
public Product readOne(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId);
}
}
}
package rest;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Price;
import sklep.model.Product;
import sklep.model.ProductList;
@Path("/products.xml")
@Produces("application/xml")
@Consumes("application/xml")
public class RProductsXML {
@GET
public ProductList readAll() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return new ProductList(productDAO.readAll());
}
}
@GET
@Path("/{id}")
public Product readOne(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId);
}
}
@POST
public void saveProduct(Product product) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.save(product);
db.commit();
}
}
@GET
@Path("/{id}/price")
public Price getPrice(@PathParam("id") int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return new Price(productDAO.findById(productId).getPrice());
}
}
@PUT
@Path("/{id}/price")
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.update(product);
db.commit();
}
}
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") int productId) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.delete(productId);
db.commit();
}
}
@GET
@Path("/{id}/photo")
@Produces("image/jpeg")
public byte[] getPhoto(@PathParam("id") int productId) throws DBException, RecordNotFound {
return PhotoUtil.readBytes(productId);
}
}
package rest;
import java.time.LocalDateTime;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/dt")
public class RTime {
// Obiekt tej klasy jest tworzony za każdym razem do obsługi każdego pojedynczego zapytania.
private LocalDateTime dt = LocalDateTime.now();
{ System.out.println("Jest tworzony obiekt RTime , dt = " + dt); }
// działa pod adresem: /dt
@GET
public String getDateTime() {
return dt.toString();
}
// działa pod adresem: /dt/date
@GET
@Path("/date")
public String getDate() {
return dt.toLocalDate().toString();
}
@GET
@Path("/time")
public String getTime() {
return dt.toLocalTime().toString();
}
@GET
@Path("/time/second")
public int getSecond() {
return dt.getSecond();
}
}
package rest.ext;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.ext.MessageBodyWriter;
import jakarta.ws.rs.ext.Provider;
import sklep.model.Product;
@Provider
public class Product2HtmlWriter implements MessageBodyWriter<Product> {
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
System.out.println("Sprawdzam isWriteable " + type + " " + mediaType);
// Na podstawie informacji odczytanych z kodu zw. z metodą zwracającą wynik
// mamy odpowiedzieć na pytanie "czy ten writer sobie z tym poradzi".
return type == Product.class && mediaType.isCompatible(MediaType.TEXT_HTML_TYPE);
}
@Override
public void writeTo(Product product, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream out)
throws IOException, WebApplicationException {
System.out.println("Wykonuję writeTo " + type + " " + mediaType + " dla obiektu " + product);
// Dla konkretnego obiektu mamy go wypisać w podanym formacie przez przekazany nam OutputStream.
String html = "<!DOCTYPE html>\n<html><body>" + product.toHtml() + "</body></html>";
httpHeaders.add("Content-Type", "text/html;charset=utf-8");
out.write(html.getBytes("utf-8"));
}
}
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-soap_api</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>jakarta.xml.ws</groupId>
<artifactId>jakarta.xml.ws-api</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies>
</project>
package sklep.soap;
import java.math.BigDecimal;
import java.util.List;
import jakarta.jws.WebParam;
import jakarta.jws.WebResult;
import jakarta.jws.WebService;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Customer;
import sklep.model.Order;
import sklep.model.Product;
@WebService(name="Sklep", targetNamespace=Sklep.NAMESPACE)
public interface Sklep {
static final String NAMESPACE = "http://sklep.alx.pl/";
@WebResult(name="product")
public List<Product> readAll() throws DBException;
@WebResult(name="product")
public List<Product> readByPrice(@WebParam(name="min") BigDecimal min, @WebParam(name="max") BigDecimal max) throws DBException;
@WebResult(name="product")
public Product readOne(@WebParam(name="id") int productId) throws DBException, RecordNotFound;
public void saveProduct(@WebParam(name="product") Product product) throws DBException;
@WebResult(name="customer")
public Customer oneCustomer(@WebParam(name="email") String email) throws DBException, RecordNotFound;
@WebResult(name="order")
public Order oneOrder(@WebParam(name="id") int orderId) throws DBException, RecordNotFound;
@WebResult(name="bytes")
public byte[] getPhoto(@WebParam(name="id") int productId) throws DBException, RecordNotFound;
public void savePhoto(@WebParam(name="id") int productId, @WebParam(name="bytes") byte[] bytes);
}
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-soap_klient</artifactId>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-soap_api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>4.0.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
package sklep.klient;
import java.util.List;
import sklep.exn.DBException;
import sklep.model.Product;
import sklep.soap.Sklep;
public class Klient1_WszystkieProdukty {
public static void main(String[] args) {
System.out.println("Startujemy");
SklepService service = new SklepService();
Sklep sklep = service.getSklepPort();
System.out.println("Mam obiekt proxy: " + sklep);
try {
List<Product> produkty = sklep.readAll();
System.out.println("Odczytano " + produkty.size() + " produktów:");
for (Product product : produkty) {
System.out.println(product.getProductName() + " za cenę " + product.getPrice());
}
} catch (DBException e) {
e.printStackTrace();
}
System.out.println("Koniec");
}
}
package sklep.klient;
import java.util.Scanner;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
import sklep.soap.Sklep;
public class Klient2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
SklepService service = new SklepService();
Sklep sklep = service.getSklepPort();
while(true) {
System.out.println("Podaj ID produktu lub 0, aby zakończyć");
int id = scanner.nextInt();
if(id == 0) break;
try {
Product product = sklep.readOne(id);
System.out.println("Znaleziono produkt: " + product.getProductName() + " za cenę " + product.getPrice());
if(product.getDescription() != null) {
System.out.println("Opis: " + product.getDescription());
}
} catch (RecordNotFound e) {
System.out.println("Nie ma takiego rekordu");
} catch (DBException e) {
System.out.println("Inny błąd: " + e);
e.printStackTrace();
}
}
}
}
package sklep.klient;
import java.math.BigDecimal;
import java.util.Locale;
import java.util.Scanner;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
import sklep.soap.Sklep;
public class Klient3 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
scanner.useLocale(Locale.US);
SklepService service = new SklepService();
Sklep sklep = service.getSklepPort();
while(true) {
System.out.println("Podaj ID produktu lub 0, aby zakończyć");
int id = scanner.nextInt();
if(id == 0) break;
try {
Product product = sklep.readOne(id);
System.out.println("Znaleziono produkt: " + product.getProductName() + " za cenę " + product.getPrice());
if(product.getDescription() != null) {
System.out.println("Opis: " + product.getDescription());
}
boolean czyCosSieZmienilo = false;
System.out.println("Podaj zmianę ceny: ");
BigDecimal zmiana = scanner.nextBigDecimal();
if(zmiana.compareTo(BigDecimal.ZERO) != 0) {
product.setPrice(product.getPrice().add(zmiana));
czyCosSieZmienilo = true;
}
scanner.nextLine();
System.out.println("Podaj nową nazwę (enter, aby nie zmieniać): ");
String nazwa = scanner.nextLine();
if(!nazwa.isEmpty()) {
product.setProductName(nazwa);
czyCosSieZmienilo = true;
}
System.out.println("Podaj nowy opis (enter, aby nie zmieniać): ");
String opis = scanner.nextLine();
if(!opis.isEmpty()) {
product.setDescription(opis);
czyCosSieZmienilo = true;
}
if(czyCosSieZmienilo) {
sklep.saveProduct(product);
System.out.println("Zapisano zmiany");
}
System.out.println();
} catch (RecordNotFound e) {
System.out.println("Nie ma takiego rekordu");
} catch (DBException e) {
System.out.println("Inny błąd: " + e);
e.printStackTrace();
}
}
}
}
package sklep.klient;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
import sklep.soap.Sklep;
public class OknoSoap {
private Sklep proxy;
private JFrame frame;
private JTextField txtTytul;
private JTextField txtMarka;
private JTextField txtCena;
private JSpinner spinner;
private JLabel lblFoto;
private Product biezacyProdukt;
private ImageIcon ikonaZeZdjeciem;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
OknoSoap window = new OknoSoap();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public OknoSoap() {
SklepService serwis = new SklepService();
proxy = serwis.getSklepPort();
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 841, 801);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
spinner = new JSpinner();
spinner.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
wyswietl();
}
});
spinner.setFont(new Font("Dialog", Font.BOLD, 22));
JLabel lblPodajIdOgoszenia = new JLabel("Podaj ID ogłoszenia");
lblPodajIdOgoszenia.setFont(new Font("Dialog", Font.PLAIN, 20));
JButton btnWywietl = new JButton("Wyświetl");
btnWywietl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
wyswietl();
}
});
btnWywietl.setFont(new Font("Dialog", Font.BOLD, 20));
JPanel panel = new JPanel();
lblFoto = new JLabel("FOTO");
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.TRAILING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(lblFoto, GroupLayout.DEFAULT_SIZE, 817, Short.MAX_VALUE)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(lblPodajIdOgoszenia)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(spinner, GroupLayout.PREFERRED_SIZE, 72, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED, 437, Short.MAX_VALUE)
.addComponent(btnWywietl))
.addComponent(panel, GroupLayout.DEFAULT_SIZE, 817, Short.MAX_VALUE))
.addContainerGap())
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
.addGroup(groupLayout.createSequentialGroup()
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
.addComponent(lblPodajIdOgoszenia)
.addComponent(spinner, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGap(20))
.addGroup(groupLayout.createSequentialGroup()
.addComponent(btnWywietl)
.addPreferredGap(ComponentPlacement.UNRELATED)))
.addComponent(panel, GroupLayout.PREFERRED_SIZE, 155, GroupLayout.PREFERRED_SIZE)
.addGap(18)
.addComponent(lblFoto, GroupLayout.DEFAULT_SIZE, 523, Short.MAX_VALUE)
.addContainerGap())
);
JLabel lblTytu = new JLabel("Nazwa");
lblTytu.setFont(new Font("Dialog", Font.PLAIN, 18));
txtTytul = new JTextField();
txtTytul.setFont(new Font("Dialog", Font.BOLD, 16));
txtTytul.setColumns(10);
JLabel lblMarka = new JLabel("Opis");
lblMarka.setFont(new Font("Dialog", Font.PLAIN, 18));
txtMarka = new JTextField();
txtMarka.setFont(new Font("Dialog", Font.BOLD, 16));
txtMarka.setColumns(10);
JLabel lblCena = new JLabel("Cena");
lblCena.setFont(new Font("Dialog", Font.PLAIN, 18));
txtCena = new JTextField();
txtCena.setFont(new Font("Dialog", Font.BOLD, 16));
txtCena.setColumns(10);
GroupLayout gl_panel = new GroupLayout(panel);
gl_panel.setHorizontalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panel.createSequentialGroup()
.addContainerGap()
.addGroup(gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panel.createSequentialGroup()
.addGroup(gl_panel.createParallelGroup(Alignment.TRAILING, false)
.addComponent(lblMarka, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lblTytu, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 152, Short.MAX_VALUE))
.addPreferredGap(ComponentPlacement.UNRELATED)
.addGroup(gl_panel.createParallelGroup(Alignment.LEADING)
.addComponent(txtMarka, GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE)
.addComponent(txtTytul, GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE)))
.addGroup(Alignment.TRAILING, gl_panel.createSequentialGroup()
.addComponent(lblCena)
.addGap(128)
.addComponent(txtCena, GroupLayout.DEFAULT_SIZE, 623, Short.MAX_VALUE)))
.addContainerGap())
);
gl_panel.setVerticalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panel.createSequentialGroup()
.addContainerGap()
.addGroup(gl_panel.createParallelGroup(Alignment.BASELINE)
.addComponent(lblTytu)
.addComponent(txtTytul, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addPreferredGap(ComponentPlacement.UNRELATED)
.addGroup(gl_panel.createParallelGroup(Alignment.BASELINE)
.addComponent(lblMarka)
.addComponent(txtMarka, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGap(18)
.addGroup(gl_panel.createParallelGroup(Alignment.BASELINE)
.addComponent(txtCena, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(lblCena))
.addContainerGap(44, Short.MAX_VALUE))
);
panel.setLayout(gl_panel);
frame.getContentPane().setLayout(groupLayout);
}
// jest wywoływane przez Swinga po kliknięciu guzika itp.
// ta metoda jest wykonywana w wątku EDT
protected void wyswietl() {
int idOgloszenia = (Integer)spinner.getValue();
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// to wykona się w oddzielnym wątku,
// nie zablokuj okna, ale tutaj nie powinniśmy korzystać z elementów okna
pobierzDane(idOgloszenia);
return null;
}
@Override
protected void done() {
// tu powinniśmy wpisać polecenia dotyczące okna, które mają być wykonane przez EDT po zakończeniu operacji
uaktualnijWidok();
}
};
worker.execute();
}
private void pobierzDane(int id) {
// ma być wykonane w tle
try {
ikonaZeZdjeciem = null;
biezacyProdukt = null;
biezacyProdukt = proxy.readOne(id);
try {
byte[] bajtyZeZdjeciem = proxy.getPhoto(id);
if(bajtyZeZdjeciem != null) {
ikonaZeZdjeciem = new ImageIcon(bajtyZeZdjeciem);
}
} catch (RecordNotFound e) {
// zdjecie zostaje nullem
}
} catch (DBException e) {
e.printStackTrace();
} catch (RecordNotFound e) {
}
}
private void uaktualnijWidok() {
// ma być wykonane przez okno (czyli wątek EDT)
if(biezacyProdukt != null) {
txtTytul.setText(biezacyProdukt.getProductName());
txtMarka.setText(biezacyProdukt.getDescription());
txtCena.setText(String.valueOf(biezacyProdukt.getPrice()));
} else {
txtTytul.setText("");
txtMarka.setText("");
txtCena.setText("");
}
lblFoto.setIcon(ikonaZeZdjeciem);
}
}
package sklep.klient;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import jakarta.xml.ws.Service;
import jakarta.xml.ws.WebEndpoint;
import jakarta.xml.ws.WebServiceClient;
import jakarta.xml.ws.WebServiceFeature;
import sklep.soap.Sklep;
@WebServiceClient(name="SklepService",
wsdlLocation=SklepService.ADRES_WSDL,
targetNamespace=Sklep.NAMESPACE)
public class SklepService extends Service {
final static String ADRES_WSDL = "http://localhost:8080/wielomodulowy-soap_serwer/SklepService?wsdl";
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName(Sklep.NAMESPACE, "SklepService");
public final static QName SklepPort = new QName(Sklep.NAMESPACE, "SklepPort");
static {
URL url = null;
try {
url = new URL(ADRES_WSDL);
} catch (MalformedURLException e) {
System.err.println("Can not initialize the default wsdl from " + ADRES_WSDL);
}
WSDL_LOCATION = url;
}
public SklepService(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public SklepService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SklepService() {
super(WSDL_LOCATION, SERVICE);
}
public SklepService(WebServiceFeature... features) {
super(WSDL_LOCATION, SERVICE, features);
}
public SklepService(URL wsdlLocation, WebServiceFeature... features) {
super(wsdlLocation, SERVICE, features);
}
public SklepService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
super(wsdlLocation, serviceName, features);
}
@WebEndpoint(name = "SklepPort")
public Sklep getSklepPort() {
return super.getPort(SklepPort, Sklep.class);
}
@WebEndpoint(name = "SklepPort")
public Sklep getSklepPort(WebServiceFeature... features) {
return super.getPort(SklepPort, Sklep.class, features);
}
}
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-soap_serwer</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-soap_api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-baza</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
package sklep.soap;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import sklep.db.DBSettings;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
public class PhotoUtil {
private static final String EXT = ".jpg";
public static File getFile(int productId) throws DBException, RecordNotFound {
Path path = getPath(productId);
File file = path.toFile();
if(file.exists()) {
return file;
} else {
throw new RecordNotFound("Cannot read photo for product id = " + productId);
}
}
public static byte[] readBytes(int productId) throws DBException, RecordNotFound {
Path path = getPath(productId);
try {
return Files.readAllBytes(path);
} catch (IOException e) {
// System.err.println(e);
throw new RecordNotFound("Cannot read photo for product id = " + productId);
}
}
public static void writeStream(int productId, InputStream inputStream) {
try {
Path path = getPath(productId);
Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
// wypisujemy błąd, ale metoda kończy się normalnie
e.printStackTrace();
}
}
public static void writeBytes(int productId, byte[] bytes) {
try {
Path path = getPath(productId);
Files.write(path, bytes, StandardOpenOption.CREATE);
} catch (Exception e) {
// wypisujemy błąd, ale metoda kończy się normalnie
e.printStackTrace();
}
}
private static Path getPath(int productId) throws DBException {
String dir = DBSettings.load().getProperty("photo_dir");
String fileName = productId + EXT;
return Paths.get(dir, fileName);
}
}
package sklep.soap;
import java.math.BigDecimal;
import java.util.List;
import jakarta.jws.WebService;
import jakarta.xml.ws.soap.MTOM;
import sklep.db.CustomerDAO;
import sklep.db.DBConnection;
import sklep.db.OrderDAO;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Customer;
import sklep.model.Order;
import sklep.model.Product;
@WebService(endpointInterface="sklep.soap.Sklep",
targetNamespace=Sklep.NAMESPACE,
serviceName="SklepService",
portName="SklepPort")
//@MTOM
public class SklepImpl implements Sklep {
public List<Product> readAll() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.readAll();
}
}
public List<Product> readByPrice(BigDecimal min, BigDecimal max) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findByPrice(min, max);
}
}
public Product readOne(int productId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.findById(productId);
}
}
public void saveProduct(Product product) throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.save(product);
db.commit();
}
}
public Customer oneCustomer(String email) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
CustomerDAO customerDAO = db.customerDAO();
return customerDAO.findByEmail(email);
}
}
public Order oneOrder(int orderId) throws DBException, RecordNotFound {
try(DBConnection db = DBConnection.open()) {
OrderDAO orderDAO = db.orderDAO();
return orderDAO.findById(orderId);
}
}
public byte[] getPhoto(int productId) throws DBException, RecordNotFound {
return PhotoUtil.readBytes(productId);
}
public void savePhoto(int productId, byte[] bytes) {
PhotoUtil.writeBytes(productId, bytes);
}
}
<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</groupId>
<artifactId>Wielomodulowy</artifactId>
<version>1.0</version>
</parent>
<artifactId>wielomodulowy-web</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>wielomodulowy-baza</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package sklep.basket;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.model.Product;
@WebServlet("/add_to_basket")
public class AddToBasket extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
int productId = Integer.parseInt(request.getParameter("productId"));
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
Product product = productDAO.findById(productId);
HttpSession sesja = request.getSession();
Basket basket = (Basket)sesja.getAttribute("basket");
// Zakładamy, że obiekt basket został dodany do sesji przez BasketListener
basket.addProduct(product);
}
} catch(Exception e) {
// ignorujemy błędy
}
// Przekierowanie - każemy przeglądarce wejść pod ten adres.
response.sendRedirect("products9.jsp");
}
}
package sklep.basket;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import sklep.model.Product;
public class Basket {
private final Map<Integer, ProductInBasket> elementy = new HashMap<>();
public synchronized void addProduct(Product product, int quantity) {
if(elementy.containsKey(product.getProductId())) {
// jeśli w słowniku jest już taki element, to tylko zwiększamy ilość
elementy.get(product.getProductId()).increaseQuantity(quantity);
} else {
// jeśli jeszcze nie ma, to tworzymy
elementy.put(product.getProductId(),
new ProductInBasket(product.getProductId(), product.getProductName(), product.getPrice(), quantity));
}
}
public synchronized void addProduct(Product product) {
// "domyślną ilością, o którą zwiększamy, jest 1"
addProduct(product, 1);
}
public synchronized void removeProduct(int productId) {
elementy.remove(productId);
}
public synchronized Collection<ProductInBasket> getElements() {
return Collections.unmodifiableCollection(elementy.values());
}
public synchronized BigDecimal getTotalValue() {
return getElements().stream()
.map(ProductInBasket::getValue)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@Override
public synchronized String toString() {
return "Koszyk o rozmiarze " + getElements().size()
+ " i wartości " + getTotalValue();
}
}
package sklep.basket;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
@WebListener
public class BasketListener implements HttpSessionListener, ServletContextListener {
public void sessionCreated(HttpSessionEvent se) {
HttpSession sesja = se.getSession();
sesja.setMaxInactiveInterval(30); // pół minuty i sesja wygasa
System.out.println("sessionCreated " + sesja.getId());
Basket basket = new Basket();
sesja.setAttribute("basket", basket);
}
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession sesja = se.getSession();
System.out.println("sessionDestroyed " + sesja.getId());
}
public void contextInitialized(ServletContextEvent sce) {
System.out.println("contextInitialized");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextDestroyed");
}
}
package sklep.basket;
import java.math.BigDecimal;
import java.util.Objects;
public class ProductInBasket {
private int productId;
private String productName;
private BigDecimal price;
private int quantity;
public ProductInBasket(int productId, String productName, BigDecimal price, int quantity) {
this.productId = productId;
this.productName = productName;
this.price = price;
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getProductId() {
return productId;
}
public String getProductName() {
return productName;
}
@Override
public String toString() {
return "ElementKoszyka [productId=" + productId + ", productName=" + productName + ", price=" + price
+ ", quantity=" + quantity + "]";
}
@Override
public int hashCode() {
return Objects.hash(price, productId, productName, quantity);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ProductInBasket other = (ProductInBasket) obj;
return Objects.equals(price, other.price) && productId == other.productId
&& Objects.equals(productName, other.productName) && quantity == other.quantity;
}
public BigDecimal getValue() {
return price.multiply(BigDecimal.valueOf(quantity));
}
public void increaseQuantity(int change) {
quantity += change;
}
}
package sklep.basket;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@WebServlet("/remove_from_basket")
public class RemoveFromBasket extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
int productId = Integer.parseInt(request.getParameter("productId"));
HttpSession sesja = request.getSession();
Basket basket = (Basket) sesja.getAttribute("basket");
basket.removeProduct(productId);
} catch (Exception e) {
// ignorujemy błędy
}
// Przekierowanie - każemy przeglądarce wejść pod ten adres.
response.sendRedirect("products9.jsp");
}
}
package sklep.web;
import java.io.IOException;
import java.math.BigDecimal;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
import sklep.model.Product;
@WebServlet("/edit")
public class EditProduct extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String parametrId = request.getParameter("productId");
if(parametrId != null) {
int productId = Integer.parseInt(parametrId);
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
Product product = productDAO.findById(productId);
// Gdy do obiektu request dodamy atrybut, to stanie się on dostępny dla kolejnych komponentów
// naszej aplikacji, które będą obsługiwać to zapytanie.
// W tym przypadku skrypt JSP może odwoływać się do obiektu product.
// Obiekt request jest też nośnikiem danych, podobnie jak sesja i servletContext.
// To działa jak Model w Spring MVC.
// Tylko jeśli znajdę produkt, tylko wtedy dodaję go do requestu i JSP wyświetli jego dane.
// Jeśli parametru productId nie było lub produktu nie znaleziono, to wyświetli się pusty formularz.
request.setAttribute("product", product);
} catch(DBException | RecordNotFound e) {
e.printStackTrace();
}
}
// Forward to "wewnętrzne przekierowanie" obsługi zapytania do innego komponentu aplikacji.
// Tutaj "wyświetlamy" formularz edycji produktu.
RequestDispatcher dispatcher = request.getRequestDispatcher("product_form.jsp");
if(dispatcher != null)
dispatcher.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// W tej wersji nie obsługujemy błędów - w razie błędu wyświetli się strona z wyjątkiem
// W przypadku braku ID zostanie utworzony nowy produkt, a w przypadku podania ID (gdy to była edycja istniejącego) - zostanie zastąpiony.
request.setCharacterEncoding("UTF-8");
String parametrId = request.getParameter("productId");
Integer productId = (parametrId == null || parametrId.isEmpty()) ? null : Integer.valueOf(parametrId);
String parametrPrice = request.getParameter("price");
BigDecimal price = new BigDecimal(parametrPrice);
String parametrVat = request.getParameter("vat");
BigDecimal vat = (parametrVat == null || parametrVat.isEmpty()) ? null : new BigDecimal(parametrVat);
String name = request.getParameter("productName");
String description = request.getParameter("description");
Product product = new Product(productId, name, price, vat, description);
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
productDAO.save(product);
db.commit();
// Gdy udało się zapisać, to przejdziemy z powrotem do listy.
// To jest przekierowanie przeglądarki do inny adres.
response.sendRedirect("products9.jsp");
} catch (DBException e) {
e.printStackTrace();
}
}
}
package sklep.web;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import sklep.exn.RecordNotFound;
@WebServlet("/photo")
public class Photo extends HttpServlet {
private static final long serialVersionUID = 1L;
/* Ten serwlet wczytuje z dysku plik ze zdjęciem o podanym numerze (z parametru productId).
* Aby odesłać odpowiedź "binarną" (a nie tekstową) używamy getOutputStream() zamiast getWriter().
* Aby przeglądarka wiedziała, że otrzymuje grafikę, ustawiamy content-type image/jpeg.
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String parametrId = request.getParameter("productId");
if(parametrId == null) {
return;
}
try {
int id = Integer.parseInt(parametrId);
byte[] bytes = PhotoUtil.readBytes(id);
response.setContentType("image/jpeg");
ServletOutputStream output = response.getOutputStream();
output.write(bytes);
output.close();
} catch (RecordNotFound e) {
response.setStatus(404);
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().println("Nie ma zdjęcia dla produktu o nr " + parametrId);
} catch (Exception e) {
response.setStatus(500);
e.printStackTrace();
}
}
}
package sklep.web;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
// Włączona obsługa zapytań multipart ("z załącznikami"). Maks rozmiar zapytania/pliku: 16M
@WebServlet("/photo_upload")
@MultipartConfig(maxRequestSize = 16 * 1024 * 1024)
public class PhotoUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String paramId = request.getParameter("productId");
if(paramId != null) {
int productId = Integer.parseInt(paramId);
Part part = request.getPart("plik");
if(part != null) {
// przysłano plik
// Tutaj nazwa pliku jest dla nas bez znaczenia, ale gdybyśmy potrzebowali, to w ten sposób:
// String nazwaPliku = part.getSubmittedFileName();
// Przypisujemy bajty ze strumienia do pliku w katalogu ze zdjęciami:
PhotoUtil.writeStream(productId, part.getInputStream());
}
}
} catch (Exception e) {
// wypisujemy błąd, ale metoda kończy się normalnie
e.printStackTrace();
}
response.sendRedirect("products9.jsp");
}
}
package sklep.web;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import sklep.db.DBSettings;
import sklep.exn.DBException;
import sklep.exn.RecordNotFound;
public class PhotoUtil {
private static final String EXT = ".jpg";
public static File getFile(int productId) throws DBException, RecordNotFound {
Path path = getPath(productId);
File file = path.toFile();
if(file.exists()) {
return file;
} else {
throw new RecordNotFound("Cannot read photo for product id = " + productId);
}
}
public static byte[] readBytes(int productId) throws DBException, RecordNotFound {
Path path = getPath(productId);
try {
return Files.readAllBytes(path);
} catch (IOException e) {
// System.err.println(e);
throw new RecordNotFound("Cannot read photo for product id = " + productId);
}
}
public static void writeStream(int productId, InputStream inputStream) {
try {
Path path = getPath(productId);
Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
// wypisujemy błąd, ale metoda kończy się normalnie
e.printStackTrace();
}
}
private static Path getPath(int productId) throws DBException {
String dir = DBSettings.load().getProperty("photo_dir");
String fileName = productId + EXT;
return Paths.get(dir, fileName);
}
}
package sklep.web;
import java.math.BigDecimal;
import java.util.List;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.model.Product;
/* Ta klasa jest po to, aby w skrypcie JSP w wygodny sposób odczytać sobie listę produktów z bazy danych. */
public class ProductBean {
private BigDecimal minPrice, maxPrice;
// Chociaż wewnętrznie zmienna jest typu BigDecimal, to gettery i settery napiszemy tak, jakby to były Stringi.
// Robimy to po to, aby w JSP zadziałało setProperty.
public String getMinPrice() {
return minPrice == null ? null : minPrice.toString();
}
public void setMinPrice(String minPrice) {
if(minPrice == null || minPrice.isEmpty()) {
this.minPrice = null;
} else {
this.minPrice = new BigDecimal(minPrice);
}
}
public String getMaxPrice() {
return maxPrice == null ? null : maxPrice.toString();
}
public void setMaxPrice(String maxPrice) {
if(maxPrice == null || maxPrice.isEmpty()) {
this.maxPrice = null;
} else {
this.maxPrice = new BigDecimal(maxPrice);
}
}
// Metoda wygląda jak getter, ale wewnętrznie czyta dane z bazy, a nie z własnej zmiennej.
public List<Product> getAllProducts() throws DBException {
try(DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
return productDAO.readAll();
}
}
// Metoda odczytuje produkty zgodnie z ustawionymi wcześniej kryteriami (w tym przykładzie są to ceny, ale może być więcej filtrów).
public List<Product> getFilteredProducts() throws DBException {
try(DBConnection db = DBConnection.open()) {
return db.productDAO().findByPrice(minPrice, maxPrice);
}
}
}
package sklep.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/products0")
public class Products0 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println("Zaraz odczytam produkty z bazy...");
final String url = "jdbc:postgresql://localhost/sklep";
final String sql = "SELECT * FROM products";
try(Connection c = DriverManager.getConnection(url , "kurs", "abc123");
Statement stmt = c.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while(rs.next()) {
out.printf("Produkt nr %s to jest %s za cenę %s\n",
rs.getInt("product_id"), rs.getString("product_name"), rs.getBigDecimal("price"));
}
} catch(SQLException e) {
out.println("Wielka bieda!");
e.printStackTrace(out);
}
}
}
package sklep.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.model.Product;
@WebServlet("/products1")
public class Products1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println("Zaraz odczytam produkty z bazy...");
try (DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
List<Product> products = productDAO.readAll();
for (Product product : products) {
out.println(product);
}
} catch (DBException e) {
out.println("Wielka bieda!");
e.printStackTrace(out);
}
}
}
package sklep.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import sklep.db.DBConnection;
import sklep.db.ProductDAO;
import sklep.exn.DBException;
import sklep.model.Product;
@WebServlet("/products2")
public class Products2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest requets, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println("""
<!DOCTYPE html>
<html>
<head>
<title>Lista produktów</title>
<link rel='stylesheet' type='text/css' href='styl.css'>
</head>
<body>
<h1>Produkty</h1>
""");
try (DBConnection db = DBConnection.open()) {
ProductDAO productDAO = db.productDAO();
List<Product> products = productDAO.readAll();
for (Product product : products) {
out.println(product.toHtml());
}
} catch (DBException e) {
out.println("Wielka bieda!");
out.print("<pre>");
e.printStackTrace(out);
out.print("</pre>");
}
out.println("</body></html>");
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sklep - spis treści</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Sklep Web</h1>
<h2>Lista produktów w różnych wersjach</h2>
<h3>Wersje niedoskonałe, nie do naśladowania.</h3>
<ul>
<li><a href="products0">wersja 0</a> - samodzielny prosty serwlet</li>
<li><a href="products1">wersja 1</a> - serwlet oparty o klasy DAO</li>
<li><a href="products2">wersja 2</a> - serwlet oparty o klasy DAO z HTMLem</li>
<li><a href="products3.jsp">wersja 3</a> - JSP ze skryptletami</li>
<li><a href="products4.jsp">wersja 4</a> - JSP z tagami SQL</li>
</ul>
<h3>Wersje przyzwoite ;-)</h3>
<ul>
<li><a href="products5.jsp">wersja 5</a> - JSP oparty o klasę bean</li>
<li><a href="products6.jsp">wersja 6</a> - wyszukiwanie wg ceny - bean</li>
<li><a href="products7.jsp">wersja 7</a> - fotki</li>
<li><a href="products8.jsp">wersja 8</a> - koszyk</li>
<li><a href="products9.jsp">wersja 9</a> - edycja produktów</li>
</ul>
<h3>Dodatkowe strony</h3>
<ul>
<li><a href="photo?productId=2">Foto</a> - przykładowe zdjęcie</li>
<li><a href="photo_upload.jsp?productId=2">Zmień zdjęcie</a> nr 2</li>
<li><a href="edit_product?productId=1">Edytuj produkt nr 1</a></li>
<li><a href="edit_product">Dodaj nowy produkt</a></li>
</ul>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Edycja zdjęcia</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Wgraj zdjęcie produktu</h1>
<div>Produkt nr <strong>${param.productId}</strong></div>
<div>Aktualne zdjęcie:<br/>
<img class="photo" src="photo?productId=${param.productId}" alt="Brak zdjęcia">
</div>
<%-- action powoduje, że zapytanie z formularza jest wysyłane pod podany adres, a nie bieżący.
Aby wysłać zawartość pliku (a nie tylko jego nazwę), należy ustawić enctype jak poniżej.
Sam plik to pole formularza typu file; oprócz niego mogą być inne zwykłe pola.
Odpowiednio trzeba to też obsłużyć w serwlecie - patrz klasa DoUploadPhoto.
--%>
<form id="photo-form" method="post" action="photo_upload" enctype="multipart/form-data">
<input type="hidden" name="productId" value="${param.productId}">
<label for="plik">Wybierz plik ze zdjęciem</label>
<input id="plik" type="file" name="plik" accept="image/jpeg">
<br>
<button>Wyślij</button>
</form>
<p>[<a href="products9.jsp">powrót do listy produktów</a>]</p>
<p>[<a href="index.html">powrót do spisu treści</a>]</p>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Edycja danych produktu</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Edycja produktu</h1>
<form id="product-form" method="post">
<table class="form">
<tr>
<td><label for="productId">Numer:</label></td>
<td><input name="productId" placeholder="brak" type="number" readonly="readonly" value="${product.productId}"/></td>
</tr>
<tr>
<td><label for="productName">Nazwa towaru:</label></td>
<td><input name="productName" placeholder="nazwa..." type="text" value="${product.productName}"/>
</td>
</tr>
<tr>
<td><label for="price">Cena:</label></td>
<td><input name="price" placeholder="12.90" title="tu wpisz cenę" type="number" step="0.01" value="${product.price}"/>
</td>
</tr>
<tr>
<td><label for="vat">Stawka VAT:</label></td>
<td><input name="vat" placeholder="0.23" title="tu wpisz vat" type="number" step="0.01" value="${product.vat}"/>
</td>
</tr>
<tr>
<td><label for="description">Opis:</label></td>
<td><textarea name="description" rows="10" cols="120">${product.description}</textarea></td>
</tr>
<tr>
<td><button>Zapisz</button></td>
</tr>
</table>
</form>
<div class="action"><a href="products9.jsp">powrót do listy produktów</a></div>
<div class="action"><a href="index.html">powrót do spisu treści</a></div>
</body>
</html>
<%@page import="sklep.model.Product"%>
<%@page import="java.util.List"%>
<%@page import="sklep.db.ProductDAO"%>
<%@page import="sklep.db.DBConnection"%>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 3</title>
</head>
<body>
<h1>Lista produktów - wersja 3 JSP</h1>
<p>W tej wersji wewnątrz skryptu JSP umieścimy fragmenty Javy, tzw. scriptlets.
To jest pierwsza techniczna możliwość, którą oferował standard JSP.</p>
<p>Uwaga - ta wersja nadal jest nieporządna i <strong>nie jest</strong> wzorem do naśladowania.
Mieszanie kodu HTML z Javą w taki sposób, szczególnie jak zrobiliśmy z pętlą pod koniec, jest w bardzo złym stylu.
</p>
<p>[<a href="index.html">powrót do spisu treści</a>]</p>
<%-- Poniżej skryptlet, który otwiera połączenie z bazą danych: --%>
<%
DBConnection db = DBConnection.open();
ProductDAO dao = db.productDAO();
%>
<p>Pobieranie danych...</p>
<%
List<Product> products = dao.readAll();
%>
<p>Pobrano <%= products.size() %> produktów. </p>
<h3>Wszystkie produkty</h3>
<ul>
<% for(Product product : products) { %>
<li><%= product.getProductName() %> za <%= product.getPrice() %></li>
<% } %>
</ul>
<% db.close(); %>
<p>[<a href="index.html">powrót do spisu treści</a>]</p>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<%@taglib prefix="sql" uri="jakarta.tags.sql"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 4</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Lista produktów - wersja 4 JSP</h1>
<p>W tej wersji korzystamy ze standardowej biblioteki tagów (JSTL), a dokładnie z jej fragmentu obsługującego SQL.</p>
<p>Bezpośrednio w JSP wykonamy zapytanie w bazie danych - to też jeszcze nie będzie najładniejszy styl...</p>
<%-- W tej wersji za pomocą dedykowanych tagów JSP zadamy zapytanie SQL.
Ta wersja W OGÓLE nie używa klas stworzonych przez nas w projekcie; jest samowystarczalna.
--%>
<%-- "taglibs" - biblioteki tagów, zaimplementowane w Javie, a w JSP używa się ich za pomocą składni "tagowej" (dokładnie składni XML) --%>
<sql:setDataSource var="baza" driver="org.postgresql.Driver"
url="jdbc:postgresql://localhost/sklep"
user="kurs" password="abc123"/>
<sql:query dataSource="${baza}" scope="page" var="result">
SELECT * FROM products ORDER BY product_id
</sql:query>
<%-- .product_name .price itp - to są nazwy kolumn w tabeli SQL --%>
<c:forEach var="row" items="${result.rows}">
<div class="product">
<h3>${row.product_name}</h3>
<div class="price">${row.price}</div>
<p>${row.description}</p>
</div>
</c:forEach>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 5</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Lista produktów - wersja 5</h1>
<jsp:useBean id="productBean" class="sklep.web.ProductBean"/>
<c:forEach var="product" items="${productBean.allProducts}">
<div class="product">
<h3>${product.productName}</h3>
<div class="price">Cena: ${product.price}</div>
<div class="price">VAT ${product.vat * 100}%</div>
<c:if test="${not empty(product.description)}">
<p class="description">${product.description}</p>
</c:if>
</div>
</c:forEach>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 6</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Lista produktów - wersja 6</h1>
<form id="wyszukiwarka" method="get">
<h2>Filtr cen</h2>
<table class="formularz">
<tr><td><label for="min_price">Cena minimalna:</label></td>
<td><input id="min_price" name="min_price" type="number" value="${param.min_price}"></td></tr>
<tr><td><label for="max_price">Cena maksymalna:</label></td>
<td><input id="max_price" name="max_price" type="number" value="${param.max_price}"></td></tr>
<tr><td><button>Filtruj</button></td></tr>
</table>
</form>
<jsp:useBean id="productBean" class="sklep.web.ProductBean"/>
<jsp:setProperty name="productBean" property="minPrice" param="min_price"/>
<jsp:setProperty name="productBean" property="maxPrice" param="max_price"/>
<c:forEach var="product" items="${productBean.filteredProducts}">
<div class="product">
<h3>${product.productName}</h3>
<div class="price">Cena: ${product.price}</div>
<div class="price">VAT ${product.vat * 100}%</div>
<c:if test="${not empty(product.description)}">
<p class="description">${product.description}</p>
</c:if>
</div>
</c:forEach>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 7</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Lista produktów - wersja 7</h1>
<form id="wyszukiwarka" method="get">
<h2>Filtr cen</h2>
<table class="formularz">
<tr><td><label for="min_price">Cena minimalna:</label></td>
<td><input id="min_price" name="min_price" type="number" value="${param.min_price}"></td></tr>
<tr><td><label for="max_price">Cena maksymalna:</label></td>
<td><input id="max_price" name="max_price" type="number" value="${param.max_price}"></td></tr>
<tr><td><button>Filtruj</button></td></tr>
</table>
</form>
<jsp:useBean id="productBean" class="sklep.web.ProductBean"/>
<jsp:setProperty name="productBean" property="minPrice" param="min_price"/>
<jsp:setProperty name="productBean" property="maxPrice" param="max_price"/>
<c:forEach var="product" items="${productBean.filteredProducts}">
<div class="product">
<img class="photo" src="photo?productId=${product.productId}" alt=""/>
<h3>${product.productName}</h3>
<div class="price">Cena: ${product.price}</div>
<div class="price">VAT ${product.vat * 100}%</div>
<c:if test="${not empty(product.description)}">
<p class="description">${product.description}</p>
</c:if>
</div>
</c:forEach>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 8</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Lista produktów - wersja 8</h1>
<div class="koszyk">
<h4>Koszyk</h4>
<ul>
<%-- Zauważmy, że dla obiektu koszyk nie wykonujemy już useBean.
Po prostu zakładamy, że jest obecny (w sesji). Gdyby go nie było, to pętla się nie wykona. --%>
<c:forEach var="elm" items="${basket.elements}">
<li>${elm.productName} (${elm.quantity}) za <b>${elm.value}</b></li>
</c:forEach>
</ul>
<p class="total">Do zapłaty: ${basket.totalValue}</p>
</div>
<form id="wyszukiwarka" method="get">
<h2>Filtr cen</h2>
<table class="formularz">
<tr><td><label for="min_price">Cena minimalna:</label></td>
<td><input id="min_price" name="min_price" type="number" value="${param.min_price}"></td></tr>
<tr><td><label for="max_price">Cena maksymalna:</label></td>
<td><input id="max_price" name="max_price" type="number" value="${param.max_price}"></td></tr>
<tr><td><button>Filtruj</button></td></tr>
</table>
</form>
<jsp:useBean id="productBean" class="sklep.web.ProductBean"/>
<jsp:setProperty name="productBean" property="minPrice" param="min_price"/>
<jsp:setProperty name="productBean" property="maxPrice" param="max_price"/>
<c:forEach var="product" items="${productBean.filteredProducts}">
<div class="product">
<img class="photo" src="photo?productId=${product.productId}" alt=""/>
<h3>${product.productName}</h3>
<div class="price">Cena: ${product.price}</div>
<div class="price">VAT ${product.vat * 100}%</div>
<c:if test="${not empty(product.description)}">
<p class="description">${product.description}</p>
</c:if>
<div class="action"><a href="add_to_basket?productId=${product.productId}">dodaj do koszyka</a></div>
</div>
</c:forEach>
</body>
</html>
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lista produktów 9</title>
<link rel="stylesheet" type="text/css" href="styl.css">
</head>
<body>
<h1>Lista produktów - wersja 9</h1>
<div class="koszyk">
<h4>Koszyk</h4>
<ul>
<%-- Zauważmy, że dla obiektu koszyk nie wykonujemy już useBean.
Po prostu zakładamy, że jest obecny (w sesji). Gdyby go nie było, to pętla się nie wykona. --%>
<c:forEach var="elm" items="${basket.elements}">
<li>${elm.productName} (${elm.quantity}) za <b>${elm.value}</b> <a href="remove_from_basket?productId=${elm.productId}">(–)</a></li>
</c:forEach>
</ul>
<p class="total">Do zapłaty: ${basket.totalValue}</p>
</div>
<form id="wyszukiwarka" method="get">
<h2>Filtr cen</h2>
<table class="formularz">
<tr><td><label for="min_price">Cena minimalna:</label></td>
<td><input id="min_price" name="min_price" type="number" value="${param.min_price}"></td></tr>
<tr><td><label for="max_price">Cena maksymalna:</label></td>
<td><input id="max_price" name="max_price" type="number" value="${param.max_price}"></td></tr>
<tr><td><button>Filtruj</button></td></tr>
</table>
</form>
<jsp:useBean id="productBean" class="sklep.web.ProductBean"/>
<jsp:setProperty name="productBean" property="minPrice" param="min_price"/>
<jsp:setProperty name="productBean" property="maxPrice" param="max_price"/>
<c:forEach var="product" items="${productBean.filteredProducts}">
<div class="product">
<img class="photo" src="photo?productId=${product.productId}" alt=""/>
<h3>${product.productName}</h3>
<div class="price">Cena: ${product.price}</div>
<div class="price">VAT ${product.vat * 100}%</div>
<c:if test="${not empty(product.description)}">
<p class="description">${product.description}</p>
</c:if>
<div class="action"><a href="add_to_basket?productId=${product.productId}">dodaj do koszyka</a></div>
<div class="action"><a href="edit?productId=${product.productId}">edytuj</a></div>
<div class="action"><a href="photo_upload.jsp?productId=${product.productId}">zmień zdjęcie</a></div>
</div>
</c:forEach>
<div class="action"><a href="edit">Dodaj nowy produkt</a></div>
</body>
</html>
body {
background-color: #FFFFDD;
font-family: 'Arial', sans-serif;
}
/* komentarz w CSS */
h4 {
text-align: center;
}
h2, h3, h4 {
margin-top: 0;
}
.product {
border: solid 2px blue;
margin: 1em auto 1em 50px;
padding: 1em;
background-color: white;
width: 800px;
min-height: 230px;
clear: right;
}
.koszyk {
position: fixed;
right: 0;
top: 0;
width: 300px;
height: 400px;
background-color: white;
border: outset 3px green;
}
#wyszukiwarka {
background-color: #AAEEFF;
width: 800px;
border: 2px black solid;
margin: 1em 400px 1em 50px;
padding: 1em;
}
.error {
background-color: #FFFFFF;
border: 6px double red;
margin: 20px;
padding: 10px;
color: red;
}
.photo {
display: block;
float: right;
max-width: 300px;
max-height: 200px;
margin: 5px;
}
.description {
font-size: smaller;
font-style: italic;
}
div.action {
font-size: smaller;
font-family: 'Arial', sans-serif;
font-weight: bold;
background-color: #DDDDDD;
border: 2px #444466 outset;
padding: 6px;
margin: 4px auto 4px 4px;
max-width: 200px;
}
.action:hover {
background-color: #EEEEEE;
border: 2px #4455CC outset;
}
.action:active {
background-color: #EEEEEE;
border: 2px #CC4455 inset;
}
.action a {
display: inline-block;
color: inherit;
text-decoration: none;
width: 100%;
}
.action a:hover {
color: #0000CC;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment