Detta är den sista delen av vår översikt över REST. I de tidigare delarna täckte vi:
Klicka på knappen "Nästa". I nästa fönster, ange "Maven Project" som projekttyp, ange "Group" och "Artifact":
Klicka på "Next"-knappen. I nästa fönster måste vi välja de Spring Framework-komponenter som är nödvändiga för projektet. Spring Web kommer att räcka för oss:
Klicka på knappen "Nästa". Nu återstår bara att ange projektets namn och dess plats i filsystemet:
Klicka på knappen "Slutför". Projektet är skapat och nu kan vi se dess struktur:
IDEA genererade en Maven-deployment descriptor (pom.xml) och applikationens huvudklass ( )
Klicka på knappen "Ny" i det övre vänstra hörnet. Välj sedan "Begäran":
Ge det sedan ett namn och spara det. Låt oss nu försöka skicka en POST-förfrågan till servern och skapa den första kunden:
Vi skapar flera kunder på detta sätt. Sedan ändrar vi förfrågningstypen till GET och skickar förfrågan till servern:

Skapa ett projekt
I det här avsnittet kommer vi att skapa en liten RESTful-applikation med Spring Boot. Vår applikation kommer att implementera CRUD-operationer (Create, Read, Update, Delete) på kunderna från exemplet i föregående del av översikten. Till att börja med skapar vi en ny Spring Boot-applikation via menyn: Arkiv -> Nytt -> Projekt... I fönstret som öppnas, välj Spring Initializr och ange Project SDK:




