CUBA 7: Apa yang baru?


Tiga tahun lalu, kami mengumumkan rilis CUBA 6 . Versi itu menjadi revolusioner: alih-alih lisensi kepemilikan tertutup, kami mulai mendistribusikan kerangka kerja secara bebas, di bawah lisensi Apache 2.0. Pada saat itu, kami bahkan tidak dapat memiliki gagasan yang dekat tentang bagaimana ini akan mempengaruhi pengembangan kerangka kerja dalam jangka panjang. Komunitas CUBA mulai tumbuh secara eksponensial, dan kami dihadapkan dengan semua cara yang mungkin (dan kadang-kadang tidak mungkin) untuk menggunakan kerangka tersebut. Kami sekarang memperkenalkan CUBA 7 . Kami berharap bahwa versi ini akan membuat pengembangan lebih mudah dan lebih menyenangkan bagi semua anggota komunitas: dari pemula yang baru berkenalan dengan CUBA dan Java, hingga pengembang berpengalaman yang memiliki lebih dari satu proyek selesai di tingkat perusahaan besar.


Alat pengembangan


Bagian penting dari kesuksesan CUBA, kami berutang CUBA Studio . Lingkungan pengembangan ini telah sangat menyederhanakan pelaksanaan tugas-tugas khas yang dilakukan di setiap proyek Java, mengurangi mereka untuk membuat konfigurasi sederhana dalam desainer visual. Anda tidak perlu tahu semua atribut anotasi API Persisten, sintaks Gradle atau seluk-beluk konfigurasi Spring untuk mengembangkan aplikasi CRUD yang lengkap dan kaya fitur - CUBA Studio menangani pembuatan kode khas.



Studio adalah aplikasi web terpisah, yang menyebabkan sejumlah batasan signifikan:


  • Pertama, Studio bukan IDE yang lengkap, sehingga pengembang harus beralih antara Studio dan IntelliJ IDEA atau Eclipse untuk mengembangkan logika bisnis dan pada saat yang sama menggunakan navigasi yang nyaman, penyelesaian kode dan hal-hal lain yang diperlukan, yang agak mengganggu.
  • Kedua, semua kesederhanaan ajaib ini dibangun di atas sejumlah besar pekerjaan yang kami habiskan untuk menulis algoritma untuk parsing dan menghasilkan kode sumber. Menerapkan fungsionalitas yang lebih maju akan berarti pindah ke pengembangan IDE penuh - terlalu ambisius untuk kita.

Kami memutuskan untuk mengandalkan raksasa lain untuk mengatasi keterbatasan ini dan membangun Studio berdasarkan IntelliJ IDEA. Sekarang Anda dapat menginstal Studio baik sebagai aplikasi mandiri (IntelliJ IDEA Bundle), dan sebagai plug-in untuk IDEA.



Dan ini memberi kita peluang baru:


  • Dukungan untuk bahasa JVM lainnya (dan, yang terpenting, Kotlin)
  • Superior Hot deploy
  • Navigasi seluruh proyek yang intuitif
  • Petunjuk yang lebih cerdas dan generator kode

Saat ini, kami secara aktif mengembangkan versi baru Studio - kami mentransfer fungsionalitas dari versi lama dan menambahkan hal-hal baru menggunakan fungsi platform IntelliJ. Dalam waktu dekat - terjemahan editor khusus CUBA ke komponen IntelliJ dan meningkatkan navigasi melalui kode proyek.


Pembaruan Teknologi Stack


Secara tradisional, tumpukan teknologi di inti CUBA telah diperbarui ke versi baru: Java 8/11, Vaadin 8, Spring 5.


Secara default, proyek baru menggunakan Java 8, tetapi Anda bisa menentukan versi Java dengan menambahkan kode berikut ke file build.gradle:


subprojects { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } 

Masalah yang sangat besar adalah peningkatan ke Vaadin 8, di mana API pengikat data telah banyak berubah. Untungnya, CUBA melindungi pengembang dari komponen internal Vaadin, membungkusnya dengan API mereka sendiri. Tim CUBA melakukan pekerjaan yang baik untuk memperbarui komponen internal tanpa mengubah API CUBA. Ini berarti kompatibilitas sepenuhnya terpelihara, dan Anda dapat memanfaatkan semua fitur baru Vaadin 8 segera setelah memigrasi proyek ke CUBA 7, tanpa melakukan refactoring apa pun.


Daftar lengkap dependensi yang diperbarui tersedia di daftar perubahan .


API layar baru


