Commit 6b786cce by Patryk Czarnik

Obsługa XML w serwisie RestSpring

parent 535824e8
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
...@@ -2,6 +2,8 @@ package sklep.model; ...@@ -2,6 +2,8 @@ package sklep.model;
import java.io.Serializable; import java.io.Serializable;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlRootElement;
import java.math.BigDecimal; import java.math.BigDecimal;
...@@ -12,12 +14,14 @@ import java.math.BigDecimal; ...@@ -12,12 +14,14 @@ import java.math.BigDecimal;
@Entity @Entity
@Table(name="products") @Table(name="products")
@NamedQuery(name="Product.findAll", query="SELECT p FROM Product p") @NamedQuery(name="Product.findAll", query="SELECT p FROM Product p")
@XmlRootElement
public class Product implements Serializable { public class Product implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Id @Id
@GeneratedValue(strategy=GenerationType.IDENTITY) @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="product_id", insertable=false, updatable=false) @Column(name="product_id", insertable=false, updatable=false)
@XmlAttribute(name="id")
private Integer productId; private Integer productId;
private String description; private String description;
......
@XmlAccessorType(XmlAccessType.FIELD)
package sklep.model;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlAccessType;
...@@ -27,22 +27,21 @@ public class ProductEndpoint { ...@@ -27,22 +27,21 @@ public class ProductEndpoint {
this.productRepository = productRepository; this.productRepository = productRepository;
} }
@GetMapping @GetMapping(produces={"application/json", "application/xml"})
public List<Product> getAllProducts() { public List<Product> getAllProducts() {
return productRepository.findAll(); return productRepository.findAll();
} }
@GetMapping("/{id}") @GetMapping(path="/{id}", produces={"application/json", "application/xml"})
public Product getOneProduct(@PathVariable("id") Integer id) { public Product getOneProduct(@PathVariable("id") Integer id) {
return productRepository return productRepository
.findById(id) .findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
} }
// Ta metoda pokazana tylko po to, aby wytłumaczyć, że struktura adresów powinna odpowiadać logicznej strukturze danych. // Ta metoda pokazana tylko po to, aby wytłumaczyć, że struktura adresów powinna odpowiadać logicznej strukturze danych.
// W prawdziwej aplikacji raczej nie dochodzi się do poziomu pojedynczych pól. Teoretycznie można. // W prawdziwej aplikacji raczej nie dochodzi się do poziomu pojedynczych pól. Teoretycznie można.
@GetMapping(path="/{id}/price", produces="text/plain") @GetMapping(path="/{id}/price", produces="application/json")
public BigDecimal getPrice(@PathVariable Integer id) { public BigDecimal getPrice(@PathVariable Integer id) {
return getOneProduct(id).getPrice(); return getOneProduct(id).getPrice();
} }
...@@ -79,7 +78,8 @@ public class ProductEndpoint { ...@@ -79,7 +78,8 @@ public class ProductEndpoint {
* konwencja, że aby dodać nowy rekord do katalogu, wysyła się POST z danymi * konwencja, że aby dodać nowy rekord do katalogu, wysyła się POST z danymi
* tego rekordu pod ogólny adres całego katalogu. * tego rekordu pod ogólny adres całego katalogu.
*/ */
@PostMapping @PostMapping(produces={"application/json", "application/xml"},
consumes={"application/json", "application/xml"})
public Product insert(@RequestBody Product product) { public Product insert(@RequestBody Product product) {
/* Operacja save (a wewnętrznie persist z Hibernate) spowoduje ustawienie nowego ID w obiekcie. /* Operacja save (a wewnętrznie persist z Hibernate) spowoduje ustawienie nowego ID w obiekcie.
* Warto taką informację przekazać klientowi. Można: * Warto taką informację przekazać klientowi. Można:
......
package sklep.rest;
import java.math.BigDecimal;
import java.util.List;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import sklep.model.Product;
import sklep.repository.ProductRepository;
@RestController
@RequestMapping("/products.json")
public class ProductEndpointJson {
private ProductRepository productRepository;
public ProductEndpointJson(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@GetMapping
public List<Product> getAllProducts() {
return productRepository.findAll();
}
@GetMapping("/{id}")
public Product getOneProduct(@PathVariable("id") Integer id) {
return productRepository
.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
@GetMapping(path="/{id}/price", produces="text/plain")
public BigDecimal getPrice(@PathVariable Integer id) {
return getOneProduct(id).getPrice();
}
@PutMapping("/{id}/price")
public void setPrice(@PathVariable Integer id, @RequestBody BigDecimal newPrice) {
Product product = productRepository.findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
product.setPrice(newPrice);
productRepository.save(product);
}
@PostMapping
public Product insert(@RequestBody Product product) {
/* Operacja save (a wewnętrznie persist z Hibernate) spowoduje ustawienie nowego ID w obiekcie.
* Warto taką informację przekazać klientowi. Można:
* 1) odesłać uzupełniony rekord (i tak zrobimy tutaj),
* 2) odesłać "małego JSON-a" z informacją o tym ID
* (i innymi informacjami, które serwer chce przekazać klientowi)
* 3) tylko nagłówek Location z URL-em nowego rekordu (to zobaczymy w wersji JAX-RS).
*/
productRepository.save(product);
return product;
}
@DeleteMapping("/{id}")
public void delete(@PathVariable("id") Integer productId) {
try {
productRepository.deleteById(productId);
} catch (EmptyResultDataAccessException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Brak produktu nr " + productId);
}
}
}
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