JavaRush /Блоги Java /Random-TG /Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTf...
Artur
Сатҳи
Tallinn

Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot. Қисми 2

Дар гурӯҳ нашр шудааст
Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot. Қисми 1 Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot.  Қисми 2 - 1 Ҳамин тавр, дар қисми охир мо фаҳмидем, ки чӣ гуна насб кардани пойгоҳи додаҳои PostgresSQL дар компютер, эҷоди пойгоҳи додаҳо дар pgAdmin ва инчунин ба таври дастӣ ва барномавӣ дар он ҷадвалҳо эҷод ва нест кардан лозим аст. Дар ин қисмат мо барномаи худро аз нав менависем, то он кор бо ин база ва ҷадвалҳоро ёд гирад. Чаро мо? Зеро худам бо шумо аз ин мавод меомӯзам. Ва он гоҳ мо на танҳо вазифаи дар пешистодаро ҳал мекунем, балки хатогиҳоеро, ки дар роҳ ба миён меоянд, бо маслиҳати барномасозони ботаҷриба ислоҳ мекунем. Ҳамин тавр, мо дар як даста кор карданро ёд мегирем;) Аввалан, биёед com.javarush.lectures.rest_exampleдар папка бастаи нав эҷод кунем ва онро даъват кунем repository. Дар ин баста мо интерфейси нав эҷод мекунем ClientRepository:
package com.javarush.lectures.rest_example.repository;

import com.javarush.lectures.rest_example.model.Client;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ClientRepository extends JpaRepository<Client, Integer>  {
}
Ин интерфейс бо пойгоҳи додаҳо ва ҷадвалҳои мо "сеҳрона" ҳамкорӣ хоҳад кард. Чаро ҷодугарӣ? Зеро ба мо лозим нест, ки татбиқи онро нависем ва чаҳорчӯбаи баҳорӣ онро ба мо медиҳад. Ба шумо танҳо лозим аст, ки чунин интерфейсро эҷод кунед ва шумо аллакай метавонед аз ин "ҷодугарӣ" истифода баред. ClientҚадами навбатӣ ин таҳрири синф аст :
package com.javarush.lectures.rest_example.model;

import javax.persistence.*;

@Entity
@Table(name = "clients")
public class Client {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "phone")
    private String phone;

    //… getters and setters
}
Ҳамаи мо дар ин синф танҳо илова кардани баъзе эзоҳҳо буд. Биёед онҳоро аз сар гузаронем:
  • @Entity - нишон медиҳад, ки ин лӯбиё (синф) an object аст.
  • @Table - номи ҷадвалеро, ки дар ин an object намоиш дода мешавад, нишон медиҳад.
  • @Id - сутун id (калиди ибтидоӣ - арзише, ки барои таъмини ягонагии додаҳо дар ҷадвали ҷорӣ истифода мешавад. Эзоҳ: Андрей )
  • @Column - номи сутунеро, ки ба моликияти an object харита шудааст, нишон медиҳад.
  • @GeneratedValue - нишон медиҳад, ки ин амвол мувофиқи стратегияи муайяншуда тавлид мешавад.
Номҳои майдонҳои ҷадвал набояд ба номҳои тағирёбандаҳои синф мувофиқат кунанд. Масалан, агар мо тағирёбанда дошта бошем firstName, пас мо майдонро дар ҷадвал номбар мекунем first_name. Ин эзоҳҳоро ҳам бевосита дар майдонҳо ва ҳам дар гирандагони онҳо гузоштан мумкин аст. Аммо агар шумо яке аз ин усулҳоро интихоб кунед, пас кӯшиш кунед, ки ин услубро дар тамоми барномаи худ нигоҳ доред. Ман усули аввалро танҳо барои кӯтоҳ кардани рӯйхат истифода кардам. Рӯйхати мукаммали эзоҳҳоро барои кор бо пойгоҳи додаҳо дар ин ҷо пайдо кардан мумкин аст . Акнун биёед ба синф равем ClientServiceImplва онро ба таври зерин нависем:
package com.javarush.lectures.rest_example.service;

