Integrasi Java dalam CFML: createObject, classpath dan JDBC
Cara memanggil kelas Java dari CFML dalam Lucee: createObject, javacast, java.time, classpath dan pemacu JDBC, dengan contoh yang telah diuji dalam enjin.

Kandungan
- Integrasi Java dalam CFML: createObject, classpath dan JDBC
- Dua Cara Memanggil: Kaedah Statik dan Kaedah Tika
- Menukar Jenis dengan javacast
- java.time dan java.util.UUID
- Membaca Sifat Sistem dan Sifat JVM
- Menambah JAR ke Classpath Lucee
- JDBC Terus Tanpa Datasource
- Bila Guna Integrasi Java dan Bila Tidak
- Soalan Lazim
Integrasi Java dalam CFML: createObject, classpath dan JDBC
Lucee berjalan di atas Mesin Maya Java (JVM), jadi integrasi dengan kelas Java bukan ciri sampingan, ia asas enjin itu sendiri. Fungsi createObject("java", namaKelas) membuka akses terus kepada hampir mana-mana kelas dalam JVM, daripada java.util.UUID hingga java.time, tanpa memasang sambungan tambahan. Artikel ini menunjukkan cara memanggil kelas Java, menukar jenis dengan javacast, menambah JAR ke classpath, dan membuka sambungan JDBC terus tanpa datasource. Semua contoh diuji pada Lucee 7.1 dengan Java 25.
Dua Cara Memanggil: Kaedah Statik dan Kaedah Tika
createObject menerima tiga hujah utama apabila menyentuh Java: rentetan "java" sebagai jenis, nama kelas penuh, dan pilihan untuk pembina. Kelas yang kaedahnya statik boleh dipanggil terus tanpa mencipta tika terlebih dahulu, manakala kaedah tika memerlukan anda memanggil pembina dahulu.
// Kaedah statik dipanggil terus pada objek kelas, tanpa .init().
uuid = createObject("java", "java.util.UUID").randomUUID();
versi = createObject("java", "java.lang.System").getProperty("java.version");
namaOs = createObject("java", "java.lang.System").getProperty("os.name");
writeOutput("UUID: " & uuid.toString());
writeOutput("<br>Java: " & versi & " pada " & namaOs);
randomUUID() dan getProperty() ialah kaedah statik, jadi ia dipanggil terus pada objek kelas. getProperty("java.version") memulangkan versi Java yang menjalankan enjin, manakala getProperty("os.name") memulangkan nama sistem pengendalian. Kedua-duanya berguna untuk log diagnostik atau panel status aplikasi.
Kaedah tika pula memerlukan objek sebenar. Di CFML, pembina dipanggil melalui .init(), kemudian barulah kaedah biasa boleh dipanggil pada tika itu:
// Kaedah tika: panggil .init(argumen) untuk pembina, kemudian kaedah pada tika.
sb = createObject("java", "java.lang.StringBuilder").init("Lucee");
sb.append(" ");
sb.append("CFML");
writeOutput(sb.toString());
writeOutput("<br>" & createObject("java", "java.lang.String").init("lucee").toUpperCase());
.init("Lucee") memanggil pembina StringBuilder yang menerima satu rentetan, kemudian append() menambah teks, dan toString() memulangkan hasilnya. Perhatikan bahawa kaedah rentetan Java tidak boleh dipanggil terus pada literal CFML seperti "abc".toUpperCase(), kerana Lucee tidak menjamin pemetaan itu. Anda perlu mencipta objek java.lang.String dahulu, seperti dalam baris terakhir contoh di atas.
Menukar Jenis dengan javacast
CFML ialah bahasa jenis longgar, tetapi Java menuntut jenis yang tepat. Apabila anda menghantar nilai CFML kepada kaedah Java, Lucee cuba meneka jenisnya, dan tekaan itu kadangkala salah. javacast memaksa jenis tertentu supaya kaedah Java menerima hujah yang betul.
// javacast memaksa jenis Java yang tepat sebelum nilai dihantar ke kaedah.
bulat = javacast("int", 42);
besar = javacast("long", 12345678901);
pi = javacast("double", 3.14159);
maks = createObject("java", "java.lang.Integer").MAX_VALUE;
writeOutput("int=" & bulat & " long=" & besar & " pi=" & pi);
writeOutput("<br>Integer.MAX_VALUE=" & maks);
Jenis yang paling kerap digunakan ialah int, long, double, boolean dan string. Tanpa javacast, nombor literal besar seperti 12345678901 mungkin dihantar sebagai jenis yang salah kepada kaedah yang menunggu long, dan ini menghasilkan ralat yang sukar dikesan. Jadual berikut meringkaskan laluan yang paling kerap digunakan:
| Tujuan | Kod CFML | Kelas atau jenis Java |
|---|---|---|
| UUID rawak | createObject("java", "java.util.UUID").randomUUID() | java.util.UUID |
| Versi Java | createObject("java", "java.lang.System").getProperty("java.version") | java.lang.System |
| Tarikh hari ini | createObject("java", "java.time.LocalDate").now() | java.time.LocalDate |
| Paksa integer | javacast("int", nilai) | int |
| Paksa long | javacast("long", nilai) | long |
java.time dan java.util.UUID
Kelas java.time seperti LocalDate, LocalDateTime dan ZonedDateTime menggantikan java.util.Date yang lama dan lebih selamat untuk kerja tarikh. java.util.UUID pula menjana pengecam unik versi 4 yang sesuai untuk kunci sesi, token atau id rekod.
// java.time untuk tarikh dan masa moden, lebih jelas daripada java.util.Date lama.
LocalDate = createObject("java", "java.time.LocalDate");
hariIni = LocalDate.now();
lahir = LocalDate.of(1990, 5, 15);
umur = createObject("java", "java.time.Period").between(lahir, hariIni).getYears();
fmt = createObject("java", "java.time.format.DateTimeFormatter").ofPattern("dd MMMM yyyy");
writeOutput("umur: " & umur & " tahun");
writeOutput("<br>tarikh: " & hariIni.format(fmt));
Period.between() mengira selang antara dua tarikh dan getYears() mengambil komponen tahunnya, jadi contoh ini mengira umur daripada tarikh lahir. DateTimeFormatter.ofPattern() kemudian memformat tarikh mengikut corak anda. Kesemua kelas ini berada dalam modul java.base JVM, jadi ia tersedia terus tanpa sebarang konfigurasi classpath.
Membaca Sifat Sistem dan Sifat JVM
java.lang.System memberikan akses kepada sifat JVM yang ditetapkan semasa pelayan dimulakan. Ini berbeza daripada fungsi CFML getSystemSetting yang membaca pemboleh ubah persekitaran. Sifat JVM berguna untuk menyemak versi Java, nama vendor, atau bendera khusus yang anda tetapkan semasa menghidupkan pelayan. Jika aplikasi anda perlu berkelakuan berbeza mengikut versi Java, ini cara untuk mengetahuinya pada masa jalan. Untuk memahami versi Java yang disokong dan kesannya, baca artikel Java 25 dan Lucee, dan untuk mengoptimumkan pelayan, lihat panduan tala JVM.
Menambah JAR ke Classpath Lucee
Kelas dalam java.base tersedia terus, tetapi pustaka pihak ketiga seperti pemacu JDBC tidak. Lucee memisahkan kelas itu di sebalik sempadan OSGi, jadi anda mesti menambah JAR secara eksplisit melalui this.javaSettings dalam Application.cfc:
component {
this.name = "kedaiapp";
this.javaSettings = {
loadPaths: [ expandPath("./lib") ]
};
}
loadPaths menerima senarai laluan ke fail JAR atau direktori yang mengandungi JAR. Letakkan JAR dalam folder lib di bawah akar aplikasi, dan Lucee memuatkannya ke classloader aplikasi. Selepas itu, kelas dalam JAR boleh dicapai dengan createObject. Ini didokumenkan dalam resipi Java Settings rasmi Lucee. Untuk pustaka yang boleh ditarik dari Maven Central, Lucee 6.2 ke atas juga menyokong tetapan this.javaSettings.maven supaya anda tidak perlu mengurus fail JAR secara manual.
JDBC Terus Tanpa Datasource
Untuk hampir semua kerja pangkalan data, queryExecute dan cfquery sudah mencukupi dan lebih selamat, kerana ia menguruskan sambungan dan parameter untuk anda. Tetapi ada kes yang menuntut kawalan penuh, contohnya memanggil API java.sql terus untuk transaksi yang sangat khusus. Untuk itu, pemacu JDBC mesti berada di classpath dahulu, seperti yang ditunjukkan dalam bahagian sebelumnya.
// Pemacu mesti berada di loadPaths dahulu, lihat javaSettings di atas.
d = createObject("java", "com.mysql.cj.jdbc.Driver").init();
props = createObject("java", "java.util.Properties").init();
props.setProperty("user", "kod");
props.setProperty("password", "kod123");
jd = "jdbc:mysql://172.17.0.5:3306/kedai?useUnicode=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC";
conn = d.connect(jd, props);
st = conn.createStatement();
rs = st.executeQuery("SELECT id, nama, harga FROM produk ORDER BY id LIMIT 3");
while (rs.next()) {
writeOutput(rs.getInt("id") & " | " & rs.getString("nama") & " | " & rs.getBigDecimal("harga") & "<br>");
}
rs.close();
st.close();
conn.close();
Tiga perangkap penting di sini, dan semuanya disahkan dengan menjalankan kod. Pertama, jangan gunakan DriverManager.getConnection, kerana sempadan OSGi Lucee menghalang pemacu daripada didaftarkan kepada DriverManager, lalu anda mendapat ralat "No suitable driver found". Kedua, jangan guna Class.forName, kerana ia memulangkan "com.mysql.cj.jdbc.Driver not found by lucee.core". Cara yang berfungsi ialah mencipta tika pemacu terus dengan .init() dan memanggil connect() pada tika itu, seperti di atas. Ketiga, jangan namakan pemboleh ubah url, kerana url ialah skop CFML dan rentetan anda akan bertukar menjadi struct. Nilai kod dan kod123 dalam contoh ialah kredensial ujian, jadi gantikan dengan hos dan kredensial aplikasi anda sendiri, dan simpan ia di luar kod, sama ada dalam pemboleh ubah persekitaran atau fail konfigurasi.
Bila Guna Integrasi Java dan Bila Tidak
Integrasi Java ialah alat berkuasa, bukan pengganti fungsi bawaan. Gunakan createObject apabila tiada fungsi CFML setara, contohnya UUID versi 4, pengiraan tarikh kompleks dengan java.time, atau pustaka Java khusus yang tiada pembalut CFML. Untuk kerja pangkalan data biasa, queryExecute dan ORM lebih ringkas dan selamat, jadi baca pengenalan ORM Hibernate sebelum mencapai JDBC mentah. Untuk API HTTP, cfhttp dan fungsi bawaan lebih mudah daripada membina permintaan dengan java.net, jadi rujuk panduan REST API dalam Lucee. Panggilan Java juga boleh melempar pengecualian yang perlu anda tangkap, jadi balut kod yang menyentuh Java dalam blok pengendalian ralat cftry. Akhir sekali, prestasi aplikasi lebih banyak ditentukan oleh caching dan konfigurasi daripada pilihan Java atau CFML, jadi lihat panduan caching dan prestasi untuk melengkapkan gambar.
Soalan Lazim
Adakah integrasi Java memerlukan sambungan atau pemasangan tambahan?
Tidak untuk kelas dalam JVM seperti java.lang, java.util dan java.time. Kelas ini dalam modul java.base dan tersedia terus melalui createObject. Hanya pustaka pihak ketiga, seperti pemacu JDBC, yang perlu ditambah ke classpath melalui this.javaSettings.loadPaths.
Bila saya perlu menggunakan javacast?
Gunakan javacast apabila anda menghantar nilai kepada kaedah Java yang menuntut jenis tertentu, contohnya long, double atau boolean, dan anda mahu memastikan Lucee tidak meneka jenis secara salah. Ia paling penting apabila nilai literal besar atau jenis tidak jelas daripada konteks.
Kenapa DriverManager.getConnection gagal dalam Lucee?
Lucee menjalankan kelas pihak ketiga dalam sempadan OSGi, jadi pemacu JDBC yang dimuatkan melalui loadPaths tidak didaftarkan kepada java.sql.DriverManager. Anda mendapat ralat "No suitable driver found". Penyelesaiannya ialah mencipta tika pemacu dengan .init() dan memanggil connect() terus pada tika itu.
Bagaimana cara menambah JAR baharu ke aplikasi Lucee?
Letakkan fail JAR dalam folder di bawah akar aplikasi, contohnya lib, kemudian tetapkan this.javaSettings.loadPaths dalam Application.cfc untuk menunjuk ke folder itu. Selepas itu, kelas dalam JAR boleh dicapai dengan createObject("java", "nama.kelas").
Adakah saya patut menggantikan queryExecute dengan JDBC terus?
Tidak. queryExecute dan cfquery menguruskan sambungan dan parameter dengan selamat, dan ia mencukupi untuk hampir semua kes. Gunakan JDBC terus hanya apabila anda benar-benar memerlukan kawalan java.sql peringkat rendah, dan sedar bahawa anda bertanggungjawab menutup sambungan dan menangani ralat sendiri.