Информациони системи 1/JPA и REST

Извор: SI Wiki
Пређи на навигацију Пређи на претрагу

На другој лабораторијској вежби ради се JPA (Java Persistence API) и REST (Representational State Transfer). Водич испод служи за успешно постављање алата на вашем рачунару и као помоћ при најчешћим грешкама на које можете наићи при вежбању и изради лабораторијске вежбе и написан је тако да се најчешће грешке могу лако потражити.

Виртуелна машина

Пошто поставке ових алата тако да раде могу да буду компликоване, дуге и са грешкама, можете да преузмете незваничну ИС1 виртуелну машину са свим алатима већ постављеним. Ово значи да на страницама са водичима нећете морати да испратите Поставка одељке, јер су алати већ постављени за вас, као и да су неке од честих грешки већ исправљене.

Поставка

Следећи поступак би требало да вас доведе до успешне поставке како бисте били спремни за покретање неког REST пројекта са странице предмета. Инструкције за прву лабораторијску вежбу су и даље потребне.

  1. Инсталирајте MySQL Workbench. Алтернативно, покретање било каквог MySQL (или MariaDB) сервера на рачунару ће радити. На пример, можете инсталирати XAMPP, покренути MySQL сервер на њему и користити phpMyAdmin као интерфејс.
    • При инсталацији MySQL Workbench, изаберите Developer Default опцију, од које ће вам релевантне компоненте бити MySQL Server и MySQL Workbench, па уколико инсталација пријави да се нека друга компонента не може инсталирати можете је прескочити.
    • Обавезно поставите лозинку за root корисника при инсталацији. Уколико је заборавите, можете покушати да је поново поставите помоћу овог упутства. Уколико ни то не ради, најбоље инсталирајте MySQL Server изнова.
    • Да бисте покренули MySQL сервер на Windows оперативном систему, можете отворити Command Prompt као администратор и покренути следеће команде:
      cd "C:\Program Files\MySQL\MySQL Server 8.0\bin"
      mysqld --install
      mysqld --initialize
      
      затим потражити Services опцију у Старт менију, и укључити сервис са префиксом MySQL.
    • Стефан Тубић је на вежбама мењао my.ini фајл како би подесио подразумевани storage engine на InnoDB. Ово није потребно, јер је након нове инсталације storage engine већ постављен на InnoDB.
    • Уколико вас нервира што сваког дана у поноћ искаче конзола за ажурирање MySQL, можете је угасити тако што отворите Task Scheduler програм и из Task Scheduler LibraryMySQLInstaller искључите ManifestUpdate задатак.
  2. Преузмите Connector/J. Када вас пита за верзију, изаберите Platform Independent, и требало би да добијете један JAR фајл. Након тога, тај фајл можете убацити у директоријум са вашом инсталацијом GlassFish сервера, у директоријум glassfish/lib.
  3. Покрените NetBeans и GlassFish сервер. Уколико је био покренут пре него што сте убацили Connector/J, зауставите га и поново покрените.
  4. Направите нови JDBC Connection Pool. Параметри су следећи:
    • Resource Type: javax.sql.DataSource
    • Database Driver Vendor: MySql
      • Уколико сте на GlassFish 5.0 и пређете преко текстуалног поља након Database Driver Vendor, вредност ће бити избрисана.
    • Datasource Classname: com.mysql.cj.jdbc.MysqlDataSource
    • У додатним својствима конекције подесити:
      • password: Лозинка вашег MySQL корисника, не сме да буде празна и можете је променити из MySQL WorkbenchAdmnistrationUsers And Privileges (или користећи ALTER USER)
      • databaseName: Назив ваше MySQL базе
      • serverName: localhost
      • user: Назив вашег MySQL корисника, подразумевано постоји корисник са називом root.
      • portNumber: Подразумевано 3306, али понекад MySQL Workbench може да постави на 3308.
  5. Тестирати Connection Pool користећи Ping дугме.
    • Уколико добијате грешку у вези са com.mysql.cj.jdbc.MysqlDataSource или неким keystore фајлом (Keystore was tampered with...), пробајте да преко дугмета Add Property у Additional Properties табу додате својство useSSL са вредношћу false.
      • Уколико након овога добијате грешку у вези са public key retrieval, додајте својство allowPublicKeyRetrieval и поставите га на true.
    • Уколико и након корака изнад добијате грешку у вези са драјверском класом, проверите да ли сте на добро место убацили JAR фајл од Connector/J. Уколико имате више GlassFish сервера на рачунару, проверите да ли сте у добар сервер убацили. Пробајте да поред glassfish/lib убаците JAR фајл и у glassfish/bin и domains/domain1/lib.
    • Уколико као грешка изађе "Communications link failure", проверите да ли вам је укључен MySQL сервер, односно да ли можете да се на њега повежете из неког другог програма, попут MySQL Workbench. Такође проверите да ли гађате добар порт, пошто је подразумевани порт 3306, а не 3308 како је показано на вежбама.
    • Уколико у било ком тренутку поставке GlassFish сервер избаци грешку у вези са getOutputStream(), само покушајте поново.
  6. Направити JDBC Resource са новонаправљеним Connection Pool као конекцијом.
  7. Унутар NetBeans у ServicesDatabases кликните десним кликом на Drivers и изаберите New Driver.
  8. Код Driver File(s) изаберите Add и онда изаберите Connector/J JAR фајл који сте убацили у glassfish/lib директоријум, па додајте драјвер.
  9. Требало би да вам постане доступна опција Register MySQL server при десном клику на ServicesDatabases. Када то изаберете, можете додати параметре вашег MySQL сервера сличне онима које сте додавали за JDBC Connection Pool.
    • Овај корак вам омогућава да изаберете ову конекцију када радите NewEntity Classes from Database.
  10. У вашем persistence.xml фајлу, у Source табу, сада можете заменити садржај <jta-data-source> тага са називом вашег JDBC ресурса.
  11. Као додатан алат за тестирање ваше REST апликације можете преузети Postman.

