إدخال Vuecket





Russian Version

Vuecket هو إطار عمل ويب يدمج VueJS من جانب العميل و Apache Wicket على جانب الخادم. إنه يأخذ أفضل ما في كلا الأمرين ويجعل تطوير التطبيقات كاملة المكدس أسرع وأسهل. بالطبع هذه كلها كلمات كبيرة ، لأن عمر فوكيت حاليًا (أغسطس 2020) أقل من شهر ، ولم يمر بعد بمعمودية خوادم إنتاج "النار والدم". لكنها تضمنت بالفعل أفضل ما قمنا بتطويره أثناء تطوير منتجنا الرئيسي المفتوح المصدر Orienteer (منصة للتطوير السريع لتطبيقات الأعمال). وبسبب صغر سنها تحديدًا ، تحتاج Vuecket إلى مساعدتك: يرجى مشاركة ما أعجبك ، وما هو غير جيد جدًا ، حيث يلزم إجراء تحسينات ، إلخ.



المبادئ الأساسية التي ترشدنا عند بناء Vuecket هي:



  1. أن تكون صريحًا ليس أمرًا ضروريًا. لا يفرض Vuecket أي متطلبات كود خاصة. يمكن تطبيقه بسرعة وسهولة على مشاريع Vue.JS أو Apache Wicket الحالية.
  2. اتبع مبدأ باريتو. يجب أن يوفر Vuecket 80٪ من الوظائف التي تريدها خارج الصندوق ، ولكن يجب أن تكون هناك نقاط تمديد جيدة ومريحة لـ 20٪ المتبقية.


من السهل ملاحظة أن هذه المبادئ تنطبق أيضًا على Vue.JS و Apache Wicket.



إذن كيف بالضبط سنبدأ مع Vuecket؟ أقترح إجراء دردشة / لوحة ضيف مع دعم Markdown. لن أعذب كثيرًا: التطبيق النهائي هنا ، والكود هنا .



نقوم بإنشاء مشروع



دعونا ننشئ مشروعنا عبر `mvn archetype: create`. للقيام بذلك ، يمكنك استخدام الأمر التالي ، على سبيل المثال:



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 بعد على نموذج مشروع Maven الخاص بها. ربما سنضيف هذا أيضًا في المستقبل . الآن دعنا نربط Vuecket نفسها. أضف التبعية التالية إلى المشروع `pom.xml`:



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


إخراج النص في Markdown



يحتوي مشروع Wicket بالفعل على صفحة ترحيب Wicket بشكل افتراضي. دعنا نضيف بعض التعليمات البرمجية إليها للتأكد من أن Vuecket يعمل بالفعل. على سبيل المثال ، دعنا نعرض Hello World ، ولكن في Markdown ، بحيث يتم تعيين النص نفسه على جانب الخادم في مكون Apache Wicket. سنستخدم مكتبة vue-markdown لتقديم Markdown .



في HomePage.html ، بدلاً من تحية Wicket ، أضف:



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


وفي HomePage.java الكود التالي:



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


ولكن أين هي فئة VueMarkdown؟ وسوف نحدده على النحو التالي:



@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);
	}
}


انتبه إلى التعليق التوضيحيVueNpm. يلزم تمكين Vuecket على مكون Wicket هذا ، والذي سيحمل كل ما هو مطلوب من NPM لمساعدة المتصفح في عرض مكون Vue بالفعل لـ Markdown بشكل صحيح.



إذا فعلت كل شيء بشكل صحيح ، فبعد بدء المشروع من خلال "mvn jetty: run" ، يجب أن ترى شيئًا كهذا على http: // localhost: 8080




إذن ماذا حدث هنا ولماذا يعمل؟



  • لقد قمنا بترميز الصفحة بإضافة مكونين Vue إليها: للتطبيق ولإخراج Markdown
  • قمنا بتجميع مكونات Vue مع مكونات Wicket على جانب الخادم (في HomePage.java)
  • أخبرنا Vuecket عن مكتبة Vue.JS التي تحتاجها لتقديم "vue-markdown"
  • ثم كل شيء بسيط: عند عرض الصفحة على المتصفح ، استخدم Wicket السطر "# Hello World from Vuecket" ، الذي قمنا بتعيينه عند إضافة مكون Wicket ، وساعد Vuecket المتصفح في تحميل مكتبات VueJS الضرورية ، وتشغيل تطبيق VueJS وتقديم التحية بالفعل كما تم عرض Markdown