Bagian ini mungkin disebut "API layar pertama", karena CUBA tidak pernah memiliki API layar yang diumumkan secara resmi dalam modul klien web. Ini terjadi secara historis, termasuk karena beberapa asumsi yang muncul pada tahap awal:


  • Pendekatan yang berorientasi deklaratif - segala sesuatu yang dapat dideskripsikan secara deklaratif harus dideklarasikan dalam deskriptor layar, dan bukan dalam kode pengontrol.
  • Layar standar (browser dan editor) menyediakan fungsionalitas umum tertentu, dan tidak perlu mengubahnya.


Pada saat seribu anggota pertama bergabung dengan komunitas kami, kami menyadari berapa banyak persyaratan yang berbeda yang ditempatkan pada layar CRUD "standar". Dan semua persyaratan ini jauh melampaui fungsi awal. Namun, untuk waktu yang lama kami dapat memenuhi permintaan untuk menerapkan perilaku layar atipikal tanpa mengubah API - berkat prinsip arsitektur lain yang ditetapkan pada tahap awal: Buka Warisan. Faktanya, Open Inheritance berarti Anda dapat menulis ulang metode umum atau terlindung dari kelas utama untuk menyesuaikan perilakunya sesuai dengan kebutuhan Anda. Ini mungkin tampak seperti obat mujarab yang ajaib, tetapi sebenarnya Anda tidak bisa mengandalkannya bahkan dalam jangka pendek. Bagaimana jika metode yang diganti diganti, dihapus, atau tidak pernah digunakan dalam versi kerangka kerja yang akan datang?


Jadi sebagai tanggapan terhadap permintaan komunitas yang berkembang, kami memutuskan untuk memperkenalkan API layar baru. API ini memberikan poin ekstensi yang jelas (tanpa sihir tersembunyi), fleksibel dan mudah digunakan yang dijamin tidak akan berubah untuk waktu yang lama.


Deklarasi layar


Di CUBA 7, mendeklarasikan layar sangat sederhana:


 @UiController("new-screen") // screen id public class NewScreen extends Screen { } 

Contoh di atas menunjukkan bahwa pengidentifikasi layar secara eksplisit didefinisikan langsung di atas deklarasi kelas controller. Dengan kata lain, ID layar dan kelas pengontrol sekarang cocok satu sama lain dengan cara yang unik. Jadi, kami memiliki kabar baik: sekarang Anda dapat dengan aman mengakses layar langsung berdasarkan jenis pengontrol:


 @Inject private ScreenBuilders screenBuilders; @Subscribe private void onBeforeClose(BeforeCloseEvent event) { screenBuilders.screen(this) .withScreenClass(SomeConfirmationScreen.class) .build() .show(); } 

Deskriptor layar menjadi bagian opsional dari layar. UI dapat dibuat secara terprogram atau dideklarasikan sebagai deskriptor layar xml, yang ditentukan oleh anotasi @UiDescriptor pada kelas controller. Ini membuat pengontrol dan markup jauh lebih mudah dibaca dan dipahami - pendekatan ini sangat mirip dengan yang digunakan dalam pengembangan Android.


Sebelumnya, itu juga perlu mendaftarkan pegangan layar di file web-screens.xml dan menetapkannya sebagai pengidentifikasi. Di CUBA 7, file ini disimpan untuk tujuan kompatibilitas, tetapi cara baru untuk membuat layar tidak memerlukan pendaftaran tersebut.


Siklus hidup layar


API baru memperkenalkan acara siklus hidup layar sederhana dan jelas:


  • Init
  • Setelah itu
  • Di depan
  • Entah bagaimana
  • Sebelum ditutup
  • Setelah ditutup

Anda dapat berlangganan semua acara di CUBA 7 sebagai berikut:


 @UiController("new-screen") public class NewScreen extends Screen { @Subscribe private void onInit(InitEvent event) { } @Subscribe private void onBeforeShow(BeforeShowEvent event) { } } 

Dibandingkan dengan pendekatan lama, API baru menunjukkan bahwa kami tidak tumpang tindih dengan metode hook yang secara implisit dipanggil saat inisialisasi, tetapi secara eksplisit menentukan logika untuk memproses peristiwa siklus hidup layar spesifik dan spesifik.


Penanganan Acara dan Delegasi Fungsional


Di bagian sebelumnya, kami belajar cara berlangganan acara siklus hidup, tetapi bagaimana dengan komponen lainnya? Apakah masih perlu untuk menuangkan semua pendengar yang diperlukan ke tumpukan yang sama ketika menginisialisasi layar, dalam metode init (), seperti pada versi 6.x? API baru ini cukup konsisten, sehingga Anda dapat berlangganan ke acara lain dengan cara yang sama seperti pada acara kehidupan layar.


Pertimbangkan contoh sederhana dengan dua elemen UI: tombol dan bidang untuk menampilkan jumlah uang dalam mata uang tertentu; Deskriptor XML akan terlihat seperti ini:


 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="msg://caption" messagesPack="com.company.demo.web"> <layout> <hbox spacing="true"> <currencyField id="currencyField" currency="$" currencyLabelPosition="LEFT"/> <button id="calcPriceBtn" caption="Calculate Price"/> </hbox> </layout> </window> 

Ketika Anda mengklik tombol, kami memanggil layanan dari backend, yang mengembalikan nomor, kami menuliskannya di bidang jumlah. Bidang ini harus mengubah gaya tergantung pada nilai harga.


 @UiController("demo_MyFirstScreen") @UiDescriptor("my-first-screen.xml") public class MyFirstScreen extends Screen { @Inject private PricingService pricingService; @Inject private CurrencyField<BigDecimal> currencyField; @Subscribe("calcPriceBtn") private void onCalcPriceBtnClick(Button.ClickEvent event) { currencyField.setValue(pricingService.calculatePrice()); } @Subscribe("currencyField") private void onPriceChange (HasValue.ValueChangeEvent<BigDecimal> event) { currencyField.setStyleName(getStyleNameByPrice(event.getValue())); } private String getStyleNameByPrice(BigDecimal price) { ... } } 

Dalam contoh di atas, kita melihat dua pengendali acara: satu dipanggil ketika tombol ditekan, dan yang lainnya diluncurkan ketika bidang mata uang mengubah nilainya - semuanya sederhana.


Sekarang bayangkan kita perlu memeriksa harga dan memastikan nilainya positif. Ini bisa dilakukan "dahi" - tambahkan validator selama inisialisasi layar:


 @UiController("demo_MyFirstScreen") @UiDescriptor("my-first-screen.xml") public class MyFirstScreen extends Screen { @Inject private CurrencyField<BigDecimal> currencyField; @Subscribe private void onInit(InitEvent event) { currencyField.addValidator(value -> { if (value.compareTo(BigDecimal.ZERO) <= 0) throw new ValidationException("Price should be greater than zero"); }); } } 

Dalam aplikasi nyata, setelah beberapa waktu metode inisialisasi akan menjadi kekacauan inisialisasi, validator, pendengar, dll. Untuk mengatasi masalah ini, CUBA memiliki anotasi @Install berguna. Mari kita lihat bagaimana ini dapat membantu dalam kasus kami:


 @UiController("demo_MyFirstScreen") @UiDescriptor("my-first-screen.xml") public class MyFirstScreen extends Screen { @Inject private CurrencyField<BigDecimal> currencyField; @Install(to = "currencyField", subject = "validator") private void currencyFieldValidator(BigDecimal value) { if (value.compareTo(BigDecimal.ZERO) <= 0) throw new ValidationException("Price should be greater than zero"); } } 

Bahkan, kami mendelegasikan logika validasi bidang mata uang ke metode currencyFieldValidator di layar. Ini mungkin tampak sedikit rumit pada pandangan pertama, tetapi para pengembang dengan cepat terbiasa dengan metode penambahan fungsi ini dan segera mulai menggunakannya.


Pembuat layar, notifikasi, dialog



