Wir stellen vor: Vuecket





Die russische Version

Vuecket ist ein Webframework, das VueJS auf der Clientseite und Apache Wicket auf der Serverseite integriert. Es nutzt das Beste aus beiden und macht die Entwicklung von Full-Stack-Anwendungen noch schneller und einfacher. Das sind natürlich alles große Worte, denn Vuecket ist derzeit (August 2020) weniger als einen Monat alt und hat die Taufe der Produktionsserver "Feuer und Blut" noch nicht bestanden. Aber es enthält bereits das Beste, was wir während der Entwicklung unseres wichtigsten Open Source-Produkts Orienteer (einer Plattform für die schnelle Entwicklung von Geschäftsanwendungen) entwickelt haben. Und gerade wegen seines jungen Alters braucht Vuecket Ihre Hilfe: Bitte teilen Sie uns mit, was Ihnen gefallen hat, was nicht sehr gut ist, wo Verbesserungen erforderlich sind usw.



Die Grundprinzipien, die uns beim Aufbau von Vuecket leiten, sind:



  1. Deklarativ zu sein ist nicht zwingend erforderlich. Vuecket schreibt keine speziellen Code-Anforderungen vor. Es kann relativ schnell und einfach auf vorhandene Vue.JS- oder Apache Wicket-Projekte angewendet werden.
  2. Folgen Sie dem Pareto-Prinzip. Vuecket sollte 80% der gewünschten Funktionen bereitstellen, für die restlichen 20% sollten jedoch gute und bequeme Erweiterungspunkte vorhanden sein.


Es ist leicht zu erkennen, dass diese Prinzipien auch für Vue.JS und Apache Wicket gelten.



Wie genau werden wir mit Vuecket beginnen? Ich schlage vor, ein Chat / Guest Board mit Markdown-Unterstützung zu erstellen. Ich werde nicht zu viel quälen: Die fertige Bewerbung ist hier und der Code ist hier .



Wir erstellen ein Projekt



Lassen Sie uns unser Projekt über `mvn archetype: generate` generieren. Dazu können Sie beispielsweise den folgenden Befehl verwenden:



mvn archetype:generate -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=8.9.0 -DgroupId=com.mycompany -DartifactId=mychat -DarchetypeRepository=https://repository.apache.org/ -DinteractiveMode=false


Vuecket hat noch keine eigene Maven-Projektvorlage. Vielleicht werden wir dies in Zukunft auch hinzufügen. Jetzt verbinden wir Vuecket selbst. Fügen Sie dem Projekt `pom.xml` die folgende Abhängigkeit hinzu:



<dependency>
	<groupId>org.orienteer.vuecket</groupId>
	<artifactId>vuecket</artifactId>
	<version>1.0-SNAPSHOT</version>
</dependency>


Text in Markdown ausgeben



Das Wicket-Projekt enthält standardmäßig bereits eine Wicket-Begrüßungsseite. Fügen wir Code hinzu, um sicherzustellen, dass Vuecket bereits funktioniert. Lassen Sie uns beispielsweise Hello World anzeigen, jedoch in Markdown, und so, dass der Text selbst auf der Serverseite in der Apache Wicket-Komponente festgelegt wird. Wir werden die vue-markdown- Bibliothek verwenden, um Markdown zu rendern .



Fügen Sie in HomePage.html anstelle der Wicket-Begrüßung Folgendes hinzu:



<div wicket:id="app">
	<vue-markdown wicket:id="markdown">This will be replaced</vue-markdown>
</div>


Und in HomePage.java den folgenden Code:



public HomePage(final PageParameters parameters) {
	super(parameters);
	add(new VueComponent<String>("app")
			.add(new VueMarkdown("markdown", "# Hello World from Vuecket")));
}


Aber wo ist die VueMarkdown-Klasse? Und wir werden es wie folgt definieren:



@VueNpm(packageName = "vue-markdown", path = "dist/vue-markdown.js", enablement = "Vue.use(VueMarkdown)")
public class VueMarkdown extends Label {
	public VueMarkdown(String id) {
		super(id);
	}
	public VueMarkdown(String id, Serializable label) {
		super(id, label);
	}
}