تلتزم جيثب بالمساعدة



إدخال الرسالة ومعاينتها



في هذه الخطوة ، سنعقد تطبيقنا: سنقوم بإدخال الرسالة ومعاينتها.

دعونا نضيف منطقة نصية إلى HomePage.html لإدخال رسالة ، وكذلك ربط هذا الحقل و vue-markdown بمتغير VueJS "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>


نحن نستخدم بالفعل المتغير "text" ، ولكننا الآن بحاجة إلى إضافته إلى مكون البيانات Vue. هناك عدة طرق للقيام بذلك في Vuecket ، لكن دعنا نذهب لأطول فترة:



  • قم بإنشاء VueComponent for Vue الخاص بك
  • دعونا نربطها بملفنا * .vue
  • لنكتب المنطق في ملف * .vue: في الوقت الحالي ، فقط حقل "النص"


فيما يلي بعض التغييرات التي سنجريها:



//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);
	}
}


حسنًا ، ChatApp.vue نفسه:



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


نتيجة لذلك ، عند بدء تشغيل "mvn jetty: run" وإدخال بعض النصوص ، يمكنك مشاهدة ما يلي




في هذا الفصل ، تعلمنا كيفية: إنشاء ملفات * .vue مألوفة وربطها بمكونات Apache Wicket



يلتزم GitHub بالمساعدة



اعرض قائمة بالرسائل وأضف قائمة جديدة



لن يكون هناك أي شيء محدد لـ Vuecket أو Wicket في هذا الفصل: تألق VueJS النقي.

إذا حللنا المهمة ، فسنحتاج إلى القيام بما يلي:



  • أضف مربع قائمة إلى تطبيق Vue لحفظ الرسائل
  • أضف طريقة لإضافة رسالة جديدة إلى القائمة
  • اعرض قائمة بالرسائل ولا تنسى تخفيض السعر


أولاً ، دعنا نغير ChatApp.vue ونضيف المنطق الضروري: حقل جديد "الرسائل" بقائمة من الرسائل وطريقة "addMessage "لإضافة رسالة جديدة. ودعنا لا ننسى أنه عند إضافة رسالة إلى القائمة ، من الجيد مسح حقل الإدخال الأصلي. بالنسبة للرسائل ، لن نقوم بتخزين النص فقط ، ولكن أيضًا تاريخ الإضافة / الإرسال. في المستقبل ، سيكون من الممكن التوسع مع حقول إضافية ، على سبيل المثال ، من أرسل هذه الرسالة ، والأولوية ، والتمييز المطلوب ، وما إلى ذلك.



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


سنقوم أيضًا بتغيير HomePage.html ، وإضافة عرض لقائمة الرسائل وإضافة مكالمة إلى طريقة addMessage الخاصة بنا عند الضغط على Ctrl-Enter.



<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>


عند تشغيل "mvn jetty: run" وإدخال بعض الرسائل ، سترى شيئًا كهذا




في هذا الفصل ، قمنا فقط بتعليم التطبيق باستخدام VueJS لإضافة رسالة إلى القائمة وعرض الأخير.



يلتزم جيثب بالمساعدة



قم بتشغيل التعاون



إذا كان محتوى سجل الزوار قبل ذلك فريدًا لكل زائر للصفحة ، فسنعمل في هذا الفصل على تمكين الاتصال بالخادم والسماح بالمزامنة مع جميع الزوار. لهذا نحتاج إلى Vuecket Data Fibers ، وهو حل يسمح بمزامنة الكائنات من جانب المستعرض مع كائنات جانب الخادم. والشيء الأكثر إثارة للاهتمام هو أننا لسنا بحاجة إلى فعل أي شيء من أجل هذا من جانب العميل! يبدو جيدا؟ لنبدأ الكود! على الرغم من ... لا يوجد سوى سطرين جديدين في مكون ChatApp.java:



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

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


ماذا حدث هنا:



  • لقد أنشأنا نموذج MESSAGES متاحًا للجميع ، حيث تم إنشاؤه كنموذج نهائي ثابت.
  • تمت إضافة ألياف البيانات ، والتي تربط كائن الرسائل من جانب العميل والكائن داخل نموذج الرسائل على جانب الخادم.
  • , data-fiber 3 : load, observe, refresh. Load — , Observe — , Refresh — .


