Thứ Ba, 15 tháng 12, 2020

Bài 6: Thực hiện chức năng register user sử dụng Spring TagLib

Xây dựng ứng dụng CRUD với Spring 5

Bài 6: Thực hiện chức năng register user sử dụng Spring TagLib

Mã Hoàng Nhật Phi, Trương Trần Tiến

 

-          Mục đích: Tiếp nối series bài viết về xây dựng ứng dụng web dùng Spring 5 Framework, bài viết trước chúng ta đã hiện thực hóa chức năng Delete và Register User sử dụng XMLHTTPRequest để gọi RESTful web service. Đồng thời, chúng ta cũng được giới thiệu về cách tự tạo các Validator, Annotation để phục vụ ràng buộc các dữ liệu với logic phức tập. Trong bài viết này, chúng ta sẽ thực hiện lại chức năng Register sử dụng Spring Taglib để tạo form. Taglib của Spring giúp chúng ta dễ dàng binding dữ liệu của form đến object ở back-end, giúp render lỗi một cách dễ dàng. Đồng thời chúng ta sẽ hiện thực tạo custom message để hiện lỗi cho người dùng.

-         Yêu cầu kiến thức cơ bản:

o        Nắm vững và sử dụng các kỹ năng để về việc xây dựng hoàn tất ứng dụng với mô hình MVC2

o        Nắm vững các khái niệm về ngôn ngữ lập trình Java, lập trình thao tác hướng đối tượng.

o        Nắm vững các khái niệm về lập trình web sử dụng J2EE hay JavaEE với các kiến thức về Servlet, JSP. http://www.kieutrongkhanh.net/search/label/Servlet%26JSP

o        Đã hoàn tất các bài xây dựng chức năng liên quan đến Spring MVC5 tại địa chỉ http://www.kieutrongkhanh.net/search/label/Spring5

-          Tool sử dụng:

o   Netbeans 8.x

o   JDK 8 update 66

o   DBMS: SQL Server từ 2005 đến 2019, PostgreSQL 10 (Đón xem nội dung bổ sung trong loạt bài viết tiếp theo)

I.        Giới thiệu