Beachten Sie die Annotation @VueNpm. Es ist erforderlich, Vuecket für diese Wicket-Komponente zu aktivieren, wodurch alles geladen wird, was von NPM benötigt wird, damit der Browser die bereits vorhandene Vue-Komponente für Markdown korrekt rendern kann.



Wenn Sie alles richtig gemacht haben, sollten Sie nach dem Starten des Projekts über `mvn jetty: run` so etwas auf http: // localhost: 8080 sehen




Was ist hier passiert und warum funktioniert es?



  • Wir haben die Seite durch Hinzufügen von 2 Vue-Komponenten markiert: für die Anwendung und für die Markdown-Ausgabe
  • Wir haben Vue-Komponenten mit Wicket-Komponenten auf der Serverseite gebündelt (in HomePage.java).
  • Wir haben Vuecket mitgeteilt, welche Vue.JS-Bibliothek zum Rendern von 'vue-markdown' benötigt wird.
  • Und dann ist alles einfach: Wicket verwendete beim Rendern der Seite im Browser die Zeile "# Hello World from Vuecket", die wir beim Hinzufügen der Wicket-Komponente festgelegt haben, und Vuecket half dem Browser, die erforderlichen VueJS-Bibliotheken zu laden, die VueJS-Anwendung zu starten und die Begrüßung bereits als gerenderten Markdown zu rendern


Github verpflichtet sich zu helfen



Eine Nachricht eingeben und eine Vorschau anzeigen



In diesem Schritt werden wir unsere Anwendung komplizieren: Wir werden die Nachricht eingeben und eine Vorschau anzeigen.

Fügen Sie HomePage.html einen Textbereich zum Eingeben einer Nachricht hinzu und binden Sie dieses Feld und den Vue-Markdown an die VueJS-Variable "text".



<div wicket:id="app">
	<textarea v-model="text" style="width:100%" rows="5"></textarea>
	<vue-markdown wicket:id="markdown" :source="text">Will be replaced</vue-markdown>
</div>


Wir verwenden bereits die Variable "text", aber jetzt müssen wir sie der Daten-Vue-Komponente hinzufügen. Es gibt verschiedene Möglichkeiten, dies in Vuecket zu tun, aber lassen Sie uns am längsten gehen:



  • Erstellen Sie Ihre eigene VueComponent for Vue-Anwendung
  • Lassen Sie es uns mit unserer * .vue-Datei verknüpfen
  • Schreiben wir die Logik in die * .vue-Datei: Im Moment nur das Feld "Text"


Hier sind einige der Änderungen, die wir vornehmen werden:



//HomePage.java:
public HomePage(final PageParameters parameters) {
	super(parameters);
	add(new ChatApp("app")
			.add(new VueMarkdown("markdown")));
}
//ChatApp.java:
@VueFile("ChatApp.vue")
public class ChatApp extends VueComponent<Void> {
	public ChatApp(String id) {
		super(id);
	}
}


Nun, ChatApp.vue selbst:



<script>
module.exports = {
    data: function() {
        return {
            text : ""
        }
    }
}
</script>


Wenn Sie "mvn jetty: run" starten und Text eingeben, sehen Sie Folgendes




In diesem Kapitel haben wir gelernt, wie man: vertraute * .vue-Dateien erstellt und sie mit Apache Wicket-Komponenten verknüpft, die



GitHub zur Hilfe verpflichtet



Zeigen Sie eine Liste mit Nachrichten an und fügen Sie eine neue hinzu



In diesem Kapitel gibt es nichts Vuecket- oder Wicket-spezifisches: reinen VueJS-Glanz.

Wenn wir die Aufgabe zerlegen, müssen wir Folgendes tun:



  • Fügen Sie unserer Vue-Anwendung ein Listenfeld hinzu, um Nachrichten zu speichern
  • Fügen Sie eine Methode hinzu, um der Liste eine neue Nachricht hinzuzufügen
  • Zeigen Sie eine Liste mit Nachrichten an und vergessen Sie den Abschlag nicht


