Jump to content
Geekforum.cz

Bindik

Gays
  • Posts

    316
  • Joined

  • Last visited

  • Days Won

    26

Reputation Activity

  1. Like
    Bindik reacted to Ariczek in [jsoup] Parser webu   
    V dnešním díle nepravidelného cyklu se podíváme na to, jak v javě parsovat html stránku.
     
    Spousta webů dneska se proti parsování snaží bránit. Různý redirecty, javascript a podobně.
    Aby dokázal Java program si poradit i s takovými weby, musí si v principu zahrát na webový prohlížeč.
     
    Na pomoc si vezmeme již vytvořenou knihovnu jsoup - https://jsoup.org/
    Web obsahuje i cookbook, jak se s knihovnou pracuje.
     
    S pomocí této knihovny je napsání parseru poměrně triviální záležitost.
    Ukážeme si to na reálném webu - http://1url.cz/ptb6J, knihovna si poradí i s redirect, takže správně zpracovává až ov.ihned.cz
     
    Jako první krok potřebujeme načíst stránku, to se provede:

    // fetch URI and parse Document doc = Jsoup.connect(url).get();
     
    Hledáme na stránce tabulku, pro každý její řádek chceme vypsat IČO a datum.

    // we are looking for a table Elements tables = doc.select("table"); // there should be just one, but use foreach, just to be sure for (Element table : tables) { // need rows Elements rows = table.select("tr"); for (Element row : rows) { // need columns Elements cols = row.select("td"); // basically, the first row will not have any td, skip if (cols.size() > 2) { // // needed there just to get URL, if wanted // Element link = cols.get(0).select("a").first(); // control what will be printed. ICO, date System.out.println(String.format("%s, %s", cols.get(2).text(), cols.get(4).text()); } } }
     
    Fórko s tím vložením kódu pracuje úplně na nic, tak snad si to rozluštíte
     
    V případě potřeby pro daný záznam máme připraven i link na samotný zápis, který by se zase otevřel a zpracoval.
    Enjoy!
     
    Ariczek
  2. Like
    Bindik reacted to Wladass in Rok 2017   
    Byl pro Vás něčím zajímavý? Čeho jste v tomto roce dosáhli a čeho litujete? Jaké jsou Vaše plány na rok 2018? Pochlubte se.
  3. Like
    Bindik reacted to Ariczek in Rok 2017   
    Když nad tím tak přemýšlím, tak rok 2017 pro mě byl šedý a nezajímavý...
    Práci mám pořád stejnou, letos žrala extrémně času. Všechno ostatní šlo tak nějak do kelu. Vyjma práce jsem neměl na nic čas.
    Aspoň drobný pozitivum - vím, že dokážu vést 2 denní kurz IT v angličtině.
     
    Doufám, že 2018 bude zajímavější, asi se budu muset řídit dle YOLO.
  4. Like
    Bindik reacted to odysey in BuboCloud, VIP VPS SSD Hosting!   
    Já se k tý bezpečnosti raději ani nevyjadřuju. Brečím z toho jak je to děravé ještě teď..
  5. Like
    Bindik reacted to Jamira40 in Minecraft   
    Ari i keď ti sem asi nik neodpíše ja sa pridám
     
    1. FTB Infinity Evolved
    2. Žiadne len to čo je s modom
    3. Multiplayer, Skype a pivko
    4. Privátny server
  6. Like
    Bindik reacted to Wladass in 2017   
    Já jsem přestal chlastat a zatím to celkem zvládám
  7. Like
    Bindik reacted to Wladass in Geekbazar.cz   
    Proběhl redesign menší viz. http://www.geekbazar.cz/
    Nějaké další postřehy?
     
    Za logo thx Bindikovi
  8. Like
    Bindik reacted to Jamira40 in Geekbazar.cz   
    Wlade áno pošlem ti banner na reklamu :D
    Ako sponzor hostingu
  9. Like
    Bindik reacted to Ariczek in Nah! Hry zadarmo berte si to! ;)   
    NEVERWINTER NIGHTS DIAMOND
     
    https://www.gog.com/...diamond_edition - ještě cca 48 hodin bude k dispozici zadarmo, berte.
     
    https://twitter.com/...278951967412232 enjoy!
  10. Like
    Bindik got a reaction from Ariczek in Blogr.cz - rádi uvítáme všechny blogery   
    A niekto napr. ani facebook nema
  11. Like
    Bindik got a reaction from Henzigo in Funny topic - Věci co vás pobavily   
  12. Like
    Bindik got a reaction from Wladass in Funny topic - Věci co vás pobavily   
  13. Like
    Bindik reacted to Henzigo in Funkcia header - nefunguje   
    Copen a jeho další epicky velký projekt :lol:
  14. Like
    Bindik reacted to Wladass in Kto sme / ste?   
    Kdo jsi ty?
  15. Like
    Bindik reacted to Ariczek in Kto sme / ste?   
    Ahoj, jmenuju se ariczek a jsem alkoholik...
     
    THX Bindik za inspiraci
  16. Like
    Bindik reacted to ntdrt in Driver Booster   
    Nehrab se v ovladačích, pokud to funguje. Maximálně stáhni nejnovější ovladače pro grafiku (z nvidia/amd.com). Zbytek ovladačů nech být, pokud to funguje/je to stabilní. Na USB/chipsetu/síťový kartě a já nevím na čem ještě, nemáš co vylepšovat, můžeš to akorát rozbít .
     
    A platit za nějakej náhodnej vyhledávač, co instaluje bůh ví co... To určitě ne. Když už, tak si najdi stabilní verzi ovladačů z oficiálních stránek a neinstaluj náhodný verze, co najdeš na netu.
  17. Like
    Bindik reacted to ntdrt in Struktura databáze   
    ORM je v PHP stejně tak dlouho, jako je v .NET. Doctrine september 2008. Entity framework august 2008. Což se okopírovalo z Javy - Hibernate 2001. Není to nic speciálního, i blbej JavaScript má ORM .
     
    Jinak na složitý selecty se ORM vůbec nehodí. Máš sice krásný API, ale to v pozadí generuje pěkný hovadiny a musíš se hodně snažit, aby framework pokládal optimalizovaný dotazy. ORM je určený hlavně na tuctový CRUD aplikace. Kde se operace pořád dokola opakujou. Ne na projekty, kde budeš mít v podstatě pár super-selectů. Tam ti to práci jen přidělá a mapping na entity ani neoceníš.
     
    --
     
    Jinak velký tabulky nejsou problém, databáze sou navržený (MySQL, MS SQL Server, Postgres, cokoliv co si vybereš), aby zvládaly miliony a miliony záznamů v jedný tabulce. Stovky milionů řádků není problém. V tomhle případě je klíčem optimalizace a využívání indexů. Pokud budeš vyhledávat podle sloupců, který maj index a datový set hned omezíš, tak není problém, aby ti MySQL vrátil subset dat do pár ms i když bude tabulka gigantická. MySQL zvládá při správném zacházení i miliardy záznamů v jedný tabulce.
  18. Like
    Bindik reacted to glararan in Pomoc s objektovým javascriptem   
    Protože callback se volá z daného elementu nikoliv z třídy, kde jí máš deklarovanou.
     
    Musíš udělat něco takovéhoto

    var instance = null; function LinkTrack() { instance = this; // ... }
     
    a pak následně v callbacku říct "instance.vlastnost"
     
     
    To stejné jako jsem vysvětloval nahoře... opět callback je z jiného elementu, který instanci nezná.
  19. Like
    Bindik reacted to Jamira40 in VPS Hosting - 1. mesiac 0€ - AKCIA   
    Seruste všedcia na Geekfore. Mám tu pre vás takú menšiu akciu.
    Ostalo pár volných VM bežne nie sú dostupné na prenájom... exon stále nemá web **joke**
     
    Ak by niekto mal seriózne záujem sú dostupné nasledovné parametre. Dostupnosť je ihneď.
    Inštalácia OS je cez vSphere klienta. Môžete si naištalovať čo chcete. Linux, Windows etc...
    Na žiadosť nainštalujeme Linux podla výberu zadarmo.
     

    Procesor: 2x vCPU Intel Xeon E3-1231v3 @3.4Ghz
    Pamäť: 2GB DDR3
    Disk: 60GB (možnosť dohodnúť sa na viac)  
    Cena: 8€ (9.60€ vrátane DPH) mesačne. 1. mesiac zadarmo.
     

    Procesor: 2x vCPU Intel Xeon E3-1231v3 @3.4Ghz
    Pamäť: 4GB DDR3
    Disk: 120GB (možnosť dohodnúť sa na viac)  
    Cena: 13€ (15.60€ vrátane DPH) mesačne. 1. mesiac zadarmo.

    Konekt: 1Gbps (traffic shaping na 300Mbit/s)
    IP: 1x IPv4 + Možnosť dokúpiť si ďalšie IP
    Virtualizácia: vmware + pristup na vSphere  
    Pokiaľ by chcel niekto custom VM. Dá sa dohodnúť stačí napísať.
    Kontaktovať ma môžete cez PM na GF prípaden [email protected] alebo skype craft3001.
  20. Like
    Bindik reacted to LMRig in Jak vybrat správnou herní grafickou kartu   
    Hodně lidí v dnešní době si pořizuje PC jen na hraní her. Proto byste měli svoji pozornost při vybírání věnovat hlavně grafické kartě. Samozřejmě jsou i hry, které těží hlavně z výkonu CPU, patří mezi ně například CS:GO a celkově jejich Source Engine. Většina her, ale těží právě z grafické karty.
     
     
    Hlouposti, na které narazíte:
     
    Větší paměť = více výkonu
    - ano, toto opravdu platí, ovšem pokud karta umí paměť využít a je možno ji využít -> vyšší rozlišení, vysoké nastavení textur.
    Jsou karty (např. GT630), které disponují 4GB VRAM, ovšem jejich jádro je tak slabé, že je v životě nemůžou využít. Není vůbec určena na hraní, maximálně starších her. Je určena hlavně uživatelům, co sledují filmy, pracují v nenáročných programech atp.
     
     
    AMD CPU = AMD GPU / Intel CPU = Nvidia GPU
    - opravdu nemusíte používat tyto kombinace CPU a GK, jsou mezi sebou kompatibilní a nenesou vůbec žádné mínusy nebo problémy. Je úplně jedno jestli dáte Intel CPU, AMD GK, je to to stejné, jako dávat MSI GK do ASRock desky, ničemu to nevadí.
     
     
    Nvidia má lepší grafiky / AMD má lepší grafiky
    - o tomto se již šířilo mnoho debat, válek mezi uživateli obou výrobců. Realita je taková, že žádný z výrobců, není horší nebo lepší. Vždycky konkurence vydá stejně výkonnou kartu, aby mohla soupeřit s kartami toho druhého. Je pravda, že AMD má častěji vyšší spotřebu, to se ale s příchodem nových R9 NANO, Fury,... zlepšilo. Technologie má každý výrobce svoje, většina jsou si podobná, jen každá funguje ve svém teritoriu.
     
     
    GDDR5 = Nekompatibilní s deskami s DDR3
    - toto je samozřejmě nesmysl, je to podobné, jako u kombinace AMD/AMD, Intel/Nvidia. Karta má svoje paměti, deska má svoje paměti, na toto nemusíte brát vůbec ohled.
     
     
    Výběr
     
    Cena
     
    Asi nejdůležitější věc, při výběru karty. Často nejdražší komponenta v sestavě. Rozdělit je můžeme do low-endu, mainstreamu a hi-end.
     
    Pokud budeme počítat s PC na hry, nemá opravdu smysl kupovat karty pod 2500Kč, kde už se pohybují už jenom takové karty, které já nazývám jako "pouze zobrazovače plochy" (730 / 740 / 240).
     
    Takové použitelnější už se jeví 750Ti / 260X po 1050 / 460 .
    Mainstreamem se dnes již myslí R9 270X / 470 až po 290X / 1060 / 480 / 390X / Nano / 970 / 780Ti, pomalu už i 980 a 1070.
    Hi-end samozřejmě 980Ti / Fury X / 1080 ....
     
     
    Brát ohled musíme samozřejmě i na CPU, je zbytečné kupovat i7 k 270X a naopak 980 k i3.
     
     
     
    Externí výrobci
     
    Druhá věc, která bude rozhodovat při vašem výběru, bude od jakého výrobce, nemyslím tím už Nvidia nebo AMD, ale výrobce, kteří kartu upravují po svém - chladič, PCB, součástky, frekvence.
     
    V ČR jsou obecně nejrozšířenější MSI, Gigabyte, ASUS, Sapphire, Evga.
    Méně známí Palit, Gainward, Zotac, na bazarech někdy i Club3D.
     
     
    Kvalitativně jsou na tom nejlépe MSI, Gigabyte, ASUS, Evga. Z těch výrobců, co u nás jsou špatně k sehnání je to např. Club3D, Zotac vyšší verze, Inno3D, KFA2. Bohužel u nás právě jen s dvouletou zárukou.
     
    Dále se karty řadí do různých edic, od limitovaných až po stálé vyšší a nižší. Pokud chcete opravdu tu nejkvalitnější kartu od daných výrobců, jsou to např. tyto:
     
    MSI - Hawk, Lightning
    ASUS - ROG
    Gigabyte - Extreme
    Sapphire - Toxic
    EVGA - Kingpin
     
    Tyto karty mají většinou pár věcí, které ulehčí taktování. Vždy mají lépe řešené chlazení, napájení a více součástek, které pomáhají stabilitě a vyššímu taktování.
     
     
    Zdroj
     
    Ovšem to nejhlavnější, podle čeho musíte kartu vybírat je - zdroj. Nejdůležitější komponenta v PC, s nekvalitním zdrojem, můžete přijít o jednu, ale také o všechny komponenty, pokud jeho ochrana selže.
     
    U nás nejprodávanější kvalitní výrobce zdrojů, je bezpochyby Seasonic, již od OEM verzí až po jejich top edice se jedná o kvalitní zdroje s kvalitními součástkami, nižší verze sice nemají např. opletené kabely nebo mají vyšší zvlnění, ale velmi málo se stává, že by tento zdroj vyhořel a případně s sebou vzal jinou komponentu.
     
    Další, kteří se řadí mezi ty kvalitnější, jsou např. Corsairy. Jejich řady RM a výše, jsou velmi kvalitní. Nejnižší řada, kterou poradím, jsou CXxxxM Buildery.
     
    Celkem nedávno se u nás objevily zdroje od Evgy. Verze G2 a GS jsou to nejkvalitnější, co od těchto výrobců můžete pořídit a přitom stojí na svou kvalitu velmi málo. Po registraci do 14 dní od koupě na ně máte 10 let záruku a nabízí i semipasivní režim.
     
    Většinou můžete v obchodech u karet napsáno "Doporučený výkon zdroje". Tyto hodnoty mohou být docela matoucí, u karet, které potřebují maximálně 250W najdete 600W zdroj, přitom celá sestava bude mít maximálně 500W. Je to hlavně z toho důvodu, když si někdo koupí 600W Zalman, který je rád za to, že se vůbec dostal na trh. Případně kdybyste vlastnili 200W AMD CPU .
     
    Levné dostatečně kvalitní zdroje jsou ještě např. Fortron Hexa+ a Fortron Hyper.
     
     
     
    Rada: Jestliže se rozmýšlíte mezi několika stejnými kartami (např. 4x 1060 atp.). Vyberte si tu nejlevnější nebo tu, která má u sebe nejvíce věcí navíc (bývají to myši, kódy na hry, podložky a jiné...), které můžete prodat. Důvod je jednoduchý, většinou se karty od různých výrobců za podobnou cenu liší jenom tím, jaké mají frekvence, ovšem těchto frekvencí můžete na 90% případů dosáhnout i sami (tento odstavec se netýká karet, které se liší použitým chladičem, tam už je pak rozdíl klidně znatelný - hlučnost, teploty, kvalita PCB a součástek).
     
     
    Pokud vás napadá, co bych mohl doplnit nebo mám někde chyby, dejte prosím vědět.
    Díky a přeju šťastný výběr.
  21. Like
    Bindik reacted to odysey in Funny topic - Věci co vás pobavily   
    Jakožto sysadmin potvrzuji

  22. Like
    Bindik reacted to Jamira40 in Funny topic - Věci co vás pobavily   
  23. Like
    Bindik reacted to Hookyns in [Node.js] Jumbo - web framework   
    Zase pár úprav.
     
    Jelikož už na tom frameworku něco stavím, tak budou úpravy asi častější a jak v tomto případě, budou to praktické věci.
     
    Přidal jsem možnost live editace kódu. Na node.js je na prd, že když člověk něco upraví, musí restartovat aplikaci, aby se změny projevily. Dvakrát tak otravné to je, když člověk kóduje šablonu. Pro každý pixel restartovat aplikaci,.. To je prostě na prd.
    Já jsem Jumba upravil tak, aby si hlídal změny v souborech a mazal require.cache z Node.js - případ úpravy JS kódu - presentery, modely aj.
    Do Jumbovi template cache jsem přidal detekci no-cache požadavku (ctrl+F5 na stránce), takže při změně template stačí na webu dát ctrl+F5 a aktualizuje se template cache.
    Další věc je LESS. Jumbo primárně podporuje stylování v LESS, které automaticky při startu kompiloval na CSS. Zde byl problém při stylování template. Člověk upraví LESS, ale musí restartovat aplikaci, aby se LESS zkompiloval. Tomu je už konec. Přidal jsem i detekci změn u .less souborů, které se po změně automaticky zkompilují.
     
    Další věc byla úprava u posílání statických souborů. Aby se zrychlila odpověď serveru, jestli soubor existuje nebo ne, jestli má požadavek zpracovávat node-static nebo normálně server, tak byl v Jumbovi při startu vytvářen seznam statických souboru na jehož základě se poté rozhodovalo, jestli bude požadavek zpracovávat node-static nebo Jumbo. Pokud jsem však do složky public přidal obrázek až po startu serveru, tak nebyl v seznamu a požadavek šel na Jumba, který však pod adresou nic nenašel. Takže opět byla přidána detekce změn na složku public a každý nově přidaný soubor se přidá i do seznamu statických souborů.
     
     
    A jedna z hlavních věcí co jsem potřeboval na projekt bylo zprovoznění modulů/sub-applikací. Tak jak Nette podporuje moduly, tak má jumbo sub-apps. Jenže Nette to bere z url domena.tld/modul/presenter/akce a Jumbo je frajer, protože si s URL může dělat co chce, tak podporuje sub-app.domena.tld/presenter/akce.
     
     
    Shrnuto.
    Lze vytvářet sub-apps - můžu mít normálně web a na subdoméně např. admin můžu mít CMS.
    Lze editovat kódy LIVE - automatická live kompilace LESS souborů za běru, ctrl+F5 pro reload template cache, mazání require.cache při změně JS.
  24. Like
    Bindik reacted to Hookyns in Fce pro snadné OOP v JS   
    Zdravím,
     
    když už vám zde káži slovo boží a snažím se vám JS přiblížit, tak vám zde poskytnu i svou fci, se kterou tvořím třídy.
     
    Donedávna jsem používal celkem jednoduchou fci, která neměla přes 50 řádků, ale na reakci kolegy v práci, že JS nemá privátní vlastnosti u tříd, jsem svou fci trošičku vylepšil. OOP v JS je celkem krkolomné a složitější konstrukce vyžadují hlubší znalosti.
     
    Je několik způsobů jak vytvořit private vlastnosti a metody u tříd, ale většina je jich špatně. Způsob, který jsem vymyslel je imho asi jeden z nejlepších.
     
    BTW, zkoumal jsem zpětně ještě jiné metody řešení private vlastností u tříd v JS a našel jsem skoro to samé řešení jako mé, takže asi nejsem zase takový frajer. To řešení však není zrovna jednoduché, takže jsem byl vážně překvapený, že to napadlo i někoho jiného.
     
    Díky mé fci je možné vytvořit třídy s public a private statickými vlastnostmi/metodami a klasickými private a public vlast./met.
     
     
    Jen pro představu. Jeden z celkem rozšířených a poměrně špatných způsobů tvorby tříd je toto:

    var MojeTrida = function(xxx, yyy) { var privatniVlastnost = xxx; this.publicVlastnost = yyy; var privateMethod = function() { return "foo"; } this.publicMethod = function() { return "bar"; } };
     
    Použití lokální proměnné zde není špatně, ale abychom se k ní mohly dostat, musíme zde definovat i metody, a to už špatně je. V první řadě se budou metody vytvářet při každém zavolání konstruktoru a zbytečně se budou znovu a znovu vytvářet i když jsou všechny stejné. Druhý problém je dědičnost. Když nevyužijeme prototype, tak nedocílíme dědičnosti. Tohle řešení se dá použít, pokud nemáte v plánu používat dědičnost, nezáleží vám na výkonu a nutně potřebujete private vlastnosti. Jinak je to nepoužitelné.
     
     
    Já třídy vytvářím pomocí své fce Class, která třídy za mě sestaví a umožní mi i pohodlnou dědičnost i implementaci interface.
     
    Má fce:

    /** * Funkce pro vytáření tříd * @param defs * @returns {{class: *, privateAccessor: Function, extends: (Function|*), implements: (Function|*), private: {constructor: *}}} */ var Class = (function() { var classIdCounter = 0; var classPrivateProperties = {}; return function(defs) { var classId = classIdCounter++; classPrivateProperties[classId] = {}; var privateProperties = classPrivateProperties[classId]; var idCounter = 0; var constructor; var hasPrivateConstructor = false; var ctor; var p = function(self) { return classPrivateProperties[self.classprivateCallIdentifier][self.privateCallIdentifier]; }; if (defs.hasOwnProperty("constructor")) { ctor = defs.constructor; constructor = function() { if (this.constructor == ctor) { // V případě že dědíme, můžeme volat super konstruktor => Pokud bychom ho zavolali, došlo by k namixování private identifikátorů privateProperties[idCounter] = {}; // Uložíme privátní vlastnosti if (typeof defs.private === "object") { for (s in defs.private) { if (defs.private.hasOwnProperty(s) && s != "constructor") { privateProperties[idCounter][s] = defs.private[s]; } } } this.privateCallIdentifier = idCounter++; this.classprivateCallIdentifier = classId; } defs.constructor.apply(this, arguments); }; } else if (defs.hasOwnProperty("private") && defs.private.hasOwnProperty("constructor")) { ctor = function() { throw new Error("This class's constructor is private!"); }; constructor = function() { privateProperties[idCounter] = {}; // Uložíme privátní vlastnosti if (typeof defs.private === "object") { for (s in defs.private) { if (defs.private.hasOwnProperty(s) && s != "constructor") { privateProperties[idCounter][s] = defs.private[s]; } } } this.privateCallIdentifier = idCounter++; this.classprivateCallIdentifier = classId; defs.private.constructor.apply(this, arguments); }; hasPrivateConstructor = true; } else { ctor = function() {}; constructor = function() { if (this.constructor == ctor) { privateProperties[idCounter] = {}; // Uložíme privátní vlastnosti if (typeof defs.private === "object") { for (s in defs.private) { if (defs.private.hasOwnProperty(s) && s != "constructor") { privateProperties[idCounter][s] = defs.private[s]; } } } } this.privateCallIdentifier = idCounter++; this.classprivateCallIdentifier = classId; } } // Pokud definice obsahují konstruktor, vytvoříme jej, jinak použijeme prázdnou fci var c = hasPrivateConstructor ? ctor : constructor; /** * Pole zaznamenávající které objekty třída implementuje * @type {Array} * @private */ var implementations = []; var implementsFunc; var extendsFunc; var privateCtor; /** * Ověřuje, zda třída používá dané rozhraní * @param {Object} o * @return {Boolean} */ var implementationFunc = function(o) { if (o !== defs) { if (implementations.indexOf(o) != -1) { return true; } } return false; }; /** * Slouží k podědění třídy * @param {Function} parent Třída k podědění * @return {{class: Function, privateAccessor: Function}} */ extendsFunc = function(parent) { if (typeof parent === "function") { c.prototype = Object.create(parent.prototype); c.super = parent.prototype; c.prototype.super = function() { parent.apply(this, arguments); //parent.apply(this, arguments); }; // Zkopírujeme také statické vlastnosti z předka for (var prop in parent) { if (parent.hasOwnProperty(prop) && prop != "super" && prop != "constructor") { c[prop] = parent[prop]; } } // Musíme znovu nabalit vlastní metody, protože podědění nám smaže existující prototype - bohužel je to nevýhoda pozdního volání Extends implementsFunc(defs); c.prototype.implementationOf = implementationFunc; // Aktualizujeme c.prototype.constructor = ctor; } return { /** * @type {Function} */ class: c, privateAccessor: p, extends: extendsFunc, implements: implementsFunc, private: { /** * @type {Function} */ constructor: privateCtor } }; }; /** * Slouží k převzení prvků z objektu/interface. Jedná se o mixing což se dá nazvat jako implementace rozhraní. * @param obj {Object} Objekt/interface * @return {{class: Function, privateAccessor: Function}} */ implementsFunc = function(obj) { if (obj !== defs) { if (implementations.indexOf(obj) != -1) { console.log("Toto rozhranní je již implementováno"); return c; } implementations.push(obj); } // Přidáme vlastnosti na náš prototype var objs = Object.getOwnPropertyNames(obj); var count = objs.length; var objsp; for (var p = 0; p < count; p++) { objsp = objs[p]; if (objsp != "static" && objsp != "private" && objsp != "constructor" && objsp != "private_constructor" && (typeof c.prototype[objsp] == "undefined" || obj === defs)) { c.prototype[objsp] = obj[objsp]; } } if (obj === defs && !c.prototype.hasOwnProperty("destructor")) { c.prototype.destruct = function() { delete privateProperties[this.privateCallIdentifier]; }; } return { /** * @type {Function} */ class: c, privateAccessor: p, extends: extendsFunc, implements: implementsFunc, private: { /** * @type {Function} */ constructor: privateCtor } }; }; var s; // Uložíme statické vlastnosti if (typeof defs.static === "object") { for (s in defs.static) { if (defs.static.hasOwnProperty(s)) { c[s] = defs.static[s]; } } } // Nabalíme požadované metody na konstruktor, využijeme naší metody Implements implementsFunc(defs); // Nastavíme constructor na konstruktor c.prototype.constructor = ctor; c.constructor = ctor; c.prototype.implementationOf = implementationFunc; // Privátní konstruktor if (hasPrivateConstructor) { var Trida = constructor; Trida.prototype = c.prototype; Trida.constructor = ctor; //Trida.prototype.constructor = c; privateCtor = Trida; } return { /** * @type {Function} */ class: c, privateAccessor: p, extends: extendsFunc, implements: implementsFunc, private: { /** * @type {Function} */ constructor: privateCtor } }; }; })();
     
    250 řádků nadbytečného balastu.
    Ale řekněte sami, jestli se to vyplatí.
     

    var Osoba = (function() { var p; var Cls = Class( { private: { jmeno: "", prijmeni: "" }, constructor: function(jmeno, prijmeni) { p(this).jmeno = jmeno; p(this).prijmeni = prijmeni; this.normalniPublicVlastnost = jmeno + " " + prijmeni; }, getJmeno: function() { return p(this).jmeno; }, getPrijmeni: function() { return p(this).prijmeni; }, toString: function() { return "Osoba:" + this.getJmeno() + " " + this.getPrijmeni(); } } ); p = Cls.privateAccessor; return Cls.class; })();
     
    Zápis je kvůli přístupu k privátním vlastnostem trochu složitější. Je třeba, aby má fce Class vracela accessor k private vlastnostem a kvůli tomu musí být také celá třída obalena anonymní fcí, aby tento accessor nebyl veřejný.
     

    BTW dřívější zápis bez private vlastností vypadal takto:




    var Trida = Class({
    constructor: function(foo, bar) {
    this.foo = foo;
    this.bar = bar;
    },
    pblicMethod: function() {
    ...
    }
    });



    Žádná věda, jen zavolám třídu se seznamem metod a hotovo.


     
    Třídu osoba můžeme jednoduše podědit.

    var Student = (function() { var p; var Cls = Class({ private: { skola: "" }, constructor: function(jmeno, prijmeni, skola) { this.super(jmeno, prijmeni); p(this).skola = skola; } }).extends(Osoba); p = Cls.privateAccessor; return Cls.class; })();
     
    Funkce Class vrací objekt, který obsahuje pár položek. Hlavní položka je class, která obsahuje výslednou funkci s prototypem, která tvoří třídu. Další položky jsou třeba právě extends a implements. Obě položky jsou fce, které naši třídu upraví. Extends vytvoří potomka třídy. Implements načte položky z "interface" v JS obyčejný objekt. To by samo o sobě ale nemělo moc velký význam, tak je k prototypu všech tříd přidána metoda .implementationOf(), kterou můžeme ověřit, jestli je třída implementací některého rozhranní.
     
    Zde jsme tedy použili fci extends a podědili jsme třídu Osoba. Z konstruktoru i volám konstruktor předka.
    BTW, ony privátní vlastnosti jsou ve skutečnosti spíše protected, protože v JS nemá moc cenu řešit private/protected, protože i kdyby vlastnosti neexistovali, tak si je JS přece vytvoří, když je poprvé použijeme.
     
    A není problém ani vytvořit Singleton.

    var Trida = (function() { var p; // Private static property - uchování instance singletonu var instance = null; var Cls = Class({ private: { // Private jmeno: "unknown", constructor: function(jmeno) { // Private konstruktor p(this).jmeno = jmeno; } }, static: { // Public static coToJe: "no přece public static property", getInstance: function(jmeno) { if (instance === null) { instance = new Cls.private.constructor(jmeno); // Private konstruktor je uložen vždy v return objektu fce Class() tedy Cls.private.constructor } return instance; } }, getJmeno: function() { return p(this).jmeno; } }); p = Cls.privateAccessor; return Cls.class; })();
     
    Dal jsem si s tím práci, takže když budete chtít vytvořit instanci třídy, tak vám to vyhodí vyjímku, protože konstruktor je private. A jak se uvnitř dostanete ke svému private konstruktoru? Uvidíte v public static metodě getInstance(). Private konstruktor dostanete v tom objektu od fce Class.
     
    Abych ještě ukázal tu implementaci interface.

    var Serializable = { serialize: function() { throw new Error("Metoda serialize() není implementována."); } }; var Test = Class({ constructor: function(jmeno, prijmeni) { this.jmeno = jmeno; this.prijmeni = prijmeni; }, serialize: function() { return JSON.stringify({className: "Test", properties: {jmeno: this.jmeno, prijmeni: this.prijmeni}}); } }).implements(Serializable).class; var t1 = new Test("Foo", "Bar"); console.log("t1.implementationOf(Serializable)", t1.implementationOf(Serializable)," t1.serialize():", t1.serialize());
     
    Když implementujeme interface, tak bychom ho asi měli opravdu implementovat, takže když řeknu Class().implements(Serializable), tak si funkce implements kontroluje, jestli jsou položky Interface implementované nebo ne. Pokud ne, vypíše chybu do konzole, ale přitom nechá akce doběhnout a nahraje na chybějící místo to co je v Interface. I když bych tedy neimplementoval metodu serialize, tak by ji fce implements vytvořila, zkopírovala by implementaci přímo z Interface. V interface mám ale v té metodě vyhození vyjímky, takže to ani tak neprojde. Ale kdybych tam to vyhození vyjímky neměl, vše by fungovalo.
     
    Pokud máte dotazy nebo připomínky, ptejte se.
     
    Doufám, že se vám to bude někomu hodit.
     
    I když nevím co si myslím. Všichni na to serete.
  25. Like
    Bindik reacted to Hookyns in [Serial Node.js] Díl 2. REST API   
    Zdravím,
     
    tak tu mám další díl a vzal jsem to celkem hopem.
     
    Přeskočil jsem původně plánovaný druhý díl, který měl jen rozšířit základ z prvního dílu. Bylo by tam maximálně jen nějaké hraní s třídami, které tedy podle Jamiho není zajímavé, a tak jsem přešel rovnou na díl třetí.
     
    V tomto díle si společně vytvoříme TODO list, kde klient bude v AngularJS a na pozadí bude Node.js server, který bude poskytovat CRUD operace a dohromady tak tvořit REST API.
     
    Hned na úvod říkám, že implementuji pouze CRU operace a D nechám na vás. Chtěl bych vidět vaše implementace, aby se mi dostala nějaká zpětná vazba. D bude opravdu jednoduchý, takže nezoufejte.
     
    Aby toho najednou nebylo moc, tak zatím do toho ještě nezapojím databáze. Data budeme uchovávat v operační paměti, tzn. jen ukládat do proměnné.
     
     
    Server
     
    Struktura serveru, kterou si však můžete přizpůsobit dle sebe.
    core
    Model.js
    Server.js
    [*]public

    app.js
    controllers.js
    index.html
    style.css
    [*]app.js


    Základem je spouštěný script, který jsem si nazval app.js. V souboru bude jen pár řádků na inicializaci serveru. Zbytek bude rozdělen do tříd.
     
    app.js

    // Náš server modul
    var Server = require("./core/Server.js");
     
    // Spustíme server
    var server = new Server("127.0.0.1", 80);
    server.run();

     
    Nahoře načítáme náš modul Server.js, který ještě nemáme vytvořený.
    Po jeho načtení vytváříme instanci serveru, předáváme mu IP a port a zavoláme jeho metodu run(), která server spustí.
     
     
    core/Server.js - rozhraní

    var http = require("http");
    var path = require("path");
    var nodeStatic = require("node-static");
     
    /**
    * @type {Model}
    */
    var Model = require("./Model.js");
     
    /**
    * Třída Server vytvářející HTTP server, který odesílá statické soubory a tvoří REST API
    * @param {String} ip
    * @param {Number} port
    * @constructor
    * @class
    */
    var Server = function (ip, port) {
    /**
    * IP serveru
    * @type {String}
    */
    this.ip = ip;
     
    /**
    * Port
    * @type {Number}
    */
    this.port = port;
     
    /**
    * http server
    * @type {http.createServer}
    */
    this.httpServer = null;
     
    /**
    * Model
    * @type {Model}
    */
    this.model = new Model();
     
    /**
    * node-static server pro odesílání statických souborů
    * @type {nodeStatic.Server}
    */
    this.fileServer = new nodeStatic.Server(path.resolve(__dirname, "..", "public"), {cache: 7200});
    };
     
    /**
    * Metoda zpracovávající příchozí requesty
    * @param request
    * @param res
    * @private
    */
    Server.prototype.acceptRequest = function(request, res);
     
    /**
    * Zpracování normálního get požadavku
    * @param request
    * @param response
    */
    Server.prototype.processGet = function(request, response);
     
    /**
    * Posbírá data z body requestu a vrátí je do callbacku
    * @param request
    * @param callback
    */
    Server.prototype.getBodyContent = function(request, callback);
     
    /**
    * Zpracování REST API GET požadavku
    * @param request
    * @param res
    */
    Server.prototype.processRestGet = function(request, res);
     
    /**
    * Zpracování REST API POST požadavku
    * @param request
    * @param res
    */
    Server.prototype.processRestPost = function(request, res);
     
    /**
    * Zpracování REST API PUT požadavku
    * @param request
    * @param res
    */
    Server.prototype.processRestPut = function(request, res);
     
    /**
    * Zpracování REST API DELETE požadavku
    * @param request
    * @param res
    */
    Server.prototype.processRestDelete = function(request, res);
     
    /**
    * Metoda ukončující request a odesílající response
    * @param {Number} code HTTP return code
    * @param {String} contentType
    * @param {String|Object} data
    * @param request
    * @param res
    */
    Server.prototype.return = function(code, contentType, data, request, res);
     
    /**
    * Spuštění serveru
    */
    Server.prototype.run = function();
     
    module.exports = Server;

     
    Nejprve ukazuji "rozhraní" třídy, abyste měli nějaký ucelený přehled o metodách a vlastnostech.
    Kód klidně použijte a zkopírujte si ho do souboru. Postupně jej budeme doplňovat o implementace.
     
    Nahoře načítám dva základní moduly http a path. Http modul již znáte z předchozího dílu. Druhý modul path slouží pro práci s cestami. Umí ověřovat existenci cest a umí i tvořit cross-platform cesty. Třetí modul je node-static. 3rd side modul pro posílání statických souborů. Tento modul si stáhněte pomocí npm viz následující odstavec.
     
    Otevřete si konzoli a přejděte do složky s aplikací, tam kde máte app.js. A spusťte "npm install node-static". Stáhne se vám modul a jeho vazby. Vytvoří se vám složka node_modules, do které se umisťují všechny moduly.
     
    Teď trochu vysvětlím, jak má tato třída fungovat a co má která metoda dělat.
     
    Základem je konstruktor třídy, který přijímá dva parametry, a to port a IP.
    Vytváříme zde node-static Server a říkáme mu odkud bude brát statické soubory. Statické soubory, které node-static bude posílat jsou klientské soubory html, js a css pro naši app.
    Nakonec zde vytváříme to nejdůležitější, http server. Jako parametr mu předávám anonymní callback, který volá naši metodu.
     
    Takže pokaždé když přijde dotaz na náš server, tak se spustí naše metoda acceptRequest, která obdrží 2 parametry, a to request a response.
     
    acceptRequest

    // Zapíšeme čas startu
    console.time("request-time");
     
    var api = request.url.split("/");
    api.shift();
     
    if (!!api && api[0] == "rest") {
    switch (request.method) {
    case "GET":
    return this.processRestGet(request, res);
    case "POST":
    return this.processRestPost(request, res);
    case "PUT":
    return this.processRestPut(request, res);
    case "DELETE":
    return this.processRestDelete(request, res);
    case "OPTIONS":
    return this.return(200, "application/json", "", request, res);
    default:
    return this.return(501, "application/json", {error: "This type of action is not supported."}, request, res);
    }
    }
     
    this.processGet(request, res);

     
    Co tahle metoda dělá? Myslím že je to na první pohled jasné. Tato metoda je pouze rozcestník našeho serveru. Podle URL adresy z requestu rozhodujeme co se stane.
     
    Na začátku mám console.time(), je to trigger na měření času. Mám to zde jen pro přehled abyste věděli jak dlouho serveru trvá odpověď na vaše budoucí dotazy.
     
    Pod tím si parsuju url do pole. Url je jen jeden hloupý parametr. Když zadáte do prohlížeče libovolnou URL směřovanou na váš server, tak se vždy provede to samé. Vždy zavoláte stejný kód a URL je jen parametr se kterým si můžete dělat co chcete. Kdo říká, že má být formát URL domena.tld/neco/neco?neco=neco&dalsi=neco? Je to sice základní formát, ale je jen na vás jak váš server bude zpracovávat požadavky. Klidně můžete přijímat domena.tld/neco-neco|neco=neco+dalsi=neco. Vždy to bude jen stringový parametr v requestu a je jen na vás, jak si tento string zpracujete.
    Já tedy používám základní lomítkový formát, proto dělím string podle lomítka. Hned v zápětí odstraňuji první položku pole, protože ta bude vždy prázdná, protože url vždy začíná lomítkem, předním nic není.
     
    Po rozdělení URL následuje rozcestí kam dál. Pokud je URL je tvaru /rest/... půjdeme na switch a přesměrujeme dotaz na metodu zpracovávající konkrétní method requestu (POST, GET, PUT, DELETE). AngularJS ještě odesílá před každým XHR (AJAX) dotazem OPTIONs, kterým si ověřuje platnost akce, takže OPTIONS musí vracet kód 200. Pokud bude metoda jiná než těchto pět, vrátíme error.
     
    Celé API stavíme na JSONu, takže pokud náš server bude něco vracet, vždy to musí být ve formátu JSON. I když to bude chyba, musí být zabalená v JSONu, aby s tím potom mohly klienti počítat.
     
    Pokud není dotaz na /rest, tak pokračujeme do metody processGet, která zpracovává normální GET požadavek.
     
    proccessGet

    var self = this;
     
    this.fileServer.serve(request, response, function (err, res) {
    if (err) {
    console.log("Chyba při zpracování přenosu statického souboru " + request.url, err);
     
    // Vrátíme chybu
    self.return(404, "text/plain", err.message, request, response);
    } else {
    console.log("Přenos statického souboru " + request.url);
    }
    });

     
    Tato metoda vezme požadavek a předá ho node-static serveru. Asi není třeba nic vysvětlovat. Buď bude soubor nalezen a odešleme ho nebo vrátíme 404.
     
    To nás přivádí k metodě return, kterou volám už i v předchozí metodě.
     
    return

    // Nastavíme hlavičku
    res.writeHead(code, { 'Content-Type': contentType, 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type'});
     
    // Pokud se nejedná o String
    if (contentType == "application/json" && typeof data != "string") data = JSON.stringify(data);
     
    // Odešleme data
    res.end(data);
     
    // Vypíšeme si dobu zpracování dotazu
    console.timeEnd("request-time");

     
    Zde zpracováváme odpověď na dotaz.
    Na začátku odesíláme hlavičky. Říkáme jaký je návratový kód, content-type a říkáme jaké povolujeme metody, na jaký server a co povolujeme v hlavičce.
    Pak si jen případně upravíme data a výsledek odešleme.
     
    Další metoda z našeho rozcestí acceptRequest je processRestGet
     
    processRestGet

     
    console.log("GET požadavek na: ", request.url);
     
    var getUrl = request.url.split("/");
    getUrl.shift();
    var what = getUrl[2];
     
    // Get dotaz na /rest
    if (getUrl[0] == "rest" && (typeof getUrl[1] == "undefined" || getUrl[1] == "")) {
    this.return(200, "application/json", {
    get: {
    url: "/rest/get/",
    actions: [
    {
    name: "todolist",
    url: "/rest/get/todolist"
    },
    {
    name: "ukol",
    url: "/rest/get/ukol/",
    params: [
    {
    name: "id",
    type: "number",
    desc: "ID požadovaného úkolu",
    url: "/rest/get/ukol/id"
    }
    ]
    }
    ]
    },
    post: {
     
    },
    put: {
     
    },
    delete: {
     
    }
    }, request, res);
    return;
    }
     
    switch (what) {
    case "todolist":
    return this.return(200, "application/json", this.model.getUkoly(), request, res);
     
    case "ukol":
    return this.return(200, "application/json", this.model.getUkol(getUrl.pop()), request, res);
     
    }
     
    this.return(501, "application/json", { error: "This action is not implemented!" }, request, res);

     
    Původně byla tato metoda podstatně kratší, ale přidal jsem tam podmínku, aby se klient mohl zeptat na API. Na zátku metody si tedy opět rozeberu URL. Pokud je dotaz pouze na /rest/, vrátím mu JSON popisující API. Vytvořil jsem to jen v rychlosti. Ani jsem moc nevěděl jak to popsat. Když poskytujete REST API jen sobě, tak to nepotřebujete. Jen pokud byste dělali nějaké veřejné služby, tak byste asi měli vracet nějaký ten popis.
     
    Pod dotazem na API je switch s možnými akcemi. /rest/get/todolist a /rest/get/ukol/id.
    Tyto akce už rovnou komunikují s Modelem a vytahují z něj požadovaná data. Pokud nebude akce nalezena, vrátíme error.
     
     
     
    No, už se mi to nechce všechno tak moc dopodrobna projíždět, protože je toho celkem dost. Jen jsem se teď zamyslel nad tím, kolik metod ještě je a jaké to má všechno souvislosti, že jsem si řekl, že to zde všechno vypisovat nebudu. Text by byl strašně dlouhý a u konce by vás to už stejně nebavilo číst, protože základní věci stejně ovládáte, takže si funkcionalitu dokážete vyvodit.
     
    Hodím tedy celý projekt na bitbucket, odkud si ho můžete v klidu stáhnout.
    https://bitbucket.org/HookCZ/nodejs-serial-rest-todolist
     
    Pokud byste měli nějaké problémy nebo chtěli něco vysvětlit, tak piště.
     
    Aplikaci nastartujete spuštěním app.js.
    Pak stačí najet v prohlížeči na adresu serveru nastavenou v app.js a stáhnou se vám statické soubory pro klienta a zobrazí se vám gui. Na serveru v modelu jsou staticky uloženy 2 úkoly, takže se nedivte proč už tam 2 úkoly jsou. Můžete přidávat nové úkoly a měnit jejich stav. Smazat je však nemůžete a to je úkol pro vás. Chci abyste sem přidali vaše řešení pro mazání úkolů. Základ je asi řešení na serveru, protože klient není součástí seriálu, ale pokud postnete i úpravu klienta, tím líp.
     
    App si můžete libovolně rozšířit o další funkcionality. Úkol má teď pouze jeden text, tak to můžete rozdělit na title a popisek. Můžete umožnit editaci textů u úkolů. Vše co upravíte sem můžete postnout, pokud se tím budete chtít pochlubit a nechat si to třeba i zkontrolovat.
     
    V dalším díle si do našeho TODO listu přidáme MySQL databázi.
×
×
  • Create New...