CUBA 7 memiliki serangkaian komponen yang berguna dengan API yang nyaman:


  • ScreenBuilders menggabungkan pabrik yang fasih untuk membuat layar standar untuk melihat dan mengedit entitas, serta layar khusus. Contoh di bawah ini menunjukkan bagaimana Anda dapat membuka satu layar dari yang lain. Perhatikan bahwa metode build () segera mengembalikan layar dari jenis yang diinginkan tanpa perlu pemain:
     CurrencyConversions currencyConversions = screenBuilders.screen(this) .withScreenClass(CurrencyConversions.class) .withLaunchMode(OpenMode.DIALOG) .build(); currencyConversions.setBaseCurrency(Currency.EUR); currencyConversions.show(); 
  • Komponen Layar menyediakan tingkat abstraksi yang lebih rendah untuk membuat dan menampilkan layar, tidak seperti API ScreenBuilders . Ini juga menyediakan akses ke informasi tentang semua layar terbuka di aplikasi CUBA Anda ( Layar # getOpenedScreens ), jika Anda tiba-tiba harus melalui semuanya dalam satu siklus.
  • Komponen Notifikasi dan Dialog menyediakan API yang mudah didokumentasikan sendiri dan praktis. Berikut ini adalah contoh membuat dan menampilkan kotak dialog dan pemberitahuan:
     dialogs.createOptionDialog() .withCaption("My first dialog") .withMessage("Would you like to thank CUBA team?") .withActions( new DialogAction(DialogAction.Type.YES).withHandler(e -> notifications.create() .withCaption("Thank you!") .withDescription("We appreciate all community members") .withPosition(Notifications.Position.MIDDLE_CENTER) .withHideDelayMs(3000) .show()), new DialogAction(DialogAction.Type.CANCEL) ) .show(); 

Pengikatan data


CUBA menyediakan pengembangan antarmuka pengguna yang sangat cepat untuk back office, tidak hanya dengan alat pengembangan visual canggih dan sistem pembuatan kode yang kuat, tetapi juga dengan serangkaian komponen kaya yang tersedia langsung di luar kotak. Komponen-komponen ini hanya perlu mengetahui data apa yang mereka kerjakan, dan sisanya akan dilakukan secara otomatis. Misalnya, daftar drop-down, kalender, tabel dengan operasi CRUD bawaan, dan sebagainya.


Sebelum versi 7, pengikatan data dilakukan melalui apa yang disebut sumber data - objek yang membungkus satu atau lebih entitas untuk pengikatan reaktifnya terhadap komponen. Pendekatan ini bekerja dengan sangat baik, tetapi dalam hal implementasi, itu adalah monolit. Arsitektur monolitik biasanya bermasalah untuk dikonfigurasi, sehingga dalam CUBA 7 batu besar ini dibagi menjadi tiga komponen untuk bekerja dengan data:


  • Pemuat data adalah penyedia data untuk wadah data. Loader tidak menyimpan data, ia hanya meneruskan semua parameter kueri yang diperlukan ke gudang data dan menempatkan data yang dihasilkan dalam wadah data.
  • Wadah data menyimpan data yang dimuat (satu entitas atau lebih) dan memberikannya kepada komponen data: semua perubahan dalam entitas ini ditransfer ke komponen yang sesuai, dan sebaliknya, semua perubahan dalam komponen akan mengarah ke perubahan yang sesuai pada entitas yang terletak di dalam wadah data.
  • Datacontext (konteks data) adalah kelas yang melacak perubahan dan menyimpan semua entitas yang diubah. Entitas yang dipantau ditandai sebagai kotor setiap kali atributnya berubah, dan DataContext menyimpan instance yang kotor di Middleware ketika metode commit () dipanggil.

Dengan demikian, ada fleksibilitas dalam bekerja dengan data. Contoh buatan: loader dapat memilih data di UI dari RDBMS, dan konteksnya dapat menyimpan perubahan ke layanan REST.


Dalam CUBA 6.x, Anda harus menulis sumber data Anda sendiri untuk ini, yang dapat bekerja dengan RDBMS dan REST. Di CUBA 7, Anda dapat mengambil loader standar yang dapat bekerja dengan database dan hanya menulis implementasi konteksnya untuk bekerja dengan REST.


Komponen untuk bekerja dengan data dapat dideklarasikan dalam deskriptor layar atau dibuat secara terprogram menggunakan pabrik khusus - DataComponents.


Lainnya


Uff ... Bagian terpenting dari API di layar yang baru dijelaskan, jadi mari kita daftarkan secara singkat fungsi-fungsi penting lainnya di tingkat klien web:


  • Riwayat URL dan navigasi . Fungsi ini memecahkan masalah SPA yang sangat umum - perilaku tombol kembali di browser web tidak selalu benar. Sekarang menyediakan cara mudah untuk menetapkan rute ke layar aplikasi dan memungkinkan API untuk menampilkan kondisi layar saat ini dalam URL.
  • Bentuk bukan FieldGroup . FieldGroup adalah komponen untuk menampilkan dan mengubah bidang dari satu entitas. Ini menampilkan UI untuk bidang dalam runtime. Dengan kata lain, jika entitas memiliki bidang Tanggal, itu akan ditampilkan sebagai DateField . Namun, jika Anda ingin bekerja dengan bidang ini secara terprogram, Anda harus memasukkannya ke pengontrol layar dan secara manual melemparkannya ke jenis yang benar ( DateField dalam contoh kami ). Jika nanti kita mengubah jenis bidang ke bidang lainnya, maka aplikasi kita akan macet saat runtime. Formulir memecahkan masalah ini dengan secara eksplisit mendeklarasikan tipe bidang. Informasi lebih lanjut tentang komponen dapat ditemukan di sini .
  • Integrasi komponen JavaScript pihak ketiga sangat disederhanakan, baca dokumentasi tentang penyematan komponen JavaScript khusus dalam aplikasi CUBA.
  • Atribut HTML / CSS sekarang dapat dengan mudah didefinisikan langsung dari deskriptor layar xml atau diatur secara terprogram. Informasi lebih lanjut dapat ditemukan di sini .

Fitur baru dari modul backend


Bagian sebelumnya pada layar API baru ternyata lebih dari yang saya harapkan, jadi di bagian ini saya akan singkat.


Entitas Berubah Peristiwa


Acara Entity Changed adalah acara di aplikasi Musim Semi yang menyala saat entitas memasuki penyimpanan data, ditempatkan secara fisik, dan satu langkah lagi dari komit. Saat memproses acara ini, Anda dapat mengonfigurasi cek tambahan (misalnya, memeriksa ketersediaan barang di gudang sebelum mengonfirmasi pesanan) dan mengubah data (misalnya, menghitung ulang total) tepat sebelum terlihat oleh transaksi lain (tentu saja, jika Anda memiliki level baca isolasi yang dilakukan). Acara ini juga dapat menjadi kesempatan terakhir untuk membatalkan transaksi dengan melemparkan pengecualian, yang mungkin berguna dalam beberapa kasus rumit.


Ada juga cara untuk menangani acara Entity Changed segera setelah komit.


Anda dapat melihat contoh di bab dokumentasi ini .


Manajer data transaksional


Saat mengembangkan aplikasi, kami biasanya bekerja dengan entitas terpisah - entitas yang tidak dalam konteks transaksi apa pun. Namun, bekerja dengan entitas yang terpisah tidak selalu mungkin, terutama ketika Anda harus sepenuhnya mematuhi persyaratan ACID - ini adalah kasus ketika Anda dapat menggunakan manajer data transaksional. Ia sangat mirip dengan manajer biasa, tetapi berbeda dalam aspek-aspek berikut:


  • Dia dapat bergabung dengan transaksi yang ada (dipanggil dalam konteks transaksi ini) atau membuat transaksi sendiri.
  • Itu tidak memiliki metode komit, tetapi ada metode save yang tidak langsung melakukan, tetapi menunggu transaksi saat ini untuk berkomitmen.

Berikut ini adalah contoh penggunaannya.


Callback JPA


Akhirnya, CUBA 7 mendukung panggilan balik JPA. Agar tidak mengulangi materi yang diketahui untuk apa callback ini dapat digunakan, saya hanya meninggalkan tautan di sini. Dalam materi ini, topik panggilan balik sepenuhnya diungkapkan.


Bagaimana dengan kompatibilitas?



Sebuah pertanyaan yang wajar untuk setiap rilis besar, terutama ketika ada begitu banyak perubahan kritis! Kami mengembangkan semua fitur dan API baru ini dengan kompatibilitas ke belakang:


  • API lama didukung di CUBA 7 dan diimplementasikan melalui yang baru di bawah tenda :)
  • Kami juga menyediakan adaptor untuk pengikatan data melalui API lama. Adaptor ini akan bekerja dengan sempurna untuk layar yang dibuat sesuai dengan skema lama.

Berita baiknya adalah proses migrasi dari versi 6 ke 7 seharusnya cukup sederhana.


Kesimpulan


Sebagai penutup tinjauan teknis, saya ingin mencatat bahwa ada inovasi penting lainnya, terutama di bidang perizinan:


  • Batas 10 entitas untuk Studio sekarang dihapus
  • Add-on untuk Pelaporan, BPM, Bagan dan Peta, dan pencarian teks lengkap sekarang gratis dan open source.
  • Versi komersial Studio menambah pengembangan kenyamanan dengan bantuan desainer visual dari entitas, layar, menu, dan elemen platform lainnya, dan versi gratisnya difokuskan untuk bekerja dengan kode.
  • Harap dicatat bahwa untuk versi 6.x dan versi sebelumnya, ketentuan lisensi untuk Platform dan Studio tetap sama!

Akhirnya, izinkan saya sekali lagi berterima kasih kepada komunitas atas dukungan dan umpan balik mereka. Saya harap Anda menyukai versi 7! Informasi lengkap tersedia secara tradisional di changelog resmi.

Source: https://habr.com/ru/post/id447538/


All Articles