- vừa được xem lúc

Tạo một project với Spring Boot - Thymeleaf - Elasticsearch sử dụng HTTP/2 - Tạo service run Elasticsearch

0 0 39

Người đăng: Kien Pham

Theo Viblo Asia

Trong bài viết này, tôi sẽ hướng dẫn cách tạo một project với Spring boot kết hợp với Thymeleaf và Elasticsearch sử dụng HTTP/2:

Công cụ và thư viện được sử dụng trong bài viết:

  • Spring boot 2.7.4
  • Spring tool suite 4
  • Spring data elasticsearch 4.4.2
  • Maven 3
  • Java 11
  • Elasticsearch 7.17.6
  • Nssm
  • Elasticsearch head extension

1. Cài đặt Elasticsearch:

Vui lòng tham khảo bài viết bên dưới để cài đặt elasticsearch:

https://viblo.asia/p/tao-mot-project-voi-spring-boot-va-elasticsearch-841-su-dung-thu-vien-spring-data-elasticsearch-huong-dan-cai-dat-va-su-khac-nhau-giua-2-phien-ban-8xx-voi-7xx-elasticsearch-Rk74aRXvJeO

Trong bài viết này tôi sẽ hướng dẫn thêm cách tạo 1 service để khởi động elasticsearch:

  • Mở Command Prompt với quyền "Administrator"

  • Nhập câu lệnh như sau:

    sc.exe create ElasticsearchService binPath="G:\elasticsearch-7.17.6\bin\elasticsearch.bat
    

Trong đó:

  • "ElasticsearchService" là tên service bạn muốn đặt
  • binPath: Đường dẫn tới file khởi động elasticsearch(elasticsearch.bat)

Tiến hành chạy câu lệnh bên trên và kết quả:

Kiểm tra xem service với name "ElasticsearchService" đã được tạo thành công chưa, nhấn tổ hợp phím "WIN + R" -> nhập "services.msc" và click "OK":

Ta thấy service với tên "ElasticsearchService" đã được tạo thành công:

Tiến hành Start service lên:

Như các bạn thấy, khi tôi start service thì báo lỗi như ở trên, với trường hợp này tôi sẽ dùng một công cụ khác để hỗ trợ việc tạo và start service thành công

Tôi dùng công cụ NSSM:

Link download: https://nssm.cc/download

Chọn bản mới nhất:

Sau khi tải xong nssm, tiến hành giải nén, cấu trúc thư mục nssm như bên dưới:

Tiếp theo để tạo service, trong thư mục nssm tôi vào thư mục "win64"(nếu bạn nào còn xài windows 32 bit thì chọn thư mục "win32", còn xài windows 64 bit thì chọn cái nào cũng được)

Trong thư mục "win64" có file "nssm.exe", tại đây các bạn mở Command prompt lên hoặc có thể dùng Powershell bằng cách nhấn giữ phím Shift -> click phải chuột chọn "Open PowerShell ....", nếu xài windows 10 thì chọn "Show more options -> chọn "Open PowerShell ...."

Tại giao diện Command prompt, với service name "ElasticsearchService" vừa tạo ở trên có thể dùng lệnh nssm để remove service đó ra và tiến hành tạo service mới nếu vẫn muốn dùng tên service "ElasticsearchService":

nssm remove ElasticsearchService

Chọn "Yes" tại popup "Remove the service"

Sau khi remove ta tiến hành tạo một service mới, ở đây tôi sẽ đặt tên service khác:

nssm install ESService

Sau khi chạy câu lệnh ở trên sẽ show popup như hình, các bạn cần thiết lập đường dẫn đến file khởi động của Elasticsearch, sau khi nhập đường dẫn -> click "Install sevice"

Thông báo service được cài đặt thành công, vào giao diện "Services" kiểm tra:

Service mới được tạo thành công, tiến hành start service:

Service được start thành công

Kiểm tra Elasticsearch đã được khởi động thành công hay chưa, tại trình duyệt nhập đường dẫn "localhost:9200":

=> Elasticsearch đã được khởi động thành công

Tiếp tục mở extension Elasticsearch head để kiểm tra xem trang thái:

2. Cấu trúc thư mục project:

Mặc định, tập tin cấu hình sẽ là "application.properties", nếu muốn chuyển đổi sang "application.yml" -> click phải chuột vào tập tin "application.properties" -> chọn "Convert .properties to .yaml"

3. Tạo 1 package với tên "com.example.thymeleaf.application":

Nội dung class "ThymeleafApplication":

4. Tạo 1 package model với tên "com.example.thymeleaf.model":

Tại đây, tạo 1 class tên "User" với nội dung:

5. Tạo 1 package repository với tên "com.example.thymeleaf.repository":

Tại đây tạo 1 interface "UserRepository" với nội dung:

Để biết nhiều thông tin hơn về repository các bạn có thể xem lại bài viết này:

https://viblo.asia/p/tao-mot-project-voi-spring-boot-va-elasticsearch-841-su-dung-thu-vien-spring-data-elasticsearch-huong-dan-cai-dat-va-su-khac-nhau-giua-2-phien-ban-8xx-voi-7xx-elasticsearch-Rk74aRXvJeO

6. Tạo 1 package controller với tên "com.example.thymeleaf.controller":

Tại đây, tạo 1 class controller tên "UserController" với nội dung bao gồm các chức năng cơ bản "Thêm - Xem thông tin user"

7. Tạo 1 trang login đơn giản với Thymeleaf:

Nguồn tải template: https://colorlib.com/wp/html5-and-css3-login-forms/

Sau khỉ tải template về sẽ gồm những thư mục - tập tin:

Sao chép tất cả thư mục sources đến thư mục "static" trong "resources" của project:

Riêng file "index.html" sao chép đến thư mục "templates" trong thư mục "resources":

Sau khi thực hiện xong các bước trên, tiến hành tạo 1 request mapping trong "UserController" để load trang "index.html":

Mặc định, spring sẽ tự động load page trong thư mục "templates", muốn load page nào thì nhập đúng tên page cần load

Tôi sẽ kiểm tra thử xem thymeleaf có hoạt động chưa, tại "UserController" tôi sẽ dùng Model để thêm 1 giá trị và tại "index.html" dùng thư viện thymeleaf để load giá trị đó:

Trong file "index.html" chúng ta cần thêm "xmlns:th="http://www.thymeleaf.org"" trong html tag và tại đây tôi sẽ thêm 1 tag với nội dung "<h2 th:text="${name}"></h2>", trong đó:

  • Biến giá trị "name" chính là name attribute tôi đã tạo trong UserController

  • "th:text" chính là thư viện được hỗ trợ bởi Thymelead để in giá trị từ Model

Bây giờ, restart lại project và kiểm tra:

Như các bạn thấy, thay vì tải trang "index.html" thì lại trả về nội dung là "index". Lý do là vì trong class UserController sử dùng annotation "@RestController", với annotation "@RestController" với giá trị trả về là "index" -> nó sẽ chỉ hiểu là trả về nội dung là "index". Ngược lại, với annotation "@Controller" nếu giá trị trả về là "index" nó sẽ chỉ hiểu là tìm đến trang html với tên là "index" trong thư mục "templates" và nếu trả về tên giá trị không nằm trong thư mục "templates" -> sẽ báo lỗi

Bây giờ tôi sẽ thay annotation "@RestController" đến annotation "@Controller" với giá trị trả về là "index" -> chắc chắn lúc này page "index.html" sẽ được tải thành công:

Các bạn thấy, page "index.html" được tải thành công, giá trị từ biến "name" được in ra thành công

Tiếp tục, tôi sẽ sửa lại code html cho phần form kết hợp với những thuộc tính được hỗ trợ từ Thymeleaf cho page "index.html"

Tôi sẽ phân 1 vài thuộc tính Thymeleaf hỗ trợ mà tôi sử dụng:

  • th:action: Chỉ định mapping tại controller sẽ nhận form data, ở đây tôi để mapping là "/login" và tôi sẽ khai báo thêm mapping này trong UserController

  • th:object: Chỉ định đối tượng model được khai báo trong UserController, tại đây trong controller tôi dùng annotation "@ModelAttribute" để nhận data model

Restart lại project và kiểm tra. Với mapping "/login" -> redirect đến page "dashboard.html":

Tải trang dashboard thành công. Tiếp theo, tôi sẽ lấy giá trị "name" vừa nhập tại trang "index.html" lưu trong model và in ra field "firstname" của trang "dashboard.html" dùng Thymeleaf:

Với thẻ <input> để in giá trị ta có thể dùng thuộc tính "th:value" của Thymeleaf:

Giá trị "name" được in ra thành công

Tiếp theo, tại trang dashboard chức năng "Log out" tôi sẽ dùng thuộc tính "th:href" của Thymeleaf để thiếp lập giá trị mapping là "/" để redirect đến trang "index.html"

Hoặc các bạn có thể tạo thêm 1 mapping như "/logout" trong controller để dễ xử lý cho những nhu cầu khác, ở đây tôi dùng chung với mapping đã tạo trước đó

Qua những phần ở trên tôi đã demo một vài thuộc tính Thymeleaf hỗ trợ, tiếp theo tôi sẽ đi đến phần data, tôi sẽ thêm 1 trang "register.html" để tiến hành tạo user và lưu dữ liệu trong elasticsearch

Nguồn templates cho dashboard và register: https://themewagon.com/themes/free-responsive-bootstrap-5-html5-admin-template-sneat/

Trong UseController tạo thêm mapping "/register":

Kiểm tra và thấy trang "register.html" được tải thành công:

Tại trang register tôi cũng sẽ dùng những thuộc tính từ Thymeleaf cho form data tương tự như trang index

Tôi chỉ add thuộc tính th:field cho 2 field là "name" và "password" bởi vì field "email" tôi không khai báo trong model User

Tôi khai báo mapping cho "th:action" là "/register" -> call đến controller mapping "/register", tại đây sẽ kiểm tra "name" có tồn tại hay chưa, nếu chưa sẽ tiến hành tạo mới dữ liệu cho user còn ngược lại sẽ in ra message

Thấy user đăng ký thành công:

Kiểm tra xem dữ liệu đã được lưu thành công hay chưa, dùng extension Elasticsearch head:

=> Dữ liệu được tạo thành công

Với user được tạo mới tôi sẽ tiến hành đăng nhập để thấy có redirect đến trang dashboard hay không, trước tiên tôi cũng cần kiểm tra thông tin user đăng nhập trong controller mapping "/login" đúng hoặc không:

Kiểm tra cho kịch bản user login đúng thông tin. Tôi đã tạo user trước đó với "name" là "Mask" và "password" là "123"

=> Login success

Kiểm tra cho kịch bản user login sai thông tin. Tôi thử login với "name" là "Mask" và "password" là "123456":

Với thông tin sai sẽ redirect về lại trang login "index.html", tôi sẽ thêm 1 tag tại trang index để in ra message:

Kiểm tra lại với thông tin login sai:

=> Message in ra thành công

Tiếp theo, tại trang register tôi thử dùng thông tin user đã tạo trước đó và kiểm tra xem khi click "Sign up" -> có in ra thông báo lỗi hay không:

=> In ra thông báo lỗi thành công

Tiếp tục với kịch bản đăng ký user mới:

Kiểm tra Data trong elasticsearch:

8. Cấu hình HTTP/2:

Các bạn thấy, hiện tại khi tôi load trang thì tất các các request url có protocol là HTTP/1.1, không phải HTTP/2:

Để bật tính năng HTTP/2 trong Spring Boot, tôi sẽ vào file "application.yml" thêm 1 khai báo:

server: http2: enabled: true

Sau khi restart project -> load lại trang để thấy protocol có thay đổi hay không:

=> Protocol không thay đổi, vẫn là HTTP/1.1. Lý do là HTTP/2 chỉ hỗ trợ với giao thức HTTPS, còn hiện tại localhost sử dụng HTTP:

Để cấu hình localhost sử dụng HTTPS, ta cần bật chế độ SSL, ta cấu hình SSL trong "application.yml":

Tiến hành restart lại project và kiểm tra, nhưng lúc này nhập url là "https://localhost:8080" để thấy HTTPS có được chấp nhận hay không:

Như các bạn thấy, sau khi enable SSL -> vẫn không có thay đổi gì, kiểm tra console log và thấy lỗi:

Để xứ lý lỗi này, chúng ta cần tạo 1 certificate và thêm certificate này cấu hình trong "application.yml":

Tạo certificate:

Đầu tiên tôi tạo 1 thư mục với tên là "ssl_certificate":

Trong thư mục này, mở Command prompt lên và nhập dòng lệnh sau:

keytool -genkeypair -alias local_ssl -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore local-ssl.p12 –validity 365 -ext san=dns:localhost

Trong đó:

  • -alias: Đặt tên tuỳ ý, ở đây tôi đặt tên là "local_ssl"
  • -storetype: Để mặc định như trên

  • -keystore: Đặt tên tuỳ ý, ở đây tôi để tên là "local-ssl.p12"
  • san=dns: Để là "localhost" bởi vì tôi muốn thiết lập HTTPS cho domain là "localhost"

Sau khi nhập dòng lệnh trên -> enter:

Trong tất cả thông tin trong hình, chỉ cần quan tâm "keystore password", khuyến nghị chỉ nên nhập số cho dễ nhớ và ít sai, chú ý khi nhập password -> sẽ không in ra bất kỳ ký tự nào nhưng thực chất giá trị đã được nhập thành công. Ở đây tôi để "keystore password" là "123456"

Cuối cùng, sau khi nhập tất cả thông tin -> nhập "yes" để generate certificate. Vào thư mục "ssl_certificate" vừa tạo để kiểm tra:

=> Certificate được tạo thành công

Tiếp theo cần thêm certificate này đến thư mục "resources" của project. Ở đây tôi sẽ tạo 1 thư mục tên là "ssl_config" trong thư mục "resources" và copy certificate đến thư mục này:

Cấu trúc thư mục project:

Tiếp theo, tôi sẽ khai báo thông tin certificate trong "application.yml":

server: ssl: key-store: classpath:ssl_config/local-ssl.p12 key-store-type: PKCS12 key-store-password: 123456 enabled: true http2: enabled: true

Các bạn cần thay thế thông tin của mình như "password" cho đúng

Sau khi khai báo xong thông tin cho certificate, re-build lại project và start project sẽ thấy tại console log HTTPS đã được chấp nhận:

Tôi sẽ load lại trang với đường dẫn là "https://localhost:8080" và thấy kết quả:

Nếu các bạn gặp màn hình này thì không cần lo lắng, click "Advanced" và click "Process to localhost(unsafe)":

Kiểm tra tất cả request url:

=> Tất cả request url giao thức đã được chuyển đổi thành HTTP/2

Lưu ý dành cho những bạn nào muốn apply HTTP/2 với java 8 -> báo lỗi thì xem tại đây:

Link nguồn: https://tomcat.apache.org/tomcat-9.0-doc/config/http.html#HTTP/2_Support

Cuối cùng, bài viết khá dài vì tôi muốn mô tả chi tiết những tình huống lỗi có thể xảy ra trong quá trình làm và cách xử lý lỗi. Trong thời gian tiếp theo, có thể tôi sẽ viết về việc mã hoá password khi login bởi vì như các bạn thấy nếu sử dụng form data -> mặc định trong "payload" sẽ có thông tin username và password. Ngoài ra trong các project lớn thường không lưu password trong database, một vài project sẽ sử dụng ldap. Trong thời gian tới, nếu có thể tôi sẽ dành thời gian để demo 1 project sử dụng ldap để quản lý password.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Elasticsearch là gì ?

. Lời nói đầu. Elasticsearch là gì .

0 0 35

- vừa được xem lúc

Backup và Restore Elasticsearch snapshot với AWS S3 trong Kubernetes

Ở công ty mình vừa có mấy task devops liên quan đến scaling, clustering Elasticsearch nên viết lại đề phòng sau này cần dùng. Có một task là chuyển dữ liệu từ single-node Elasticsearch cũ lên cluster mới.

0 0 50

- vừa được xem lúc

Reindex Elasticsearch data with zero downtime

Elasticsearch là một search engine tuyệt vời cho mọi dự án muốn áp dụng chức năng search cho sản phẩm của mình, với những tính năng như là near-realtime search, auto-complete, suggestion,.... Cùng với đó là lợi thế kiến trúc distributed search system, có thể dễ dàng scaling, failing handle. Khi muốn

0 0 40

- vừa được xem lúc

Fork you ElasticSearch! How Open Source Works

ElasticSearch recently dropped its open-source licensing strategy, prompting AWS to fork it. Learn how "Open Source" actually works and how companies profit from it.

0 0 48

- vừa được xem lúc

Tìm hiểu Text và Keyword trong Elasticsearch

Giới thiệu. Khi mình mới bắt đầu tìm hiểu về Elasticsearch mình không nghĩ rằng giữa kiểu dữ liệu Text và Keyword có sự khác nhau nhưng khi vào dự án thực tế mình mới nhận ra được sự khác biệt giữa 2

0 0 140

- vừa được xem lúc

Tìm hiểu và cài đặt Elasticsearch

Elasticsearch là gì. Elasticsearch cung cấp công cụ tìm tiếm và phân tích gần như là thời gian thực, áp dụng với mọi kiểu dữ liệu - văn bản có cấu trúc hoặc phi cấu trúc, số, thông tin địa lý.

0 0 114