Ändern wir zunächst unsere ChatApp.vue und fügen die erforderliche Logik hinzu: ein neues Feld "Nachrichten" mit einer Liste von Nachrichten und die Methode "addMessage" zum Hinzufügen einer neuen Nachricht. Und vergessen wir nicht, dass es beim Hinzufügen einer Nachricht zur Liste eine gute Idee ist, das ursprüngliche Eingabefeld zu löschen. Bei Nachrichten speichern wir nicht nur den Text, sondern auch das Datum des Hinzufügens / Sendens. In Zukunft wird es möglich sein, um zusätzliche Felder zu erweitern, z. B. wer diese Nachricht gesendet hat, Priorität, erforderliche Hervorhebung usw.



<script>
module.exports = {
    data: function() {
        return {
            text : "",
            messages: []
        }
    },
    methods: {
    	addMessage : function() {
    		this.messages.push({
    			message: this.text,
    			date: new Date()
    		});
    		this.text = "";
    	}
    }
}
</script>


Wir werden auch HomePage.html ändern, eine Anzeige der Liste der Nachrichten hinzufügen und unsere addMessage-Methode aufrufen, wenn wir Strg-Eingabetaste drücken.



<div wicket:id="app">
	<div v-for="(m, index) in messages">
		<h5>{{ index }}: {{ m.date }}</h5>
		<vue-markdown :source="m.message"></vue-markdown>
	</div>
	<textarea v-model="text" 
			  style="width:100%" 
			  rows="5" 
			  @keyup.ctrl.enter="addMessage"
			  placeholder="Enter message and Ctrl-Enter to add the message">
	 </textarea>
	<vue-markdown wicket:id="markdown" :source="text">Will be replaced</vue-markdown>
</div>


Wenn Sie "mvn jetty: run" ausführen und einige Nachrichten eingeben, sehen Sie so etwas




In diesem Kapitel haben wir der Anwendung nur das Verwenden von VueJS beigebracht, um der Liste eine Nachricht hinzuzufügen und diese anzuzeigen.



GitHub verpflichtet sich zu helfen



Aktivieren Sie die Zusammenarbeit



Wenn der Inhalt unseres Gästebuchs zuvor für jeden Besucher der Seite eindeutig war, aktivieren wir in diesem Kapitel die Kommunikation mit dem Server und ermöglichen die Synchronisierung mit allen Besuchern. Dazu benötigen wir Vuecket Data Fibers, eine Lösung, mit der browserbasierte Objekte mit serverseitigen Objekten synchronisiert werden können. Und was am interessantesten ist, wir müssen auf Kundenseite nichts dafür tun! Hört sich cool an? Lass uns Code gehen! Obwohl ... Unsere ChatApp.java-Komponente enthält nur zwei neue Zeilen:



private static final IModel<List<JsonNode>> MESSAGES = Model.ofList(new ArrayList<JsonNode>());

public ChatApp(String id) {
	super(id);
	addDataFiber("messages", MESSAGES, true, true, true);
}


Was ist hier passiert:



  • Wir haben ein MESSAGES-Modell erstellt, das allen zur Verfügung steht, da es als statisches Finale erstellt wird.
  • Datenfaser hinzugefügt, die das Nachrichtenobjekt auf der Clientseite und das Objekt im MESSAGES-Modell auf der Serverseite bindet.
  • , data-fiber 3 : load, observe, refresh. Load — , Observe — , Refresh — .


-




GitHub commit





Im vorherigen Kapitel habe ich ein wenig geschummelt, indem ich allen Website-Besuchern gleichzeitig Lese- / Schreibzugriff auf die Nachrichtensammlung gewährt habe. Es wird dringend davon abgeraten, dies zu tun, da dann jeder Absender über Datenfaser alle Nachrichten auf dem Server mit etwas Eigenem überschreiben oder sogar ganz löschen kann. Datenfasern sollten nur verwendet werden, um benutzerdefinierte Objekte auf der Browserseite mit serverseitigen Datenobjekten zu verknüpfen, die demselben Benutzer gehören. Dies bedeutet keine statischen Modelle oder Daten!



Wie können wir die Situation beheben? Dafür müssen wir:



  • Ditch-Datenfaser, die auf der ganzen Linie funktioniert und nur zum erstmaligen Laden der Nachrichtenliste verwendet wird.
  • Verwenden Sie die serverseitige Methode, um der Liste eine neue Nachricht hinzuzufügen.


