- Sản phẩm & Dịch vụSản phẩm & Dịch vụ
- Giải phápGiải pháp
- Bảng giáBảng giá
- Công tyCông ty
- Tài liệuTài liệu
vi
vi
Chuyên mục với các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.
Web Developer
I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.
Thảo luận (0)
Đăng nhập để thảo luận
Struts 2 là một trong những framework phổ biến để phát triển ứng dụng web bằng Java. Bài viết này sẽ tổng hợp một số câu hỏi phỏng vấn quan trọng về Struts 2 kèm theo câu trả lời để giúp bạn ôn tập và chuẩn bị kĩ lưỡng các kiến thức cơ bản về công cụ này.

Apache Struts 2 là một framework mã nguồn mở chuyên dùng để xây dựng ứng dụng web bằng Java. Nó được phát triển dựa trên một framework khác là OpenSymphony WebWork.
Struts 2 có nhiều cải tiến so với Struts 1, giúp framework này trở nên linh hoạt, dễ sử dụng và mở rộng hơn. Các thành phần cốt lõi của Struts 2 là Action (xử lý logic cho một request của người dùng), Interceptor (thêm logic xử lý trước và sau một Action) và Result page (trang kết quả).
Framework này cung cấp nhiều cách để tạo các class Action và cấu hình chúng thông qua file struts.xml hoặc annotation. Ta có thể tạo các interceptor của riêng mình cho các tác vụ chung. Struts 2 đi kèm với nhiều tag và sử dụng ngôn ngữ biểu thức OGNL. Ngoài ra, ta cũng có thể tạo các bộ chuyển đổi kiểu riêng để hiển thị các result page. Result page có thể là JSP và các mẫu FreeMarker.
Struts 2 được tạo ra để khắc phục những nhược điểm của Struts 1 và làm cho nó linh hoạt và dễ mở rộng hơn. Dưới đây là bảng so sánh điểm khác biệt cơ bản giữa Struts 1 và Struts 2:
| Thành phần | Struts 1 | Struts 2 |
|---|---|---|
| Lớp Action | Các lớp action của Struts 1 buộc phải kế thừa một lớp trừu tượng, nên chúng không thể mở rộng được nữa. | Các lớp action của Struts 2 có tính linh hoạt hơn. Ta có thể tạo chúng bằng cách triển khai interface Action, kế thừa class ActionSupport, hoặc đơn giản là tạo một class có phương thức execute(). |
| An toàn luồng | Lớp Action trong Struts 1 có thiết kế singleton và không có tính an toàn luồng. Lập trình viên phải xử lý cẩn thận việc chạy đa luồng để tránh các tác dụng phụ. | Mỗi lớp action của Struts 2 được khởi tạo cho từng request, do đó không có vấn đề về đa luồng và mặc định được coi là an toàn luồng. |
| Ràng buộc với Servlet API | API của Struts 1 bị ràng buộc chặt chẽ với Servlet API. Các đối tượng Request và Response được truyền trực tiếp vào phương thức execute() của action class. | API của Struts 2 chỉ có sự ràng buộc lỏng lẻo với Servlet API và tự động map (ánh xạ) dữ liệu từ form vào các property (thuộc tính) trong action class. Nếu cần truy cập đến các đối tượng của Servlet API, ta có thể dùng các interface *Aware. |
| Kiểm thử | Các action class của Struts 1 rất khó để test vì sự phụ thuộc chặt chẽ vào Servlet API. | Các action class của Struts 2 hoạt động như class Java thông thường. Chúng có thể được test một cách dễ dàng bằng cách khởi tạo và gán giá trị cho các property của chúng. |
| Map tham số request | Struts 1 yêu cầu chúng ta phải tạo các class ActionForm để chứa tham số từ request và phải đặt chúng trong file cấu hình của Struts. | Struts 2 thực hiện việc map tham số request một cách tự động. Tất cả những gì ta cần làm là khai báo các property JavaBean trong action class hoặc triển khai interfce ModelDriven để cung cấp tên class JavaBean cần map. |
| Tag | Struts 1 sử dụng các tag của JSTL, do đó bị hạn chế về chức năng. | Struts 2 sử dụng OGNL và cung cấp nhiều loại tag khác nhau như UI, Control, và Data. Điều này giúp các tag trở nên đa dụng và dễ sử dụng hơn. |
| Xác thực dữ liệu | Struts 1 hỗ trợ xác thực thông qua việc triển khai thủ công phương thức validate(). | Struts 2 hỗ trợ cả xác thực thủ công lẫn tích hợp với các framework xác thực. |
| Hiển thị View | Struts 1 sử dụng công nghệ JSP tiêu chuẩn để hiển thị giá trị từ các bean lên view. | Struts 2 sử dụng ValueStack để lưu các tham số và thuộc tính của request. Ta có thể dùng OGNL và các tag của Struts 2 để truy cập các giá trị này. |
| Mô hình hỗ trợ | Việc thiết kế module trong Struts 1 rất phức tạp, tương đương như những dự án riêng biệt. | Struts 2 cung cấp cấu hình namespace (không gian tên) cho các gói, giúp việc tạo các module trở nên dễ dàng hơn. |
Các thành phần chính của Struts 2 là:

Interceptor là xương sống của Struts 2. Các interceptor chịu trách nhiệm cho hầu hết các công việc xử lý của framework này, chẳng hạn như việc truyền tham số request đến các class Action, cung cấp Servlet API request, response, session cho các class Action, xác thực, hỗ trợ i18n, v.v. ActionInvocation chịu trách nhiệm đóng gói các class Action và interceptor, cũng như kích hoạt chúng theo thứ tự.
Phương thức quan trọng nhất được sử dụng trong ActionInvocation là invoke() Nó có nhiệm vụ theo dõi chuỗi interceptor và gọi interceptor hoặc action tiếp theo. Đây là một trong những ví dụ điển hình nhất về mẫu thiết kế Chain of Responsibility (Chuỗi trách nhiệm) trong các framework Java EE.
Interceptor trong Struts 2 được xây dựng dựa trên thiết kế kiểu Intercepting Filter (Bộ lọc chặn). Việc gọi các interceptor trong một stack (tập hợp các interceptor xử lý theo thứ tự) rất giống với mẫu thiết kế Chain of Responsibility.
Struts 2 cung cấp nhiều cách khác nhau để tạo các class Action:
Các class Action của Struts 2 có tính an toàn luồng vì với mỗi request sẽ có một đối tượng mới được khởi tạo để xử lý nó. Các interceptor của Struts 2 là các class singleton và một luồng mới sẽ được tạo ra để xử lý request. Do đó chúng không có tính an toàn luồng và chúng ta cần viết code cẩn thận để tránh các vấn đề với dữ liệu chia sẻ.
org.apache.Struts 2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter là class Front Controller trong Struts 2 và mọi quá trình xử lý request đều bắt đầu từ class này. Các phiên bản trước của Struts 2 sử dụng org.apache.Struts 2.dispatcher.FilterDispatcher làm class Front Controller.
Một số lợi ích của interceptor là:
ValueStack là khu vực lưu trữ nơi dữ liệu ứng dụng được Struts 2 dùng để xử lý các request từ client. Dữ liệu được lưu trong các đối tượng ActionContext sử dụng ThreadLocal để chứa các giá trị cụ thể cho từng luồng request.
Object-Graph Navigation Language (OGNL) là một ngôn ngữ biểu thức (Expression language) mạnh mẽ được sử dụng để thao tác dữ liệu được lưu trên ValueStack. Như bạn có thể thấy trong sơ đồ kiến trúc, cả interceptor và result page đều có thể truy cập dữ liệu được lưu trên ValueStack bằng OGNL.
Một số annotation quan trọng được thêm vào trong Struts 2 là:
Một số hằng số quan trọng của Struts 2 bao gồm:
struts.devMode để chạy ứng dụng ở chế độ development. Nó sẽ tải lại các thuộc tính file và cung cấp thêm tính năng ghi log và debug. Chế độ rất hữu ích khi phát triển ứng dụng nhưng chúng ta nên tắt nó khi đưa code lên môi trường production.struts.convention.result.path để cấu hình vị trí của các result page. Mặc định Struts 2 tìm kiếm result page tại {WEBAPP-ROOT}/{Namespace}/ và ta có thể thay đổi vị trí đó bằng hằng số này.struts.custom.i18n.resources để định nghĩa gói resource toàn cầu cho việc hỗ trợ i18n.struts.action.extension để cấu hình hậu tố URL cho ứng dụng Struts 2. Hậu tố mặc định là .action nhưng đôi khi chúng ta có thể muốn đổi nó thành .do hoặc một giá trị khác.Ta có thể thiết lập các hằng trên trong file struts.xml như bên dưới:
<constant name="struts.devMode" value="true"></constant> <constant name="struts.action.extension" value="action,do"></constant> <constant name="struts.custom.i18n.resources" value="global"></constant> <constant name="struts.convention.result.path" value="/"></constant>
Cấu hình của namespace (không gian tên) trong Struts 2 cho phép chúng ta tạo các module một cách dễ dàng. Ta có thể sử dụng chúng để phân tách các class action dựa trên chức năng, ví dụ như admin, user, customer, v.v.
Interceptor com.opensymphony.xwork2.interceptor.ParametersInterceptor có trách nhiệm map các tham số request vào các thuộc tính Java Bean của class Action. Nó được cấu hình trong package struts-default với tên là “params”. Đây là một phần của các interceptor stack basicStack và defaultStack.
Interceptor com.opensymphony.xwork2.interceptor.I18nInterceptor chịu trách nhiệm hỗ trợ i18n trong các ứng dụng Struts 2. Nó này được cấu hình trong package struts-default với tên là “i18n” và là một phần của i18nStack và defaultStack.
Chúng ta có thể dùng interface Action để tạo các class Action. Interface này chỉ có một phương thức execute() mà ta cần phải triển khai. Lợi ích duy nhất của việc chọn interface này là nó chứa một số hằng số mà ta có thể dùng cho các result page, đó là SUCCESS, ERROR, NONE, INPUT và LOGIN.
Class ActionSupport là một bản triển khai mặc định của interface Action và nó cũng triển khai các interface liên quan đến xác thực dữ liệu và hỗ trợ i18n. Class ActionSupport triển khai các interface Action, Validateable, ValidationAware, TextProvider và LocaleProvider. Ta có thể ghi đè phương thức validate() của class ActionSupport để thêm logic xác thực ở cấp độ field vào các class Action của mình.
Tùy thuộc vào yêu cầu, ta có thể sử dụng bất kỳ cách tiếp cận nào để tạo class Action trong Struts 2. Tuy vậy, class ActionSupport thường được ưu tiên hơn vì nó giúp viết logic xác thực và i18n trong các class Action một cách dễ dàng hơn.
Các class Action của Struts 2 không cung cấp quyền truy cập trực tiếp vào các thành phần Servlet API như Request, Response và Session. Tuy nhiên, đôi khi chúng ta cần truy cập chúng trong các class Action, ví dụ như để kiểm tra phương thức HTTP hoặc đặt cookie trong response.
Đó là lý do tại sao Struts 2 API cung cấp một loạt các interface *Aware mà chúng ta có thể triển khai để truy cập các đối tượng này. Struts 2 API sử dụng dependency injection (kỹ thuật cung cấp đối tượng phụ thuộc từ bên ngoài) để thêm các thành phần Servlet API vào các class Action. Một số interface Aware quan trọng là SessionAware, ApplicationAware, ServletRequestAware, và ServletResponseAware.
Struts 2 cung cấp interceptor execAndWait cho các class Action chạy trong thời gian dài. Ta có thể sử dụng nó để trả về một trang phản hồi tạm thời cho client. Khi quá trình xử lý hoàn tất, phản hồi cuối cùng sẽ được trả về cho client. Interceptor này được định nghĩa trong package struts-default và được triển khai trong class ExecuteAndWaitInterceptor.
Một trong những vấn đề lớn với các ứng dụng web là việc gửi cùng một form hai lần. Nếu không được xử lý, việc này có thể dẫn đến các sai sót như tính phí khách hàng hoặc cập nhật giá trị cơ sở dữ liệu hai lần.
Ta có thể sử dụng interceptor token để giải quyết vấn đề này. Tuy được định nghĩa trong package struts-default, nó không phải là một phần của bất kỳ interceptor stack nào. Vì vậy chúng ta cần phải thêm nó vào các class Action của mình một cách thủ công.
Struts 2 cung cấp khả năng tích hợp dễ dàng với log4j API cho mục đích ghi log. Tất cả những gì chúng ta cần làm là đặt file cấu hình log4j trong thư mục WEB-INF/classes.
Struts 2 cung cấp rất nhiều tag tùy chỉnh mà ta có thể sử dụng trong các result page để tạo view cho client request. Các tag này được chia thành ba loại chính: Data tag, Control tag và UI tag. Ta có thể sử dụng các tag này bằng cách thêm chúng vào các trang JSP bằng chỉ thị taglib.
<%@ taglib uri="/struts-tags" prefix="s" %>
Một số Data tag quan trọng là property, set, push, bean, action, include, i18n và text. Control tag được sử dụng để thao tác và điều hướng dữ liệu từ một collection. Một số Control tag quan trọng là if-elseif-else, iterator, append, merge, sort, subset và generator. UI tag của Struts 2 được sử dụng để tạo mã HTML, binding dữ liệu form HTML với các thuộc tính của class action, chuyển đổi kiểu, xác thực và hỗ trợ i18n. Một số UI tag quan trọng là form, textfield, password, textarea, checkbox, select, radio và submit.
Struts 2 hỗ trợ ngôn ngữ biểu thức OGNL. Nó thực hiện hai công việc quan trọng là truyền dữ liệu và chuyển đổi kiểu. OGNL rất linh hoạt và ta có thể dễ dàng mở rộng nó để tạo ra class converter tùy chỉnh của riêng mình.
Việc tạo và cấu hình một class custom type converter (bộ chuyển đổi kiểu tùy chỉnh) rất dễ dàng. Bước đầu tiên là xác định định dạng đầu vào cho class tùy chỉnh. Bước thứ hai là triển khai class chuyển đổi. Các class này phải triển khai interface com.opensymphony.xwork2.conversion.TypeConverter.
Vì trong ứng dụng web, chúng ta luôn nhận request và gửi response dưới dạng String, Struts 2 API cung cấp một triển khai mặc định của interface TypeConverter là StrutsTypeConverter. Nó chứa hai phương thức trừu tượng: convertFromString để chuyển đổi từ String sang Object và convertToString để chuyển đổi từ Object sang String.
Ta có thể triển khai interface com.opensymphony.xwork2.interceptor.Interceptor để tạo interceptor của riêng mình. Khi đã tạo xong class interceptor, ta cần định nghĩa nó trong file struts.xml trong package mà ta muốn sử dụng.
Ta cũng có thể tạo một interceptor stack với interceptor tự tạo này với các interceptor của defaultStack. Sau đó, ta có thể cấu hình nó cho các class Action nơi ta muốn sử dụng. Một trong những ví dụ điển hình nhất về việc sử dụng interceptor tùy chỉnh là để xác thực session.
Interface Interceptor định nghĩa ba phương thức: init(), destroy() và intercept(). init() và destroy() là các phương thức vòng đời của một interceptor.
Interceptor là các class Singleton và Struts 2 khởi tạo một luồng mới để xử lý mỗi request. Phương thức init() được gọi khi một cá thể của interceptor được tạo ra và ta có thể khởi tạo bất kỳ tài nguyên nào trong phương thức này. Phương thức destroy() được gọi khi ứng dụng dừng chạy và ta có thể giải phóng bất kỳ tài nguyên nào trong phương thức này. intercept() là phương thức được gọi mỗi khi request của client đi qua interceptor.
Một interceptor stack giúp chúng ta nhóm nhiều interceptor lại với nhau trong một package để sử dụng sau này. Package struts-default tạo ra một số interceptor stack được sử dụng thường xuyên nhất: basicStack và defaultStack. Ta có thể tạo interceptor stack của riêng mình ở đầu package và sau đó cấu hình các class Action để sử dụng nó.
struts-default là một package trừu tượng định nghĩa tất cả các interceptor của Struts 2 và các interceptor stack thường được sử dụng. Bạn nên kế thừa package này khi cấu hình package ứng dụng của mình để tránh phải cấu hình lại các interceptor. Nó được cung cấp để giúp các lập trình viên loại bỏ một số công việc không cần thiết là cấu hình interceptor và result page trong ứng dụng.
Hậu tố URI mặc định cho action của Struts 2 là .action, trong khi hậu tố mặc định của Struts 1 là .do. Ta có thể thay đổi hậu tố này bằng cách định nghĩa giá trị hằng số struts.action.extension trong file cấu hình Struts 2.
<constant name="struts.action.extension" value="action,do"></constant>
Mặc định, Struts 2 tìm kiếm các result page trong thư mục {WEBAPP-ROOT}/{Namespace}/. Khi muốn giữ các result page ở một vị trí khác, ta có thể cung cấp giá trị hằng số struts.convention.result.path trong file cấu hình Struts 2 để thay đổi vị trí của chúng. Một cách khác là sử dụng annotation @ResultPath trong các class Action để cung cấp thẳng vị trí của result page.
Tải file lên (upload) là một trong những tác vụ phổ biến trong ứng dụng web. Struts 2 cung cấp hỗ trợ tích hợp sẵn cho việc này thông qua FileUploadInterceptor. Interceptor này được cấu hình trong package struts-default và cung cấp các tùy chọn để đặt kích thước tối đa của file và các loại file có thể được tải lên server.
Một số nguyên tắc nên cân nhắc khi phát triển ứng dụng Struts 2 là:
Struts 2 cung cấp một framework rất mạnh để xử lý exception. Ta có thể chỉ định các kết quả toàn cục trong các package và sau đó map các exception cụ thể tới các result page này. Việc map exception có thể được thực hiện ở cấp độ package toàn cục cũng như ở cấp độ action.
Bạn nên có các result page cho exception để cung cấp một số thông tin cho người dùng khi có một lỗi bất ngờ xảy ra mà không được ứng dụng xử lý. Đây là một cấu hình mẫu trong fiel struts.xml:
<package name="user" namespace="/" extends="struts-default"><global-results> <result name="exception">/exception.jsp</result> <result name="runtime_exception">/runtime_exception.jsp</result> <result name="error">/error.jsp</result> </global-results>
<global-exception-mappings> <exception-mapping exception="java.lang.Exception" result="exception"></exception-mapping> <exception-mapping exception="java.lang.Error" result="error"></exception-mapping> <exception-mapping exception="java.lang.RuntimeException" result="runtime_exception"></exception-mapping> </global-exception-mappings>
<action name="myaction" class="com.journaldev.struts2.exception.MyAction"> </action> <action name="myspecialaction" class="com.journaldev.struts2.exception.MySpecialAction"> <exception-mapping exception="java.io.IOException" result="login"></exception-mapping> <result name="login">/error.jsp</result> </action></package>
Chúng tôi tin rằng với những giải thích cho các câu hỏi phỏng vấn Struts 2 trong bài này, bạn sẽ có đủ kiến thức và kỹ năng để tự tin cho những thử thách sắp tới. Nếu có bất kỳ câu hỏi nào – hoặc muốn chúng tôi trả lời thêm, đừng ngần ngại – để lại phản hồi cho chúng tôi ở phần bình luận bên dưới.