Trong tình huống thứ nhất, nếu bạn validate data tại client qua java script thì chương trình của bạn vẫn có thể bị đổ vỡ khi người dùng vô tình hay cố ý truy cập action của bạn qua address bar hoặc qua history. Những truy cập trực tiếp đó không được validate data nên chương trình của bạn sẽ không chống đỡ được. Giờ thì có thể bạn nghĩ sẽ phải validate data trên action thay vì tại client. Nhưng đó không phải giải pháp hay. Validate data không phải là business logic chính của chương trình. Validate data là rất cần cho tất cả các application và cần ở nhiều nơi trong chương trình nhưng nếu validate bừa bãi thì code của bạn sẽ bị lộn xộn và khó quản lý. Code xuất hiện nhiều nơi cho các mục đích tương đương sẽ gây ra duplicate code. Những code loại này được gọi là concern. Lập trình hiện đại hạn chế càng nhiều càng tốt các concern. Người ta sẽ tìm cách gom các concern code này vào một khu vực và có thể tham chiếu sử dụng chúng từ bất cứ nơi đâu trong chương trình.
Xem xét tình huống thứ hai. Validate data tại action còn gặp trở ngại khi bạn cần trả thông báo về cho người dùng. Có nhiều cách để thực hiện trả thông báo mà không cần hỗ trợ của struts validation framework như nối tham số vào link gọi JSP. Tại JSP sẽ phải bắt và nhận diện tham số để xuất thông báo phù hợp. Cách khác là dựa vào ActionForward để trả về một trang chỉ chứa câu thông báo phù hợp với ActionForward đó. Sau đó include trang đó vào trang chính bằng ajax để hiển thị cho người dùng xem trên trang chính. Cả hai cách đều rất rắc rối và khiến cho việc quản lý thông báo khó khăn. Bạn phải chỉnh sửa tương đối trên cả action và jsp, struts-config cho mỗi một thông báo.
Struts validation framework giải quyết khó khăn trong cả hai tình huống.
Vậy thì cần chuẩn bị những gì để áp dụng được struts validation framework vào project
Đầu tiên và tất nhiên là bạn phải chuẩn bị thư viện rồi. Mình khuyến cáo bạn sử dụng maven để tìm thư viện nhanh chóng. Sau đó bạn cần chuẩn bị một số file sau:
Vậy thì cần chuẩn bị những gì để áp dụng được struts validation framework vào project
Đầu tiên và tất nhiên là bạn phải chuẩn bị thư viện rồi. Mình khuyến cáo bạn sử dụng maven để tìm thư viện nhanh chóng. Sau đó bạn cần chuẩn bị một số file sau:
- File properties, tên đặt tùy ý, thường thì nó có tên là MessageResources.properties.
- File validation gốc, thường thì là validator-rules.xml. Bạn không sửa file này.
- File validation của bạn, tên đặt tùy ý, thường thì là validation.xml
- Thực hiện một số cấu hình để struts nhận diện cả ba file trên.
File properties chứa key và value cho các thông báo hệ thống. Nó phải chứa bộ properties gốc của struts:
File validation.xml chứa các user-defined rules của bạn. Mình sẽ giải thích chi tiết nội dung file này sau.
Cấu hình struts-config cần thiết:
<message-resources parameter="MessageResources" null="false" key="globalMsg" />
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
property="pathnames"/>
</plug-in>
Vị trí validator-rules.xml và validation.xml đều nằm trong /src/main/webapp/WEB-INF. Còn MessageResources.properties thì nằm trong /src/main/resources. Có thể bạn thấy hơi lạ nhưng đây là cấu trúc web project trong maven. Mình sẽ nói về maven trong một entry khác.
Xem xét thẻ message-resource:
Trong thẻ message-resources có thuộc tính null="false". Thuộc tính này sẽ hướng dẫn struts validation framework xử lý các properties mà missing key xuất ra thông báo: ' ???keyname??? ' thay vì hiện null. Mặc định thuộc tính này là null="true" và đây không phải là thuộc tính bắt buộc.
Thuộc tính parameter="MessageResource" là đường dẫn đến vị trí file properties. MessageResource là tên file properties. Đây là thuộc tính bắt buộc.
Thuộc tính key="globalMsg" dùng để phân biệt các properties với nhau. Tại sao phải phân biệt qua key vì giá trị key này sẽ được dùng để xác định file properties nào được tham chiếu từ thẻ <html:errors> Thẻ này phân biết các properties qua key chứ không phải bản thân tên file properties.
Thẻ plug-in không có gì để bàn vì rất dễ hiểu rồi.
Struts validation framework hỗ trợ thực hiện validation theo form hoặc action.
Lý do cần có ValidatorActionForm vì một form bean có thể được sử dụng chung bởi nhiều action. Thường thì lập trình viên hay tạo một form bean chung và nhét tất cả các trường dữ liệu cần đưa lên action vào đó. Nhưng cách sử dụng form bean của các action khác nhau thì khác nhau. Có action cần validate toàn bộ các trường khai báo trong form bean nhưng lại có action chỉ cần validate một phần các trường dữ liệu thôi. Ví dụ: Bạn có hai action createUser.do và changePass.do Action createUser.do cần validate nhiều hơn changePass.do Từ đó có thể thấy cách validate sẽ phải tương ứng với từng action dùng form bean thay vì cố định vào một form bean.
Bạn cần chỉ định action nào cần được validate trong struts-config
<action path="/createUser" type="org.springframework.web.struts.DelegatingActionProxy"
name="userForm" scope="request" validate="true" input="/inputUser.do">
<forward name="create" path="/jsp/user/list.jsp"/>
</action>
Thuộc tính validate="true". Action nào không cần validate thì set là false
Thuộc tính input dùng để trỏ về action hoặc jsp chứa form đầu vào của action.
Ví dụ: Bạn có hai action. Action createUser.do để lưu user đó vào db còn một action là inputUser.do để hiện form nhập liệu. Khi đó createUser.do sẽ là action cần validate và thuộc tính input="/inputUser.do" Khi validate thất bại, createUser.do sẽ thực hiện forward đến inputUser.do Tốt nhất là tách ra hai action như vầy, vì có action cần validate, có action thì không cần và trong các action cần validate lại có các input khác nhau.
Luồng thực hiện khi có một request đến action /createUser.do như sau:
Struts validation framework sẽ validate form trong request theo các rules mà bạn khai báo trong validation.xml. Nếu thất bại nó sẽ trả lại /inputUser.do Trường hợp này, request của bạn sẽ chưa đến được /createUser.do Ngược lại, nếu validation thành công, request sẽ đi thẳng đến /createUser.do và tiếp tục được thực hiện xử lý như bình thường.
Gần như là xong rồi, bạn cần xây dựng rules nữa. Tham khảo: http://struts.apache.org/release/1.2.x/userGuide/dev_validator.html
Để hiển thị messages trên jsp, bạn sử dụng thẻ <html:errors /> Nên kết hợp với cặp thẻ <logic:messagesPresent></logic:messagesPresent>
<logic:messagesPresent>
<html:errors bundle="globalMsg" />
</logic:messagesPresent>
Đoạn mã trên có nghĩa là sẽ kiểm tra xem có message trong attribute của request hay không. Nếu có sẽ dịch thẻ <html:errors /> Thuộc tính bundle có giá trị khớp với key của MessageResources mà bạn đã khai báo.
Sức mạnh của struts validation framework chưa dừng ở đó. Bạn có thể tận dụng cơ chế truyền tải message về jsp của nó để hiển thị thông báo trong action của bạn sau khi validation. Giả sử bạn được validation thành công. Request của bạn đến /createUser.do Tại đây, /createUser.do cần kiểm tra xem username có trùng lặp không. Nếu trùng lặp, /createUser.do sẽ tạo một ActionMessages và đẩy vào request attribute để hiển thị trên jsp.
ActionMessages errors = new ActionMessages();
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(key, arg);
saveErrors(request, errors);
Ngoài saveErrors(request, errors) còn có addErrors(request, errors). Khác biệt giữa chúng là saveErrors(request, errors) sẽ xóa sạch các action messages hiện tại và ghi action message vừa tạo ra vào còn addErrors(request, errors) chỉ đơn giản nối thêm vào.
Thêm một chú ý nữa: Để message của bạn hiển thị trên jsp, bạn không được redirect="true" cho ActionForward trả về vì redirect="true" sẽ gửi về client mã 302 để client tạo một request khác đến đích khuyến nghị trong response có status 302.
Hướng dẫn trên là cho cách truyền tải errors messages từ action về client nhưng bạn có thể dùng cách làm đó để truyền tải các messages thông thường. Tất nhiên, struts có hỗ trợ cách thức riêng cho truyền tải các messages thông thường. Tuy nhiên các messages đó đều được hiểu là plain text, bạn không thể mong nhúng thẻ html vào message và hi vọng messages sẽ được hiển thị ở dạng html.
Ví dụ: Thông bảo của bạn là <strong>Exception</strong> chả hạn nếu bạn dùng cách truyền tải thông điệp kiểu errors thì bạn sẽ nhận được chữ Exception được in đậm còn nếu bạn dùng cách truyền tải thông điệp kiểu message thì sẽ nhận được chữ <strong>Exception</Exception>
# -- validator -- errors.invalid={0} is invalid. errors.maxlength={0} can not be greater than {1} characters. errors.minlength={0} can not be less than {1} characters. errors.range={0} is not in the range {1} through {2}. errors.required={0} is required. errors.byte={0} must be an byte. errors.date={0} is not a date. errors.double={0} must be an double. errors.float={0} must be an float. errors.integer={0} must be an integer. errors.long={0} must be an long. errors.short={0} must be an short. errors.creditcard={0} is not a valid credit card number. errors.email={0} is an invalid e-mail address. errors.url={0} is not a valid URL.File validator-rules.xml chứa các default rules của struts như required, minlength, maxlength. Bạn lấy file này ở đâu ? Mình không biết :D IDE của mình hỗ trợ nên nó đưa cho mình luôn.
File validation.xml chứa các user-defined rules của bạn. Mình sẽ giải thích chi tiết nội dung file này sau.
Cấu hình struts-config cần thiết:
<message-resources parameter="MessageResources" null="false" key="globalMsg" />
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"
property="pathnames"/>
</plug-in>
Vị trí validator-rules.xml và validation.xml đều nằm trong /src/main/webapp/WEB-INF. Còn MessageResources.properties thì nằm trong /src/main/resources. Có thể bạn thấy hơi lạ nhưng đây là cấu trúc web project trong maven. Mình sẽ nói về maven trong một entry khác.
Xem xét thẻ message-resource:
Trong thẻ message-resources có thuộc tính null="false". Thuộc tính này sẽ hướng dẫn struts validation framework xử lý các properties mà missing key xuất ra thông báo: ' ???keyname??? ' thay vì hiện null. Mặc định thuộc tính này là null="true" và đây không phải là thuộc tính bắt buộc.
Thuộc tính parameter="MessageResource" là đường dẫn đến vị trí file properties. MessageResource là tên file properties. Đây là thuộc tính bắt buộc.
Thuộc tính key="globalMsg" dùng để phân biệt các properties với nhau. Tại sao phải phân biệt qua key vì giá trị key này sẽ được dùng để xác định file properties nào được tham chiếu từ thẻ <html:errors> Thẻ này phân biết các properties qua key chứ không phải bản thân tên file properties.
Thẻ plug-in không có gì để bàn vì rất dễ hiểu rồi.
Struts validation framework hỗ trợ thực hiện validation theo form hoặc action.
Trường hợp validation theo form: Bạn sẽ kế thừa form bean của bạn từ ValidationForm
Trường hợp validation theo action: Bạn sẽ kế thừa form bean của bạn từ ValidationActionForm
Khác biệt giữa hai class này là: Khi kế thừa ValidatorForm, struts validation framework sẽ validate form của bạn theo formbean mà action của bạn sử dụng còn khi kế thừa ValidatorActionForm, struts validation framework sẽ validate form của bạn theo action.
Lý do cần có ValidatorActionForm vì một form bean có thể được sử dụng chung bởi nhiều action. Thường thì lập trình viên hay tạo một form bean chung và nhét tất cả các trường dữ liệu cần đưa lên action vào đó. Nhưng cách sử dụng form bean của các action khác nhau thì khác nhau. Có action cần validate toàn bộ các trường khai báo trong form bean nhưng lại có action chỉ cần validate một phần các trường dữ liệu thôi. Ví dụ: Bạn có hai action createUser.do và changePass.do Action createUser.do cần validate nhiều hơn changePass.do Từ đó có thể thấy cách validate sẽ phải tương ứng với từng action dùng form bean thay vì cố định vào một form bean.
Bạn cần chỉ định action nào cần được validate trong struts-config
<action path="/createUser" type="org.springframework.web.struts.DelegatingActionProxy"
name="userForm" scope="request" validate="true" input="/inputUser.do">
<forward name="create" path="/jsp/user/list.jsp"/>
</action>
Thuộc tính validate="true". Action nào không cần validate thì set là false
Thuộc tính input dùng để trỏ về action hoặc jsp chứa form đầu vào của action.
Ví dụ: Bạn có hai action. Action createUser.do để lưu user đó vào db còn một action là inputUser.do để hiện form nhập liệu. Khi đó createUser.do sẽ là action cần validate và thuộc tính input="/inputUser.do" Khi validate thất bại, createUser.do sẽ thực hiện forward đến inputUser.do Tốt nhất là tách ra hai action như vầy, vì có action cần validate, có action thì không cần và trong các action cần validate lại có các input khác nhau.
Luồng thực hiện khi có một request đến action /createUser.do như sau:
Struts validation framework sẽ validate form trong request theo các rules mà bạn khai báo trong validation.xml. Nếu thất bại nó sẽ trả lại /inputUser.do Trường hợp này, request của bạn sẽ chưa đến được /createUser.do Ngược lại, nếu validation thành công, request sẽ đi thẳng đến /createUser.do và tiếp tục được thực hiện xử lý như bình thường.
Gần như là xong rồi, bạn cần xây dựng rules nữa. Tham khảo: http://struts.apache.org/release/1.2.x/userGuide/dev_validator.html
Để hiển thị messages trên jsp, bạn sử dụng thẻ <html:errors /> Nên kết hợp với cặp thẻ <logic:messagesPresent></logic:messagesPresent>
<logic:messagesPresent>
<html:errors bundle="globalMsg" />
</logic:messagesPresent>
Đoạn mã trên có nghĩa là sẽ kiểm tra xem có message trong attribute của request hay không. Nếu có sẽ dịch thẻ <html:errors /> Thuộc tính bundle có giá trị khớp với key của MessageResources mà bạn đã khai báo.
Sức mạnh của struts validation framework chưa dừng ở đó. Bạn có thể tận dụng cơ chế truyền tải message về jsp của nó để hiển thị thông báo trong action của bạn sau khi validation. Giả sử bạn được validation thành công. Request của bạn đến /createUser.do Tại đây, /createUser.do cần kiểm tra xem username có trùng lặp không. Nếu trùng lặp, /createUser.do sẽ tạo một ActionMessages và đẩy vào request attribute để hiển thị trên jsp.
ActionMessages errors = new ActionMessages();
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(key, arg);
saveErrors(request, errors);
Ngoài saveErrors(request, errors) còn có addErrors(request, errors). Khác biệt giữa chúng là saveErrors(request, errors) sẽ xóa sạch các action messages hiện tại và ghi action message vừa tạo ra vào còn addErrors(request, errors) chỉ đơn giản nối thêm vào.
Thêm một chú ý nữa: Để message của bạn hiển thị trên jsp, bạn không được redirect="true" cho ActionForward trả về vì redirect="true" sẽ gửi về client mã 302 để client tạo một request khác đến đích khuyến nghị trong response có status 302.
Hướng dẫn trên là cho cách truyền tải errors messages từ action về client nhưng bạn có thể dùng cách làm đó để truyền tải các messages thông thường. Tất nhiên, struts có hỗ trợ cách thức riêng cho truyền tải các messages thông thường. Tuy nhiên các messages đó đều được hiểu là plain text, bạn không thể mong nhúng thẻ html vào message và hi vọng messages sẽ được hiển thị ở dạng html.
Ví dụ: Thông bảo của bạn là <strong>Exception</strong> chả hạn nếu bạn dùng cách truyền tải thông điệp kiểu errors thì bạn sẽ nhận được chữ Exception được in đậm còn nếu bạn dùng cách truyền tải thông điệp kiểu message thì sẽ nhận được chữ <strong>Exception</Exception>
Không có nhận xét nào:
Đăng nhận xét