RestExampleApplication
åt oss. Så här ser de ut:
pom.xml:
<?xml version="1.0" encoding="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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codegym.lessons/groupId>
<artifactId>rest_example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rest_example</name>
<description>REST example project</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
RestExampleApplication:
@SpringBootApplication
public class RestExampleApplication {
public static void main(String[] args) {
SpringApplication.run(RestExampleApplication.class, args);
}
}
Skapa REST-funktionalitet
Vår applikation är ett kundhanteringssystem. Så det första vi behöver göra är att skapa en kundenhet. Det kommer att vara en POJO-klass (vanligt gammalt Java-objekt). Skapa ettmodel
paket inuti com.codegym.lessons.rest_example
paketet. Inuti model
paketet skapar du Customer
:
public class Customer {
private Integer id;
private String name;
private String email;
private String phone;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Tjänsten kommer att implementera CRUD-verksamhet på kunder. Nästa steg är att skapa en tjänst som kommer att implementera dessa operationer. com.codegym.lessons.rest_example
Skapa ett service
paket i paketet. Och inuti det, skapa ett CustomerService
gränssnitt. Här är gränssnittskoden med kommentarer:
public interface CustomerService {
/**
* Creates a new customer
* @param customer - Customer to be created
*/
void create(Customer customer);
/**
* Returns a list of all existing customers
* @return List of customers
*/
List<Customer> readAll();
/**
* Returns a customer based on its ID
* @param id - Customer ID
* @return - Customer object with the given ID
*/
Customer read(int id);
/**
* Updates the customer with the given ID,
* according to the passed customer
* @param customer - Customer to use to update the data
* @param id - ID of the customer you want to update
* @return - true if the data has been updated, otherwise false
*/
boolean update(Customer customer, int id);
/**
* Deletes the customer with the given ID
* @param id - ID of the customer to be deleted
* @return - true if the customer was deleted, otherwise false
*/
boolean delete(int id);
}
Därefter måste vi implementera detta gränssnitt. Nu Map<Integer, Customer>
kommer en att lagra våra kunder. Kartans nycklar kommer att vara kund-id:n, och värdena kommer att vara kunderna själva. Detta görs för att inte överbelasta detta exempel med detaljerna för att arbeta med en riktig databas. Men i framtiden kommer vi att kunna skriva ytterligare en implementering av gränssnittet, vilket gör det möjligt att ansluta till en riktig databas. service
Skapa en implementering av gränssnittet i paketet CustomerService
:
@Service
public class CustomerServiceImpl implements CustomerService {
// Customer repository
private static final Map<Integer, Customer> CUSTOMER_REPOSITORY_MAP = new HashMap<>();
// Variable for generating a customer ID
private static final AtomicInteger CUSTOMER_ID_HOLDER = new AtomicInteger();
@Override
public void create(Customer customer) {
final int customerId = CUSTOMER_ID_HOLDER.incrementAndGet();
customer.setId(customerId);
CUSTOMER_REPOSITORY_MAP.put(customerId, customer);
}
@Override
public List<Customer> readAll() {
return new ArrayList<>(CUSTOMER_REPOSITORY_MAP.values());
}
@Override
public Customer read(int id) {
return CUSTOMER_REPOSITORY_MAP.get(id);
}
@Override
public boolean update(Customer customer, int id) {
if (CUSTOMER_REPOSITORY_MAP.containsKey(id)) {
customer.setId(id);
CUSTOMER_REPOSITORY_MAP.put(id, customer);
return true;
}
return false;
}
@Override
public boolean delete(int id) {
return CUSTOMER_REPOSITORY_MAP.remove(id) != null;
}
}
Anteckningen @Service
berättar för våren att denna klass är en tjänst. Detta är en speciell typ av klass som implementerar viss affärsapplikationslogik. Därefter, tack vare denna annotering, kommer Spring att använda beroendeinjektion för att förse oss med en instans av den här klassen på alla platser där den behövs. Nu är det dags att skapa en kontroller. Detta är en specialklass där vi kommer att implementera logiken för att behandla klientförfrågningar som skickas till slutpunkter (URI). För att göra allt detta tydligare kommer vi att skapa den här klassen stegvis. Skapa först själva klassen och lägg till ett beroende av CustomerService
:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
}
Låt oss förklara kommentarerna: @RestController säger till Spring att den här klassen är en REST-kontroller. Med andra ord implementerar den här klassen logiken för att behandla klientförfrågningar. @Autowired säger till Spring att ett beroende måste läggas till här. Vi skickar gränssnittet CustomerService
till konstruktören. Tidigare markerade vi implementeringen av den här tjänsten med anteckningen, @Service
och nu kommer Spring att kunna skicka en instans av denna implementering till kontrollenhetens konstruktör. Därefter kommer vi att implementera varje kontrollmetod för att hantera CRUD-operationer. Låt oss börja med skapa operationen. För att göra detta skriver vi en create
metod:
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
Låt oss analysera denna metod: @PostMapping(value = "/customers")
menar att den här metoden behandlar POST-förfrågningar som skickas till adressen "/kunder". Metoden returnerar en ResponseEntity<?>
. A ResponseEntity
är en specialklass för att returnera svar. Senare kommer vi att använda den för att returnera en HTTP-statuskod till klienten. Metoden har en @RequestBody Customer customer
parameter. Värdet på denna parameter kommer från förfrågan. Anteckningen @RequestBody
indikerar detta. Inuti metoden anropar vi create()
metoden på den tidigare skapade tjänsten och skickar den till kundkontrollanten som tagits emot i parametrarna. Sedan returnerar vi statusen "201 Skapad" genom att skapa ett nytt ResponseEntity
objekt och skicka motsvarande HttpStatus
uppräkningsfält till det. Därefter kommer vi att implementeraread
operation: Först implementerar vi operationen för att få en lista över alla tillgängliga kunder:
@GetMapping(value = "/customers")
public ResponseEntity<List<Customer>> read() {
final List<Customer> customers = customerService.readAll();
return customers != null && !customers.isEmpty()
? new ResponseEntity<>(customers, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Låt oss dyka in: @GetMapping(value = "/customers")
— allt här liknar anteckningen @PostMapping
, men nu behandlar vi GET-förfrågningar. Den här gången returnerar vi en ResponseEntity<List<Customer>>
, och förutom en HTTP-status kommer vi även att returnera en svarskropp, som kommer att vara listan över kunder. I Springs REST-kontroller är allt POJO-objekt och samlingar av POJO-objekt, som returneras som svarskroppar och serialiseras automatiskt till JSON, om inget annat anges. Detta passar oss perfekt. Inuti metoden använder vi vår tjänst för att få en lista över alla kunder. Därefter, om listan inte är null och inte tom, använder viResponseEntity
klass för att returnera listan över kunder och HTTP-statuskoden "200 OK". Annars returnerar vi helt enkelt HTTP-statuskoden "404 Not Found". Nu kommer vi att implementera möjligheten att få en kund med hjälp av dess ID:
@GetMapping(value = "/customers/{id}")
public ResponseEntity<Customer> read(@PathVariable(name = "id") int id) {
final Customer customer = customerService.read(id);
return customer != null
? new ResponseEntity<>(customer, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
En ny sak här är sökvägsvariabeln. Variabeln definieras i URI:n: value = "/customers/{id}"
. Vi anger det i lockiga hängslen. Och vi får den som en int
metodparameter med hjälp av @PathVariable(name = "id")
anteckningen. Den här metoden accepterar förfrågningar som skickas till URI:er i formen , /customers/{id}
där {id}
representerar vilket numeriskt värde som helst. Detta värde överförs sedan via int id
variabeln till metodparametern. I kroppen får vi föremålet Customer
med hjälp av vår tjänst och det mottagna id
. Och sedan, i analogi med listan, returnerar vi antingen statusen "200 OK" och Customer
själva objektet, eller helt enkelt statusen "404 Not Found" om systemet inte har någon kund med det id
. Vi behöver fortfarande implementera två operationer: uppdatera och ta bort. Här är koden för dessa metoder:
@PutMapping(value = "/customers/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Customer customer) {
final boolean updated = customerService.update(customer, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/customers/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = customerService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
Det finns inget väsentligt nytt i dessa metoder, så vi hoppar över den detaljerade beskrivningen. Det enda som är värt att nämna är att update()
metoden hanterar PUT-förfrågningar ( @PutMapping
annotation), och delete()
metoden hanterar DELETE-förfrågningar ( DeleteMapping
annotation). Här är hela koden för kontrollenheten:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@GetMapping(value = "/customers")
public ResponseEntity<List<Customer>> read() {
final List<Customer> customers = customerService.readAll();
return customers != null && !customers.isEmpty()
? new ResponseEntity<>(customers, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@GetMapping(value = "/customers/{id}")
public ResponseEntity<Customer> read(@PathVariable(name = "id") int id) {
final Customer customer = customerService.read(id);
return customer != null
? new ResponseEntity<>(customer, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@PutMapping(value = "/customers/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Customer customer) {
final boolean updated = customerService.update(customer, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/customers/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = customerService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
}
Som ett resultat är strukturen för vårt projekt som följer: 
Lansering och testning
För att starta vår applikation, kör baramain()
metoden i RestExampleApplication
klassen. Men för att testa RESTful webbtjänster måste vi ladda ner ytterligare programvara. Faktum är att GET-förfrågningar är ganska enkla att skicka från en vanlig webbläsare, men en vanlig webbläsare kan inte skicka POST-, PUT- och DELETE-förfrågningar. Oroa dig inte: du kan använda ett program som heter Postman för att skicka alla HTTP-förfrågningar. Du kan ladda ner den här . Efter att ha laddat ner och installerat Postman börjar vi testa vår applikation. För att göra detta, öppna programmet och skapa en ny begäran: 



Sammanfattning
Grattis! Vi har täckt REST tillräckligt. Det fanns en stor mängd material, men förhoppningsvis var det användbart för dig:-
Vi lärde oss vad REST är.
-
Vi lärde oss om hur REST uppstod.
-
Vi pratade om begränsningarna och principerna bakom denna arkitektoniska stil:
- klient-server-arkitektur
- statslös
- cachelagring
- enhetligt gränssnitt
- skikten
- kod på begäran (valfritt)
-
Vi undersökte fördelarna med REST
-
Vi undersökte i detalj hur servern och klienten interagerar med varandra via HTTP-protokollet.
-
Vi tittade närmare på förfrågningar och svar. Vi dissekerade deras beståndsdelar.
-
Slutligen fick vi lite praktisk erfarenhet genom att skriva vår egen lilla RESTful-applikation med Spring Boot. Och vi lärde oss till och med hur man testar det med Postman.
Läxa
Prova följande:- Följ beskrivningen ovan, skapa ditt eget Spring Boot-projekt och implementera samma logik som i lektionen. Upprepa allt exakt.
- Starta applikationen.
- Ladda ner och konfigurera Postman (eller något annat verktyg för att skicka förfrågningar, till exempel curl).
- Testa POST- och GET-förfrågningar på samma sätt som beskrivs i lektionen.
- Testa PUT- och DELETE-förfrågningar själv.
GO TO FULL VERSION