Dette er den siste delen av vår oversikt over REST. I de foregående delene dekket vi:
Klikk på "Neste"-knappen. I neste vindu, spesifiser "Maven Project" som prosjekttype, spesifiser "Gruppe" og "Artefakt":
Klikk på "Neste"-knappen. I det neste vinduet må vi velge Spring Framework-komponentene som er nødvendige for prosjektet. Spring Web vil være tilstrekkelig for oss:
Klikk på "Neste"-knappen. Nå gjenstår det bare å angi navnet på prosjektet og dets plassering i filsystemet:
Klikk på "Fullfør"-knappen. Prosjektet er opprettet, og nå kan vi se strukturen:
IDEA genererte en Maven deployment descriptor (pom.xml) og applikasjonens hovedklasse (
Klikk på "Ny"-knappen i øvre venstre hjørne. Deretter velger du "Request":
Deretter gir du den et navn og lagrer den. La oss nå prøve å sende en POST-forespørsel til serveren og opprette den første kunden:
Vi skaper flere kunder på denne måten. Deretter endrer vi forespørselstypen til GET og sender forespørselen til serveren:

Opprette et prosjekt
I denne delen vil vi lage en liten RESTful-applikasjon ved å bruke Spring Boot. Vår applikasjon vil implementere CRUD-operasjoner (Create, Read, Update, Delete) på kundene fra eksemplet i forrige del av oversikten. For å starte, vil vi lage en ny Spring Boot-applikasjon via menyen: Fil -> Ny -> Prosjekt... I vinduet som åpnes, velg Spring Initializr og spesifiser Project SDK:




RestExampleApplication
) for oss. Slik 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);
}
}
Opprette REST-funksjonalitet
Vår applikasjon er et kundestyringssystem. Så det første vi må gjøre er å opprette en kundeenhet. Det vil være en POJO-klasse (vanlig gammelt Java-objekt). Lag enmodel
pakke inne i com.codegym.lessons.rest_example
pakken. Inne i model
pakken oppretter 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;
}
}
Tjenesten vil implementere CRUD-operasjoner på kunder. Det neste trinnet er å lage en tjeneste som skal implementere disse operasjonene. com.codegym.lessons.rest_example
Opprett en pakke i pakken service
. Og inni det, lag et CustomerService
grensesnitt. Her er grensesnittkoden 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);
}
Deretter må vi implementere dette grensesnittet. Nå Map<Integer, Customer>
vil en lagre våre kunder. Kartets nøkler vil være kunde-IDene, og verdiene vil være kundene selv. Dette gjøres for ikke å overbelaste dette eksemplet med detaljene ved å jobbe med en ekte database. Imidlertid vil vi i fremtiden kunne skrive en annen implementering av grensesnittet, som vil gjøre det mulig å koble til en ekte database. I service
pakken oppretter du en implementering av CustomerService
grensesnittet:
@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;
}
}
Merknaden @Service
forteller våren at denne timen er en tjeneste. Dette er en spesiell type klasse som implementerer noe forretningsapplikasjonslogikk. Deretter, takket være denne merknaden, vil Spring bruke avhengighetsinjeksjon for å gi oss en forekomst av denne klassen på alle stedene der den er nødvendig. Nå er det på tide å lage en kontroller. Dette er en spesiell klasse hvor vi skal implementere logikken for å behandle klientforespørsler sendt til endepunkter (URI). For å gjøre alt dette klarere, vil vi opprette denne klassen trinnvis. Opprett først selve klassen og legg til en avhengighet av CustomerService
:
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
}
La oss forklare merknadene: @RestController forteller Spring at denne klassen er en REST-kontroller. Med andre ord implementerer denne klassen logikken for å behandle klientforespørsler. @Autowired forteller Spring at en avhengighet må legges til her. Vi sender CustomerService
grensesnittet til konstruktøren. Tidligere markerte vi implementeringen av denne tjenesten med merknaden @Service
, og nå vil Spring kunne sende en forekomst av denne implementeringen til kontrollerens konstruktør. Deretter vil vi implementere hver kontrollmetode for håndtering av CRUD-operasjoner. La oss starte med opprette-operasjonen. For å gjøre dette skriver vi en create
metode:
@PostMapping(value = "/customers")
public ResponseEntity<?> create(@RequestBody Customer customer) {
customerService.create(customer);
return new ResponseEntity<>(HttpStatus.CREATED);
}
La oss analysere denne metoden: @PostMapping(value = "/customers")
mener at denne metoden behandler POST-forespørsler sendt til adressen "/kunder". Metoden returnerer en ResponseEntity<?>
. A ResponseEntity
er en spesiell klasse for å returnere svar. Senere vil vi bruke den til å returnere en HTTP-statuskode til klienten. Metoden har en @RequestBody Customer customer
parameter. Verdien av denne parameteren kommer fra forespørselsteksten. Merknaden @RequestBody
indikerer dette. Inne i metoden kaller vi create()
metoden på den tidligere opprettede tjenesten og sender den til kundekontrolleren mottok i parameterne. Deretter returnerer vi "201 Opprettet"-statusen ved å lage et nytt ResponseEntity
objekt og sende det tilsvarende HttpStatus
enum-feltet til det. Deretter implementerer viread
operasjon: Først implementerer vi operasjonen for å få en liste over alle tilgjengelige 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);
}
La oss dykke inn: @GetMapping(value = "/customers")
— alt her ligner på @PostMapping
kommentaren, men nå behandler vi GET-forespørsler. Denne gangen returnerer vi en ResponseEntity<List<Customer>>
, og i tillegg til en HTTP-status vil vi også returnere en svartekst, som vil være listen over kunder. I Springs REST-kontrollere er alt POJO-objekter og samlinger av POJO-objekter, som returneres som responslegemer og automatisk serialisert til JSON, med mindre annet er spesifisert. Dette passer oss perfekt. Inne i metoden bruker vi vår tjeneste for å få en liste over alle kunder. Deretter, hvis listen ikke er null og ikke tom, bruker viResponseEntity
klasse for å returnere listen over kunder og HTTP-statuskoden "200 OK". Ellers returnerer vi ganske enkelt HTTP-statuskoden "404 Not Found". Nå skal vi implementere muligheten til å få en kunde ved å bruke IDen sin:
@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 ting her er banevariabelen. Variabelen er definert i URI: value = "/customers/{id}"
. Vi indikerer det i krøllete seler. Og vi mottar det som en int
metodeparameter ved å bruke @PathVariable(name = "id")
merknaden. Denne metoden aksepterer forespørsler sendt til URIer i skjemaet /customers/{id}
, der {id}
representerer enhver numerisk verdi. Denne verdien sendes deretter via int id
variabelen til metodeparameteren. I kroppen får vi gjenstanden Customer
ved hjelp av vår tjeneste og den mottatte id
. Og så, analogt med listen, returnerer vi enten "200 OK"-statusen og Customer
selve objektet, eller ganske enkelt "404 Not Found"-statusen hvis systemet ikke har noen kunde med det id
. Vi må fortsatt implementere to operasjoner: oppdatering og sletting. Her er koden for disse metodene:
@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 er ikke noe vesentlig nytt i disse metodene, så vi hopper over den detaljerte beskrivelsen. Det eneste som er verdt å nevne er at update()
metoden håndterer PUT-forespørsler ( @PutMapping
merknad), og delete()
metoden håndterer DELETE-forespørsler ( DeleteMapping
merknad). Her er hele koden for kontrolleren:
@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 et resultat er strukturen til prosjektet vårt som følger: 
Lansering og testing
For å starte applikasjonen vår, bare kjørmain()
metoden i RestExampleApplication
klassen. Men for å teste RESTful webtjenester, må vi laste ned ekstra programvare. Faktum er at GET-forespørsler er ganske enkle å sende fra en vanlig nettleser, men en vanlig nettleser kan ikke sende POST, PUT og DELETE-forespørsler. Ikke bekymre deg: du kan bruke et program kalt Postman til å sende HTTP-forespørsler. Du kan laste den ned her . Etter å ha lastet ned og installert Postman, begynner vi å teste applikasjonen vår. For å gjøre dette, åpne programmet og opprett en ny forespørsel: 