Уколико покрећете нови REST пројекат, изаберите Java with MavenWeb Application. Обавезно гледајте GlassFish Server таб како бисте уочили грешке које се јављају током извршавања.

Проблеми са окружењем

  • Уколико сте направили нови празан пројекат и он не може да вам се покрене због грешке попут "Unable to load the mojo 'war' in the plugin 'org.apache.maven.plugins:maven-war-plugin:2.3' due to an API incompatibility", могуће је да имате више верзија JDK (Java Development Kit) инсталираних на рачунару, и да подразумевани JDK није подешен на 1.8. Покушајте да обришете остале JDK са рачунара, и да поставите подразумевани на 1.8. Подразумевани JDK може да се мења додавањем путање до JDK 1.8 у netbeans_jdkhome опцију у netbeans.conf фајл, или једноставно реинсталацијом NetBeans. (Овај проблем је решен на ИС1 виртуелној машини.)
  • Уколико имате проблема са генерисањем ентитетских класа, попут тога да се генеришу празне класе, инсталирајте NetBeans верзију 12.0. (Овај проблем је решен на ИС1 виртуелној машини.)
    • Уколико вам се ентитетске класе генеришу без JAXB анотација и немате опцију да то изаберете приликом генерисања, проверите да ли вам је верзија JDK добро подешена за пројекат, а онда урадите Clean and Rebuild.
  • Уколико добијате грешку <entitet> cannot be added because it is already mapped to the <klasa> entity class and the entity is not in current project source приликом генерисања ентитетских класа, потребно је да очистите NetBeans кеш из %LOCALAPPDATA/NetBeans/Cache директоријума (можете му приступити тако што ту путању куцате у прозор који се појави када притиснете Windows дугме + R).

