java language
Tartalomjegyzék
dokumentáció
adatbázis eljárás hívás
-
Function hívása:
-
Procedure hívása:
-
Ha az adatbázis procedure/function adott paramétere OUT-ra van definiálva,
akkor a cs.executeQuery() előtt ezt kell beállítani:
majd a cs.executeQuery() után így kapható meg az adat:
adat minősítés
-
Nincs adat:
- null (bármely adattípus esetén)
- 0 karaktert tartalmazó text (html form field, http-get parameter)
- 0 karaktert tartalmazó string (üres string)
- 0 elemet tartalmazó collection (tömb, lista, halmaz, map)
-
Van adat:
- Legalább 1 karaktert tartalmazó string. Az egyetlen karakter akár space, vagy tabulátor is lehet!
- Legalább 1 elemet tartalmazó collection (tömb, lista, halmaz, map). Az egyetlen elem akár null is lehet!
annotation
-
Annotáció létrehozása:
-
@Retention
Meghatározza az annotáció bejegyzési helyét. Szinte mindig ezt használjuk:
Ekkor ugyanis a lefordított osztályokba is bekerül az annotáció, és programból is olvasható.
-
@Target
Meghatározza, hogy az annotáció milyen program elemhez rendelhető. Több is beállítható.
Például ha osztályra, és metódusra is rátehető:
-
Annotáció paramétere:
Az annotáció paramétere csak bizonyos típusú lehet:
- primitív típusok
- String
- Class
- enum
- annotation
- és ezen felsoroltak tömbje
Ha megadjuk a paraméter default értékét is, nem adhatunk meg null-t!
Az annotáció felhasználásakor mindenképp értéket kell adni azoknak a paramétereknek,
melyek nem rendelkeznek default-tal.
A fenti példában a 3. paraméternek nincs default értéke, ezért azt mindenképp meg kell adni,
az annotáció felhasználásakor:
Az annotációnak lehet value nevű paramétere. Ha az annotáció felhasználásakor csak
ezt akarjuk megadni akkor a value kulcsot nem kell kiírni, az érték automatikusan a value-hoz fog tartozni.
Mindkét sor ugyanazt jelenti:
-
Annotáció felderítése:
A program futása során fel kell deríteni milyen program elem lett megjelölve az annotációval,
illetve hogy lettek beállítva az annotáció paraméterei.
Ezt a Reflection API segítségével lehet felderíteni.
A Class, Method, Field, Parameter mind rendelkeznek a következő metódusokkal, a felderítéshez:
A példában egy Class-t vizsgálunk:
argumentum
-
Program indításkor az argumentumokat egy tömbben kapjuk meg.
Az argumentumokat elválasztani space karakterekkel lehet.
Egy vagy több space egymás után ugyanúgy választ el egymástól 2 argumentumot.
-
Ha az argumentumban space karakter van, akkor idézőjelek közé kell tenni,
de a java tömbben már nem kapjuk meg az idézőjelet:
-
Ha az argumentumban space karakter és idézőjel is van, akkor így kell megadni:
-
Az argumentumot ráadásul nem kell idézőjellel kezdeni, elég az előbb említett karakterek előtt:
Ezzel a módszerrel az argumentumokat látszólag kulcs-érték párokként tudjuk megadni.
Az argumentum feldolgozónak pedig az első egyenlőségjelet kell megkeresnie, hogy szétválassza a kulcsot és az értékét.
array
-
Arrays.copyOfRange(baseArray, from, to)
Egy meglévő tömb alapján új tömböt készít úgy, hogy az új tömb a meglévő tömb egy része.
A from indexű elem része lesz az új tömbnek, a to indexű elem pedig nem.
A to index nagyobb is lehet a meglévő tömb méreténél, ekkor az új tömb fel lesz töltve
alap értékekkel, mely int[] tömb esetén 0:
-
System.arraycopy(srcArray, srcPos, destArray, destPos, length)
Átmásolja a forrás tömb adott pozíciójától az elemeket a cél tömb adott pozíciójába, a megadott hosszon:
Sem a pozíciók, sem a hossz nem mutathat a tömbökön kívülre!
base64 kódolás
-
Base64 kódolás a 8-as java Base64 osztályával:
-
Base64 dekódolás a 8-as java Base64 osztályával:
-
Base64 kódolás a 7-es java beépített osztályával:
-
Base64 dekódolás a 7-es java beépített osztályával:
basic autentikáció
-
Basic autentikáció esetén a http-request header része egy ilyen kulcs-értéket tartalmaz:
Ha az xxxxxxxx rész helyett egy username/password páros van megadva,
akkor abból így állítható elő az xxxxxxxx:
Tehát össze kell fűzni a 2 adatot kettősponttal elválasztva, majd ezen egy base64 kódolást kell végrehajtani.
bean validation
-
Egy java pojo-t el lehet látni validációs annotációkkal, melyek ebből a package-ből származnak:
Példa:
-
Ha a beágyazott Child osztály tartalmaz validációs annotációt,
akkor a hivatkozására rá kell tenni a @Valid annotációt, mint a fenti példában.
A @Valid nélkül a beágyazott osztályra nem fog végrehajtódni a validáció.
-
A pojo tetszőleges módon feltölthető, például példányosítással, vagy a Jackson által json fájlból,
de pojo feltöltésnél még nem lesznek figyelembe véve a validációs annotációk. Ezt külön kell aktiválni!
Például a "person" példány esetében a validáció aktiválása, és hiba kezelése:
-
Néhány validációs annotáció:
-
@NotNull
Nem lehet null, de lehet üres.
Alkalmazható bármely típusra.
-
@NotEmpty
Nem lehet null, és nem lehet üres (string).
Alkalmazható CharSequence, Collection, Map, Array esetén.
-
@NotBlank
Nem lehet null, és legalább 1 látható karaktert kell tartalmaznia.
Alkalmazható CharSequence esetén.
-
@Size
Megengedett értékek: null, a megadott hosszúságú elem.
Alkalmazható CharSequence, Collection, Map, Array esetén.
Példa: string esetén 3-5 karakter hosszúság ellenőrzése, a default hibaüzenet módosításával:
-
@Email
Megengedett értékek: null, üres string, szintaktikailag helyes email cím.
-
@Future, @FutureOrPresent
Megengedett értékek: null, jövőbeli dátum (vagy a mai).
-
@Past, @PastOrPresent
Megengedett értékek: null, múltbéli dátum (vagy a mai).
-
@Min, @Max
Megengedett értékek: null, a minimum és a maximum értéket nem túlhaladó érték.
Alkalmazható számok esetén.
-
@Pattern(regexp = "[abc]{3}")
Megengedett értékek: null, a reguláris kifejezésnek megfelelő string.
Alkalmazható CharSequence esetén.
-
dokumentáció
bitműveletek
-
Integer cast (bővítés, szűkítés):
-
Ha primitív numerikus adattípust bővítünk (byte -> short -> int -> long),
akkor numerikusan értékhelyesen kerül át az adat az új adattípusba.
-
Ha char adattípust bővítünk (char -> int, char -> long),
akkor a baloldali bitek mindig 0-val lesznek feltöltve.
-
Szűkebb adattípusra váltáskor (long -> int -> short -> byte, char -> byte)
a baloldali bitek le lesznek vágva.
- Nincs változás hossz egyezéskor (char -> short, short -> char).
-
Bitműveletek:
<<
>>
>>>
&
|
^
~
-
byte, short, char típusoknál a bitműveletek előszőr numerikusan értékhelyesen int-re bővítenek
(2 operandusos műveletnél mindkét operandust int-re), az int típuson történnek a műveletetek,
az eredmény int típusú.
-
int, long típusoknál a bitenkénti műveletek nem bővítenek, az eredmény is ilyen típusú.
- A << művelet balra lépteti a biteket, jobbról mindig 0-val tölti fel őket.
-
A >> művelet jobbra lépteti a biteket, balról az eredeti előjelétől függően 0-val (ha pozitív volt),
vagy 1-gyel (ha negatív volt) tölti fel őket.
Így a szám numerikusan feleződik (ha nem veszik el 1-es bit jobbról).
- A >>> művelet jobbra lépteti a biteket, balról mindig 0-val tölti fel őket.
Charset
-
Azokon a helyeken ahol Charset-et kell megadni, használhatjuk a StandardCharsets osztályt.
A StandardCharsets osztállyal tudunk hivatkozni alapvető karakter kódolásokra, és így nincs az a veszély,
hogy a kódolást string-ként helytelenül írjuk le.
-
Példa:
-
Ha a karakter kódolást string-ként kell megadni, akkor is használhatjuk a StandardCharsets osztályt,
a példában mindhárom metódusa az "UTF-8" stringet adja vissza:
.class & getClass()
-
Egy adott osztályhoz tartozó .class, és ezen osztály bármely példányához tartozó .getClass()
mindig ugyanazt a class-objektumot adja vissza.
Ezért a == relációs jellel is összehasonlíthatók.
-
A .getClass() mindig a példány dinamikus típusának megfelelő class-objektumot adja vissza.
Connection
-
A PostgreSQL nem, de az Oracle adatbáziskezelő érzékeny arra, ha egy Connection objektumon belül túl sok
ResultSet (cursor) van nyitva.
Webes környezetben a Connection.close() visszarakja a pool-ba a kapcsolatot,
a le nem zárt ResultSet-ek nyitva maradnak,
tehát a close() metódus semmilyen "tisztítást" nem végez rajta.
Így ha ismét kivesszük a pool-ból, lehetséges hogy már egyetlen ResultSet sem nyitható,
és a következő hiba keletkezik:
java.sql.SQLException: ORA-01000: maximum open cursors exceeded
A java fórumon arra jutottunk, hogy nincs olyan módszer amivel a pool-ból kivéve a
kapcsolatot meg lehessen "tisztítani",
erre se a rollback, se más művelet nem alkalmas. A legjobb megoldás ha a programkódok jól vannak megírva,
és mindent lezárnak, illetve glassfish esetén van erre egy beállítás ami csak félmegoldás:
Ezzel a beállítással el lehet érni, hogy 10 másodpercenként a glassfish a pool-ban lévő "nem tiszta"
connection-öket kitisztítsa/lezárja, és így a connection megszabaduljon a benne lévő le nem zárt ResultSet,
Statement-től, így aki legközelebb a pool-ből kiveszi, tiszta connection-t kapjon.
Fontos hogy ha átállítjuk ezen jellemzőket, akkor nem elég a "save", hanem a "general" fülön lévő "flush" gomb is
szükséges hogy érvényre lépjen.
constructor
-
Ha egy konstruktorban a meghívjuk a szülő osztály konstruktorát super()-rel, annak az első sornak kell lennie.
Azonban a super() paramétereként meghívható statikus metódus,
így ez a kód előbb fut le mint a szülő konstruktor.
Például ha a szülő konstruktor egy boolean értéket vár, amit egy bonyolult eljárás ad eredményül akkor ez működik:
csv
-
CSV fájlok olvasásához, és írásához egy jó eszköz az
OpenCSV
-
Jól lekezeli azt az esetet is, amikor az elválasztó karakter az adaton belül fordul elő,
és emiatt az adat idézőjelek közé van helyezve.
-
Az OpenCSV használatához bővíteni kell a pom.xml-t:
- CSV fájl beolvasás:
DateTimeFormatter
-
A DateTimeFormatter osztályt a 8-as java-ban vezették be, de nem lehet vele kiváltani a SimpleDateFormatter-t.
Igazából a régebbi Date osztályt nem támogatja megfelelően.
-
A Date osztály formázása megfelelően működik, de csak úgy, hogy a DateTimeFormatter-nek az időzóna is meg van adva:
-
Egy String parse-olása nem minden esetben működik.
Ha csak "yyyy.MM.dd" a formátum maszk, azt nem lehet parse-olni, az időből legalább az órát is meg kellene adni:
-
dokumentáció
email küldés
-
Email küldéshez használjuk a xesj.java-17-tool library-ben lévő Email osztályt.
Az Email osztállyal való levélküldés tetszőleges környezetben működik,
mivel a library pom.xml-je már ki van egészítve a javax.mail dependency-vel:
enum
-
Amikor egy enum nemcsak felsorolást tartalmaz, hanem az elemeknek egy vagy több paramétere is van:
-
Az enum elemei akár önmagukban is használhatók a forráskódban,
ha importálva vannak az import static segítségével.
excel készítés
-
Excel készítéshez (és más Microsoft termékekhez) az
Apache Poi-t érdemes használni.
-
A "poi-ooxml" -lel lehet már xlsx-formátumot is gyártani, de nem ajánlott használni, mivel olyan nagy a jar-csomag,
hogy a glassfish-re való telepítés nagyon hosszú idő lesz: 20-30 másodperc, az 1-2 másodperc helyett.
File
-
File.getCanonicalPath()
A metódus átváltja a fájl vagy könyvtár elérési útját egy egyértelmű, egyedi stringre, kivéve belőle a "." és ".."
könyvtárakat, unix rendszereken pedig követi a szimbolikus linkeket is:
Ellenőrizni lehet, hogy egy fájl (könyvtár) egy adott könyvtáron belül van-e:
-
owner, group, permissions
Unix rendszereken lehetőség van egy fájlról megtudni a tulajdonosát, a csoportját, és a hozzátartozó jogokat
úgy, ahogy egy ls -l parancsnál látható. Ehhez már szükséges a java.nio csomag használata.
Windows-on a Posix... osztályok használata exception-t vált ki! Példa:
Files
-
Fájl tartalmának beolvasása string-be.
Ha a 2. paraméter nincs megadva, akkor UTF-8 kódolással olvas:
-
Fájl tartalmának beolvasása sorokra darabolva.
Ha a 2. paraméter nincs megadva, akkor UTF-8 kódolással olvas:
-
Fájl tartalmának beolvasása bájt-tömbbe:
for-each
-
For-each ciklussal tömb, illetve Iterable interface-t implementáló osztályokon lehet végigmenni,
ilyen például: Set, List, Map.keySet(), ...
-
Példa saját megvalósításra:
és ennek használata:
generics
-
Generikus lehet egy osztály, vagy csak egy-egy metódusa.
-
Generikus osztálynál az osztálynév után kell írni a generikus jelölést.
-
Generikus metódusnál a metódus visszatérési értéke elé kell írni a generikus jelölést.
-
Generikus jelölések:
-
Egy tetszőleges osztály:
-
Az osztály, vagy annak leszármazottja:
-
Az osztály, vagy annak szülője:
-
Példa:
-
Példa:
-
Hogy egy típust generikusként értelmezzen a fordító, legalább a <?> -et kell alkalmazni pl:
Mivel így a c1 változó generikus, az osztályon belüli metódusoknál is érvényessé válnak a generikusok,
különben elképzelhető hogy nem érvényesül.
Lásd a Class osztály getAnnotation() metódusát. A c2 esetén nem érvényesül a generikus működés,
egy külön cast-ra van szükség.
hashCode() & equals()
-
Két java objektum MEGEGYEZŐ ha:
Mindkettő hashCode() metódusa ugyanazt az integer értéket adja vissza,
és mindkettő equals() metódusa true értéket ad vissza.
-
A megegyezőség definiciójából következik:
Ha a 2 objektum hashCode értéke különböző, akkor nem lehetnek megegyezőek,
és felesleges vizsgálni az equals() metódusukat.
-
A fent leírt módon működik a Set osztály.
A Set a benne tárolandó objektumok hashCode értékeit vizsgálja előszőr.
Ha ezek különbözők, akkor meg sem hívja az equals() metódusokat.
-
A fentiek figyelembevételével egy saját osztály hashCode() megvalósításánál elég annyit biztosítani,
hogy ha két példányát egyenlőnek tekintjük, akkor a hashCode() értékük is biztos ugyanazt adja. Tehát
ha a saját osztályunkat egyenlőnek tekintjük ha az "x" és az "y" mezője is megegyezik, akkor a hashCode()
metódus lehet ilyen:
Ez akkor is működik ha a két mező valamelyike null értéket tartalmaz!
HttpServletRequest
HttpServletRequest osztály
-
Néhány fontosabb metódus:
Http-request előállítása
-
Http request kiadása:
-
Amennyiben https címet hívunk akkor ennyiben változik a fenti kód:
-
Https hívásnál ellenőrződik a szerver tanúsítványa, ha az nem megfelelő, akkor nem megy ki a request.
Ezt a problémát megoldja az általam írt HttpTool osztály, melyben a "TrustManager" úgy van beállítva
hogy megbízzon minden szerver tanúsítványban.
-
Https hívásnál lehetséges hogy a kliens-nek is van tanúsítványa melyet a szerver ellenőrizni akar.
Ezt a tanúsítványt nem kell tárolni semmilyen kulcstárolóban,
viszont a programnak el kell küldenie a https híváskor.
Példa egy P12 típusú tanúsítvány elküldésére, melyhez jelszó is tartozik.
A ...trustAllCerts... -re példa az általam írt HttpTool osztályban található.
IP-cím lekérdezése
-
Ha egy webes alkalmazás szeretné meghatározni a hívó ip-címét, de a webes alkalmazás előtt egy proxy van,
akkor a normál módszerrel sajnos csak a proxy ip-címét kapjuk meg. Azonban a proxy beállítható úgy,
hogy az X-Forwarded-For header-ben továbbítsa az eredeti
ip-címet. Az alkalmazásnak arra is figyelni kell, hogy esetleg mégsem proxy mögött fut:
image kezelés
-
Egy kép beolvasása amikor az osztállyal megegyező könyvtárban van.
Akkor is működik ha egy jar-ba van az alkalmazás csomagolva:
-
Egy 22*22 méretű kép átlátszóvá tétele. A legelső pixel szine az melyet mintának veszünk.
Ezt a színt teszi 100%-osan átlátszóvá az eljárás:
-
Kép átméretezése, elforgatása, egyéb műveletek: thumbnailator (van maven elérése).
interface
-
Az interface-ben definiált metódusoknak nem lehet body részük, kivéve a default metódusokat.
-
Az interface-ben definiált default kulcsszóval ellátott metódusok a default metódusok,
melyeknek kötelező a body részük. Az interface-t implementáló osztályokban ezeket a metódusokat
nem kötelező implementálni. Ekkor az interface-ben leírt body érvényesül.
-
Az interface-ben definiált változók automatikusan el vannak látva ezekkel a jelzőkkel,
akkor is ha ezeket nem írjuk ki:
Így tehát nem használható rájuk a "private" és a "protected" jelző.
Jackson
-
Json írásához és olvasásához a Jackson library-t érdemes használni.
-
A Spring keretrendszer is Jackson-t használ, de szerencsére a Jackson library nem springes projektben is
könnyen használható.
Ehhez csak a következő kell a pom.xml-be:
JAVA_TOOL_OPTIONS
-
A JAVA_TOOL_OPTIONS környezeti változóban tárolt beállítások a legtöbb java programra hatással van:
netbeans, maven, junit, ...
Így például elég ebben beállítani a file olvasás/írás, illetve a konzolra írás karakter encoding értékét:
javac
-
Ha egy projecthez egy adott verziójú JDK compiler szükséges, az nem helyettesíthető más verziójú JDK-val.
Indoklás: ha a Proba.java tartalmaz egy java.util.Base64 osztályra való hivatkozást amit
csak a 8-as java-ban vezettek be, akkor is lefordítja a 8-as javac ezzel a módszerrel,
ahelyett hogy fordítási hibát kapnánk:
JAXB
-
A JAXB marshal() metódus java objektumból adatokat tartalmazó XML-t készít.
-
A JAXB unmarshal() metódus az adatokat tartalmazó XML-ből java objektumot készít.
-
A java osztályban biztosan használhatók a következő adattípusok:
String, Long, long, Double, double, java.util.Date, Boolean, boolean
Többszörös adatnál használhatók a fenti típusok, a List-tel kombinálva: List<...>
Az ilyen standard adattípusokat tartalmazó osztályok egymásba is ágyazhatók.
-
Használható annotációk a java osztályban:
-
@XmlRootElement
Az XML-be konvertálandó gyökér-osztály jelölése.
A "name" attribútumával adható meg milyen név kerüljön az XML-be az osztálynév helyett.
-
@XmlElement
Ennek megadása nélkül is bekerül az XML-be az osztály tagja, akár használjuk, akár nem.
A "name" attribútumával adható meg milyen név kerüljön az XML-be a tagnév helyett.
A "required = true" attribútumával kötelezővé lehet tenni a tagot, így a JAXB marshal()/unmarshal() metódusok
az adat kötelezőségét tudják ellenőrizni. Ha a tag kötelező és a típusa List,
akkor a List-nek legalább 1 elemet kell tartalmaznia !
-
@XmlAttribute
Az XML-be az adat nem tag-ként, hanem attribútumként fog bekerülni.
A "name" és "required" itt is használható, lásd a @XmlElement-nél.
-
A JAXB marshal()/unmarshal() metódusoknál mindenképp használjunk XSD-t, mert nélküle az unmarshal() metódus a
következőképpen működik:
-
Ha az XML olyan tagot tartalmaz mely nincs a java osztályban, ez nem okoz exception-t,
a tag nem lesz figyelembe véve.
-
Ha az XML-ből hiányzik olyan tag melyet tartalmaz a java osztály, ez nem okoz exception-t,
a java osztályba erre a helyre null kerül.
-
Ha az XML hibás adatot tartalmaz mely nem konvertálható a java osztály tagjába, ez nem okoz exception-t,
a java osztályba erre a helyre null kerül !!!
-
Ha a JAXB unmarshal() metódusnál használunk XSD-t, akkor a metódus a következőképpen működik:
-
Ha az XML olyan tagot tartalmaz mely nincs a java osztályban (nincs az XSD-ben definiálva), exception keletkezik.
Az exception jól leírja mi a hiba.
-
Ha az XML-ből hiányzik olyan tag melyet tartalmaz a java osztály, ez nem okoz exception-t,
a java osztályba erre a helyre null kerül.
Kivéve ha a java osztályban ez a mező a @XmlElement(required = true) által kötelezőre volt állítva,
és így az XSD definícióban is kötelezőként szerepel, ekkor exception keletkezik.
Az exception jól leírja mi a hiba.
-
Ha az XML hibás adatot tartalmaz mely nem konvertálható a java osztály tagjába, exception keletkezik,
mely jól leírja a hibát.
-
Ha a java osztályban primitív típusokat alkalmazunk, akkor ezek is kötelező adatnak minősülnek,
vagyis az XML-ben kell kapni ilyen adatot,
hiszen null nem tölthető beléjük.
-
Az XSD definiálja a mezők sorrendjét is, tehát ebben a sorrendben kötelező az XML-nek az adatokat tartalmazni.
-
A JAXB marshal()-nál is alkalmazzuk az XSD validációt !
Itt is exception keletkezik ha a java osztályban lévő adatok nem megfelelők,
például @XmlElement(required = true) annotációval jelölt java mező-ben null van,
és ebből szeretnénk XML-t előállítani marshal()-lal.
Ha a java objektum egy tagja null-t tartalmaz és az adat nem kötelező,
akkor ez a tag nem fog szerepelni az XML-ben.
-
XSD generálás java osztály(ok)ból
1. lehetőség: a JDK beépített schemagen programjával, például:
ahol a "-d" kapcsoló adja meg melyik könyvtárba rakja le az XSD fájlt, az utolsó paramétereknek pedig a
java osztályok forráskódjait kell megadni.
Itt nem csak a gyökér osztályt, hanem összes java osztályt meg kell adni amiből majd
adatok kerülnek át XML generáláskor.
2. lehetőség: a xesj.core -ban lévő XmlTool.generateXSD() metódussal.
Itt csak egyetlen osztályt kell megadni, a gyökér osztályt mely az @XmlRootElement annotációval van ellátva.
-
Java forráskód generálás XSD-ből
1. lehetőség: a JDK beépített xjc programjával, például:
ahol a "-d" kapcsoló adja meg az alapkönyvtárat ami a kiindulópontja a generálásnak,
a "-p" kapcsoló pedig a package nevét adja meg, ami bekerül a generált osztályokba.
Így tehát a generált fájlok a /tmp/com/cegnev könyvtárba kerülnek.
Figyelem: ha így állítjuk elő a java osztályt, akkor a gyökér osztályból hiányozni fog az
@XmlRootElement annotáció, tehát azt kézzel kell beleírni,
különben nem fog működni a JAXB marshal()/unmarshal() metódus !
jvm beállítások
-
JVM monitoring (memória, cpu, ...):
-
JVM és a környezeti paraméterek beállításainak lekérdezése:
-
Heap memória maximális méretének beállítása 2 gigabyte-ra:
-
NonHeap memória maximális méretének beállítása 128 mbyte-ra:
-
Környezeti paraméter beállítása, mely programból System.getProperty("kulcs") hívással olvasható:
jwt
-
A jwt (json web token) kezeléséhez a jjwt az ajánlott.
-
A jjwt használatához ki kell egészíteni a pom.xml-t.
Java 8 esetén:
Java 11 esetén:
-
A jwt-t mindig ajánlott titkosítással készíteni, hiszen a frontend megkapja,
és biztosítani kell hogy ne tudja módosítani.
Ha a frontend mégis módosítja, akkor a jwt érvénytelen lesz.
-
Jwt létrehozás példa:
-
Jwt olvasás 1. példa:
Ebben az esetben szimmetrikus kulcsunk van, ugyanazzal a kulccsal hoztuk létre a jwt-t, amelyikkel olvassuk:
-
Jwt olvasás 2. példa:
Ebben az esetben nem szimmetrikus kulcsunk van, hanem egy private + public key, de lehet hogy csak a
public key birtokában vagyunk, ezzel olvasunk.
Ha a public key pem-fájlban van, akkor el kell távolítani a "BEGIN", "END" szekciókat, az összes sortörést,
és a megmaradt tiszta szöveget kell felhasználni ahhoz, hogy előállítsuk a java PublicKey objektumot.
A jwt részeinek olvasása hasonlóan történik mint az 1. példában.
-
Kiolvasáskor többféle exception keletkezhet. Minden exception őse a JwtException.
Példa token kiolvasáskor keletkező exception-re:
-
dokumentáció
keytool
-
CA-tanúsítványok listázása windows-on, a JDK gyökérkönyvtárából indítva. A jelszó: changeit
lambda
-
A @FunctionalInterface annotációval megjelölhető egy interface akkor,
ha pontosan egyetlen nem default metódusa van!
Így olyan mintha az interface csak egy metódus (függvény) lenne:
Az így elkészített interface egy-egy implementációja a lambda operátorral (->
)
nagyon röviden írható le:
-
Olyan interface-nél is használható a lambda operátor, mely megfelel a fenti feltételeknek,
de nincs ellátva @FunctionalInterface anotációval.
-
A lambda operátor bal oldalán:
-
Elhagyható a () jel, ha pontosan 1 paraméter van.
-
Kiírható az adattípus a változó neve elé.
-
A lambda operátor jobb oldalán:
-
Ha nem írjuk {} közé a kódot, akkor az csak egy kifejezés lehet, és annak az eredménye
lesz a visszatérési érték (implicit return),
anélkül hogy a return-t kiírnánk.
-
Ha {} közé tesszük a kódot, akkor az több programsoros is lehet, és nincs return-je !
Ha return-t szeretnénk, akkor azt ki kell írni.
-
Előre elkészített @FunctionalInterface-ek a java.util.function package-ben találhatók. A fontosabbak:
Ezeknek az előre elékészített @FunctionalInterface-eknek vannak társaik is,
ahol nem egy, hanem kettő bemenő paraméter is van, például:
-
A lambda operátor helyett használhatunk metódus hivatkozást (method reference),
ha már létezik olyan metódus mely a kívánt működést produkálja.
-
Method reference formátumok:
-
Osztály::statikusMetódus
Az osztály tetszőleges lehet, de a metódusnak a paraméterei, és visszatérési értéke meg kell egyezzen
a @FunctionalInterface metódusával.
-
Osztály::példányMetódus
Az osztálynak egyeznie kell a @FunctionalInterface metódus egyetlen paraméterének típusával.
Az egyetlen paraméteren fog végrehajtódni az osztály példánymetódusa.
-
Osztály::new
A "new" jelentése: osztály konstruktora.
A konstruktor paramétereinek, és a létrejövő típusnak meg kell egyezzen a @FunctionalInterface metódusával.
-
Példány::metódus
A példány tetszőleges osztály példánya lehet, és használhatjuk a this-t is.
A metódus paraméterei, és visszatérési értéke meg kell egyezzen a @FunctionalInterface metódusával.
LinkedHash...
-
LinkedHashMap
Egy olyan Map, melyből a kulcsokat lekérdezve pont olyan sorrendben kapjuk meg, mint ahogy beletettük őket.
Ez a sorrendtartó tulajdonsága akkor hasznos, ha az elemeket belepakoljuk, és egy másik json-re konvertáló eljárás
pont ugyanilyen sorrendben rakja bele az elemeket a json struktúrába, tehát megmarad a kitalált/ésszerű sorrend.
-
LinkedHashSet
Egy olyan Set, melyből az adatokat lekérdezve pont olyan sorrendben kapjuk meg, mint ahogy beletettük őket.
LocalDate
-
Társ osztályok: LocalDate, LocalTime, LocalDateTime.
Azért hozták őket létre a java 8-ban, hogy leváltsák a Date, és Calendar osztályokat.
-
A LocalDate csak dátumot, a LocalTime csak időt, a LocalDateTime dátumot és időt is ábrázol,
és nem tárolnak időzóna információt.
-
Parse:
-
A formátum maszkban az évnél nem "yyyy"-t hanem "uuuu"-t kell megadni !
-
A formátum maszkban az évet, a hónapot, és a napot is meg kell adni, különben nem tudja parse-olni,
akárhogy is állítjuk be a ResolverStyle-t.
Ha nincs hónap és nap, nem veszi alapul a január elsejét.
-
A ResolverStyle legyen STRICT, hogy ne fogadjon el valótlan dátumot !
Ha nem STRICT, akkor egy hibás dátumot is tud parse-olni, de átváltja, például:
"2019.02.31" --> 2019.02.28
-
Példa egy helyes használatra:
-
Format:
-
Lehetséges a dátum bármelyik részére is, például: "uuuu", vagy "MM/uuuu" formátum maszkkal.
-
A hét napja szövegesen magyarul (magyar locale esetén):
Az "E", "EE", "EEE" ugyanazt az eredményt adja, 5-nél több "E" esetén exception keletkezik!
-
A hét napja 1 - 7 számmal:
-
LocalDateTime
A dátumon kívül az időt is tartalmazza, a másodperc törtrészével.
Egy jó formátum maszk, melyben az év, hónap, nap, óra, perc, másodperc szerepel:
-
Betűk a formátum maszkban
Egy szöveges dátum tartalmazhat a dátumon kívül egyéb karaktereket is.
A space, pont, kettőspont, perjel, ... nem okoz problémát, hiszen parse() esetén ezek szerepelhetnek
a formátum maszkban. Viszont a formátum maszban lévő betűk speciális jelentéssel bírnak.
Hogy ezt a speciális jelentést kikapcsoljuk, aposztróf közé kell tenni ezen
szövegeket. Példa a helyes formátum maszkra, és használatára:
-
Két dátum különbsége napokban
lock
-
A lock-ot a synchronized helyett lehet használni.
-
Nem az számít, hogy melyik osztály melyik metódusa hajtja végre a lock-ot, vagy az unlock-ot,
csak az számít melyik szál csinálja!
-
ReentrantLock
-
Létrehozás:
- Ez egy szimpla lock megvalósítás, melynek lényege, hogy egyszerre csak egy szál lock-olhat.
- Lehetséges lock-ok a ReentrantLock objektumon:
- nincs lock
- LOCK [1 - N darab] Egyetlen szál által rárakva.
-
lock():
1 lock rátevése, korlátlan várakozási idővel, amíg a lock-ot rá lehet tenni.
-
tryLock():
1 lock rátevése, adott várakozási idővel, amíg megpróbálja a lock-ot rátenni.
-
unlock():
1 lock levétele, mely csak a saját szál által feltett lock-ot veszi le.
Ha nincs levehető lock, akkor IllegalMonitorStateException keletkezik.
-
getHoldCount():
A saját szál által rátett lock-ok száma.
-
isLocked():
Lock lekérdezése, függetlenül attól melyik szál tette rá.
-
StampedLock
-
Létrehozás:
-
Ez egy read/write lock megvalósítás, melynek lényege, hogy több szál is olvashat egyszerre,
de csak egy szál írhat.
-
Lehetséges lock-ok a StampedLock objektumon:
- nincs lock
- WRITELOCK [1 darab]
- READLOCK [1 - N darab] Akármennyi szál által rárakva.
- Lock műveletnél egy azonosítót kapunk (stamp), a lock feloldásához ezt az azonosítót kell megadni.
-
readLock():
1 read lock rátevése, korlátlan várakozási idővel, amíg a lock-ot rá lehet tenni.
-
writeLock():
1 write lock rátevése, korlátlan várakozási idővel, amíg a lock-ot rá lehet tenni.
-
tryReadLock(), tryWriteLock():
1 lock rátevése, adott várakozási idővel, amíg megpróbálja a lock-ot rátenni.
-
unlock(), unlockRead(), unlockWrite():
1 read vagy write lock levétele.
Mivel meg kell adni a stamp-et is, a sima unlock() is jó, egyértelmű melyik lock kerül feloldásra.
-
isReadLocked(), isWriteLocked():
Read vagy write lock lekérdezése, függetlenül attól melyik szál tette rá.
-
getReadLockCount():
Read lock-ok számának lekérdezése, függetlenül attól melyik szál tette rá.
-
dokumentáció
Lombok Project
-
A Lombok project annotációkkal segíti a programkód írását.
A java kód fordításakor a byte-kódba kerülnek be ezen annotációk hatásai.
Ezenkívül a fejlesztőeszköz számára is láthatóvá válnak ezek a hatások, például a netbeans felajánlja
az így létrejött getter, setter metódusokat.
-
Fontos szabályok a Lombok használatához:
-
Ha nem a megfelelő lombok verziót használjuk, akkor például egy spring-es projektnél minden osztály
változtatásakor az egész projektet újra kell build-elni. Ez azért van, mert a java compiler
nem működik együtt a lombok-kal. A projekt lefordul, a lombok pedig képtelen
belerakni a lefordított osztályokba a getter, setter metódusokat. Így lehetséges,
hogy a projektet sikeresen lehet build-elni,
miközben a forráskódban hibák vannak.
-
A JDK 8-as compiler maximum az 1.16.18-as lombok-kal tud együttműködni !
-
A JDK 11-es compiler maximum az 1.18.10-es lombok-kal tud együttműködni !
-
Minden lombok-ot használó projekt pom.xml-jébe be kell illeszteni a lombok dependency-t,
és fontos hogy a scope-ja provided legyen.
Vagyis a lombok-ot ne örökölje egy projekt a másik projektből.
-
A pom.xml-be be kell írni a lombok verzióját, mely egy konkrét verzió legyen,
és nem számít hogy a netbeans figyelmeztet,
hogy ez a verzió nem egyezik a dependency management-ben megadott verzióval !
-
Példa a lombok helyes beillesztésére a pom.xml-be, java 8-as környezet esetén:
-
A lombok a legenerált getter és setter metódusokhoz nem adja hozzá azt a commentet, ami a mezőhöz tartozik.
Hogy mégis hozzáadja, ki kell egészíteni a pom.xml-t egy plugin-nel. Java 8-as környezet esetén:
-
@Getter, @Setter
Getter, és setter metódusok automatikus létrehozása. Alkalmazható egy változóra, és egy egész osztályra is.
Ezen annotációk hatása, hogy a fejlesztőeszköz is felajánlja a getter, setter metódusok meghívását.
-
@NonNull
Ellenőrzi hogy a metódus paramétere null-e. Ha igen akkor NullPointerException-t dob erre a sorra,
ahol a paramétert fogadtuk, és így meggátolja hogy a további programrész lefusson.
Ezzel feleslegessé válnak az általunk készített null-ellenőrzések, és exception kiváltások.
A dokumentáció szerint automatikusan beépül a metódus elejére egy null-t vizsgáló sor, azonban a sorok
számozása is helyes marad, így ha a metóduson belül máshol keletkezik egy exception,
annak a sornak is helyesen kapjuk meg a sorszámát:
-
Dokumentáció: Lombok Project
macOS
-
Java programozás megkezdése előtt be kell állítani a host nevet!
Ez megoldja az UnknownHostException hiba keletkezését, a Spring Boot alkalmazások lassú indulását,
a TestNG configurator lassú felépítését...stb.
A teendők a következők:
Válasszunk egy host nevet mely ".local"-ra végződik, így nem ütközünk más host nevekkel.
Például a "picurka.local" host név beállítása:
Ezután szerkesszük meg a hosts fájlt, hogy a most beállított host nevet fel lehessen oldani:
A hosts szerkesztésekor az új host nevet 2 sorba kell beírni a "localhost" után. A hosts fájlunk így fog kinézni:
Ezután indítsuk újra a gépet, és készen vagyunk.
A host név beállítás ellenőrzése:
(Az itthoni gépen egy spring boot project 14 másodperces indulása ezzel a módszerrel lecsökkent 4 másodpercre)
-
macOS futtatókörnyezet felismerése:
Mivel a System.getProperty("os.name") által visszaadott érték "Mac OS X", így döntsük el:
-
Alapesetben egy swing-es alkalmazásban a Ctrl-C, Ctrl-V, ... billentyűk működnek,
függetlenül az operációs rendszertől.
A Command-C, Command-V, ... billentyűket nekünk kell hozzárendelni a JTextField, és JTextArea komponensekhez:
-
MacOS környezetben a java -X parancs megmutatja milyen egyéb macOS specifikus kapcsolókat lehet használni.
Az -Xdock:name kapcsoló meghatározza, hogy az alma menüben mi legyen a program neve.
Amikor azonban a program ikonizálva a dock-ra kerül, ott a név továbbra is "java" marad.
Az -Xdock:icon pedig meghatározza, hogy ha futás közben a programot ikonizáljuk a dock-ra,
milyen ikonként legyen látható. Például:
-
Feltelepített JDK-k helye:
-
Java-hoz tartozó szimbolikus linkek megtekintése:
-
OpenJDK installálás macOS alá:
A http://jdk.java.net oldalról le kell tölteni a macOS-re
vonatkozó tömörített "tar.gz" kiterjesztésű fájlt, és kibontani a "~/tmp" könyvtárba,
ahol keletkezik például egy "jdk-11.jdk" könyvtár.
A "~/tmp" könyvtárban ki kell adni a következő parancsokat:
Az első parancs a "root" user, "wheel" group tulajdonába teszi a könyvtárat, és az összes alatta lévő fájlokat.
A második parancs átmozgatja a könyvtárat a megfelelő helyre.
-
Ha a macOS panaszkodik, hogy az újonnan feltelepített openJDK-t biztonsági okokból nem akarja aktiválni,
akkor itt kell beállítani a macOS-ben hogy mégis aktiválja:
-
Default JDK beállítása:
-
Ha a gépen több JDK verzió van telepítve, valószínüleg a legnagyobb verziójú JDK a default,
tehát ez indul el parancssorból egy "java" parancs kiadásakor. Ha viszont a JAVA_HOME környezeti változó
be van állítva egy JDK telepítési könyvtárra, akkor az fog elindulni a "java" parancs kiadásakor.
A JAVA_HOME beállításához segítséget nyújt a "java_home" program, mely visszaadja egy adott JDK elérési útját,
így lehet vele lekérdezni a 7, 8, 11-es verziójú JDK-k telepítési helyét:
-
Egy jó megoldás ha a "~/.bash_profile" fájlban alias neveket hozunk létre,
melyekkel a JDK verziók között könnyen tudunk váltani,
és be is állítunk egy konkrét JDK-t, mely a default lesz ha bejelentkezünk a macOS-be:
-
Dokumentáció:
Switching easily between Java JDKs on macOS
-
1. dokumentáció: a keresés írjuk be a "java" szót.
-
2. dokumentáció
memory usage
-
Memória használat lekérdezése programból
A java program így tudja a saját memória használatát lekérdezni:
-
Heap dump
A pillanatnyi memória foglalást el lehet menteni egy fájlba, ez a heap dump.
Később ez a fájl kielemezhető.
Több eszközzel is elkészíthető, például a JDK részét képező jmap programmal.
A jmap használata előtt meg kell nézni, hogy a java(.exe) milyen process id alatt fut (windows alatt: tasklist)
Ha például a 123-as process id alatt, akkor így lehet heap dump fájl-t készíteni:
-
VisualVM
Ez egy ingyenes program, innen letölthető.
Elég jól mutatja a folyamatos memória foglalást osztályok szintjén.
Heap dump-ot tud készíteni, és kész heap dump-ot szép formában tud megjeleníteni.
Az osztályszintű memória használatot a Profiler fülön lehet megtekinteni.
-
jconsole
Ez a program a JDK része. A folyamatos memória foglalás látható egy grafikus felületen, diagramok formájában,
azonban részletesebb memória foglalást a java osztály szintjén nem mutat meg.
Heap dump nem készíthető, és nem elemezhető vele.
-
top
Ezzel a unix paranccsal is lekérdezhető az összes memória foglalás egy JVM esetén.
Ha például egy szerveren, az összes spring boot alkalmazás ugyanazon unix user nevében fut, akkor egyszerre
is megnézhetők. A példában a unix user: spring
-
Elemzés
-
Normális eset amikor az alkalmazás memória foglaltsága folyamatosan növekszik még úgy is, hogy az alkalmazás
főbb funkciói nem futnak. A garbage collector (GC) időközönként takarít a memóriából, és törli az olyan
objektumokat melyre nincs hivatkozás. Így a memória használati diagramon egy fűrészfog lesz látható,
de a fűrészfog vízszintes marad.
-
Problémás eset: abban különbözik a normális esettől hogy nem vízszintes a fűrészfog, hanem folyamatosan
emelkedő. Így csak idő kérdése, hogy mikor következik be az OutOfMemoryError. Ebben az esetben
meg kell vizsgálni, hogy milyen java objektumok szaporodnak el, és ennek mi az oka.
Optional
-
Az Optional osztály egy-egy példánya ábrázolni tudja a van adat és nincs adat állapotokat,
de ehhez nincs szükség null használatára, és így a NullPointerException is elkerülhető.
Amennyiben van adat, azt az Optional példány belsőleg tartalmazza, tehát wrapper-ként működik.
-
Optional.empty()
Nincs adat állapot létrehozása.
-
Optional.of(adat)
Van adat állapot létrehozása, az adat tárolódik az Optional belsejében.
Az adat nem lehet null, különben NullPointerException keletkezik.
-
Optional.ofNullable(adat)
Van adat, vagy nincs adat állapot létrehozása. Ha van adat, akkor tárolódik az Optional belsejében.
Ha az adat null, akkor jön létre a nincs adat állapot, mely ezzel egyenértékű: Optional.empty()
-
optional.isPresent()
Az Optional példány "van adat" állapotban van ?
-
optional.isEmpty()
Az Optional példány "nincs adat" állapotban van ?
-
optional.get()
Az adat lekérdezése. Ha nincs adat, akkor NoSuchElementException váltódik ki.
-
optional.orElse(egyéb)
Az adat lekérdezése. Ha nincs adat, akkor az egyéb adatot adja vissza. Az egyéb lehet null is! Példa:
-
optional.orElseGet(Supplier)
Az adat lekérdezése. Ha nincs adat, akkor a Supplier által előállított egyéb adatot adja vissza.
A Supplier nem lehet null!
-
optional.orElseThrow(Supplier<X extends Throwable>)
Az adat lekérdezése. Ha nincs adat, akkor a Supplier által előállított exception váltódik ki.
A Supplier nem lehet null! Példa:
-
option.ifPresent(Consumer)
Műveletvégzés az adaton, ha az létezik. Adat kiírása ha az létezik:
Paths & Path
-
A Paths.get() metódussal path-részeket lehet összefűzni, és az összefűzés során nem probléma,
hogy egyes részek "/" vagy "\" karakterrel kezdődnek vagy kezdődnek.
A metódus az elemek közé az operációs rendszernek megfelelő File.separator elválasztó karaktert illeszti be.
Ezenkívül a duplán szereplő szeparátor karaktereket is lecseréli szimplára.
-
Unix példa:
Windows példa:
-
Ha a path egy része nem létezik, akkor ne null-t adjunk át paraméternek, mert az NullPointerException-t okoz,
hanem üres stringet:
-
A Path példány átalakítható File példányra is:
-
Új elem hozzáfűzése a meglévő path végéhez:
pdf készítés
-
PDF készítéshez régebben az Itext-et használták.
Az Itext fizetős lett, ezért helyette az ingyenes OpenPDF használatos, mely az itext-ből lett fork-olva.
private / public / protected
-
Ezekkel a kulcsszavakkal szabályozható egy osztály tagjainak hozzáférhetősége más osztályok számára.
-
private
Csak a saját osztály fér hozzá, még a leszármazott osztály sem.
-
public
Minden osztály hozzáfér.
-
protected
Csak ugyanebben a java package-ben lévő osztályok ÉS a leszármazott osztályok férnek hozzá.
Ez a "félnyilvános hozzáférés kiterjesztése".
-
nincs meghatározva
Csak ugyanebben a java package-ben lévő osztályok férnek hozzá.
Még a leszármazott osztály sem fér hozzá, ha másik package-ben van.
Ez a "félnyilvános hozzáférés".
regular expression
-
Pattern, matcher példányok létrehozása:
-
A kifejezésben ne számítsanak a kis/nagybetűk, és nemcsak az angol betűknél nem,
hanem egyéb (magyar ékezetes) betűknél se:
-
Annak vizsgálata hogy az egész szöveg megfelel-e a kifejezésnek:
-
Szövegdarabok keresése a teljes szövegben, melyek megfelelnek a kifejezésnek:
-
Kereséskor mindig a lehető leghosszabb darabot találja meg, ami megfelel a kifejezésnek.
Tehát "aaa" szöveg esetén, ha a kifejezés "a+", akkor csak egyetlen találat van a szövegben, nem pedig 3
ami mind megfelelne a kifejezésnek!
-
A talált szövegdarabok nem fednek át egymáson, mindegyik találat egy különálló darab a szövegben.
-
A szövegdarab csak valódi darabja lehet a szövegnek, nem az egész szöveg.
Tehát "abc" szöveg, "abc" kifejezés esetén: nincs találat.
-
A kifejezés speciális karakterei:
-
Példák:
-
Webes regexp tesztelő
Használatakor a regexp kifejezést tegyük ^ és $ közé, például: ^[a-z]$
Java programban ezek a sorkezdő és sorzáró jelek nem kellenek a regexp kifejezésbe,
ha a Matcher.matches()-t használjuk!
resource fájl beolvasás
-
Egy projektben az /src/main/resources könyvtáron belüli fájlok (resource fájlok) beolvashatók
a program futása közben, de csak korlátozott módon.
Azért, mert amíg a program az IDE-ben fut, addig ezek a fájlok önállóan léteznek a fájlrendszerben,
de ha jar-ba vagy war-ba vannak csomagolva,
akkor nem önállóak, így nem érhetők el File módon, és nem használható a hozzájuk tartozó elérési út sem.
A biztosan működő megoldás, hogy InputStream-ként érjük el őket:
-
Egy lehetséges feldolgozás, ha szöveges fájlról van szó:
-
Figyelem!
A path-ban az elválasztó karakternek mindig "/" karakternek kell lennie, nem pedig "\" karakternek!
Ilyen eset akkor fordul elő, ha windows-on File objektumban kapjuk meg a path-t.
Ilyenkor ki kell cserélni a "\" karaktert:
run
-
Ha a jar-ban definiált fő osztályt akarjuk futtatni:
-
Ha a jar-ban nincs definiálva fő osztály, vagy nem azt akarjuk futtatni, hanem a Lekerdezo osztályt:
-
Ha nincs jar-fájl, de a program le van fordítva class-fájlok formájában a target/classes könyvtárban,
és a Lekerdezo osztályt futtatjuk:
session tracking - jsessionid
-
Alapvetően egy java webalkalmazás a session azonosítót egy "jsessionid" nevű cookie-ban szeretné tárolni,
ha ez lehetséges. Nem lehetséges ha pl. a web böngészőben a cookie tiltva van, vagy más akadályozza
pl. proxy beállítás. Ekkor url rewriting történik, vagyis az url-ben jelenik meg a jsessionid és értéke.
Ha ezt nem szeretnénk, arra rossz megoldás hogy a web.xml-ben a "tracking-mode" beállítással
erőltetjük a cookie használatát,
hiszen a cookie küldés nem működik, ezért került be az url-be.
Meg kell határozni miért nem megy a cookie küldés, lásd alább a "proxy" problémát.
-
Proxy probléma:
Tegyük fel hogy van egy java webalkalmazás a http://host1/webapp8 címen, de ezt csak egy
http://host2/webapp proxy-n keresztül érjük el.
A webalkalmazás context path-ként /webapp8 -at lát, ezért /webapp8-as path jellemzővel
küld ki a kliens felé egy jsessionid sütit.
A süti keresztül megy a proxy-n (az nem akadályozza), és a böngészőben letárolódik a következő jellemzőkkel:
A host jellemző automatikusan jön létre mert onnan kapta a böngésző (a hívott proxy host-ja).
A probléma az hogy ezt a sütit a kliens
soha nem küldi vissza hiszen a proxy miatt nem /webapp8, hanem /webapp címet hívunk !
Így tehát a webalkalmazás amikor nem kapja vissza
a jsessionid sütit, az url rewriting mellett dönt, és a jsessionid megjelenik az url-ben.
Megoldás:
A proxy címet át kell alakítani úgy hogy megegyezzen a webalkalmazás context path-szal,
vagyis erre: http://host2/webapp8.
Vagy pedig az alkalmazás context path-t kell átállítani hogy megegyezzen a proxy path-al:
http://host1/webapp.
-
A Servlet 3.0 szabványban bevezették, hogy a tracking-mode paraméterrel szabályozni lehessen, a jsessionid azonosító
egy cookie-ban legyen-e tárolva 'COOKIE', vagy az url tartalmazza 'URL', esetleg 'SSL' legyen.
Ennek a szabályozása a web.xml-ben:
A COOKIE beállítást lehetőleg ne használjuk, mert nem biztos hogy működni fog az alkalmazás,
lásd fent leírtak !
sftp
-
SFTP műveletek végrehajtásához a Jsch library használata terjedt el, ezt használják a legtöbben.
-
Jsch példák
-
A Jsch library használatához ki kell egészíteni a pom.xml-t:
-
Példa:
soap
-
Java-ban a régebbi típusú webservice JAX-RPC, az újabb (glassfish3-mal működők) JAX-WS alapúak.
Ha utóbbit használuk akkor a projekthez hozzá kell rakni a JAX-WS library-t.
-
A webservice-t leíró (xml formátumú) wsdl definíció automatikusan kell hogy előálljon a java forráskód alapján,
tehát nem kézzel írjuk !
Amikor a webservice fut, akkor az url-jéhez "?wsdl" -t írva meg kell hogy kapjuk a wsdl-t
(ami további xsd-kre hivatkozik).
A wsdl-t annak kell adnia aki a webservice-t készíti. Természetesen lehetséges hogy kapott wsdl-ből állítjuk elő
a webservice-t, de ez nem normális eljárás.
A wsdl azért is szükséges mert ebből lehet előállítani a webservice-t hívó kliens programot.
-
Ha egy idegen webservice (más által készített) változik (amit mi hívünk mint kliens),
akkor elég a netbeans-ben ráállni a "Web Service References"-re majd jobb egérgombot -> Refresh
Ez újra el fogja készíteni a megfelelő generált kódokat a kliensünkhöz.
-
A netbeans a generált kódokat felülírja a következő clean+build -nél ezért azokba ne írjunk bele !
A generált kódok jók, ha hiányzik valahol a setXXX() metódus akkor enélkül is meg lehet lenni,
helyette a getXXX()-et kell használni, és a generált forráskód tartalmazza ezt a getXXX()-et hogy kell használni.
-
A "Web Service References" esetén útólag is lehet állítani melyik package-be generálja le a forráskódot.
Jobb egérgomb -> Edit Web Service Attributes -> Wsimport Options -> "Option" oszlopba fel kell venni
a "package" bejegyzést.
Egy ilyen művelet után viszont mindenféle kell: refresh, clean, rebuild, glassfish + netbeans újraindítás,
mert különben kaphatunk értelmetlen NoClassDefFound exception-t.
A Kapott wsdl-ből generált kódnál nem tudunk (nem ajánlatos) beleszólni milyen package-be teszi le.
-
Hibakezelés: a webservice-ben mindenképpen kapjuk el a keletkezett hibát, tegyük egy string-be ezt a stack trace-t,
és ezt a stringet adjuk vissza a hívó kliensnek (int errorCode, String errorMessage).
Így a kliens oldalon teljesen normálisan megkapjuk az egész stack trace hibaüzenetet.
Ha nem így csináljuk akkor keletkezik egy SOAPFaultException, ami csak a hibaszöveget tartalmazza,
és így nincs meg a stack trace, hogy nyomozni tudjuk a hiba keletkezési helyét.
Az errorCode-ot úgy érdemes használni hogy 1-ről indul alapból,
és ha a webservice sikeresen lefut a legvégén állítja 0-ra.
-
Webservice készítés normális módon (wsdl nélkül):
Ha egyszerű paramétereket szeretnénk fogadni/visszaadni (Integer, String, Date), azzal nincs baj,
de ha egy komplexebb java objektumot, akkor annak a tagjait el kell látni speciális annotációval pl:
Ha több elemet akarunk fogadni/átadni akkor használható a List<...>, illetve fájlok adatátvitelére használható
a byte[] típus. A SOAP üzenetben a byte[] automatikusan base64 kódolással fog átmenni.
-
Webservice készítés nem normál módon (kapott wsdl-ből):
A kapott wsdl, xsd állományokat egy könyvtárba kell rakni, formázni a netbeans-szel,
és átírni bennük a "schemaLocation" részeket,
hogy csak fájlneveket tartalmazzanak. Ezután létre kell hozni egy web service-t:
ahol meg kell adni a kapott wsdl állományt, vagy annak elérési url-jét.
-
Webservice kliens (hívó) készítés:
A webservice kipróbálásához létre kell hozni egy klienst:
Ennek a "wsdl url" mezőjének kitöltése: indítsuk el a webservice-t "?wsdl" utótaggal,
és ha látjuk a wsdlt a böngészőben,
akkor ez az url kell nekünk. Az eljárás le fogja generálni azokat az osztályokat melyek kellenek a kliensnek.
Ha egy servlet kódjába szeretnénk illeszteni a webservice hívó kódot akkor:
Ha JSP lap kódjába szeretnénk illeszteni a webservice hívó kódot akkor:
Ezután a servlet(vagy JSP) generált kódja üres paraméterrel hívja a webservice-t,
a paramétereket nekünk kell elkészíteni, pl:
ahol a QName megegyezik a soap-xml -ben lévő névvel.
Figyelem: egy kliens csak a konkrét gépen futó webservice-t tudja hívni,
ezért ha a webservice-t felrakjuk egy másik gépre, akkor ahhoz egy másik kliens hívó kell.
-
Paraméter átadás handler és webservice között:
A handlerben van hozzáférünk a SOAPMessageContext-hez, ezt nevezzük így: messageContext
A webservice-ben hozzáférünk a WebServiceContext-hez, ez legyen: wsContext
Handler ad át paramétert a webservice felé:
Handler:
Webservice:
Webservice ad át paramétert handler felé:
Webservice:
Handler:
-
Elképzelhető hogy egy webservice-t hívó alkalmazás a következő hibát adja:
Megoldás: a glassfish grafikus felületén az Update Tool segítségével fel kell tenni a metro add-ons elemet,
majd a glassfish-t újra kell indítani.
-
Dokumentációk:
http://netbeans.org/kb/trails/web.html
http://metro.java.net/2.0.1/guide/SOAP_headers.html
MessageHandler készítés
-
A google chrome böngészőhöz van egy Wizdler nevű kiegészítő,
mely a wsdl-fájlt olvasható formátumra tudja alakítani.
sorba rendezés
-
Egy tömböt vagy egy List-et sorba lehet rendezni a következő metódusokkal:
Ekkor a sorbarendezés az elemek compareTo() metódusa alapján történik,
vagy primitív típusoknál egy természetes sorrend alapján.
Stringek esetén ez NEM a magyar abc sorrend szerint rendez.
-
Azonban ezen metódusok második paramétereként megadható egy Comparator,
ekkor ez határozza meg a sorbarendezés módját.
Egy ilyen Comparator a Collator osztály, melynek lehet Locale-tól függő beállítása,
ezzel lehetséges a magyar sorbarendezés.
-
A Comparator egy @FunctionalInterface, tehát könnyen leírható egy fájlokat tartalmazó
tömb sorbarendezése név szerint:
-
Saját osztálynál: ha a compareTo() metódusát meg akarjuk valósítani,
akkor implementálni kell a Comparable interface-t.
stream
-
A stream műveleteit általában metódus láncban írjuk le. Ezek tipikusan így épülnek fel:
A lánc elején egy stream létrehozó metódus áll.
Ezt követik a lánc közepén elhelyezkedő metódusok, melyek szintén stream-et adnak vissza:
intermediate operations.
A lánc végén pedig olyan metódus van, mely nem stream-et ad vissza:
terminal operations.
-
Stream létrehozó metódusok:
-
Stream.empty()
Üres stream.
-
Stream.generate()
Végtelen elemű stream. A stream elemei véletlenszámok:
-
Stream.iterate()
Végtelen elemű stream. A stream elemei: 15, 17, 19, 21, ...
-
Stream.of()
A felsorolt elemekből álló stream:
-
Collection.stream()
Collection-ből (List, Set, Map, ...) létrehozott stream:
-
Files.lines()
File soraiból álló stream.
-
Files.list()
Könyvtár fájljaiból álló stream.
-
Files.walk()
Könyvtár és alkönyvtárainak fájljaiból álló stream.
-
Random osztály metódusai
Random számokból álló stream.
-
Arrays.stream()
Tömb elemeiből álló stream.
-
IntStream, LongStream, DoubleStream
Ezen osztályok metódusaival hozhatók létre konkrét adattípusokból álló stream-ek.
5, 6, 7, 8, 9, 10 elemeket tartalmazó stream:
-
Intermediate operations:
-
filter()
Leszűri az elemeket, és csak a szűrőnek megfelelő elemeket tartalmazó stream-et adja vissza.
Csak az 5-nél nagyobb elemeket tartalmazó stream:
-
distinct()
Egy elem csak egyszer szerepel az általa visszaadott stream-ben.
-
limit()
A visszaadott stream maximális elemszámának megadása.
Ha a stream végtelen elemből áll,
akkor a limit() miatt a maximális elemszám elérésekor a végtelen stream mégsem generál több elemet.
-
skip()
A visszaadott stream nem tartalmazza a stream elejéről a megadott számú elemet.
-
map()
Stream elemeinek átalakítása. Az átalakított stream-et adja vissza.
Egész számokat tartalmaző stream átalakítása hexadecimális számokat tartalmazó stream-re:
-
peek()
Visszaadja a stream-et változatlanul, de közben az elemein műveletet lehet végezni.
Egy metódus lánc közepén kiiratjuk milyen elemek haladnak át a láncon:
-
sorted()
Sorbarendezés. Hívható paraméter nélkül. Ekkor feltételezi, hogy a sorbarendezendő objektum implementálta
a Comparable interface-t, így ez alapján rendez. Ha nem implementálta, akkor exception keletkezik.
Vagy megadható paraméternek egy Comparator. Mivel a Comparator egy funkcionális interface,
leírható egy lambda kifejezéssel is, melynek 2 bemenő paramétere van (a 2 összehasonlítandó adat),
kimenete pedig egy int, melynek értékei:
- Negatív egész: Ha az első paraméter kisebbnek tekintendő.
- Nulla: Ha a két paraméter egyenlőnek tekintendő.
- Pozitív egész: ha az első paraméter nagyobbnak tekintendő.
Például stringek sorbarendezése hossz szerint:
Vagy sorbarendezés két objektum metódusa alapján:
-
Terminal operations:
-
forEach()
A stream minden elemén végrehajtódik.
A stream elemeinek kiiratása:
-
anyMatch()
Létezik-e legalább egyetlen stream-elem, melyre a megadott feltétel teljesül?
-
allMatch()
A stream összes elemére teljesül a feltétel?
-
noneMatch()
A stream egyetlen elemére sem teljesül a feltétel ?
Ez az allMatch() ellentéte.
-
findAny()
Egy tetszőleges elem visszaadása a stream-ből.
-
findFirst()
A stream első elemének visszaadása.
-
reduce()
Műveletvégzés a stream elemein.
Elemek összegének kiszámítása:
-
toArray()
Stream tömbre alakítása:
-
collect()
Stream egy objektumra alakítása.
string format
-
A string formázás ezeknél a metódusoknál alkalmazható:
-
Néhány formátum:
-
Példa:
string split
-
A String osztály split() metódusa jobb mint a StringTokenizer, ugyanis a string feldarabolásakor
megkaphatjuk az elválasztójel előtt, után, és közöttük lévő darabokat is.
Ehhez fontos hogy a split() második paramétere negatív szám legyen !
Ekkor a kapott tömb 1-gyel több elemű lesz mint ahány elválasztójel van a darabolandó stringben.
-
Ha az elválasztójel "\t" akkor a regexp miatt split("\\t",-1) formában kell megadni.
"|" esetén pedig split("\\|",-1) formát kell használni.
switch
-
A switch legalább a következő adattípusokkal használható:
-
Switch statement
Ha a "➔" szintaxist használjuk (nyíl operátor), akkor nincs szükség break-re,
mert csak a "➔" jobb oldalán található egyetlen utasítás hajtódik végre.
Ha több utasítást szeretnénk végrehajtani, akkor {} közé kell őket tenni.
-
Switch expression
Abban különbözik a switch statement-től, hogy az általa visszaadott értéket fel kell használni
(változóba kell tölteni, return-nel vissza kell adni, ...).
Tehát a java fordítónak el kell tudni dönteni, hogy a switch statement vagy expression módban van-e.
A switch expression-t pontosvesszővel is zárni kell!
A "➔" jobb oldalán található kifejezéssel tér vissza.
Ha nemcsak a visszatérési értéket akarjuk megadni, hanem más műveletet is el akarunk végezni,
akkor {} közé kell őket tenni, és a visszatérési értéket yield-del kell visszaadni.
-
case null
Ezzel lehetne kezelni a null értéket a switch-en belül, de ez még csak preview feature a java 17-ben,
ezért alapból nem használható.
system properties
-
System property lekérdezése:
-
A kulcs néhány lehetséges értéke:
szülő - gyerek
-
Szülő osztály:
Gyerek (leszármazott osztály):
Hívjuk meg a printMessage() metódust, mely csak a szülő osztályban van:
Azt fogjuk tapasztalni hogy a "GYEREK METÓDUS" jelenik meg, vagyis a szülő metódus a gyerek osztályban lévő
proba() metódust hívja meg.
-
A fent leírt metódus felülírás, nem működik az osztály tagjaival.
Ha a gyerekben is definiálunk ugyanolyan nevű tag-ot, az nem írja felül a szülő tag-ját, csak elfedi,
hiszen itt nincs @Override.
A Netbeans is problémázik hogy elfedjük a szülő tagját.
-
A gyerek osztály nem örökli meg a szülő konstruktorát.
Tehát hiába van a szülő osztálynak egy olyan konstruktora ami egy String paramétert
vár, a gyerek osztályt nem lehet úgy példányosítani, hogy egy String paraméterrel hívjuk meg a konstruktorát.
Hacsak nem készítünk a gyerek osztályban is String-et fogadó konstruktort,
ami super(String)-rel meghívja a szülő konstruktort.
tcp
-
TCP szerver:
- A TCP szervernek csak egyszer kell létrehoznia a ServerSocket példányt.
-
A ServerSocket.accept() addig vár amíg a kliens nem csatlakozik be egy új socket-tel (new Socket()),
ezután továbblép. Ekkor érdemes egy új szálat elindítani ami a kapott socket-en keresztül megvalósítja
a kommunikációt a klienssel. A szál elindítása után ismét hajtsa végre a ServerSocket.accept() metódust,
várva egy másik bejövő kapcsolódást.
-
TCP kliens:
-
A kliens oldalon a Socket objektum létrehozásakor automatikusan egy lokális port is le lesz foglalva,
ide lesznek küldve a szerverről érkező adatok.
-
A kliens a Socket objektum létrehozásakor nagyon sok ideig várakozik a szerverre,
ha pl. azon a porton nem is fogad a szerver.
Egy rövidebb várakozási idő így állítható be:
Ha nem jön létre a kapcsolat SocketTimeoutException keletkezik.
-
A TCP kliens a létrehozott Socket objektumon keresztül tetszőlegesen sok kérés-választ lebonyolíthat
a TCP szerverrel. A kommunikáció a kapott InputStream, és OutputStream objektumokon keresztül történik,
de ehhez ki kell találni egy protokolt, hogy a kliens/szerver tudja meddig kell olvasni az InputStream-en.
Például előszőr át kell küldeni az adatfolyam hosszát, így a másik fél tudja hány byte-ot kell olvasni.
Az InputStream/OutputStream nem zárható le, csak a kommunikáció legvégén!
-
Az InputStream.read() várakozni fog amíg a stream nyitva van, és a másik oldal nem küld adatot.
Ha a stream-et a másik oldal lezárta,
akkor EOF jelet(-1) lehet olvasni a stream-en tetszőleges sokszor.
-
A kliens - szerver között tetszőleges nagy mennyiségű byte-sorozat átküldhető.
-
Az OutputStream-be írás végén meg kell hívni a flush() metódust hogy az adatok valóban el legyenek küldve.
try with resources
-
A try with resources formánál az a jellemző, hogy a try után zárójelben egy vagy több olyan példány
van definiálva mely megvalósítja
az AutoCloseable vagy Closeable interface-t.
Az interface miatt ezeknek a példányoknak van close() metódusa, mely a try befejeződésekor
mindig automatikusan meghívódik, még akkor is ha a try-on belül exception keletkezik.
A close() metódusok fordított sorrendben hívódnak meg mint ahogy a try után szerepelnek,
tehát ebben a példában az sql2.close(), majd az sql1.close() hajtódik végre!
-
Ellentétben a try-finally blokkal, ha a try-with-resources szerkezetben a try blokkban exception keletkezik,
azt nem nyomja el a close() híváskor keletkező exception! A stack trace-ben minkét exception megtalálható,
a try blokkon belüli a fő exception, és a close()-on belül keletkezett pedig alatta szerepel
egy Suppressed felirattal.
-
A try utáni zárójelben kötelező lokális változót deklarálni, melynek az érvényessége csak a try blokk,
a catch és finally ágban nem látható.
terminal
-
Windows cmd-terminal
Az ékezetes karakterek helyes megjelenéséhez UTF-8 kódolást állítsunk be,
ami windows-on a 65001-es kódolásnak felel meg.
Batch fájlban a hosszú sorok megtörhetők a "^" karakterrel.
A path separator "\" karaktere helyett használhatjuk a "/" karaktert is.
A jobb átláthatóság érdekében üres sorokat is hagyhatunk.
text blokk
-
A text blokk is egy string, mely ezzel kezdődik és végződik:
"""
-
A kezdő
"""
(0. sor) után nem állhat más a sorban, csak space-ek, és sorváltás.
A 0. sor nem része a stringnek, csak az utána következő sorok.
-
Az 1. sortól, a záró
"""
-t tartalmazó sorig a fordító ütközésig balra tolja a sorokat.
Az így kieső space-ek nem részei a stringnek.
-
A sorok végén lévő space-ek nem részei a stringnek.
A záró """
előtti space-ek sem részei a stringnek.
Ezt ki lehet küszöbölni ha a sor tartalmaz "\s"
(direkt space) karaktert,
így ő, és az őt megelőző space karakterek is részei a stringnek.
-
A sorok végén lévő sorváltás
"\n"
karakterként bekerül a stringbe.
Ezt ki lehet küszöbölni egy adott sornál, ha a sor "\"
karakterrel végződik.
A "\"
karakter előtti space-ek a string részei maradnak!
-
Ha a záró
"""
külön sorban van, akkor a string sorváltás karakterrel végződik.
-
Példa:
A kiírás eredménye, melyben a space-t
"."
,
a sorváltást "^"
jelöl:
típushiba
var
-
A var kulcsszóval is definiálható lokális változó.
Azért vezették be a 10-es java-ban, hogy a forráskód olvashatóbb legyen.
-
A var-ral definiált változóhoz szükséges egy inicializátor, vagyis az egyenlőség jobboldalán
kell álljon egy olyan kifejezés, melyből a fordító egyértelműen eldönti milyen lesz a változó statikus típusa.
A példában az m1, m2, és m3 változók ugyanolyan típusúak lesznek,
de a var-ral írt sor a legrövidebb, és legolvashatóbb:
-
Null nem lehet a jobboldali kifejezés, hiszen abból a fordító nem tudná eldönteni a típust:
-
"var" kulcsszóval csak lokális változó deklarálható, osztály tagjánál nem használható!
varargs
-
A változó paraméterszámú (varargs) metódus paraméterénél a típus után 3 darab pontot kell tenni.
A metódus belsejében egy tömbben kapjuk meg a paramétereket:
-
A metódus meghívásakor egy tömbben is átadhatjuk a paramétereket, és vesszővel elválasztva is:
-
Ha a metódus hívója nem ad át paramétert, akkor a tömb üres lesz (nem pedig null):
-
Ha a metódus hívója egyetlen null paramétert ad át, akkor a tömb nem egyetlen null elemet fog tartalmazni,
hanem null lesz:
Itt nem lehet eldönteni, hogy a fentiek közül ez az 1. eset, vagy a 2. eset, így a java futtató
ezt tömbként értelmezi.
Így tehát a metódus belsejében is null lesz a tömb, nem pedig egy 1-elemű null-t tartalmazó tömb!
Ha nem ezt a működést szeretnénk, akkor a metódus meghívásakor meg kell adni a típust, hogy ne tömbnek értelmezze:
web browser no-cache
-
Rákényszeríthető a web böngésző hogy a weblapokat ne tárolja.
Ezt úgy lehet elérni hogy a http response header-be a következő bejegyzéseket írjuk:
Ezzel a megoldással azt lehet elérni, hogy a böngésző vissza és előre gombjai úgy hozzák be az oldalakat,
hogy mindenképpen a szerverhez fordul,
és attól kéri az oldalt, tehát semmiképp sem a saját cache-ből veszi.
A módszer működik Firefox, Chrome, Edge böngészőkkel.
-
Egyes web böngészők (pl. safari) hibásan kezelik a fenti headert.
A header ellenére is megőrzik cache-ben a tartalmat, a böngésző back gombjával vissza lehet menni
az előző (nem kívánatos) lapokra, és ezek az oldalak a cache-ből jelennek meg.
xml-rpc
-
XML-RPC technológiához a Redstone-t érdemes használni.
zip
-
ZIP fájl készítése
-
ZIP fájl kicsomagolása (unzip)