-




GitHub commit





في الفصل السابق ، خدعت قليلاً من خلال منح حق الوصول للقراءة / الكتابة إلى مجموعة الرسائل لجميع زوار الموقع مرة واحدة. لا نشجع على القيام بذلك ، لأنه بعد ذلك ، من خلال ألياف البيانات ، يمكن لأي مرسل الكتابة فوق جميع الرسائل الموجودة على الخادم بشيء خاص به أو حتى محوها تمامًا. يجب استخدام ألياف البيانات فقط لربط الكائنات المخصصة من جانب المستعرض بكائنات بيانات جانب الخادم التي تنتمي إلى نفس المستخدم. هذا يعني عدم وجود نماذج ثابتة أو بيانات!



كيف يمكننا إصلاح الوضع؟ لهذا علينا:



  • تخلص من ألياف البيانات ، التي تعمل في جميع المجالات ، واستخدمها فقط لتحميل قائمة الرسائل في البداية.
  • استخدم طريقة جانب الخادم لإضافة رسالة جديدة إلى القائمة.


وبالتالي ، سيتمكن الجميع من إضافة رسائل جديدة فقط إلى القائمة العامة ، لكن لن يتمكنوا من حذف أو تغيير الرسائل الموجودة. دعونا أيضًا نعقد جانب الخادم قليلاً: سنحفظ ليس فقط JSON المستلم من العميل ، ولكن فئة الرسائل المتخصصة مع الحقول والأساليب اللازمة وما إلى ذلك. للعمل مع البيانات على جانب الخادم.



لنبدأ بفئة الرسائل لتخزين رسائل المستخدم. بالمناسبة ، قد تكون هذه فئة JPA تسمح لك بحفظ البيانات في قاعدة بيانات.



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;
	}	
}


انتبه إلىJsonProperty. وبالتالي ، قمنا بإعادة توجيه "رسالة" حقل JSON إلى "نص" حقل جافا الخاص بنا.



بعد ذلك ، دعنا نغير ChatApp.java للقيام بما هو موضح أعلاه: أضف طريقة vuecket لحفظ الرسالة. أيضًا ، في الكود ، يمكنك ملاحظة اختزال قائمة الرسائل إلى 20 رسالة فقط (مستخدمو Habr مجتهدون جدًا) ، ولكن عندما تحذف رسالة ، فإنها تظل محفوظة إلى الأبد في سجلات الخادم.



@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));
	}
}


انظر طريقة التعليق التوضيحيVueMethod؟ في ذلك ، نتلقى رسالة جديدة ، ونحفظها في القائمة ، ونقطعها ونرسل القائمة المحدثة بالفعل إلى العميل. لاحظ أيضًا أنه قد تمت إعادة تكوين ألياف البيانات لطلب البيانات فقط عند تشغيل تطبيق Vue.



نحتاج أيضًا إلى تغيير المنطق في ChatApp.vue لإرسال رسالة جديدة إلى الخادم في الوضع غير المتزامن (vcInvoke) بدلاً من حقل "الرسائل" المحلي



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


ما تعلمناه من الفصل:



  • كيفية إنشاء طرق جانب الخادم لـ Vuecket
  • كيفية استدعاء الطرق على الخادم من المستعرض
  • كيفية إرسال التغييرات المطلوبة للعميل


بالنسبة للزائر الملتزم بالقانون ، لم يتغير شيء ، ولكن لم يعد بإمكان المتسلل تغيير القائمة العامة للرسائل على الخادم بسهولة




يلتزم GitHub بالمساعدة



خاتمة



حول هذا اليوم ، اسمحوا لي أن اختتم. هناك العديد من التحسينات التي يمكن إجراؤها على الكود الخاص بنا ، لكنني سأترك ذلك لك ، أيها القراء الأعزاء. إذا كنت بحاجة إلى مساعدة ، اكتب ، سنساعدك!



هل تحب الإطار؟ يرجى مشاركة رأيك. بعد كل شيء ، من وجهة نظرك أن المصدر المفتوح يعيش ويتطور.



المفسد لتحسينات Vuecket القادمة
  • WebSocket' .
  • , .
  • data-fiber' .
  • Vuecket/Wicket , VueJS , , Markdown





All Articles