Грешке у коду

  • Уколико вам се деси HTTP грешка 404 (Not Found):
    • Прво проверите да ли сте добро уписали путању endpoint-а. Endpoint-ови су генерално на путањи localhost:8080/ProjectName/ApplicationPath/ResourcePath/EndpointPath, где:
      • ProjectName је име вашег пројекта, на пример restapi,
      • ApplicationPath је одређено анотацијом @ApplicationPath изнад главне класе вашег пројекта, односно класе изведене из Application (подразумевано постављено на resources),
      • ResourcePath је одређено анотацијом @Path изнад класе ресурса којем приступа, на пример popravke, и
      • EndpointPath је одређено анотацијом @Path изнад методе за тај endpoint.
    • Уколико је endpoint сигурно добар, могуће је да је апликација undeploy-ована због неке грешке у тренутном пројекту или некој од претходних итерација. Можете покушати да рестартујете GlassFish сервер и пратити сервер лог (GlassFish Server таб у Output прозору) да видите уколико се појављује нека грешка.
  • Уколико вам се дешава HTTP грешка 500 (Internal Server Error), требало би да део грешке видите на страници, али целу грешку можете пронаћи у сервер логу.
  • Уколико вам се у endpoint методи нађе аргумент без анотације поред себе, такав аргумент се шаље кроз тело (body) захтева, и у Postman треба поставити body на raw опцију. На пример, String аргумент се шаље са типом садржаја text/plain (Text опција у Postman), док се тип садржаја неке друге класе шаље као XML репрезентација те класе са типом садржаја application/xml (XML опција у Postman).
  • Уколико добијате TransactionRequiredException грешку при слању упита на неки endpoint, проверите да ли сте ставили @Stateless анотацију изнад класе ресурса.
  • Уколико добијате HTTP 405 (Method Not Allowed) грешку, то вероватно значи да шаљете GET захтеве на endpoint који прима захтеве само преко других метода.
  • Уколико вам се приликом враћања одговора са сервера деси StackOverflowException, вероватно вам се десила бесконачна рекурзија при серијализацији објекта због недостатка @XmlTransient анотације која спречава серијализацију неког поља. То се обично дешава када класа A има поље типа B или List<B>, а класа B поље типа A или List<A>, па серијализатор ради следеће:
    1. креће са серијализацијом објекта класе A,
    2. нађе његово поље типа B и види да нема анотацију @XmlTransient,
    3. креће са серијализацијом објекта класе B,
    4. нађе његово поље типа A и види да нема анотацију @XmlTransient,
    5. поново креће са серијализацијом истог објекта класе A и тако у круг...
    • Пример овога може да буде са вежби са компанијом за превоз, где, уколико ентитет Zaposlen не би имао @XmlTransient анотацију изнад getMehanicar() или getVozac() методе, дешавала би се бесконачна серијализација тих ентитета.

Грешке на вежбама

  • Стефан Тубић на вежбама за MySQL сервер користи порт 3308. Стандардни и подразумевани порт за MySQL је 3306, тако да би требало да тај порт користите осим ако га нисте мењали.
    • Ако имате више од једног MySQL сервера на рачунару, можда буде потребно да једном промените порт. Могуће је да је због овога Стефану Тубићу порт био промењен на 3308.
  • Стефан Тубић је пред крај једних вежби направио грешку када је писао persistence.xml фајл и написао <jta-data-resource> уместо <jta-data-source>, па је на следећем снимку учитао готов пројекат и грешку приписао погрешној верзији Јаве. Ово вам може правити проблем уколико вам се јавља грешка како табела Kamion не постоји. Такође, у истом том persistence.xml фајлу је писало transactionType уместо transaction-type, што вам исто може правити проблем.
  • У готовом пројекту за компанију за превозе (kzp, пројекат restapi) у Mehanicari.java фајлу налази се @PersistenceContext(unitName = "my_persistence_unit"), иако се јединица перзистенције зове Zad3PU. То може проузроковати неке грешке, барем у овом ресурсу. (Овај проблем је исправљен у пројекту на ИС1 виртуелној машини.)
  • У том истом пројекту, на /api/users/{datum} endpoint није могуће послати упит док се мало не промени путања, јер иначе JAX-RS не зна да ли се упит шаље ту или на /api/users/{idUsr} endpoint (иста путања, различит параметар).

Лабораторијска вежба

  • На лабораторијској вежби је дата слика базе у поставци, креденцијали за базу, опис поставке JDBC ресурса, dump фајл базе који можете да увезете кроз MySQL Workbench и материјали са странице предмета у директоријуму Materijal za drugu laboratorijsku vezbu.
  • Лабораторијска вежба, уколико нема аутоматских тестова, се не прегледа нарочито детаљно. Бодови се добијају на лицу места.
  • Подразумевана JDK верзија на лабораторијским рачунарима је JDK 11, па је након прављења пројекта потребно да је промените на JDK 8 у PropertiesCompile.