Bald ist wieder die Zeit der Bewerbungstest und -gespräche für Fachinformatiker AE(=Anwendungsentwicklung) Ausbildungsstellen oder man ist noch in der Schule und überlegt sich, ob man sich den Abi-Stress wirklich antun soll. In beiden Fällen hat man sich wohl schon einige Gedanken gemacht und wollte sich schon mal ein Bild davon machen wie Programmieren in de, Beruf aussieht. Privat zu entwickeln ist doch immer etwas anderes als anderes.
In den meisten Fällen wird man sich seinen Ausbildungsplatz nicht danach aussuchen, welche Programmiersprachen in der jeweiligen Firma verwendet werden. Man wird nehmen was man bekommt. Wenn man sich aber mal grob auf ein Gespräch vorbereiten will und man in eine neue Sprache hinein schnuppern möchte, muss man sich erst einmal eine Umgebung einrichten. Es gibt genug Tutorials dazu.. deswegen möchte ich in nichts nachstehen.
Ich musste damals mir auf die Schnelle alles einrichten um ein C-Programm unter Linux zu schreiben und zu compilieren. Mit Hilfe des Internets ging es auch ganz gut. Aber für C bringt Linux auch alles.
Ich zeige hier aber einfach mal, was man alles braucht, um mit Java, PHP und JavaScript ein kleines "Hello World" Programm zu schreiben. Wobei die Einrichtung der Umgebung im Vordergrund steht und nicht das kleine Programm.
Java (Teil 1) Java Umgebungen sind nicht immer das einfachste. Wenn man eine Webanwendung schreiben möchte, hat man schon relativ viel zu konfigurieren. Deswegen erst einmal ein kleine und einfache Anwendung.
Als erstes brauchen wir Java. Für die Entwicklung mit Java benutzt man am Besten das JDK (Java SE Development Kit). Es enthält zusätzliche Werkzeuge und den Source-Code zu den Java-Klassen. Außerdem wird keine komische Ask-Toolbar mit installiert. Das JRE ist mit dabei, so dass man mit dem JDK allein auskommt.
Die aktuelle Version der 8er Reihe findet man hier: Oracle Java 8 JDK
Man könnte jetzt theoretisch schon mit einem Text-Editor sein erstes Java-Programm schreiben und mit dem Java-Compiler compilieren. In einem Text-Editor zu schreiben ist aber alles andere als angenehm und man hat keine Syntax-Highlighting, Code-Vervollständigung oder automatische Anzeige von Fehlern. So eine Integrierte Entwicklungsumgebung (IDE) erleichtert einen schon sehr viel.
Die IDE meiner Wahl ist Eclipse. Man kann aber auch NetBeans oder IntelliJ verwenden. Das Grundprinzip ist bei allen gleich. Aber hier nehmen wir Eclipse.
Hier findet man den Download von Eclpise J2EE. Die J2EE-Version, weil da alles mit dabei ist, was man so braucht. Auch alles was man braucht, um ein einfaches Web-Project mit einem Tomcat zu realisieren.
Bei Eclipse einfach die Zip-Datei downloaden und entpacken. Beim ersten Start wird ein Workspace angelegt. Der Workspace ist ein Verzeichnis in dem die Projekte abgelegt werden.
Man kann beliebig viele Workspaces haben und auch mehrere Eclipse Instanzen mit verschiedenen Workspaces gleichzeitig geöffnet haben.
Sollte man schonvorher eine Java-Version installtiert gehabt haben, sollte man nun das neu installierte JDK auswählen. Dazu geht man im Menu in den Menüpunkt.
Window -- Preferences -- Java -- Installed JREs
Dort mit Hilfe der Search... Funktion nach dem neuen JDK suchen lassen. Wenn es gefunden wurde dieses mit dem Hacken vorne als default JRE definieren. Dann wird es automatisch für jedes Projekt verwendet, dass keine eigenen Einstellungen für JRE-Libs hat. Aber das ist jetzt erst einmal nicht so wichtig. Für uns ist nur wichtig, dass unser neues Project das JDK verwendet.
Wenn wir unser JDK eingebunden haben können wir nun unser Project erstellen.
Wir geben dem Project einen Namen. Hier kann man auch gleich sehen, ob unser JDK die default JRE ist. Hier könnten wir auch ein abweichendes JRE auswählen.
Weitere Einstellungen nehmen wir nicht vor und klicken einfach auf finish.
Das Project wird angelegt und wir legen uns unsere Klasse an, die unser Haupt-Programm enthalten wird. Die Klasse ist Main und wird im Package de.hannespries.blog.ides liegen. Packages sind so etwas wie Verzeichnisse, um die Klassen zu strukturieren, aber auch nur ähnlich, weil ein Package über mehrere JAR-Dateien verteilt sein können.
In die Main Methode kommt unser Code. Da wir schreibfaul sind und jetzt eine tolle IDE haben geben wir nur syso ein
jetzt drücken wir Strg+Space und nutzen unser syso zu einem System.out.println() zumachen. Das geht so sehr viel schneller als wenn man alles per Hand schreiben würde, wie man es in einem Text-Editor machen müsste.
package de.hannespries.blog.ides;
public class Main {
public Main() {
// TODO Auto-generated constructor stub
}
Nun wollen wir den Code einmal testen. Erst einmal Speichern. Dann öffnen wir mit einem Rechtsclick das Context-Menü, wählen Run as und dann Java-Application.
Damit wir immer die Console direkt anzeigt bekommen, wenn eine Ausgabe kommt, selbst, wenn wir einen anderen Tab gerade offenen hatten, nehmen wir noch folgende Einstellung vor.
Wenn man das Programm dann mal mit anderen Teilen möchten, kann man über die Export-Funktion eine JAR-Datei erstellen. Wichtig dabei ist, dass man die main-Methode der entsprechenden Klasse auswählt, damit das Programm direkt gestartet werden kann. Die Manifest-Datei ist aber sehr komplex und ist an sich einen eigenen Artikel wert.
Damit haben wir Java und Eclipse installiert. Der Test lief auch. Im nächsten Teil werden wir dieser Installation einen Tomcat hinzufügen und unsere erste kleine JSP-Seite erstellen und im Browser anzeigen lassen.
Die PREG_-Funktionen von PHP sind sehr einfach zu verwenden und sehr mächtig.
Ich habe die Einfachheit bei Java vermisst. Java ist da sehr viel komplexer. Also habe ich die Java Funktionalität in Methoden verpackt, die von der Struktur den PHP-Funktionen sehr gleichen und sich auch genau so verwenden lassen. Etwas Prozedur-orientiertes Programmieren in Java.
public static List<String> matchAll(String pattern, String source) {
List<String> result = new ArrayList<String>();
Matcher m = Pattern.compile(pattern).matcher(source);
while (m.find()) {
result.add(m.group());
}
return result;
}
public static List<String> split(String pattern, String source) {
String[] parts = source.split(pattern);
List<String> list = new ArrayList<String>();
for (int ii = 0; ii < parts.length; ii++) {
list.add(parts[ii]);
}
return list;
}
public static List<String> find(String pattern, String source) {
List<String> result = new ArrayList<String>();
Pattern compiled = Pattern.compile(pattern);
Matcher matcher = compiled.matcher(source);
while (matcher.find()) {
result.add(matcher.group());
}
Da ich momentan das Blog-Modul noch mal überarbeite, wollte ich gerne meine momentane Upload-Methode für Bilder beibehalten und trotzdem den TinyMCE integrieren. Hier ist eine gute Anleitung, wie man ein img-Tag von außen in den Content des TinyMCE einbringen kann.
Ich habe den ersten Schritt gemacht und 2 einfache Filter in MP4toGIF.com eingebaut. Man kann nun direkt schwarz/weiß Animationen aus farbigen Ausgangsmaterial erstellen. Auch eine Farbgebung, die etwas "vintage" aussieht.
Die Filter basieren auf dem Code den ich hier schon mal vor einiger Zeit veröffentlicht habe. Alles natürlich HTML5 Canvas basiert.
Mit der Zeit werden noch ein paar mehr Filter folgen.
Wer mal curl benötigt aber gerade nur Windows zur Verfügung hat, kann es sich leicht nach installieren. Oracle hat eine gute kleine Anleitung veröffentlicht.
Bei mir reichte es dir Schritte 3 und 4 auszuführen.
Als ich mit PHP anfing war es noch Alltag, dass man wenn eine Datenbank-Abfrage notwendig war diese auch einfach direkt an Ort und Stelle einbaute. Kapselung in einer eigenen Funktion oder Klasse war nicht wirklich verbreitet. Es wurde meistens direkt mit den entsprechenden Datenbank Funktionen gearbeitet und keine Abstraktion verwendet.
Nur in großen Anwendungen war es anders. Vorher hatte ich mit Java, JDBC und DataSources im Tomcat gearbeitet, wo es am Ende egal war welche Datenbank dahinter lief und man dies nur beim Anlegen der DataSource abgeben musste. Zuhause war ich auf Oracle Datenbanken und hatte nur so am Rande mit MySQL zu tun. Ich sollte ein Projekt von MySQL auf Oracle portieren und merkte schnell wie doof es war keine Abstraktion zu haben. Also nahm ich mir vor, sollte ich mal ein PHP anfangen, dass ich es besser machen würde. Genau so einfach wie mit einem Tomcat und den DataSources.
Dann kam in der Berufsschule das Thema Datenbanken, dass wir mit einer XAMPP-Installation bearbeiten sollten. Ein kleines Shop-"System". CRUD, eine Liste laden und wenn wir voll gut waren sogar Joins oder mal ein COUNT mit GROUP BY.. also alles was die meistens aus ihrem normalen Arbeitstag in und auswendig kannten. Ich wollte es dann auch gerne so schreiben, dass ich SQL über eine zentrale Klasse ausführen konnte und Schleifen einfach ausführen konnte und das Problem das bei Oracle ein Array so aussah [column]
und nicht wie bei MySQL
[column] direkt dort in der Implementierung ausgeglichen wurde und man so einfach zwischen den beiden Systemen switchen kontne ohne Code ändern zu müssen.
Aber fangen wir mal an. Zuerst erstellen wir uns eine einfache Datenbank Tabelle mit ein paar Daten. Diese werden dann im Verlaufe dieses Artikels mit PDBC aus der Datenbank laden und einmal ausgeben. Unsere Tabelle sieht wie folgt aus:
CREATE TABLE tests (
test_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
test_name VARCHAR(255) NOT NULL,
PRIMARY KEY (test_id)
);
INSERT INTO tests(test_name) VALUES ('TEST_01');
INSERT INTO tests(test_name) VALUES ('TEST_02');
INSERT INTO tests(test_name) VALUES ('TEST_03');
INSERT INTO tests(test_name) VALUES ('TEST_04');
INSERT INTO tests(test_name) VALUES ('TEST_05');
Diese Tabelle repräsentiert Daten für eine einfache Klasse mit einer Id und einem Namen. Also das Grundmodel auf dem bestimmt fast 98% aller Entitäten basieren. Das normale vorgehen wäre jetzt diese Daten über ein einfaches SQL Query einzulesen. Dabei enthält man ein ResultSet oder Array mit allen Zeilen, die man dann in einer Schleife durchläuft. Während jedem Durchlauf erzeugt man ein neues Objekt der Klasse und befühlt dieses über die Setter mit den Daten aus dem Zeilen Array.
$result=array();
foreach($data as $row){
$obj=new Test();
$obj->setId($row["test_id"]);
$obj->setName($row["test_name"]);
$result[]=$obj;
}
Man muss viel per Hand schreiben, was sehr zeitintensiv, stupide und fehleranfällig ist. Wenn man an mehreren Stellen so lädt z.B. einmal laden eines Objekt anhand der Id, einmal die Liste und noch die Liste mit einem Pattern für den Namen, muss man alle Methoden und Funktionen wo man die Daten in das Objekt füllt ändern, wenn man mal eine Column der Datenbank hinzufügt, ändert oder entfernt.
Wenn man diesen Teil nun automatisiert, erleichtert einen das Leben schon sehr. Bei einer Klasse mit 10 Attributen sind es dann nicht mehr 12 Zeilen Code sondern nur noch 2. PDBC erledigt für einen diese Schritte. Vom erzeugen der Objekt, die Abfrage der Daten und dann das befüllen der Objekte.
Um nun zu wissen, welches Datenfeld aus der Datenbank in welches Klassen-Attribute gehört werden Annotationen genutzt. Es ist ganz leicht JPA und Hibernate beeinflusst. Wobei PDBC sehr viel weniger kann.
FKs werden nicht in Objekte abgebildet, also ein lazy oder eager Loading. Es werden nur wirklich Daten kopiert. Das SQL muss man komplett per Hand schreiben, was ich aber als Vorteil sehe, weil HQL/JPQL doch mich immer sehr eingeschränkt haben und viele wichtige SQL-Funktionen wie Nested-Queries und gute Joins oft nicht möglich waren. SQL bietet dort sehr viel mehr und performantere Möglichkeiten.
Aber hier geht es erst einmal um einfaches und schnelles Laden der Datensätze.
Dafür brauchen wir erst einmal unsere Klasse mit den entsprechenden Annotationen, die bestimmen zu welcher Column das Klassen-Attribute gehört. Das Schlüsselwort hierbei ist "@dbcolumn". Diese Annotationen werden mit Hilfe der Refelection Klassen von PHP und den DocComments gelesen und dann geparst.
Damit man hier performant bleibt werden die Properties einmal pro Klasse eingelesen und in einer Map gespeichert, so was man schnell über den Column-Name zum Property gelangt. Wenn man dann für die nächste Klasse die Zuordnung braucht hat man diese schon. Da die Map static ist, geschieht das Einlesen auch nur einmal pro Request für eine Klasse.
setAccessible(true) ist hier sehr wichtig, weil wir so private Attribute lesen und schreiben können und dazu bringt es noch einem wirklich spürbaren Performance-Vorteil. Ja.. auch bei PHP. Bei Java gilt genau das Selbe. Die Reflection-Klassen von PHP sind von den Bezeichnungen und Methoden auch sehr an Java angelehnt und wer mit den Relfections in Java sich auskennt, kann sofort in PHP weiter machen, da die wichtigen Methodennamen wirklich zu 100% übereinstimmen.
public function getId(){
return $this->id;
}
public function setId($id){
$this->id=$id;
}
public function getName(){
return $this->name;
}
public function setName($name){
$this->name=$name;
}
}
Man sieht hier die Annotationen an den Attributen der Klasse. Die Werte werden direkt in die Attribute geschrieben. Die Nutzung der Getter und Setter ist hier nicht implementiert. Wobei das große Vorteile hätte da man so z.B. eine "1" aus der Datenbank auf ein "true" mappen könnte. Dafür werde ich mal eine Implementierung mit eignen Properties schreiben, die zusammen mit dem Property auch die Accessor-Methoden mitliefert, wenn diese vorhanden sind.
Jetzt geht es aber weiter mit dem konkreten Beispiel. Zuerst werden wir uns unsere Datenbank-Klasse holen. Dafür muss die Datenbankverbindung in der Config-Datei angegeben sein. Der Name muss eindeutig sein und mit dessen Hilfe wird die Datenquelle auch identifiziert. Die Bezeichnungen in der Config-Datei orientieren sich Oracle, so nennt sich ein Feld "SID", also Service-ID, das entspricht bei MySQL dem Datenbanknamen. Sollte hier der Standard-Port von MySQL verwendet werden, ist dieser normaler weise nicht anzugeben.
Wir haben hier also unsere Datasource (wie im Tomcat) unter dem Namen "ds_test", die auch die lokale MySQL-Instanz und die Datenbank verweist. Wie man am Passwort schon vermuten kann, habe ich bei mir einfach den Bitnami WAMP-Stack verwendet, aber XAMPP oder eine vollständige Installation gehen natürlich genau so gut.
Wir müssen noch angeben wo die Config-Datei und wo die Datenbank-Klassen zu finden sind.
Wenn man PDBC in sein System integrieren will, kann man so die Config-Datei einfach mit im Config-Verzeichnis des Systems unterbringen.
Nun folgt ein kleines und einfaches SQL-Statement:
$sql="SELECT test_id,test_name FROM tests ORDER BY test_name ASC";
Und nun beginnt der spannende Teil, wir übergeben unser Datebank-Object, den SQL-String und den Klassennamen an den PDBCObjectMapper. Dieser nutzt das Interface der DB-Klasse, weswegen ihm egal ist welche Implementation verwendet wird. Dann wird die Klasse analysiert und deren Properties eingelesen und die passenden Spalten wie schon weiter oben beschrieben eingelesen. Der Rest ist eigentlich relativ primitiv. Erst wird eine Instanz der Klasse erzeugt und dann das Array mit dem Datensatz des Resultsets wir mit $key (Spaltenname) und $value (Wert aus der DB) durchlaufen.
Wird ein Property zu dem $key gefunden wird in dieses das $value geschrieben.
private function fillObject($row,$ref){
$obj=$ref->newInstance();
$props=$this->loadProperties($ref);
foreach($row as $key => $value){
if(isset($props[$key])){
$props[$key]->setValue($obj,$value);
}
}
return $obj;
}
public function queryList($db,$sql,$className){
$db->executeQuery($sql);
$ref=new ReflectionClass($className);
$result=array();
for($i=0;$i<$db->getCount();$i++){
$result[count($result)]=$this->fillObject($db->getRow($i),$ref);
}
return $result;
}
Die loadProperties-Methode habe ich ja weiter oben schon beschrieben. Hier wieder sich daran erinnern, dass wir setAccessible(true) für jedes Properties gesetzt haben und somit ohne Probleme in private-Properties schreiben können.
"Test" ist unser Klassename, $sql unser String mit dem Query-Statement und $db unsere oben in der config-Datei definierten Datasource.
Als Rückgabe erhalten wir, wie alle schon sicher richtig vermutet haben, ein Array mit unseren gefüllten Test-Objekten. Um zusehen, dass alles richtig befüllt wurde, geben wir diese einfach mal aus.
foreach($tests as $test){
echo $test->getId()." - ".$test->getName()."<br>\n";
}
Der gesamte Code für unser kleines Test-Script sieht dann also so aus:
Ich hoffe ich konnte einen kleinen Einblick geben, wie man sich die Arbeit mit Datenbanken in PHP einfacher machen kann und einen Teil der Konzepte aus der Java-Welt in PHP implementieren kann. Man kann natürlich noch sehr viel mehr implementieren und ein kompletes und komplexes ORM-System hier draus bauen, aber das würde hier zu weit führen und ich brauchte es auch so erst einmal nicht. Auch Inserts und Updates darüber zu realisieren und Getter und Setter benutzen zu können wäre toll und steht noch auf dem Plan, aber wohl alles erst im Laufe von 2016.
//line under value title
this.ctx.beginPath();
if(i==this.categoryValueSize-1){
this.ctx.moveTo(this.padding,((iC*this.categoryValueSize)+i+1)*this.barHeight+this.padding);
}
else{
this.ctx.moveTo(this.categoryTitleWidth,((iC*this.categoryValueSize)+i+1)*this.barHeight+this.padding);
}
Heute zum Geburtstag habe ich von meiner Frau Soft Skills geschenkt bekommen. Es ist von John Z. Sonmez, dem Besitzer von http://simpleprogrammer.com und ich habe schon sehr viel Gutes darüber gehört und gelesen. Ein Buch für Programmierer bei dem das Programmieren und die Technik nicht im Mittelpunkt stehen, sondern das ganze Drumherum. Wie auch auf dem Buchcover steht: "coding is the fun part". Kommunikation, Produktivität und Stress sind der nicht so spannende Teil, aber man muss da immer durch.
Wenn ich es lese werde ich sicher noch ein oder zwei mal meine Gedanken dazu hier veröffentlichen.
Ein wenig besinnliches zu Weihnachten. Performance-Analyse auf Oracle Datenbanken. Wenn man heraus finden will welche SQLs viel Zeit verbrauchen, kann man das Query hier verwenden. Es ist ein erster Ansatz und keine absolute Lösung. Aber wenn man Probleme hat, ist es ein guter Einstieg in die Analyse.
select ROUND(disk_reads/decode(executions,0,1,executions)/300) EXTIME, SQL_TEXT
from v$sql
where disk_reads/decode(executions,0,1,executions)/300 >1
and executions>0
order by (disk_reads/decode(executions,0,1,executions)/300) DESC
Oft hilft es am Ende einfach einen Index zu setzen. Aber manchmal muss man tiefer in die Materie gehen.
We have out data seperated in chunks now. Now we have to write a script to send this data to the PHP-script or servlet to save it in a file. This is the elementary part of the the javascript-function and also the simple part. Because we append every chunk to the final file, we can’t work with asynchron requests. If you want to, you have to send also the number of the chunk, and also the final filesize to create a dummy-file and replace the part of the sent chunk. For the javascript the changes are no this big, but the server-side script become more complex.
So.. we will use the synchrone style and work with a simple for-loop to run through our array with the data chunks.
var result=null;
for(var i=0;i<chunks.length;i++){
var last=false;
if(i==(chunks.length-1)){
last=true;
}
result=uploadFileChunk(chunks,filenamePrefix+file.name,url,params,last);
}
return result;
Only the result of the request of the last chunk is returned. Because it is the chunk where the magic (copy from temp-folder to real target folder and create and save entity to database, etc) happens.
I send add a prefix to the filename to create a filename like userid+prefix+filename+fileextension (like *.part or somethin like this). So a user can upload more than one file with the same filename, without cause problems on server side.
But you should also send the original filename as something like "clearname". In this example you can add it to die params-array (params["clearname"]=file.name;) and use it as filename in the db-entity to set this name in header-data on download of this file or in lists of the uploaded files.
function uploadFileChunk(chunk,filename,url,params,lastChunk) {
var formData = new FormData();
formData.append('upfile', chunk, filename);
formData.append("filename",filename);
for(key in params){
formData.append(key,params[key]);
}
Wer einen LG M237WDP an einem PC betreiben möchte muss auf jeden Fall DVI verwenden. HDMI liefert ein extrem matschiges Bild. Bei AMD/ATI Grafikkarten sollte der alternative DVI-Betriebsmodus deaktiviert sein. V-Schärfe und H-Schärfe laufen beide auf 44, danach tauchten bei mir Ghosting-Effekte bei der Schrift auf (Expert 1 Modus im Monitor gewählt).
Farbtemperatur habe ich auch über den Catalyst angepasst, da der Monitor selbst nicht genug Einstellungen hat.
Jetzt stimmen die Farben einiger Massen und auch die Schrift ist ansatzweise scharf.
Now we have a file-object, we need to split it in small chunks to upload this chunks one by one. JavaScript have the ability to work with files. It can’t access the filesystem directly, but the open- and save-dialogs will do every thing we need. To save data for more than one session you can use the indexeddb. But here we need only open,save and drag and drop.
function createChunksOfFile(file,chunkSize){
var chunks=new Array();
var filesize=file.size;
var counter=0;
while(filesize>counter){
var chunk=file.slice(counter,(counter+chunkSize));
counter=counter+chunkSize;
chunks[chunks.length]=chunk;
}
return chunks;
}
The method is very simple. The loop runs as long as the copied size is smaller as the size of the file. With slice(from,to) you have to set the start- and the endpoint, that is read (in bytes). If the endpoint behind the real end of the file no execption is thrown and only the existing part will be copied. That makes it very easy to us. With every run of the loop we add 250000 to the copied-size till our copied-size is greater than the file-size. In ervery run of the loop we copy/slice the bytes from copied-size to copied-size + 250000 and add this slice-chunk to the output array.
Finally we get an array with alle the sliced chunks of the file in correct order.
Yes.. you can calculate the needed count of chunks and than use a for-loop and calculate the start and end for every part. Works great too… but i did it the other way.
var chunks=createChunksOfFile(file,250000);
So we have all chunks each ~250KB. 1MB should have ~4 Parts. Yes.. it’s 1024Bytes per 1KB.. but we keep it simple :-)