import com.javarush.lectures.rest_example.model.Client;
import com.javarush.lectures.rest_example.repository.ClientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ClientServiceImpl implements ClientService {

    @Autowired
    private ClientRepository clientRepository;

    @Override
    public void create(Client client) {
        clientRepository.save(client);
    }

    @Override
    public List<Client>  readAll() {
        return clientRepository.findAll();
    }

    @Override
    public Client read(int id) {
        return clientRepository.getOne(id);
    }

    @Override
    public boolean update(Client client, int id) {
        if (clientRepository.existsById(id)) {
            client.setId(id);
            clientRepository.save(client);
            return true;
        }

        return false;
    }

    @Override
    public boolean delete(int id) {
        if (clientRepository.existsById(id)) {
            clientRepository.deleteById(id);
            return true;
        }
        return false;
    }
}
Тавре ки шумо аз рӯйхат мебинед, мо танҳо ин нест кардани сатрҳое буд, ки ба мо дигар лозим нестанд:
// Хранorще клиентов
private static final Map<Integer, Client>  CLIENT_REPOSITORY_MAP = new HashMap<>();

// Переменная для генерации ID клиента
private static final AtomicInteger CLIENT_ID_HOLDER = new AtomicInteger();
Мо ба ҷои он интерфейси худро эълон кардем ClientRepositoryва инчунин шарҳи @Autowired- ро дар болои он ҷойгир кардем , то Баҳор ба таври худкор ин вобастагиро ба синфи мо илова кунад. Мо инчунин тамоми корҳоро ба ин интерфейс вогузор кардем, дурусттараш татбиқи онро, ки Баҳор илова хоҳад кард. Биёед ба марҳилаи ниҳоӣ ва ҷолибтарин - санҷиши дархости мо гузарем. Биёед барномаи Postman -ро кушоем (бибинед, ки чӣ тавр истифода бурдани он дар ин ҷо ) ва дархости GET-ро ба ин суроға фиристед: http://localhost:8080/clients. Мо ин ҷавобро мегирем:
[
    {
        "id": 1,
        "name": "Vassily Petrov",
        "email": "vpetrov@jr.com",
        "phone": "+7 (191) 322-22-33)"
    },
    {
        "id": 2,
        "name": "Pjotr Vasechkin",
        "email": "pvasechkin@jr.com",
        "phone": "+7 (191) 223-33-22)"
    }
]
Мо дархости POST мефиристем:
{
  "name" : "Amigo",
  "email" : "amigo@jr.com",
  "phone" : "+7 (191) 746-43-23"
}
Ва... мо хатои аввалини худро дар барнома дарёфтем:
{
    "timestamp": "2020-03-06T13:21:12.180+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
    "path": "/clients"
}
Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot.  Қисми 2 - 2 Мо ба гузоришҳо назар мекунем ва хатои зеринро пайдо мекунем:

org.postgresql.util.PSQLException: ОШИБКА: повторяющееся meaning ключа нарушает ограничение уникальности "clients_pkey"
  Detail: Ключ "(id)=(1)" уже существует.
Мо боз ҳамон дархости POST-ро мефиристем, натиҷа ҳамон аст, аммо бо ин тафовут: Ключ "(id)=(2)" уже существует. Мо як дархостро бори сеюм мефиристем ва Статус: 201 Created мегирем. Мо боз дархости GET-ро мефиристем ва ҷавоб мегирем:
[
    {
        "id": 1,
        "name": "Vassily Petrov",
        "email": "vpetrov@jr.com",
        "phone": "+7 (191) 322-22-33)"
    },
    {
        "id": 2,
        "name": "Pjotr Vasechkin",
        "email": "pvasechkin@jr.com",
        "phone": "+7 (191) 223-33-22)"
    },
    {
        "id": 3,
        "name": "Amigo",
        "email": "amigo@jr.com",
        "phone": "+7 (191) 746-43-23"
    }
]
Ин аз он шаҳодат медиҳад, ки барномаи мо ба он аҳамият намедиҳад, ки ин ҷадвал аллакай пур карда шудааст ва боз аз як сар карда ID таъин мекунад. Хуб, хато як лаҳзаи корӣ аст, ноумед нашавед, ин аксар вақт рух медиҳад. Аз ин рӯ, ман барои кӯмак ба ҳамкасбони ботаҷриба муроҷиат мекунам: "Ҳамкасбони мӯҳтарам, лутфан дар шарҳҳо маслиҳат диҳед, ки ин масъаларо чӣ гуна ислоҳ кард, то барнома ба таври мӯътадил кор кунад." Кӯмак дер наомад ва Стас Пасинков дар шарҳҳо ба ман гуфт, ки ман бояд ба кадом самт назар кунам. Барои ин ба ӯ ташаккури махсус! Аммо гап дар он буд, ки Clientман дар синф стратегияи эзоҳро @GeneratedValue(strategy = GenerationType.IDENTITY)барои саҳро нодуруст муайян кардам id. Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot.  Қисми 2 - 3 Ин стратегия барои MySQL мувофиқ аст. Агар мо бо Oracle ё PostrgeSQL кор кунем, пас мо бояд стратегияи дигарро муқаррар кунем. Шумо метавонед бештар дар бораи стратегияҳо барои калидҳои аввалияро дар ин ҷо хонед . Ман стратегияи GenerationType.SEQUENCE-ро интихоб кардам. Барои татбиқи он ба мо лозим меояд, ки файли initDB.sql ва албатта эзоҳҳои майдони id-и синфи Client-ро каме аз нав нависем. initDB.sql-ро аз нав нависед:
CREATE TABLE IF NOT EXISTS clients
(
    id    INTEGER PRIMARY KEY ,
    name  VARCHAR(200) NOT NULL ,
    email VARCHAR(254) NOT NULL ,
    phone VARCHAR(50)  NOT NULL
);
CREATE SEQUENCE clients_id_seq START WITH 3 INCREMENT BY 1;
Чӣ тағир ёфт: намуди сутуни id-и ҷадвали мо тағир ёфт, аммо дар ин бора баъдтар. Мо дар зер як сатр илова кардем, ки дар он як пайдарпаии нави clients_id_seq эҷод мекунем, нишон медиҳад, ки он бояд бо се оғоз шавад (зеро id охирин дар файли populateDB.sql 2 аст) ва нишон медиҳад, ки афзоиш бояд як ба амал ояд. Биёед ба навъи сутуни id баргардем. Дар ин ҷо мо INTEGER-ро муайян кардем, зеро агар SERIAL-ро тарк кунем, пайдарпаӣ ба таври худкор бо ҳамон ном clients_id_seq сохта мешавад, аммо аз як оғоз мешавад (ки боиси хатогии барнома шуд). Аммо, ҳоло агар шумо хоҳед, ки ҷадвалро нест кунед, ба шумо лозим меояд, ки ин пайдарпайро ба таври дастӣ тавассути интерфейси pgAdmin ё тавассути файли .sql бо истифода аз фармонҳои зерин тоза кунед:
DROP TABLE IF EXISTS clients;
DROP SEQUENCE IF EXISTS clients_id_seq
Аммо агар шумо файлеро ба мисли populateDB.sql барои пур кардани ҷадвал истифода набаред, пас шумо метавонед барои калиди ибтидоӣ намудҳои SERIAL ё BIGSERIAL -ро истифода баред ва ба шумо лозим нест, ки пайдарпайро дастӣ эҷод кунед ва аз ин рӯ ҳатмӣ нестед. алоҳида. Шумо метавонед бештар дар бораи пайдарпайии дар сайти. Ҳуҷҷатҳои PostgreSQL . Биёед ба annotationҳои майдони idсинф гузарем Clientва онҳоро ба таври зерин формат кунем:
@Id
@Column(name = "id")
@SequenceGenerator(name = "clientsIdSeq", sequenceName = "clients_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "clientsIdSeq")
private Integer id;
Мо чӣ кор кардем: мо шарҳи навро @SequenceGeneratorбарои сохтани генератори пайдарпай насб кардем, ба он ном додем clientsIdSeq, нишон додем, ки ин генератор барои пайдарпай аст clients_id_seqва атрибут илова намудем. allocationSize = 1 Ин атрибути ихтиёрӣ аст, аммо агар ин корро накунем, Вақте ки мо барномаро иҷро мекунем, мо хатои зеринро мегирем:

org.hibernate.MappingException: The increment size of the [clients_id_seq] sequence is set to [50] in the entity mapping while the associated database sequence increment size is [1]
Ин аст он чизе ки корбар Андрей дар ин бора дар шарҳҳо менависад: allocationSize пеш аз ҳама барои кам кардани сафари hibernate ба пойгоҳи додаҳо барои "id-и нав" пешбинӣ шудааст. Агар арзиш == 1 бошад, барои ҳар як an objectи нав интизор шавед, пеш аз захира кардани он дар базаи маълумот, ба пойгоҳи дода барои ID "медавад". Агар арзиш > 1 бошад (масалан, 5), hibernate бо пойгоҳи додаҳо барои ID-и "нав" камтар тамос мегирад (масалан, 5 маротиба) ва ҳангоми тамос, hibernate аз базаи маълумот хоҳиш мекунад, ки ин рақамро захира кунад (дар мо ҳолат, 5) арзишҳо. Хатогие, ки шумо тавсиф кардед, аз он бармеояд, ки hibernate мехоҳад 50 идентификатори пешфарзро гирад, аммо дар базаи маълумот шумо нишон додед, ки шумо омодаед барои ин an object танҳо мувофиқи идентификатори 1-ум маълумот диҳед . Хатогии дигарро корбар Николя Кудряшов ошкор кард : Агар шумо аз мақолаи аслӣ http://localhost:8080/clients/1 дархост иҷро кунед, хатогӣ баргардонида мешавад:
{
    "timestamp": "2020-04-02T19:20:16.073+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.javarush.lectures.rest_example.model.Client$HibernateProxy$ZA2m7agZ[\"hibernateLazyInitializer\"])",
    "path": "/clients/1"
}
Ин хатогӣ ба оғозкунии танбалии Hibernate марбут аст ва барои аз он халос шудан, мо бояд ба синфи Client тавзеҳи иловагӣ илова кунем:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
Ба ин роҳ:
@Entity
@Table(name = "clients")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Client {.....}
Акнун биёед барномаи худро иҷро кунем (пас аз хориҷ кардани ҷадвали муштариён аз пойгоҳи додаҳо, агар он дар охирин бор боқӣ монад) ва аз файли application.properties 3 сатрро шарҳ диҳед:
#spring.datasource.initialization-mode=ALWAYS
#spring.datasource.schema=classpath*:database/initDB.sql
#spring.datasource.data=classpath*:database/populateDB.sql
Дафъаи гузашта мо танҳо сатри охиринро шарҳ дода будем, аммо... Азбаски мо аллакай ҷадвалро таҳия ва пур кардаем, дар айни замон ин ба назари ман мантиқтар менамуд. Биёед ба озмоиш гузарем, дархостҳои GET, POST, PUT ва DELETE -ро тавассути Postman иҷро кунем ва мо мебинем, ки хатоҳо аз байн рафтаанд ва ҳама чиз хуб кор мекунад. Хамин аст, кор тамом шуд. Акнун мо метавонем ба таври мухтасар ҷамъбаст кунем ва чизҳои омӯхтаамонро баррасӣ кунем:
  • PostgreSQL-ро дар компютери худ насб кунед
  • Дар pgAdmin пойгоҳи додаҳо эҷод кунед
  • Ҷадвалҳоро дастӣ ва барномавӣ созед ва нест кунед
  • Ҷадвалҳоро тавассути файлҳои .sql пур кунед
  • Мо каме дар бораи интерфейси "ҷодугарӣ" JpaRepository чаҳорчӯбаи Spring фаҳмидем
  • Мо дар бораи баъзе хатогиҳое, ки ҳангоми сохтани чунин барнома пайдо мешаванд, фаҳмидем
  • Мо фаҳмидем, ки мо набояд аз маслиҳати ҳамкорон шарм кунем
  • Мо итминон дорем, ки ҷомеаи JavaRush як қувваест, ки ҳамеша ба наҷот хоҳад омад;)
Ҳоло мо метавонем дар ин ҷо ба анҷом расонем. Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot.  Қисми 2 - 4Ташаккур ба ҳамаи онҳое, ки барои хондани ин мавод вақт ҷудо карданд. Ман аз дидани эродҳо, мушоҳидаҳо, иловаҳо ва интиқоди созандаи шумо шод мешавам. Эҳтимол шумо барои ҳалли ин мушкилот роҳҳои зеботареро пешниҳод кунед, ки ман ваъда медиҳам, ки тавассути UPD "калимаи калидӣ" бо зикри шумо ҳамчун муаллиф, албатта ба ин мақола илова мекунам. Хуб, дар маҷмӯъ, нависед, ки оё ин мақола ва ин услуби пешниҳоди мавод ба шумо маъқул шуд ва дар маҷмӯъ, оё ман бояд навиштани мақолаҳоро дар JR идома диҳам. Инҳоянд иловаҳо: UPD1: корбар Юстиниан тавсия дод, ки ман бастаро com.javarush.lectures.rest_exampleба com.javarush.lectures.rest.example, ва номи лоиҳа тағир диҳам, то конвенсияҳои номгузориро дар Java вайрон накунам. Корбари UPD2 Александр Пьянов пешниҳод кард, ки барои оғоз кардани майдон ClientRepositoryдар синф ClientServiceImplбеҳтар аст аз конструктор истифода баред @Autowired. Ин бо он шарҳ дода мешавад, ки дар ҳолатҳои нодир шумо метавонед ба даст оред NullPointerExceptionва дар маҷмӯъ, ин таҷрибаи беҳтарин аст ва ман бо он розӣ ҳастам. Аз ҷиҳати мантиқӣ, агар майдон барои функсияҳои ибтидоии an object талаб карда шавад, пас беҳтар аст, ки онро дар конструктор оғоз кунед, зеро синфи бе конструктор ба an object ҷамъ карда намешавад, бинобар ин, ин майдон дар марҳила оғоз карда мешавад. ташкor an object. Ман як порчаи codeро бо ислоҳҳо илова мекунам (чиро бо чӣ иваз кардан лозим аст):
@Autowired
private ClientRepository clientRepository;

private final ClientRepository clientRepository;

public ClientServiceImpl(ClientRepository clientRepository) {
   this.clientRepository = clientRepository;
}
Истинод ба қисми аввал: Илова кардани пойгоҳи додаҳои PostgreSQL ба хидмати RESTful дар Spring Boot. Қисми 1 PS Агар касе аз шумо мехоҳад таҳияи ин замимаи таълимиро идома диҳад, пас ман бо камоли майл ба дастурҳои худ дар ин мақола пайванд илова мекунам. Шояд рӯзе ин барнома ба чизе монанд шавад, ки ба як барномаи воқеии тиҷорӣ монанд бошад, ки шумо метавонед онро ба портфели худ илова кунед. PPS Вобаста ба ин мақолаи хоксорона ман тасмим гирифтам, ки ин озмоиши қаламро ба духтарон, занон ва бонувони азизамон бахшидам. Кӣ медонад, шояд ҳоло Java, JavaRush ва барномасозӣ дар табиат вуҷуд надошт, агар ин зан намебуд . Иди шумо муборак бошад, мардуми азизи мо! 8 март муборак! Хушбахт ва зебо бошед!
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION