Manchmal ist es echt unpraktisch viele kleine JAR-Dateien zu haben und man hätte gerne alles in einer großen. Keine Class-Path Probleme mehr, einfaches Deployen und ein Single-Point-Of-Failure.
Mit Maven geht das zum Glück sehr einfach. Spring Boot und Meecrowave haben eigene Plugins mit denen man auch sehr gut arbeiten kann und die dem Beispiel hier vorzuziehen sind.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>de.hannespries.time.gui.MainFrame</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Die Windeit-Software GmbH wird in der nächsten Zeit eine neue Version des Automatic XML-Export Shopware-Plugins veröffentlichen. Es hat nun die Version 2.0.0 erreicht und kann jetzt selbstständig per SCP XML-Dateien auf einen anderen Server laden.
Dafür muss die php-ssh2 Extension installiert sein, was unter Ubuntu sehr einfach geht:
sudo apt-get install php7.2-ssh2
Auf dem Ziel Server muss der Openssh-Server installiert sein.
Danach müssen nur noch die Verbindungsdaten eingegeben werden und der SCP-Upload aktiviert werden.
Ein paar kleine Code-Snippets, um grundlegende Funktionen in node.js mit Elasticsearch implementieren zu können.
Elasticsearch-Client installieren:
npm install elasticsearch get-json
Client erstellen:
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client( {
hosts: [
'http://localhost:9200/'
]
});
Index erstellen:
if(!client.indices.exists("testidx")){
client.indices.create({
index: "testidx"
}, (error, resp, status) => {console.log(status)}
);
}
Document speichern:
client.index(
{
index: "testidx",
type: "item",
id: "1",
body: {
id: "123",
value: "blubb"
}
}
);
Ein einfaches Query mit Callback-Function:
client.search({
index: 'testidx',
type: 'item',
body: {
query: {
match: { "id": "123" }
},
}
}, (error, response,status) => {
console.log("-- Hits --");
response.hits.hits.forEach((hit) => {
console.log(hit);
});
});
Ein einfaches Query mit Promise:
client.search({
index: 'testidx',
type: 'item',
body: {
query: {
match: { "id": "123" }
},
}
}).then((response) => {
response.hits.hits.forEach((hit) => {
console.log(hit);
});
}, (error) => {console.log(error);})
Mit Hilfe dieser Seite https://www.compose.com/articles/getting-started-with-elasticsearch-and-node/ zusammen gebastelt und hiermit https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/quick-start.html ergänzt.
Manchmal soll Logik auf Daten einer Map zugreifen können aber nicht ändern können. Ich habe für meine State-Implementierung Action-Dispatcher eingeführt, die Daten der Action anpassen dürfen und dafür auch Daten aus dem State zum Abgleich nutzen sollen, aber an der Stelle sollen sie nicht die Möglichkeit haben den State selbst zu ändern, weil ich an der Stelle keine Änderungen tracke. Action-Dispatcher sollen schnell und leichtgewichtig sein.
Map<String, Object> stateUnmod = Collections.unmodifiableMap(this.state);
for (ActionDispatcher dispatcher: this.dispatchers) {
dispatcher.dispatch(action, stateUnmod);
}
Zum Glück kann man mit Collections sich schnell eine unmodifiable Map erstellen. Was das für die Performance bedeutet habe ich noch nicht getestet, aber ich gehe davon aus, dass das Tracken und Behandeln von Änderungen am State am Ende auf wendiger wäre.
Viele Probleme lassen sich nicht durch einfache SQL-Queries lösen. Gerade wenn es um Daten-Generierung und Dinge geht, wo man die Logik nicht in allen Clients umsetzen möchte, die auch die Datenbank zugreifen.
Wärend Stored Procedures coole Dinge wie IF, WHILE und so können, haben die doch oft einen schlechten Ruf, weil man dann ja nicht mehr Datenbank unabhängig wäre, wenn man anfängt diese zu verwenden. Aber am Ende wird man sowie so nie wirklich die Datenbank wechseln und sollte man das tun, dann eher von SQL zu NoSQL und da ist es dann auch egal, da man alles alle neu anpassen muss.
Eine einfache Procdure in MySQL:
DELIMITER \\
DROP PROCEDURE IF EXISTS exampleProcedure\\
CREATE PROCEDURE exampleProcedure()
BEGIN
DECLARE checkval INT;
SET expectedval = 0;
START TRANSACTION;
-- implement your logic here
IF checkval = expectedval THEN
COMMIT;
ELSE
ROLLBACK;
END IF;
END \\
DELIMITER ;
CALL exampleProcedure();
DROP PROCEDURE IF EXISTS exampleProcedure;
Es gibt auch die klassischen IN und OUT Parameter. Alles ganz einfach und schnell zu schreiben. Sieht ein wenig aus wie Pascal. ABER im Vergleich zu PL/SQL fehlen doch eine Datentypen wie RECORDs, um komplexere Datenstrukturen anlegen zu können oder direkter mit Tables arbeiten zu können. SELECT .. INTO ist nett, aber RECORDs machen es doch sehr viel einfacher und strukturierter.
Aber an sich kommt man damit zurecht und man sollte doch mehr davon und auch öfters Stored Procedures verwenden, um sich in einigen Teilen das Leben etwas leichter zu machen.
Ich habe PL/SQL immer gerne verwendet, auch wenn ich oft genug daran verzweifelt bin.
Ein kleiner Tipp, wenn man in einer Webapp zulange Listen- oder Tabelleneinträge zurecht schneiden möchte. Um anzuzeigen, dass der Text gekürzt ist will man oft ... am Ende stehen lassen. Das mit PHP, JavaScript, etc zu machen ist aber doof und overflow-hidden: hidden reicht nicht. Aber es gibt in CSS text-overflow.
.cut-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
Der Text wird einzeilig und abgeschnitten. Zusätzlich werden 3 Punkte angehängt. Alles gut? Nur solange man es nicht bei einem <li> mit Bullet-Points verwendet. Die gehen dabei leider auch verloren. Aber auch hier gibt es eine Lösung, wobei man aber die Abstände des <li> zum linken Rand neu anpassen muss.
li.cut-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
list-style-position: inside;
}