Sammendrag
Gratulerer! Vi har dekket REST tilstrekkelig. Det var et stort volum av materiale, men forhåpentligvis var det nyttig for deg:-
Vi lærte hva REST er.
-
Vi lærte om hvordan REST ble til.
-
Vi snakket om begrensningene og prinsippene bak denne arkitektoniske stilen:
- klient-server-arkitektur
- statsløs
- caching
- enhetlig grensesnitt
- lag
- kode på forespørsel (valgfritt)
-
Vi utforsket fordelene gitt av REST
-
Vi undersøkte i detalj hvordan serveren og klienten samhandler med hverandre via HTTP-protokollen.
-
Vi har sett nærmere på forespørsler og svar. Vi dissekerte deres bestanddeler.
-
Til slutt fikk vi litt praktisk erfaring ved å skrive vår egen lille RESTful-applikasjon med Spring Boot. Og vi lærte til og med å teste det med Postman.
Hjemmelekser
Prøv følgende:- Følg beskrivelsen ovenfor, lag ditt eget Spring Boot-prosjekt og implementer den samme logikken som i leksjonen. Gjenta alt nøyaktig.
- Start applikasjonen.
- Last ned og konfigurer Postman (eller et annet verktøy for å sende forespørsler, for eksempel curl).
- Test POST- og GET-forespørsler på samme måte som beskrevet i leksjonen.
- Test PUT- og DELETE-forespørsler selv.
GO TO FULL VERSION