Somit kann jeder nur neue Nachrichten zur allgemeinen Liste hinzufügen, aber vorhandene Nachrichten weder löschen noch ändern. Lassen Sie uns auch die Serverseite ein wenig komplizieren: Wir speichern nicht nur JSON, das vom Client empfangen wurde, sondern eine spezielle Nachrichtenklasse mit den erforderlichen Feldern, Methoden usw. mit Daten auf der Serverseite arbeiten.



Beginnen wir mit einer Nachrichtenklasse zum Speichern von Benutzernachrichten. Dies kann übrigens eine JPA-Klasse sein, mit der Sie Daten in einer Datenbank speichern können.



public class Message implements IClusterable {
	@JsonProperty("message")
	private String text;
	private Date date;
	
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}	
}


Achten Sie auf @JsonProperty. Daher haben wir das JSON-Feld "message" in unser Java-Feld "text" umgeleitet.



Als nächstes ändern wir ChatApp.java, um das oben beschriebene zu tun: Fügen Sie eine Vuecket-Methode hinzu, um die Nachricht zu speichern. Außerdem können Sie im Code feststellen, dass die Liste der Nachrichten auf nur 20 reduziert wurde (Habr-Benutzer sind sehr fleißig). Wenn Sie jedoch eine Nachricht löschen, wird sie für immer in den Serverprotokollen gespeichert.



@VueFile("ChatApp.vue")
public class ChatApp extends VueComponent<Void> {
	
	private static final Logger LOG = LoggerFactory.getLogger(ChatApp.class);
	private static final int MAX_SIZE = 20;
	private static final IModel<List<Message>> MESSAGES = Model.ofList(new ArrayList<Message>());

	public ChatApp(String id) {
		super(id);
		addDataFiber("messages", MESSAGES, true, false, false);
	}
	
	@VueMethod
	public synchronized void addMessage(Context ctx, Message message) {
		List<Message> list = MESSAGES.getObject();
		list.add(message);
		trimToSize(list, MAX_SIZE);
		IVuecketMethod.pushDataPatch(ctx, "messages", list);
	}
	
	private void trimToSize(List<Message> list, int size) {
		//It's OK to delete one by one because in most of cases we will delete just one record
		while(list.size()>size) LOG.info("Bay-bay message: {}", list.remove(0));
	}
}


Siehe die Annotationsmethode @VueMethod? Darin erhalten wir eine neue Nachricht, speichern sie in der Liste, schneiden sie aus und senden die bereits aktualisierte Liste an den Client. Beachten Sie außerdem, dass die Datenfaser so konfiguriert wurde, dass nur Daten angefordert werden, wenn die Vue-Anwendung gestartet wird.



Wir müssen auch die Logik in ChatApp.vue ändern, um eine neue Nachricht im asynchronen Modus (vcInvoke) anstelle des lokalen Felds "Nachrichten" an den Server zu senden



module.exports = {
    data: function() {
        return {
            text : "",
            messages: []
        }
    },
    methods: {
    	addMessage : function() {
    		this.vcInvoke("addMessage", {
    			message: this.text,
    			date: new Date()
    		});
    		this.text = "";
    	}
    }
}


Was wir aus dem Kapitel gelernt haben:



  • So erstellen Sie serverseitige Methoden für Vuecket
  • So rufen Sie Methoden auf dem Server über einen Browser auf
  • So senden Sie die erforderlichen Änderungen an den Client


Für einen gesetzestreuen Besucher hat sich nichts geändert, aber ein Hacker kann die allgemeine Liste der Nachrichten auf dem Server nicht mehr so ​​einfach ändern




GitHub verpflichtet sich zu helfen



Fazit



Lassen Sie mich heute abrunden. Es gibt viele weitere Verbesserungen, die an unserem Code vorgenommen werden können, aber das überlasse ich Ihnen, liebe Leser. Wenn Sie Hilfe benötigen, schreiben Sie, wir helfen Ihnen!



Gefällt dir das Framework? Bitte teilen Sie Ihre Meinung. Schließlich sind Sie der Meinung, dass Open Source lebt und sich entwickelt.



Spoiler der kommenden Vuecket-Verbesserungen
  • WebSocket' .
  • , .
  • data-fiber' .
  • Vuecket/Wicket , VueJS , , Markdown





All Articles