این قسمت پایانی تجزیه REST است. در قسمت های قبلی:
ایجاد یک پروژه
در این قسمت با استفاده از Spring Boot یک برنامه کوچک RESTful ایجاد می کنیم. برنامه ما عملیات CRUD (ایجاد، خواندن، به روز رسانی، حذف) را بر روی مشتریان از مثال قسمت آخر تجزیه و تحلیل اجرا می کند. ابتدا از طریق منو File -> New -> Project یک اپلیکیشن Spring Boot جدید ایجاد می کنیم ... در پنجره باز شده Spring Initializr را انتخاب کرده و Project SDK را مشخص کنید: روی دکمه Next کلیک کنید. در پنجره بعدی، نوع پروژه Maven را مشخص کنید، Group and Artifact را مشخص کنید: روی دکمه Next کلیک کنید. در پنجره بعدی باید اجزای Spring Framework مورد نیاز پروژه را انتخاب کنیم. Spring Web برای ما کافی خواهد بود: روی دکمه Next کلیک کنید. بعد، تنها چیزی که باقی می ماند این است که نام پروژه و مکان آن را در سیستم فایل مشخص کنید: روی دکمه Finish کلیک کنید. پروژه ایجاد شده است، اکنون میتوانیم ساختار آن را ببینیم: IDEA برای ما توصیفگر استقرار سیستم ساخت Maven - pom.xml و کلاس برنامه اصلی:RestExampleApplication
. کد آنها این است:
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.javarush.lectures</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);
}
}
ایجاد قابلیت REST
برنامه ما مشتریان را مدیریت می کند. بنابراین اولین کاری که باید انجام دهیم این است که یک نهاد مشتری ایجاد کنیم. این یک کلاس POJO خواهد بود. بیایید یک بستهmodel
در داخل یک بسته ایجاد کنیم com.javarush.lectures.rest_example
. model
بیایید یک کلاس در داخل بسته ایجاد کنیم Client
:
public class Client {
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;
}
}
این سرویس عملیات CRUD را بر روی مشتری اجرا خواهد کرد. گام بعدی ایجاد سرویسی است که این عملیات را اجرا کند. در بسته com.javarush.lectures.rest_example
ما یک بسته ایجاد می کنیم service
که در داخل آن یک رابط ایجاد می کنیم ClientService
. در اینجا کد رابط همراه با نظرات است:
public interface ClientService {
/**
* Создает нового клиента
* @param client - клиент для создания
*/
void create(Client client);
/**
* returns список всех имеющихся клиентов
* @return список клиентов
*/
List<client> readAll();
/**
* returns клиента по его ID
* @param id - ID клиента
* @return - an object клиента с заданным ID
*/
Client read(int id);
/**
* Обновляет клиента с заданным ID,
* в соответствии с переданным клиентом
* @param client - клиент в соответсвии с которым нужно обновить данные
* @param id - id клиента которого нужно обновить
* @return - true если данные были обновлены, иначе false
*/
boolean update(Client client, int id);
/**
* Удаляет клиента с заданным ID
* @param id - id клиента, которого нужно удалить
* @return - true если клиент был удален, иначе false
*/
boolean delete(int id);
}
در مرحله بعد باید یک پیاده سازی از این رابط ایجاد کنیم. اکنون به عنوان یک مخزن مشتری عمل خواهد کرد Map<Integer, Client>
. کلید کارت، شناسه مشتری و مقدار، خود کلاینت خواهد بود. این کار برای اینکه مثال با مشخصات کار با پایگاه داده بیش از حد بارگیری نشود انجام شد. با این حال، در آینده قادر خواهیم بود پیاده سازی دیگری از اینترفیس بنویسیم که در آن امکان اتصال یک پایگاه داده واقعی وجود داشته باشد. در بسته service
ما یک پیاده سازی از رابط ایجاد خواهیم کرد ClientService
:
@Service
public class ClientServiceImpl implements ClientService {
// Хранorще клиентов
private static final Map<Integer, Client> CLIENT_REPOSITORY_MAP = new HashMap<>();
// Переменная для генерации ID клиента
private static final AtomicInteger CLIENT_ID_HOLDER = new AtomicInteger();
@Override
public void create(Client client) {
final int clientId = CLIENT_ID_HOLDER.incrementAndGet();
client.setId(clientId);
CLIENT_REPOSITORY_MAP.put(clientId, client);
}
@Override
public List<Client> readAll() {
return new ArrayList<>(CLIENT_REPOSITORY_MAP.values());
}
@Override
public Client read(int id) {
return CLIENT_REPOSITORY_MAP.get(id);
}
@Override
public boolean update(Client client, int id) {
if (CLIENT_REPOSITORY_MAP.containsKey(id)) {
client.setId(id);
CLIENT_REPOSITORY_MAP.put(id, client);
return true;
}
return false;
}
@Override
public boolean delete(int id) {
return CLIENT_REPOSITORY_MAP.remove(id) != null;
}
}
حاشیه نویسی @Service
به Spring می گوید که این کلاس یک سرویس است. این نوع خاصی از کلاس است که برخی از منطق تجاری برنامه در آن پیاده سازی می شود. متعاقباً، به لطف این حاشیهنویسی، Spring نمونهای از این کلاس را در مکانهایی که به آن نیاز داریم با استفاده از Dependency Injection در اختیار ما قرار میدهد. اکنون زمان ایجاد کنترلر است. یک کلاس ویژه که در آن منطق پردازش درخواست های مشتری برای نقاط پایانی (URI) را پیاده سازی می کنیم. برای واضح تر شدن این موضوع، این کلاس را به صورت قطعات ایجاد می کنیم. ابتدا بیایید خود کلاس را ایجاد کنیم و یک وابستگی به آن معرفی کنیم ClientService
:
@RestController
public class ClientController {
private final ClientService clientService;
@Autowired
public ClientController(ClientService clientService) {
this.clientService = clientService;
}
}
بیایید حاشیهنویسیها را روشن کنیم: @RestController - به Spring میگوید که این کلاس یک کنترلکننده REST است. آن ها این کلاس منطق پردازش درخواست های مشتری @Autowired را پیاده سازی می کند - به Spring می گوید که یک وابستگی باید در این مکان تزریق شود. ما رابط را به سازنده منتقل می کنیم ClientService
. ما اجرای این سرویس را @Service
قبلا با یک حاشیه نویسی علامت گذاری کردیم و اکنون Spring می تواند نمونه ای از این پیاده سازی را به سازنده کنترلر منتقل کند. در مرحله بعد، ما گام به گام هر روش کنترل کننده را برای پردازش عملیات CRUD پیاده سازی می کنیم. بیایید با عملیات Create شروع کنیم. برای این کار، بیایید یک روش بنویسیم create
:
@PostMapping(value = "/clients")
public ResponseEntity<?> create(@RequestBody Client client) {
clientService.create(client);
return new ResponseEntity<>(HttpStatus.CREATED);
}
بیایید به این روش نگاه کنیم: @PostMapping(value = "/clients")
- در اینجا منظور ما این است که این متد درخواست های POST را به آدرس /clients پردازش می کند ResponseEntity<?>
. ResponseEntity
- یک کلاس ویژه برای بازگرداندن پاسخ ها. با استفاده از آن، بعداً می توانیم کد وضعیت HTTP را به مشتری برگردانیم. متد یک پارامتر می گیرد @RequestBody Client client
، مقدار این پارامتر از بدنه درخواست جایگزین می شود. چکیده در این باره صحبت می کند @RequestBody
. در داخل بدنه متد، متد create را روی سرویس ایجاد شده قبلی فراخوانی می کنیم و آن را به کنترلر مشتری پذیرفته شده در پارامترها منتقل می کنیم. ResponseEntity
سپس با ایجاد یک شی جدید و ارسال مقدار enum مورد نیاز به آن، وضعیت 201 Created را برمی گردانیم HttpStatus
. در مرحله بعد، عملیات را اجرا می کنیم Read
: ابتدا عملیات به دست آوردن لیستی از تمام مشتریان موجود را اجرا می کنیم:
@GetMapping(value = "/clients")
public ResponseEntity<List<Client>> read() {
final List<Client> clients = clientService.readAll();
return clients != null && !clients.isEmpty()
? new ResponseEntity<>(clients, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
بیایید تجزیه و تحلیل را شروع کنیم: @GetMapping(value = "/clients")
- همه چیز شبیه حاشیه نویسی است @PostMapping
، فقط اکنون درخواست های GET را پردازش می کنیم. این بار ما برمی گردیم ResponseEntity<List<Client>>
، فقط این بار علاوه بر وضعیت HTTP، بدنه پاسخ را نیز برمی گردانیم که لیستی از مشتریان خواهد بود. در کنترلکنندههای Spring REST، تمام اشیاء POJO، و همچنین مجموعههایی از اشیاء POJO که به عنوان بدنههای پاسخ برگردانده میشوند، بهطور خودکار به JSON سریال میشوند، مگر اینکه به طور صریح خلاف آن مشخص شده باشد. این برای ما کاملاً مناسب است. در داخل روش، با استفاده از سرویس ما، لیستی از تمام مشتریان دریافت می کنیم. در مرحله بعد، اگر لیست خالی یا خالی نباشد، ResponseEntity
لیست کلاینت ها و وضعیت HTTP را با استفاده از کلاس 200 OK برمی گردانیم. در غیر این صورت، ما به سادگی وضعیت HTTP 404 Not Found را برمی گردانیم. در مرحله بعد، ما توانایی دریافت مشتری با شناسه او را پیاده سازی می کنیم:
@GetMapping(value = "/clients/{id}")
public ResponseEntity<Client> read(@PathVariable(name = "id") int id) {
final Client client = clientService.read(id);
return client != null
? new ResponseEntity<>(client, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
یک چیز جدید این است که ما اکنون یک متغیر مسیر داریم. متغیری که در یک URI تعریف شده است. value = "/clients/{id}"
. ما آن را در بریس های مجعد نشان دادیم. و در پارامترهای متد int
با استفاده از annotation آن را به عنوان یک متغیر می پذیریم @PathVariable(name = "id")
. این روش درخواستهای uri فرم را میپذیرد /clients/{id}
که در عوض {id}
میتواند هر مقدار عددی وجود داشته باشد. این مقدار متعاقباً به یک متغیر int id
- پارامتر متد ارسال می شود. در بدنه ما شیء را Client
با استفاده از سرویس خود دریافت می کنیم و پذیرفته می شویم id
. و سپس، بر اساس قیاس با لیست، یا وضعیت OK 200 و خود شی Client
یا به سادگی وضعیت 404 Not Found را برمیگردانیم، اگر id
کلاینت با این مورد در سیستم وجود نداشته باشد. برای اجرای دو عملیات باقی مانده است - به روز رسانی و حذف. در اینجا کد این روش ها آمده است:
@PutMapping(value = "/clients/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Client client) {
final boolean updated = clientService.update(client, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/clients/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = clientService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
اساساً هیچ چیز جدیدی در این روش ها وجود ندارد، بنابراین از توضیح مفصل صرف نظر می کنیم. تنها چیزی که شایان ذکر است این است که متد update
درخواست های PUT (annotation @PutMapping
) را پردازش می کند و متد delete
درخواست های DELETE (annotation DeleteMapping
) را پردازش می کند. در اینجا کد کنترلر کامل است:
@RestController
public class ClientController {
private final ClientService clientService;
@Autowired
public ClientController(ClientService clientService) {
this.clientService = clientService;
}
@PostMapping(value = "/clients")
public ResponseEntity<?> create(@RequestBody Client client) {
clientService.create(client);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@GetMapping(value = "/clients")
public ResponseEntity<List<Client>> read() {
final List<client> clients = clientService.readAll();
return clients != null && !clients.isEmpty()
? new ResponseEntity<>(clients, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@GetMapping(value = "/clients/{id}")
public ResponseEntity<Client> read(@PathVariable(name = "id") int id) {
final Client client = clientService.read(id);
return client != null
? new ResponseEntity<>(client, HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
@PutMapping(value = "/clients/{id}")
public ResponseEntity<?> update(@PathVariable(name = "id") int id, @RequestBody Client client) {
final boolean updated = clientService.update(client, id);
return updated
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
@DeleteMapping(value = "/clients/{id}")
public ResponseEntity<?> delete(@PathVariable(name = "id") int id) {
final boolean deleted = clientService.delete(id);
return deleted
? new ResponseEntity<>(HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.NOT_MODIFIED);
}
}
در نتیجه ساختار پروژه ما به این صورت است:
راه اندازی و تست
برای اجرای برنامه ما، فقط متد راmain
در کلاس اجرا کنید RestExampleApplication
. و برای آزمایش خدمات وب RESTful، باید نرم افزار جدید را دانلود کنید) واقعیت این است که درخواست های GET از یک مرورگر معمولی ارسال بسیار آسان است، اما برای POST، PUT و DELETE یک مرورگر معمولی کافی نیست. نگران نباشید: می توانید از Postman برای ارسال هرگونه درخواست HTTP استفاده کنید. شما می توانید آن را از اینجا دانلود کنید . پس از دانلود و نصب، ما شروع به آزمایش برنامه خود می کنیم. برای انجام این کار، برنامه را باز کنید و یک درخواست جدید ایجاد کنید: روی دکمه New در گوشه سمت چپ بالا کلیک کنید. در مرحله بعد، درخواست را انتخاب کنید: بعد، نامی برای آن بگذارید و آن را ذخیره کنید. حالا بیایید سعی کنیم یک درخواست POST به سرور ارسال کنیم و اولین مشتری را ایجاد کنیم: ما چندین مشتری را به این ترتیب ایجاد می کنیم. سپس نوع درخواست را به GET تغییر می دهیم و به سرور ارسال می کنیم:
نتایج کلی
تبریک: ما کاملاً به موضوع REST پرداخته ایم. همه مطالب حجم زیادی پیدا کرد، اما امیدواریم برای شما مفید باشد:-
ما یاد گرفتیم که REST چیست.
-
با تاریخچه REST آشنا شدیم.
-
در مورد محدودیت ها و اصول این سبک معماری صحبت کردیم:
- آوردن معماری به مدل مشتری-سرور؛
- عدم وجود شرایط؛
- ذخیره سازی؛
- یکنواختی رابط؛
- لایه های؛
- کد در صورت تقاضا (محدودیت اختیاری).
-
ما مزایایی را که REST فراهم می کند بررسی کردیم
-
ما به طور مفصل نحوه تعامل سرور و کلاینت با یکدیگر را با استفاده از پروتکل HTTP بررسی کردیم.
-
بیایید نگاهی دقیق تر به درخواست ها و پاسخ ها بیندازیم. اجزای آنها جدا شد.
-
در نهایت، ما به تمرین رفتیم و برنامه کوچک RESTful خود را در Spring Boot نوشتیم. و ما حتی یاد گرفتیم که چگونه آن را با استفاده از برنامه Postman آزمایش کنیم.
مشق شب
موارد زیر را امتحان کنید:- طبق توضیحات بالا، پروژه Spring Boot خود را بسازید و همان منطقی را که در سخنرانی در آن وجود داشت پیاده سازی کنید. همه چیز را 1 در 1 تکرار کنید.
- آن را راه اندازی کنید. کاربرد.
- Postman (یا هر ابزار دیگری برای ارسال درخواست ها، حتی curl) را دانلود و راه اندازی کنید.
- درخواست های POST و GET را به همان روشی که در سخنرانی توضیح داده شد، آزمایش کنید.
- خودتان درخواست های PUT و DELETE را آزمایش کنید.
GO TO FULL VERSION