-         Sau bài viết số 5 (tham khảo tại địa chỉ http://www.kieutrongkhanh.net/2020/12/bai-5-thuc-hien-chuc-nang-delete-va.html), chúng ta đã nắm cơ bản cách tương tác giữa client – server thông qua việc tạo RESTful API trong việc delete và tạo mới dữ liệu. Chúng ta đã nắm rõ được cách xử lý exception. Chúng ta đã biết cách linh hoạt ràng buộc dữ liệu thông qua các annotation và validator tự tạo. Qua cách tiếp cận gọi RESTful API và xử lý response trả về, chúng ta có thể nhận thấy rằng việc viết code JavaScript để tạo view, báo lỗi cho người dùng rất phức tạp, dễ dẫn đến lỗi. Vì thế ở bài viết này, chúng ta sử dụng công nghệ JSP cùng với Taglib do Spring cung cấp để có thể dễ dàng binding dữ liệu của form đến POJO, báo lỗi ở phía client. Ngoài ra, chúng ta còn biết cách sử dụng MessageSource mà Spring cung cấp để tạo custom message.

II.      Nội dung

1.      Thực hiện chức năng register sử dụng Spring Taglib

                                                            a.      Cấu trúc class RegisterForm

-                      Ở bài viết trước, khi thực hiện chức năng Register sử dụng phương pháp RESTful API, class RegisterForm (được mô tả tại mục 2.c trong bài 5) được sử dụng để chứa dữ liệu khi người dùng submit form. Client sẽ gửi về một chuỗi JSON và sẽ được Spring convert và gán giá trị vào field của RegisterForm. Trong bài viết này, chúng ta cũng sẽ sử dụng lại class RegisterForm với chức năng tương tự.

-                     Class RegisterForm có những các field và method Setter/Getter theo quy chuẩn của JavaBeans. Đồng thời các field cũng sẽ có các Annotation để ràng buộc dữ liệu như ở bài viết trước.

 

                                                            b.      Thay đổi link ở login.jsp và invalid.jsp và tạo request mapping để truy cập register_taglib.jsp

-                     Thay đổi link ở login.jsp và invalid.jsp. Chúng ta sẽ chọn trang tên register_taglib.jsp để tránh nhầm lẫn với register.jsp ở bài viết trước.

Graphical user interface, text, application, email

Description automatically generated

Graphical user interface, text, application, email

Description automatically generated

-                    Chúng ta tiến hành tạo thêm request mapping trong class MainController để có thể truy cập được register_taglib.jsp

Graphical user interface, text, application, email

Description automatically generated

-                     Chúng ta tạo một Map và đặt vào đó object RegisterForm với key là “user”.

-                     Ở bài viết số 2 (http://www.kieutrongkhanh.net/2020/08/bai-2-cau-hinh-ket-noi-csdl-su-dung.html), chúng ta được biết rằng trước khi render View với dữ liệu động, Spring sẽ đính kém Model chứa dữ liệu, thông qua class ModelAndView. Class ModelAndView ngoài nhận tên của trang JSP đồng thời còn nhận vào parameter kiểu Map và convert các phần tử trong Map thành các Attribute của Model.

-                     Trong trường hợp của chúng ta, Model sẽ có một Attribute là “user”. Attribute “user” sẽ là object Spring sẽ binding với lại dữ liệu từ register form mà người dùng nhập.

Diagram

Description automatically generated

                                                            c.      Tạo trang register_taglib.jsp trong /WEB-INF/view

A picture containing application

Description automatically generated

A picture containing text

Description automatically generated

-                     Chúng ta tạo ra form đăng ký với taglib do spring framework cung cấp. Việc dùng taglib do spring cung cấp hỗ trợ cho ta trong quá trình validate dữ liệu input của người dùng.

-                     Ngoài trừ attribute “method”, “action” tương tự như tag <form> của HTML5, tag <form:form>  còn có thêm một attribute “modelAtribute”.

o        modelAttribute báo cho Spring biết rằng các parameter của form khi được gửi về từ phía client sẽ được gán giá trị vào trong các field của Model Attribute. Trong trường hợp của chúng ta, các parameter của form sẽ được gán cho Model Attribute “user” là RegisterForm mà chúng ta đã khai báo trong MainController.

o        Trong các phiên bản trước của Spring, “modelAttribute” được thay thế bởi “commandName”

-                     Các tag <form:input>, <form:password> có chức năng tương tự như tag <input type=”text”>, <input type=”password”>. Khi người dùng bấm submit thì “path” chính là tên của parameter được gửi về phía server. Ngoài ra, thông qua “path” Spring sẽ tự động chuyển đổi giá trị của parameter cho các field tương ứng cho class RegisterForm => do đó, các giá trị của “path” cần phải trùng khớp với tên field trong class RegisterForm.

 

-                     Tag <form:errors> được Spring sử dụng để view lỗi cho người dùng trong quá trình ràng buộc dữ liệu không đạt yêu cầu. Thông tin của các lỗi này sẽ được lưu trữ trong Model. Cách Spring lưu trữ lỗi trong Model sẽ được nói rõ hơn ở phần tiếp theo.

o        Lưu ý: việc sử dụng tag attribute “path” nhưng cách sử dụng của <form:errors> khác so với các tag còn lại. “path” ở các tag khác dùng để chỉ field nào sẽ chứa dữ liệu form, “path” của <form:errors> dùng để chỉ ra lỗi theo quy tắc riêng. (Ở bài trước, chúng ta biết được rằng lỗi của một Class sẽ được chia thành 2 loại là FieldError – lỗi tương ứng cho từng field và GlobalError – lỗi tương ứng cho cả class)

·         path=”<tên field>”: hiện lỗi tương ứng với field đó – FieldError

·         path=”*”: hiện tất cả các lỗi bao gồm FieldErrorGlobalError

·         Nếu không để path: hiện các lỗi tương ứng với class – GlobalError.

o        Tại <tr> của Confirm Password <form:errors> không để “path” vì như để cập trong bài trước lỗi ConfirmPasswordNotMatch là GlobalError

Graphical user interface, text, application

Description automatically generated

                                                            d.      Tạo request mapping và inject các bean cần thiết trong MainController để xử lý chức năng Register

-                     Chúng ta thực hiện inject thêm bean FormMapper vào trong MainController để chuyển đổi kiểu RegisterForm sang RegistrationDTO

Graphical user interface, text, application, email

Description automatically generated

 

Graphical user interface, text, application, email

Description automatically generated

-                      Chúng ta thực hiện tạo ra một request mapping cho việc đăng ký với phương thức là POST. Khi phát hiện dữ liệu không hợp lệ, chúng ta trả về trang đăng ký nếu thành công trả về trang login.jsp. Nếu thành công ta tạo User mới và trả về trang Login

o        @ModelAttribute: cho phép chúng ta có thể lấy được các attribute trong Model. Trong tình huống của chúng ta là lấy được attribute “user”.

o        @Valid: dùng để kiểm tra ràng buộc dữ liệu

-                     Ở 2 bài viết trước, chúng ta xử lý mọi lỗi do ràng buộc dữ liệu không thành công thông qua ExceptionHandlerController, nhưng chúng ta cần phải lưu trữ lỗi ở Model để tag <form:errors> mới có thể tìm và hiện lỗi cho người dùng. Do vậy để giải quyết vấn đề này, chúng ta để BindingResult trong argument của method. Class BindingResult được dùng để chứa và quản lý các lỗi trong quá trình validate. Khi đặt class này trong method argument thì MethodArgumentNotValidException sẽ không được quăng ra mà sẽ được handle tại đây.

-                     Đồng thời Spring cũng sẽ tự động lưu trữ object BindingResult thành một attribute của Model. Do đó khi sử dụng tag <form:errors> Spring sẽ biết được các lỗi để render thành message thông báo cho người dùng.

-                     Lưu ý

o   Giá trị trong value của @RequestMapping tương ứng với giá trị trong action của form

o   Chúng ta phải đặt “BindingResult result” ngay sau các argument có annotation @Valid, @ModelAtribute, @RequestBody, @RequestPart. Nếu không sẽ gặp lỗi IllegalStateException.

Graphical user interface, text, application, email

Description automatically generated

                                                            e.      Chúng ta thực hiện clean-install, deploy và thực thi để kiểm tra kết quả

2.      Thực hiện tạo custom message để báo lỗi cho người dùng

                                                            a.      Add bean messageSource trong mvc-config.xml

Graphical user interface, text, application

Description automatically generated

-                     Chúng ta khai báo thêm một bean tại mvc-config.xml ở /WEB-INF.

-                     Khi render lỗi ở tag <form:errors>, Spring sẽ thực hiện tìm kiếm ở các MessageSource để xem lỗi này tương ứng với message nào. Nếu không được tìm thấy, default message sẽ được sử dụng. Spring sử dụng các file properties để lưu trữ mapping message. Ngoài ra sử dụng MessageSource có thể sử dụng để Internationalize (i18n) các message của chúng ta.

-                     Chúng ta dùng property “basename” để Spring tìm kiếm các file properties có chứa các message.

o        classpath: là đường dẫn cho folder src của project

o        messages: là prefix cho các file properties. Các file properties được đặt tên như sau <prefix>_<locale_code>.properties.

§  vd: messages_en.properties

-                     Lưu ý

o   bean của chúng ta cần phải được đặt id=”messageSource” hoặc name=”messageSource”, nếu không Spring sẽ không nhận biết được MessageSource của chúng ta.

o   Nếu chúng ta ghi sai giá trị trong thuộc tính id, ứng dụng vẫn chạy bình thường và message được thiết lập trong file properties sẽ không được kích hoạt

                                                            b.      Tạo file messages_en.properties

-                     Chúng ta tạo file messages_en.properties tại src/main/resources (nếu sử dụng netbeans, chúng ta chuyển sang tab Files – hay cửa sổ Files trong menu Window).

-                     Chúng ta chọn Loại Other và chọn Properties File

-                     Nội dung file được cập nhật như sau

 

Graphical user interface, text, application, email

Description automatically generated

 

-                     Chúng ta cần lưu ý các giá trị nhập vào file messages_en.properties phải tương ứng với các giá trị được gạch chân đỏ trong class RegisterForm.

-                     Để có thể nhận biết được lỗi nào sử dụng message nào, Spring đưa cho chúng ta quy tắc để đặt tên cho message như sau: {ValidationClass/ErrorCode}.{modelObjectName}.{field}

o        ValidationClass/ErrorCode: là tên các Annotation hoặc ErrorCode

o        modelObjectName: là tên Attribute của Model mà lỗi này sẽ được áp dụng

o        field: tên field của modelObject

o        VD: Size.user.usename sẽ được áp dụng cho lỗi của Annotation WSize ở field username của Model Attribute “user”

                                                            c.      Chúng ta thực hiện clean-install, deploy và thực hiện thực thi để kiểm tra kết quả

3.      Chỉnh sửa khi sử dụng @InitBinder để validate dữ liệu

-                     Ở bài viết trước, chúng ta biết được ngoài cách sử dụng Annotation để kiểm tra ràng buộc dữ liệu, chúng ta còn sử dụng annotation @InitBinder để khai báo class ràng buộc. Khi đó các giá trị “path” của <form:errors>messages_en.properties sẽ có sự thay đổi. Chúng ta tiến hành chỉnh sửa lại như sau.

                                                            a.      Thêm method có @InitBinder và bean RegisterValidator vào MainController

-                     Chúng ta inject RegisterValidator vào MainController

Graphical user interface, text, application, email

Description automatically generated

-                     Tương tự như ở bài trược, chúng ta tạo phương thức có @InitBinderMainController để báo cho Spring biết custom validator của chúng ta giành cho class RegisterForm.

Graphical user interface, text, application, email

Description automatically generated

-                     Lưu ý: Ở đây chúng ta sử dụng @InitBinder với giá trị là “user” mà không phải giá trị là “registerForm” như bài trước bởi vì lúc này RegisterForm đã được xác định rõ ràng là một Attribute Model có tên là “user”.

                                                            b.      Comment các annotation trong class RegisterForm

-                     Vì đã sử dụng class RegisterValidator để kiểm tra ràng buộc dữ liệu, chúng ta không cần sử dụng Annotation trên các field của class RegisterForm

 

                                                            c.      Chỉnh sửa register_taglib.jsp

-                     Vì trong class RegisterValidator, lỗi PasswordNotMatch trở thành Field Error nên chúng ta cần phải thêm “path” vào tag <form:errors> ở phần <tr> Confirm Password.

Graphical user interface, text, application

Description automatically generated

Graphical user interface, text

Description automatically generated

                                                            d.      Thêm các property mới vào file messages_en.properties

-                     Trong class RegisterValidator, khi kiểm tra ràng buộc thất bại thì chúng ta tạo một error mới thông qua method rejectValue. Hàm rejectValue sẽ tạo ra error với 3 tham số là: field, errorCode, defaultMessage. Vì errorCode của lỗi bị thay đổi, chúng ta cần thêm các các property vào file messages_en.properties để có thể mapping message.

A picture containing text

Description automatically generated

Graphical user interface, text, application, email

Description automatically generated

                                                            e.      Thực hiện clean-install, deploy và thực thi để kiểm tra kiểm tra lại kết quả

 

Chúc mừng quí vị, chúng ta vừa hoàn tất việc Register Account bằng cách sử dụng Spring Taglib và biết cách tạo custom message để thông báo lỗi cho 2 trường hợp sử dụng @InitBinder và Annotation ràng buộc dữ liệu. Hy vọng nội dung này sẽ hỗ trợ quí vị trong việc sử dụng Spring Framework để xây dựng ứng dụng.

 

Rất mong quí vị góp ý về nội dung loạt bài viết này. Hẹn gặp lại quí vị ở bài viết sau, chúng ta sẽ thực hiện việc thay đổi cơ sơ dữ liệu và custom mapping response message trả về.

 

Không có nhận xét nào:

Đăng nhận xét