Một ứng dụng web phong nha bao gồm một hỗn hợp các mẫu thiết kế. Tôi sẽ chỉ đề cập đến những người quan trọng nhất.
Mẫu thiết kế (kiến trúc) cốt lõi mà bạn muốn sử dụng là mẫu Model-View-Controller . Bộ điều khiển sẽ được đại diện bởi một Servlet mà (trực tiếp) tạo / sử dụng một Mô hình và Chế độ xem cụ thể dựa trên yêu cầu. Các mẫu phải được đại diện bởi các lớp JavaBean. Điều này thường được chia thêm trong Mô hình nghiệp vụ có chứa các hành động (hành vi) và Mô hình dữ liệu chứa dữ liệu (thông tin). Các Xem là để được đại diện bởi các file JSP mà có thể truy cập trực tiếp đến ( dữ liệu ) Mẫu bởi EL (Expression Language).
Sau đó, có các biến thể dựa trên cách xử lý các hành động và sự kiện. Những cái phổ biến là:
Yêu cầu (hành động) dựa trên MVC : đây là cách đơn giản nhất để thực hiện. Mô hình ( Kinh doanh ) làm việc trực tiếp với và các đối tượng. Bạn phải tự mình thu thập, chuyển đổi và xác thực các tham số yêu cầu (chủ yếu). Các Xem thể được đại diện bởi vani đồng bằng HTML / CSS / JS và nó không duy trì trạng thái trên yêu cầu. Đây là cách mà những người khác Spring MVC , Struts và Stripes hoạt động.HttpServletRequest
HttpServletResponse
Thành phần dựa trên MVC : điều này khó thực hiện hơn. Nhưng bạn kết thúc với một mô hình đơn giản hơn và xem trong đó tất cả API Servlet "thô" được trừu tượng hóa hoàn toàn. Bạn không cần phải thu thập, chuyển đổi và xác thực các tham số yêu cầu. Bộ điều khiển thực hiện nhiệm vụ này và đặt các tham số yêu cầu được thu thập, chuyển đổi và xác nhận trong Mô hình . Tất cả những gì bạn cần làm là xác định các phương thức hành động hoạt động trực tiếp với các thuộc tính mô hình. Các Xem được đại diện bởi "linh kiện" trong hương vị của taglibs JSP hoặc các yếu tố XML mà lần lượt tạo ra HTML / CSS / JS. Trạng thái của Chế độ xemcho các yêu cầu tiếp theo được duy trì trong phiên. Điều này đặc biệt hữu ích cho các sự kiện chuyển đổi, xác nhận và thay đổi giá trị phía máy chủ. Đây là cách mà những người khác JSF , Wicket và Play! làm.
Như một lưu ý phụ, sở thích xung quanh với khung MVC tại nhà là một bài tập học tập rất hay và tôi khuyên bạn nên sử dụng nó miễn là bạn giữ nó cho mục đích cá nhân / riêng tư. Nhưng một khi bạn trở nên chuyên nghiệp, thì chúng tôi khuyên bạn nên chọn một khung hiện có thay vì phát minh lại khung của riêng bạn. Học một khung hiện có và được phát triển tốt sẽ mất ít thời gian hơn so với việc tự mình phát triển và duy trì một khung mạnh mẽ.
Trong phần giải thích chi tiết dưới đây, tôi sẽ hạn chế yêu cầu MVC dựa trên vì điều đó dễ thực hiện hơn.
Đầu tiên, phần Bộ điều khiển phải triển khai mẫu Bộ điều khiển phía trước (là một loại mẫu của Người hòa giải chuyên biệt ). Nó chỉ bao gồm một servlet duy nhất cung cấp một điểm nhập tập trung của tất cả các yêu cầu. Nó sẽ tạo Mô hình dựa trên thông tin có sẵn theo yêu cầu, chẳng hạn như pathinfo hoặc servletpath, phương thức và / hoặc các tham số cụ thể. Các mô hình kinh doanh được gọi là Action
ở dưới đây HttpServlet
chẳng hạn.
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);
}
}
Thực hiện hành động sẽ trả về một số định danh để xác định vị trí xem. Đơn giản nhất là sử dụng nó làm tên tệp của JSP. Ánh xạ servlet này trên một cụ thể url-pattern
trong web.xml
, ví dụ /pages/*
, *.do
hoặc thậm chí chỉ *.html
.
Trong trường hợp mẫu tiền tố như ví dụ, /pages/*
bạn có thể gọi URL như http://example.com/pages/register , http://example.com/pages/login , v.v. và cung cấp /WEB-INF/register.jsp
, /WEB-INF/login.jsp
với các hành động GET và POST thích hợp . Các phần register
, login
vv sau đó có sẵn request.getPathInfo()
như trong ví dụ trên.
Khi bạn đang sử dụng các mẫu hậu tố như *.do
, *.html
v.v., thì bạn có thể gọi URL như http://example.com/register.do , http://example.com/login.do , v.v. và bạn nên thay đổi ví dụ mã trong câu trả lời này (cũng là ActionFactory
) để trích xuất register
và login
các bộ phận bằng cách request.getServletPath()
thay thế.
Các Action
nên làm theo các mô hình chiến lược . Nó cần được định nghĩa là một loại trừu tượng / giao diện, sẽ thực hiện công việc dựa trên các đối số được truyền vào của phương thức trừu tượng (đây là sự khác biệt với mẫu Lệnh , trong đó loại trừu tượng / giao diện sẽ thực hiện công việc dựa trên các đối số được thông qua trong quá trình tạo ra việc thực hiện).
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
Bạn có thể muốn làm cho Exception
cụ thể hơn với một ngoại lệ tùy chỉnh như ActionException
. Đó chỉ là một ví dụ khởi động cơ bản, phần còn lại tùy thuộc vào bạn.
Đây là một ví dụ về một LoginAction
cái mà (như tên của nó nói) đăng nhập vào người dùng. Chính User
nó là một Mô hình Dữ liệu . The View nhận thức được sự hiện diện của 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.
}
}
}
Các ActionFactory
nên làm theo các phương pháp mô hình Nhà máy . Về cơ bản, nó sẽ cung cấp một phương thức sáng tạo trả về một triển khai cụ thể của kiểu trừu tượng / giao diện. Trong trường hợp này, nó sẽ trả về việc thực hiện Action
giao diện dựa trên thông tin được cung cấp bởi yêu cầu. Ví dụ: phương thức và pathinfo (pathinfo là phần nằm sau đường dẫn ngữ cảnh và servlet trong URL yêu cầu, không bao gồm chuỗi truy vấn).
public static Action getAction(HttpServletRequest request) {
return actions.get(request.getMethod() + request.getPathInfo());
}
Các actions
lần lượt nên có một số tĩnh / applicationwide Map<String, Action>
nắm giữ tất cả các hành động được biết đến. Tùy thuộc vào bạn làm thế nào để điền vào bản đồ này. Mã hóa cứng:
actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...
Hoặc có thể định cấu hình dựa trên tệp cấu hình thuộc tính / XML trong đường dẫn lớp: (giả)
for (Entry entry : configuration) {
actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}
Hoặc tự động dựa trên quá trình quét trong đường dẫn lớp cho các lớp thực hiện một giao diện và / hoặc chú thích nhất định: (giả)
for (ClassFile classFile : classpath) {
if (classFile.isInstanceOf(Action.class)) {
actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
}
}
Hãy ghi nhớ để tạo "không làm gì" Action
cho trường hợp không có ánh xạ. Let it ví dụ trở lại trực tiếp request.getPathInfo().substring(1)
sau đó.
Các mẫu khác
Đó là những mẫu quan trọng cho đến nay.
Để tiến thêm một bước, bạn có thể sử dụng mẫu Mặt tiền để tạo một Context
lớp lần lượt bao bọc các đối tượng yêu cầu và phản hồi và đưa ra một số phương thức tiện lợi ủy thác cho các đối tượng yêu cầu và phản hồi và chuyển đối số đó thành đối số vào Action#execute()
phương thức. Điều này thêm một lớp trừu tượng bổ sung để ẩn API Servlet thô đi. Về cơ bản, bạn nên kết thúc với khai báo bằng không import javax.servlet.*
trong mỗi lần Action
thực hiện. Theo thuật ngữ của JSF, đây là những gì FacesContext
và ExternalContext
các lớp đang làm. Bạn có thể tìm thấy một ví dụ cụ thể trong câu trả lời này .
Sau đó, có mẫu Trạng thái cho trường hợp bạn muốn thêm một lớp trừu tượng bổ sung để phân chia các nhiệm vụ thu thập các tham số yêu cầu, chuyển đổi chúng, xác thực chúng, cập nhật giá trị mô hình và thực hiện các hành động. Theo thuật ngữ của JSF, đây là những gì LifeCycle
đang làm.
Sau đó, có mẫu Tổng hợp cho trường hợp bạn muốn tạo chế độ xem dựa trên thành phần có thể được đính kèm với mô hình và hành vi của chúng phụ thuộc vào trạng thái của vòng đời dựa trên yêu cầu. Theo thuật ngữ của JSF, đây là những gì UIComponent
đại diện.
Bằng cách này, bạn có thể phát triển từng chút một theo khung dựa trên thành phần.
Xem thêm: