Aplikasi web yang sedikit baik terdiri dari campuran pola desain. Saya hanya akan menyebutkan yang paling penting.
Pola desain inti (arsitektur) yang ingin Anda gunakan adalah pola Model-View-Controller . The Pengendali harus diwakili oleh Servlet yang (di) langsung menciptakan / menggunakan spesifik Model dan View berdasarkan permintaan. The Model yang akan diwakili oleh kelas JavaBean. Ini sering dibagi lagi dalam Model Bisnis yang berisi tindakan (perilaku) dan Model Data yang berisi data (informasi). The View adalah untuk diwakili oleh file JSP yang memiliki akses langsung ke ( data ) Model oleh EL (Expression Language).
Lalu, ada variasi berdasarkan bagaimana tindakan dan peristiwa ditangani. Yang populer adalah:
Permintaan (tindakan) berdasarkan MVC : ini adalah yang paling sederhana untuk diterapkan. The ( Bisnis ) Model bekerja secara langsung dengan HttpServletRequest
dan HttpServletResponse
benda-benda. Anda harus mengumpulkan, mengonversi, dan memvalidasi parameter permintaan (kebanyakan) sendiri. The View dapat diwakili oleh plain vanilla HTML / CSS / JS dan tidak mempertahankan negara di seluruh permintaan. Beginilah cara kerja Spring MVC , Struts and Stripes .
MVC berbasis komponen : ini lebih sulit untuk diterapkan. Tetapi Anda berakhir dengan model yang lebih sederhana dan melihat di mana semua API Servlet "mentah" diabstraksi sepenuhnya. Anda seharusnya tidak perlu mengumpulkan, mengonversi, dan memvalidasi sendiri parameter permintaan. The Pengendali melakukan tugas ini dan set berkumpul, parameter permintaan dikonversi dan divalidasi dalam Model . Yang perlu Anda lakukan adalah mendefinisikan metode tindakan yang bekerja langsung dengan properti model. The View diwakili oleh "komponen" di rasa taglibs JSP atau elemen XML yang pada gilirannya menghasilkan HTML / CSS / JS. Keadaan Tampilanuntuk permintaan selanjutnya dipertahankan dalam sesi. Ini sangat membantu untuk konversi sisi server, validasi, dan perubahan nilai. Ini adalah bagaimana antara lain JSF , Wicket and Play! bekerja.
Sebagai catatan tambahan, bermain-main dengan kerangka kerja MVC buatan sendiri adalah latihan pembelajaran yang sangat menyenangkan, dan saya merekomendasikannya selama Anda menyimpannya untuk keperluan pribadi / pribadi. Tetapi begitu Anda menjadi profesional, maka sangat disarankan untuk memilih kerangka kerja yang ada daripada menciptakan kembali kerangka kerja Anda sendiri. Mempelajari kerangka kerja yang sudah ada dan dikembangkan dengan baik membutuhkan waktu lebih lama daripada mengembangkan dan mempertahankan kerangka kerja yang kokoh.
Dalam penjelasan rinci di bawah ini saya akan membatasi diri untuk meminta MVC berbasis karena itu lebih mudah untuk diterapkan.
Pertama, bagian Pengendali harus menerapkan pola Pengontrol Depan (yang merupakan jenis khusus dari pola Mediator ). Ini harus terdiri dari hanya satu servlet yang menyediakan titik masuk terpusat dari semua permintaan. Ini harus membuat Model berdasarkan informasi yang tersedia oleh permintaan, seperti pathinfo atau servletpath, metode dan / atau parameter tertentu. The Model Bisnis disebut Action
di bawah ini HttpServlet
contoh.
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
}
else {
response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern).
}
}
catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
Menjalankan tindakan harus mengembalikan beberapa pengidentifikasi untuk menemukan tampilan. Paling sederhana adalah menggunakannya sebagai nama file dari JSP. Peta servlet ini pada spesifik url-pattern
di web.xml
, misalnya /pages/*
, *.do
atau bahkan hanya *.html
.
Dalam kasus pola awalan seperti misalnya /pages/*
Anda kemudian dapat memanggil URL seperti http://example.com/pages/register , http://example.com/pages/login , dll dan berikan /WEB-INF/register.jsp
, /WEB-INF/login.jsp
dengan tindakan GET dan POST yang sesuai . Bagian-bagian register
,, login
dll kemudian tersedia request.getPathInfo()
seperti pada contoh di atas.
Saat Anda menggunakan pola sufiks seperti *.do
,, *.html
dll, maka Anda dapat memunculkan URL seperti http://example.com/register.do , http://example.com/login.do , dll dan Anda harus mengubah contoh kode dalam jawaban ini (juga the ActionFactory
) untuk mengekstrak bagian register
- login
bagian dan request.getServletPath()
sebagai gantinya.
The Action
harus mengikuti pola Strategi . Itu perlu didefinisikan sebagai tipe abstrak / antarmuka yang harus melakukan pekerjaan berdasarkan argumen yang dilewatkan dari metode abstrak (ini adalah perbedaan dengan pola Command , di mana jenis abstrak / antarmuka harus melakukan pekerjaan berdasarkan pada argumen yang telah diteruskan selama penciptaan implementasi).
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
Anda mungkin ingin membuat yang Exception
lebih spesifik dengan pengecualian khusus seperti ActionException
. Ini hanya contoh awal kickoff, sisanya terserah Anda.
Berikut adalah contoh dari LoginAction
yang (seperti namanya) mencatat pengguna. Itu User
sendiri pada gilirannya Model Data . The View menyadari kehadiran User
.
public class LoginAction implements Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
return "home"; // Redirect to home page.
}
else {
request.setAttribute("error", "Unknown username/password. Please retry."); // Store error message in request scope.
return "login"; // Go back to redisplay login form with error.
}
}
}
The ActionFactory
harus mengikuti pola metode Factory . Pada dasarnya, ini harus menyediakan metode kreatif yang mengembalikan implementasi konkret dari tipe abstrak / antarmuka. Dalam hal ini, harus mengembalikan implementasi Action
antarmuka berdasarkan informasi yang disediakan oleh permintaan. Misalnya, metode dan pathinfo (pathinfo adalah bagian setelah konteks dan jalur servlet di URL permintaan, tidak termasuk string kueri).
public static Action getAction(HttpServletRequest request) {
return actions.get(request.getMethod() + request.getPathInfo());
}
Pada actions
gilirannya harus berupa static / applicationwide Map<String, Action>
yang menampung semua tindakan yang diketahui. Terserah Anda bagaimana mengisi peta ini. Hardcoding:
actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...
Atau dapat dikonfigurasi berdasarkan file konfigurasi properti / XML di classpath: (pseudo)
for (Entry entry : configuration) {
actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}
Atau secara dinamis didasarkan pada pemindaian di classpath untuk kelas yang mengimplementasikan antarmuka dan / atau anotasi tertentu: (pseudo)
for (ClassFile classFile : classpath) {
if (classFile.isInstanceOf(Action.class)) {
actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
}
}
Perlu diingat untuk membuat "tidak melakukan apa-apa" Action
untuk kasus ini tidak ada pemetaan. Biarkan misalnya mengembalikan langsung request.getPathInfo().substring(1)
itu.
Pola lainnya
Itu adalah pola penting sejauh ini.
Untuk melangkah lebih jauh, Anda bisa menggunakan pola Facade untuk membuat Context
kelas yang pada gilirannya membungkus objek permintaan dan respons dan menawarkan beberapa metode kenyamanan mendelegasikan ke objek permintaan dan respons dan meneruskannya sebagai argumen ke dalam Action#execute()
metode sebagai gantinya. Ini menambahkan lapisan abstrak ekstra untuk menyembunyikan API Servlet mentah. Anda pada dasarnya harus berakhir dengan nol import javax.servlet.*
deklarasi dalam setiap Action
implementasi. Dalam istilah JSF, inilah yang dilakukan oleh FacesContext
dan ExternalContext
kelas. Anda dapat menemukan contoh nyata dalam jawaban ini .
Lalu ada pola Status untuk kasus yang ingin Anda tambahkan lapisan abstraksi ekstra untuk membagi tugas mengumpulkan parameter permintaan, mengonversinya, memvalidasinya, memperbarui nilai-nilai model dan menjalankan tindakan. Dalam istilah JSF, inilah yang LifeCycle
dilakukannya.
Lalu ada pola Komposit untuk kasus yang ingin Anda buat tampilan berbasis komponen yang dapat dilampirkan dengan model dan yang perilakunya tergantung pada keadaan siklus hidup berdasarkan permintaan. Dalam istilah JSF, inilah yang UIComponent
diwakilinya.
Dengan cara ini Anda dapat berevolusi sedikit demi sedikit menuju kerangka kerja berbasis komponen.
Lihat juga: